cast-code 1.0.3 → 1.0.5

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/README.md CHANGED
@@ -1,217 +1,217 @@
1
1
  # Cast Code
2
2
 
3
- Cast Code is a multi-agent coding CLI for day-to-day engineering work.
4
- It is designed to feel like an in-terminal AI teammate that can read your codebase, plan work, use tools, and delegate to specialist sub-agents.
3
+ A multi-agent coding CLI for day-to-day engineering work. Cast feels like an AI teammate living inside your terminal — it reads your codebase, plans work, uses tools, and delegates to specialist sub-agents.
5
4
 
6
- ## Why this project
5
+ Inspired by [Claude Code](https://claude.ai/code), [OpenAI Codex](https://openai.com/codex), and [Kimi](https://kimi.ai).
6
+ Built by [pedrocastanha](https://github.com/pedrocastanha).
7
7
 
8
- Main goal: accelerate product delivery, especially frontend bootstrap work from design prototypes.
8
+ ---
9
9
 
10
- Typical target workflow:
11
- - connect Figma MCP,
12
- - map project context,
13
- - ask Cast to scaffold screens/components/styles,
14
- - let frontend engineers focus on integration and complex business flows.
10
+ ## Why
15
11
 
16
- ## Requirements
12
+ The main goal is to accelerate product delivery, especially frontend work from design prototypes.
17
13
 
18
- - Node.js `>= 20`
19
- - npm
20
- - At least one LLM provider configured (`/config init`)
14
+ Typical workflow:
15
+ - connect Figma Desktop MCP
16
+ - map project context with `/init`
17
+ - ask Cast to scaffold screens, components, and styles
18
+ - let engineers focus on integration and business logic
21
19
 
22
- ## Install (global, from npm)
20
+ ---
21
+
22
+ ## Install
23
23
 
24
24
  ```bash
25
25
  npm install -g cast-code
26
26
  cast
27
27
  ```
28
28
 
29
- > Requires Node.js >= 20. Works on any Linux/macOS terminal: bash, zsh, fish, dash, ksh, and others.
29
+ > Requires Node.js >= 20. Works on bash, zsh, fish, dash, ksh and any POSIX-compatible shell on Linux and macOS.
30
30
 
31
- ### If `cast` is not found after install
31
+ ### `cast` not found after install?
32
32
 
33
- The npm global bin directory may not be in your PATH. Run `npm prefix -g` to find it, then add `<prefix>/bin` to your shell:
33
+ The npm global bin directory may not be in your PATH. Find it with `npm prefix -g`, then add `<prefix>/bin` to your shell config:
34
34
 
35
- **bash** (`~/.bashrc` or `~/.bash_profile`):
36
- ```bash
37
- export PATH="$(npm prefix -g)/bin:$PATH"
38
- ```
35
+ | Shell | File | Line |
36
+ |---|---|---|
37
+ | bash | `~/.bashrc` or `~/.bash_profile` | `export PATH="$(npm prefix -g)/bin:$PATH"` |
38
+ | zsh | `~/.zshrc` | `export PATH="$(npm prefix -g)/bin:$PATH"` |
39
+ | fish | `~/.config/fish/config.fish` | `fish_add_path (npm prefix -g)/bin` |
40
+ | dash / ksh | `~/.profile` | `export PATH="$(npm prefix -g)/bin:$PATH"` |
39
41
 
40
- **zsh** (`~/.zshrc`):
41
- ```zsh
42
- export PATH="$(npm prefix -g)/bin:$PATH"
43
- ```
42
+ Reload your shell (`source ~/.zshrc`, `source ~/.bashrc`, or open a new terminal), then run `cast`.
44
43
 
45
- **fish** (`~/.config/fish/config.fish`):
46
- ```fish
47
- fish_add_path (npm prefix -g)/bin
48
- ```
44
+ ---
49
45
 
50
- **dash / ksh / others** (`~/.profile`):
51
- ```sh
52
- export PATH="$(npm prefix -g)/bin:$PATH"
53
- ```
54
-
55
- After editing, reload your shell (`source ~/.zshrc`, `source ~/.bashrc`, or open a new terminal), then run `cast`.
46
+ ## First Run
56
47
 
57
- ## Install (local development)
48
+ On first launch the setup wizard runs automatically. To reconfigure at any time:
58
49
 
59
50
  ```bash
60
- npm install
61
- npm run build
62
- npm run start
51
+ /config init
63
52
  ```
64
53
 
65
- For development mode:
54
+ Config is stored at `~/.cast/config.yaml`.
66
55
 
67
- ```bash
68
- npm run start:dev
69
- ```
56
+ ---
70
57
 
71
- ## First Run
58
+ ## Providers
72
59
 
73
- On first run, configure providers/models:
60
+ Cast supports multiple LLM providers. Configure via `/config init` or set environment variables:
74
61
 
75
- ```bash
76
- /config init
77
- ```
62
+ | Variable | Provider |
63
+ |---|---|
64
+ | `ANTHROPIC_API_KEY` | Anthropic / Claude |
65
+ | `OPENAI_API_KEY` | OpenAI / GPT |
66
+ | `GOOGLE_API_KEY` | Google Gemini |
78
67
 
79
- Configuration file:
80
- - `~/.cast/config.yaml`
68
+ You can also assign different models per purpose — `default`, `subAgent`, `coder`, `architect`, `reviewer`, `planner`, `cheap` — to tune cost and performance by task type.
81
69
 
82
- ## Frontend Daily Flow (Recommended)
70
+ ---
83
71
 
84
- 1. Connect Figma MCP
72
+ ## Commands
85
73
 
86
- ```bash
87
- /mcp add
88
- ```
74
+ ### Core
89
75
 
90
- 2. Map project context
76
+ | Command | Description |
77
+ |---|---|
78
+ | `/help` | Show command guide |
79
+ | `/init` | Analyze project and generate context |
80
+ | `/project-deep` | Deep context + specialist brief |
81
+ | `/context` | Show session, tools, agents, skills, MCP status |
82
+ | `/clear` | Clear conversation history |
83
+ | `/compact` | Compact context window |
84
+ | `/exit` | Exit CLI |
91
85
 
92
- ```bash
93
- /init
94
- ```
86
+ ### Config
95
87
 
96
- `/init` is the project bootstrap command. It analyzes the repo and refreshes `.cast/context.md`.
88
+ | Command | Description |
89
+ |---|---|
90
+ | `/config` | Config menu |
91
+ | `/config show` | Show current config |
92
+ | `/config path` | Print config file path |
93
+ | `/config add-provider` | Add a new LLM provider |
94
+ | `/config set-model` | Set model by purpose |
97
95
 
98
- 3. Validate specialists
96
+ ### MCP
99
97
 
100
- ```bash
101
- /agents
102
- /skills
103
- /context
104
- ```
98
+ | Command | Description |
99
+ |---|---|
100
+ | `/mcp` | MCP hub menu |
101
+ | `/mcp list` | List configured servers |
102
+ | `/mcp tools` | List available tools |
103
+ | `/mcp add` | Add server (from templates or custom) |
104
+ | `/mcp remove` | Remove a server |
105
+ | `/mcp what` | Explain what MCP is |
105
106
 
106
- 4. Prompt for scaffold generation
107
+ ### Git
107
108
 
108
- Example prompt:
109
+ | Command | Description |
110
+ |---|---|
111
+ | `/status`, `/diff`, `/log` | Git status, diff, log |
112
+ | `/commit` | AI-generated commit message |
113
+ | `/up`, `/split-up` | Push / push with split commits |
114
+ | `/pr` | Generate pull request description |
115
+ | `/review` | Code review |
116
+ | `/fix`, `/ident`, `/release` | Fix issues, identify patterns, generate release notes |
109
117
 
110
- ```text
111
- Use Figma to extract main screens and create a full frontend scaffold:
112
- - routes
113
- - page skeletons
114
- - reusable UI components (button, table, modal, form)
115
- - design tokens and global styling
116
- - responsive behavior
117
- ```
118
+ ### Agents & Skills
118
119
 
119
- ## Useful Commands
120
+ | Command | Description |
121
+ |---|---|
122
+ | `/agents` | List specialist agents |
123
+ | `/agents create` | Create a custom agent |
124
+ | `/skills` | List skills |
125
+ | `/skills create` | Create a custom skill |
120
126
 
121
- ### Core
122
- - `/help` show command guide
123
- - `/init` analyze project and generate context
124
- - `/project-deep` generate deep context + specialist brief
125
- - `/context` show session, tools, agents, skills, MCP status
126
- - `/clear` clear conversation history
127
- - `/compact` compact context window
128
- - `/exit` exit CLI
127
+ ---
129
128
 
130
- ### Config
131
- - `/config` config menu
132
- - `/config show` show current config
133
- - `/config path` print config path
134
- - `/config add-provider` add provider
135
- - `/config set-model` set model by purpose
129
+ ## Mentions
136
130
 
137
- ### MCP
138
- - `/mcp` MCP hub menu
139
- - `/mcp list` list servers
140
- - `/mcp tools` list tools
141
- - `/mcp add` add server from templates or custom
142
- - `/mcp remove` remove server
143
- - `/mcp what` explain MCP
131
+ Inject context directly into any prompt:
144
132
 
145
- ### Git
146
- - `/status`, `/diff`, `/log`
147
- - `/commit`, `/up`, `/split-up`, `/pr`
148
- - `/review`, `/fix`, `/ident`, `/release`
133
+ ```
134
+ @src/components/Button.tsx — single file
135
+ @src/components/ — entire directory
136
+ @git:status — current git status
137
+ @git:diff — current diff
138
+ ```
149
139
 
150
- ### Agents & Skills
151
- - `/agents`, `/agents create`
152
- - `/skills`, `/skills create`
140
+ ---
153
141
 
154
- ## Mentions
142
+ ## Plan Mode
155
143
 
156
- Use mentions to inject context directly:
144
+ For complex requests Cast enters plan mode:
145
+ - asks clarifying questions
146
+ - generates a structured plan
147
+ - lets you refine, approve, or cancel
148
+ - executes with the approved plan as context
157
149
 
158
- - `@src/file.ts`
159
- - `@path/to/dir/`
160
- - `@git:status`
161
- - `@git:diff`
150
+ ---
162
151
 
163
- ## Plan Mode
152
+ ## MCP — Model Context Protocol
164
153
 
165
- For complex requests, Cast can enter plan mode:
166
- - asks clarifying questions,
167
- - generates a structured plan,
168
- - allows refine/approve/cancel,
169
- - executes with the approved plan as context.
154
+ Cast ships with templates for 30+ MCP servers across categories: Dev Tools, Design, Data, Search, Cloud, Productivity, Payments, and Browser.
170
155
 
171
- ## Providers and Model Purposes
156
+ ### Figma Desktop (recommended)
172
157
 
173
- Cast supports multiple providers and model purposes:
174
- - `default`
175
- - `subAgent`
176
- - `coder`
177
- - `architect`
178
- - `reviewer`
179
- - `planner`
180
- - `cheap`
158
+ 1. Install [Figma Desktop](https://www.figma.com/downloads/)
159
+ 2. Open a Design file and enter Dev Mode (`<>` button, top right)
160
+ 3. In the Inspect panel, enable **"Enable desktop MCP server"**
161
+ 4. In Cast: `/mcp add` → Design → Figma Desktop
162
+ 5. Restart Cast, then `/mcp` → Conectar servidores
181
163
 
182
- This enables cost/performance tuning by task type.
164
+ For HTTP servers that require OAuth, Cast handles the full OAuth 2.0 + PKCE flow automatically and stores tokens in `~/.cast/mcp-auth/`.
183
165
 
184
- ## Project Structure (high level)
166
+ ---
185
167
 
186
- - `src/modules/repl` interactive CLI and commands
187
- - `src/modules/core` deep agent orchestration and system prompt
188
- - `src/modules/agents` specialist sub-agents
189
- - `src/modules/skills` skill definitions and knowledge
190
- - `src/modules/mcp` MCP integration
191
- - `src/modules/project` project analysis/context generation
192
- - `src/modules/tasks` task and plan tools
168
+ ## Technical Stack
193
169
 
194
- ## Notes
170
+ - **Runtime**: Node.js >= 20, TypeScript
171
+ - **Framework**: NestJS (dependency injection, modular architecture)
172
+ - **LLM**: LangChain + LangGraph (multi-agent orchestration, streaming)
173
+ - **MCP**: `@modelcontextprotocol/sdk` (stdio and HTTP/SSE transports, OAuth 2.0 + PKCE)
174
+ - **Providers**: Anthropic, OpenAI, Google Gemini, Ollama
175
+ - **Config**: YAML stored at `~/.cast/config.yaml`
176
+ - **Auth tokens**: stored at `~/.cast/mcp-auth/<server>/`
195
177
 
196
- - Keep `.cast/context.md` updated for better answers.
197
- - For MCP servers requiring OAuth (like Figma), authenticate after adding and restarting Cast.
198
- - If no agents/skills appear, run `/context` and verify project-level `.cast/agents` and `.cast/skills`.
178
+ ### Project layout
199
179
 
200
- ## Environment Variables
180
+ ```
181
+ src/modules/
182
+ repl/ interactive CLI, commands, SmartInput
183
+ core/ deep agent orchestration, system prompt, plan mode
184
+ agents/ specialist sub-agents (coder, architect, reviewer…)
185
+ skills/ skill definitions and knowledge loading
186
+ mcp/ MCP client, OAuth provider, server registry, templates
187
+ project/ project analysis and context generation
188
+ tasks/ task management and plan execution tools
189
+ git/ commit, PR, review, and release generators
190
+ config/ provider and model configuration
191
+ memory/ session memory tools
192
+ mentions/ @-mention context injection
193
+ ```
201
194
 
202
- Before running, configure at least one LLM provider via `/config init` or set the relevant environment variables:
195
+ ---
203
196
 
204
- | Variable | Provider |
205
- |---|---|
206
- | `ANTHROPIC_API_KEY` | Anthropic / Claude |
207
- | `OPENAI_API_KEY` | OpenAI |
208
- | `GOOGLE_API_KEY` | Google Gemini |
197
+ ## Local Development
209
198
 
210
- Example:
199
+ ```bash
200
+ npm install
201
+ npm run build
202
+ npm run start
203
+ ```
204
+
205
+ Watch mode:
211
206
 
212
207
  ```bash
213
- export ANTHROPIC_API_KEY=sk-ant-...
214
- cast
208
+ npm run start:dev
215
209
  ```
216
210
 
217
- Or create a `.env` file in your working directory with the keys above.
211
+ ---
212
+
213
+ ## Notes
214
+
215
+ - Keep `.cast/context.md` updated — the richer the context, the better the answers.
216
+ - Project-level agents and skills live in `.cast/agents/` and `.cast/skills/` at the repo root.
217
+ - Run `/context` to verify what Cast can currently see.
@@ -34,7 +34,7 @@ let LlmService = class LlmService {
34
34
  return new _openai.ChatOpenAI({
35
35
  modelName: this.configService.getModel(),
36
36
  temperature: this.configService.getTemperature(),
37
- openAIApiKey: this.configService.getApiKey(),
37
+ apiKey: this.configService.getApiKey(),
38
38
  streaming
39
39
  });
40
40
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/common/services/llm.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { ChatOpenAI } from '@langchain/openai';\nimport { ChatOllama } from '@langchain/ollama';\nimport { BaseChatModel } from '@langchain/core/language_models/chat_models';\nimport { ConfigService } from './config.service';\n\n@Injectable()\nexport class LlmService {\n constructor(private readonly configService: ConfigService) {}\n\n createModel(streaming = false): BaseChatModel {\n const provider = this.configService.getProvider();\n\n if (provider === 'ollama') {\n return new ChatOllama({\n model: this.configService.getModel(),\n temperature: this.configService.getTemperature(),\n baseUrl: this.configService.getOllamaBaseUrl(),\n });\n }\n\n return new ChatOpenAI({\n modelName: this.configService.getModel(),\n temperature: this.configService.getTemperature(),\n openAIApiKey: this.configService.getApiKey(),\n streaming,\n });\n }\n\n createStreamingModel(): BaseChatModel {\n return this.createModel(true);\n }\n}\n"],"names":["LlmService","createModel","streaming","provider","configService","getProvider","ChatOllama","model","getModel","temperature","getTemperature","baseUrl","getOllamaBaseUrl","ChatOpenAI","modelName","openAIApiKey","getApiKey","createStreamingModel"],"mappings":";;;;+BAOaA;;;eAAAA;;;wBAPc;wBACA;wBACA;+BAEG;;;;;;;;;;AAGvB,IAAA,AAAMA,aAAN,MAAMA;IAGXC,YAAYC,YAAY,KAAK,EAAiB;QAC5C,MAAMC,WAAW,IAAI,CAACC,aAAa,CAACC,WAAW;QAE/C,IAAIF,aAAa,UAAU;YACzB,OAAO,IAAIG,kBAAU,CAAC;gBACpBC,OAAO,IAAI,CAACH,aAAa,CAACI,QAAQ;gBAClCC,aAAa,IAAI,CAACL,aAAa,CAACM,cAAc;gBAC9CC,SAAS,IAAI,CAACP,aAAa,CAACQ,gBAAgB;YAC9C;QACF;QAEA,OAAO,IAAIC,kBAAU,CAAC;YACpBC,WAAW,IAAI,CAACV,aAAa,CAACI,QAAQ;YACtCC,aAAa,IAAI,CAACL,aAAa,CAACM,cAAc;YAC9CK,cAAc,IAAI,CAACX,aAAa,CAACY,SAAS;YAC1Cd;QACF;IACF;IAEAe,uBAAsC;QACpC,OAAO,IAAI,CAAChB,WAAW,CAAC;IAC1B;IAvBA,YAAY,AAAiBG,aAA4B,CAAE;aAA9BA,gBAAAA;IAA+B;AAwB9D"}
1
+ {"version":3,"sources":["../../../src/common/services/llm.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { ChatOpenAI } from '@langchain/openai';\nimport { ChatOllama } from '@langchain/ollama';\nimport { BaseChatModel } from '@langchain/core/language_models/chat_models';\nimport { ConfigService } from './config.service';\n\n@Injectable()\nexport class LlmService {\n constructor(private readonly configService: ConfigService) {}\n\n createModel(streaming = false): BaseChatModel {\n const provider = this.configService.getProvider();\n\n if (provider === 'ollama') {\n return new ChatOllama({\n model: this.configService.getModel(),\n temperature: this.configService.getTemperature(),\n baseUrl: this.configService.getOllamaBaseUrl(),\n });\n }\n\n return new ChatOpenAI({\n modelName: this.configService.getModel(),\n temperature: this.configService.getTemperature(),\n apiKey: this.configService.getApiKey(),\n streaming,\n });\n }\n\n createStreamingModel(): BaseChatModel {\n return this.createModel(true);\n }\n}\n"],"names":["LlmService","createModel","streaming","provider","configService","getProvider","ChatOllama","model","getModel","temperature","getTemperature","baseUrl","getOllamaBaseUrl","ChatOpenAI","modelName","apiKey","getApiKey","createStreamingModel"],"mappings":";;;;+BAOaA;;;eAAAA;;;wBAPc;wBACA;wBACA;+BAEG;;;;;;;;;;AAGvB,IAAA,AAAMA,aAAN,MAAMA;IAGXC,YAAYC,YAAY,KAAK,EAAiB;QAC5C,MAAMC,WAAW,IAAI,CAACC,aAAa,CAACC,WAAW;QAE/C,IAAIF,aAAa,UAAU;YACzB,OAAO,IAAIG,kBAAU,CAAC;gBACpBC,OAAO,IAAI,CAACH,aAAa,CAACI,QAAQ;gBAClCC,aAAa,IAAI,CAACL,aAAa,CAACM,cAAc;gBAC9CC,SAAS,IAAI,CAACP,aAAa,CAACQ,gBAAgB;YAC9C;QACF;QAEA,OAAO,IAAIC,kBAAU,CAAC;YACpBC,WAAW,IAAI,CAACV,aAAa,CAACI,QAAQ;YACtCC,aAAa,IAAI,CAACL,aAAa,CAACM,cAAc;YAC9CK,QAAQ,IAAI,CAACX,aAAa,CAACY,SAAS;YACpCd;QACF;IACF;IAEAe,uBAAsC;QACpC,OAAO,IAAI,CAAChB,WAAW,CAAC;IAC1B;IAvBA,YAAY,AAAiBG,aAA4B,CAAE;aAA9BA,gBAAAA;IAA+B;AAwB9D"}
@@ -49,7 +49,7 @@ let MultiLlmService = class MultiLlmService {
49
49
  ...temperature !== undefined ? {
50
50
  temperature
51
51
  } : {},
52
- openAIApiKey: config.apiKey,
52
+ apiKey: config.apiKey,
53
53
  configuration: {
54
54
  baseURL: config.baseUrl
55
55
  },
@@ -81,7 +81,7 @@ let MultiLlmService = class MultiLlmService {
81
81
  ...temperature !== undefined ? {
82
82
  temperature
83
83
  } : {},
84
- openAIApiKey: config.apiKey,
84
+ apiKey: config.apiKey,
85
85
  configuration: {
86
86
  baseURL: config.baseUrl || 'https://api.moonshot.cn/v1'
87
87
  },
@@ -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 openAIApiKey: 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 openAIApiKey: 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","openAIApiKey","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,cAAcJ,OAAOK,MAAM;oBAC3BC,eAAe;wBACbC,SAASP,OAAOQ,OAAO;oBACzB;oBACApB;oBACAqB,aAAarB;gBACf;YAEF,KAAK;gBACH,OAAO,IAAIsB,wBAAa,CAAC;oBACvBR,WAAWR;oBACX,GAAIC,gBAAgBQ,YAAY;wBAAER;oBAAY,IAAI,CAAC,CAAC;oBACpDgB,iBAAiBX,OAAOK,MAAM;oBAC9BO,iBAAiBZ,OAAOQ,OAAO;oBAC/BpB;gBACF;YAEF,KAAK;gBACH,OAAO,IAAIyB,mCAAsB,CAAC;oBAChCX,WAAWR;oBACX,GAAIC,gBAAgBQ,YAAY;wBAAER;oBAAY,IAAI,CAAC,CAAC;oBACpDU,QAAQL,OAAOK,MAAM;oBACrBjB;gBACF;YAEF,KAAK;gBACH,OAAO,IAAIa,kBAAU,CAAC;oBACpBC,WAAWR;oBACX,GAAIC,gBAAgBQ,YAAY;wBAAER;oBAAY,IAAI,CAAC,CAAC;oBACpDS,cAAcJ,OAAOK,MAAM;oBAC3BC,eAAe;wBACbC,SAASP,OAAOQ,OAAO,IAAI;oBAC7B;oBACApB;oBACAqB,aAAarB;gBACf;YAEF,KAAK;gBACH,OAAO,IAAI0B,kBAAU,CAAC;oBACpBpB;oBACA,GAAIC,gBAAgBQ,YAAY;wBAAER;oBAAY,IAAI,CAAC,CAAC;oBACpDa,SAASR,OAAOQ,OAAO,IAAI;gBAC7B;YAEF;gBACE,MAAM,IAAIhB,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 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"}
@@ -235,14 +235,20 @@ let ConfigCommandsService = class ConfigCommandsService {
235
235
  };
236
236
  } else {
237
237
  console.log(_chalk.default.gray(`→ Obtenha sua API key em: ${meta.websiteUrl}`));
238
- const apiKey = await (0, _promptswithesc.inputWithEsc)({
238
+ const apiKeyRaw = await (0, _promptswithesc.inputWithEsc)({
239
239
  message: `API Key para ${meta.name}:`,
240
- validate: (v)=>v.length > 5 || 'API key muito curta'
240
+ validate: (v)=>{
241
+ const clean = v.trim();
242
+ if (clean.length <= 5) return 'API key muito curta';
243
+ if (/[\s%]/.test(clean)) return 'API key contém caracteres inválidos (espaços ou %)';
244
+ return true;
245
+ }
241
246
  });
242
- if (apiKey === null) {
247
+ if (apiKeyRaw === null) {
243
248
  console.log(_chalk.default.yellow('\n❌ Cancelado.\n'));
244
249
  return;
245
250
  }
251
+ const apiKey = apiKeyRaw.trim();
246
252
  const useCustom = await (0, _promptswithesc.confirmWithEsc)({
247
253
  message: 'Usar URL customizada?',
248
254
  default: false
@@ -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 apiKey = await inputWithEsc({\n message: `API Key para ${meta.name}:`,\n validate: (v) => v.length > 5 || 'API key muito curta',\n });\n\n if (apiKey === null) {\n console.log(chalk.yellow('\\n❌ Cancelado.\\n'));\n return;\n }\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","apiKey","validate","v","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', '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":";;;;+BA0BaA;;;eAAAA;;;wBA1Bc;8DACT;sCACmB;mCACH;6BAM3B;gCAOA;;;;;;;;;;;;;;;AAUA,IAAA,AAAMA,wBAAN,MAAMA;IAMX,MAAMC,oBAAoBC,IAAc,EAAEC,UAAuB,EAAiB;QAChF,MAAMC,aAAaF,IAAI,CAAC,EAAE;QAC1B,MAAMG,kBAAkB;YAAC;YAAQ;YAAS;YAAgB;YAAa;SAAkB,CAACC,QAAQ,CAACF,cAAc;QAEjH,IAAIC,iBAAiB;YACnBF,YAAYI;QACd;QAEA,IAAI;YACF,OAAQH;gBACR,KAAK;gBACL,KAAK;oBACH,MAAM,IAAI,CAACI,cAAc,CAAC,IAAM,IAAI,CAACC,WAAW,CAACC,eAAe;oBAChE;gBAEF,KAAK;oBACH,MAAM,IAAI,CAACC,UAAU;oBACrB;gBAEF,KAAK;oBACH,MAAM,IAAI,CAACH,cAAc,CAAC,IAAM,IAAI,CAACI,sBAAsB;oBAC3D;gBAEF,KAAK;oBACH,MAAM,IAAI,CAACJ,cAAc,CAAC,IAAM,IAAI,CAACK,mBAAmB;oBACxD;gBAEF,KAAK;oBACH,MAAM,IAAI,CAACL,cAAc,CAAC,IAAM,IAAI,CAACM,yBAAyB;oBAC9D;gBAEF,KAAK;oBACHC,QAAQC,GAAG,CAAC,IAAI,CAACC,aAAa,CAACC,aAAa;oBAC5C;gBAEF;oBACE,IAAIf,YAAY;wBACd,MAAM,IAAI,CAACgB,cAAc,CAAChB;oBAC5B,OAAO;wBACL,MAAM,IAAI,CAACQ,UAAU;oBACvB;YACJ;QACA,SAAU;YACR,IAAIN,iBAAiB;gBACnBF,YAAYiB;YACd;QACF;IACF;IAEA,MAAcZ,eAAkBa,EAAoB,EAAiB;QACnE,MAAMC,SAAS,MAAMC,IAAAA,uBAAO,EAACF;QAC7B,IAAIC,WAAW,MAAM;YACnBP,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;QAC3B;IACF;IAEA,MAAcN,eAAehB,UAAsB,EAAiB;QAClE,MAAMuB,IAAI,CAACC,IAAcC,QAAQC,MAAM,CAACC,KAAK,CAACH;QAC9C,MAAMI,SAAS;YACbC,MAAM;YACNC,OAAO;YACPR,QAAQ;YACRS,MAAM;YACNC,MAAM;YACNC,OAAO;QACT;QAEA,MAAM,IAAI,CAACnB,aAAa,CAACoB,UAAU;QAEnC,MAAO,KAAM;YACXX,EAAE,CAAC,EAAE,EAAEK,OAAOC,IAAI,GAAGD,OAAOI,IAAI,CAAC,0BAA0B,EAAEJ,OAAOK,KAAK,CAAC,EAAE,CAAC;YAC7EV,EAAE,GAAGK,OAAOG,IAAI,GAAG,IAAII,MAAM,CAAC,MAAMP,OAAOK,KAAK,CAAC,IAAI,CAAC;YAEtD,MAAMG,SAAS,MAAMhB,IAAAA,uBAAO,EAAC,IAAMpB,WAAWqC,SAAS,CAAC,uBAAuB;oBAC7E;wBAAEC,KAAK;wBAAKC,OAAO;wBAA0BC,aAAa;oBAA+B;oBACzF;wBAAEF,KAAK;wBAAKC,OAAO;wBAAiCC,aAAa;oBAAkB;oBACnF;wBAAEF,KAAK;wBAAKC,OAAO;wBAAsBC,aAAa;oBAAqB;oBAC3E;wBAAEF,KAAK;wBAAKC,OAAO;wBAAoBC,aAAa;oBAAkB;oBACtE;wBAAEF,KAAK;wBAAKC,OAAO;wBAAqBC,aAAa;oBAAiC;oBACtF;wBAAEF,KAAK;wBAAKC,OAAO;wBAA0BC,aAAa;oBAAuB;oBACjF;wBAAEF,KAAK;wBAAKC,OAAO;wBAAQC,aAAa;oBAAiB;iBAC1D;YAED,IAAIJ,WAAW,MAAM;gBACnBxB,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;gBACzB;YACF;YAEA,OAAQc;gBACN,KAAK;oBACH,MAAM,IAAI,CAAC5B,UAAU;oBACrB;gBACF,KAAK;oBACH,MAAM,IAAI,CAACH,cAAc,CAAC,IAAM,IAAI,CAACC,WAAW,CAACC,eAAe;oBAChE;gBACF,KAAK;oBACH,MAAM,IAAI,CAACF,cAAc,CAAC,IAAM,IAAI,CAACI,sBAAsB;oBAC3D;gBACF,KAAK;oBACH,MAAM,IAAI,CAACJ,cAAc,CAAC,IAAM,IAAI,CAACM,yBAAyB;oBAC9D;gBACF,KAAK;oBACH,MAAM,IAAI,CAACN,cAAc,CAAC,IAAM,IAAI,CAACK,mBAAmB;oBACxD;gBACF,KAAK;oBACHE,QAAQC,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,CAACC,aAAa,CAACC,aAAa,GAAG,EAAE,CAAC;oBAC1D;gBACF,KAAK;oBACH;YACJ;QACF;IACF;IAEA,MAAcP,aAA4B;QACxC,MAAM,IAAI,CAACM,aAAa,CAACoB,UAAU;QACnC,MAAMO,SAAS,IAAI,CAAC3B,aAAa,CAAC4B,SAAS;QAE3C,MAAMnB,IAAI,CAACC,IAAcC,QAAQC,MAAM,CAACC,KAAK,CAACH;QAC9C,MAAMI,SAAS;YACbC,MAAM;YACNC,OAAO;YACPa,KAAK;YACLrB,QAAQ;YACRS,MAAM;YACNC,MAAM;YACNC,OAAO;QACT;QAEAV,EAAE,CAAC,EAAE,EAAEK,OAAOC,IAAI,GAAGD,OAAOI,IAAI,CAAC,sBAAsB,EAAEJ,OAAOK,KAAK,CAAC,EAAE,CAAC;QACzEV,EAAE,GAAGK,OAAOG,IAAI,GAAG,IAAII,MAAM,CAAC,MAAMP,OAAOK,KAAK,CAAC,IAAI,CAAC;QAEtDV,EAAE,GAAGK,OAAON,MAAM,CAAC,2BAA2B,EAAEM,OAAOK,KAAK,CAAC,EAAE,CAAC;QAChE,MAAMW,YAAY,IAAI,CAAC9B,aAAa,CAAC+B,sBAAsB;QAC3D,IAAID,UAAUE,MAAM,KAAK,GAAG;YAC1BvB,EAAE,GAAGK,OAAOG,IAAI,CAAC,8BAA8B,EAAEH,OAAOK,KAAK,CAAC,EAAE,CAAC;YACjEV,EAAE,GAAGK,OAAOG,IAAI,CAAC,iDAAiD,EAAEH,OAAOK,KAAK,CAAC,EAAE,CAAC;QACtF,OAAO;YACL,KAAK,MAAMc,YAAYH,UAAW;gBAChC,MAAMI,OAAOC,8BAAiB,CAACF,SAAS;gBACxC,MAAMG,eAAe,IAAI,CAACpC,aAAa,CAACqC,oBAAoB,CAACJ;gBAC7D,MAAMK,SAASF,eACX,GAAGtB,OAAOE,KAAK,CAAC,CAAC,CAAC,GAClB,GAAGF,OAAOe,GAAG,CAAC,CAAC,CAAC;gBACpBpB,EAAE,CAAC,GAAG,EAAE6B,OAAO,CAAC,EAAEJ,KAAKK,IAAI,CAAC,CAAC,EAAEzB,OAAOG,IAAI,CAAC,CAAC,EAAEgB,SAAS,CAAC,EAAEnB,OAAOK,KAAK,CAAC,EAAE,CAAC;YAC5E;QACF;QAEAV,EAAE,CAAC,EAAE,EAAEK,OAAON,MAAM,CAAC,wBAAwB,EAAEM,OAAOK,KAAK,CAAC,EAAE,CAAC;QAC/D,KAAK,MAAMqB,WAAWC,2BAAc,CAAE;YACpC,MAAMC,cAAcf,OAAOgB,MAAM,CAACH,QAAQI,KAAK,CAAC;YAChD,IAAIF,aAAa;gBACf,MAAMG,eAAeV,8BAAiB,CAACO,YAAYT,QAAQ,CAAC,CAACM,IAAI;gBACjE9B,EAAE,CAAC,GAAG,EAAEK,OAAOC,IAAI,GAAGyB,QAAQf,KAAK,CAACqB,MAAM,CAAC,MAAMhC,OAAOK,KAAK,CAAC,GAAG,EAAEuB,YAAYK,KAAK,CAAC,EAAE,CAAC;gBACxFtC,EAAE,CAAC,GAAG,EAAEK,OAAOG,IAAI,GAAG,IAAII,MAAM,CAAC,IAAI,GAAG,EAAEwB,eAAe/B,OAAOK,KAAK,CAAC,EAAE,CAAC;YAC3E;QACF;QAEAV,EAAE,CAAC,EAAE,EAAEK,OAAOG,IAAI,CAAC,YAAY,EAAE,IAAI,CAACjB,aAAa,CAACC,aAAa,KAAKa,OAAOK,KAAK,CAAC,IAAI,CAAC;IAC1F;IAEA,MAAcxB,yBAAwC;QACpD,MAAM,IAAI,CAACK,aAAa,CAACoB,UAAU;QAEnC,MAAM4B,qBAAqBC,OAAOC,IAAI,CAACf,8BAAiB,EAAEgB,MAAM,CAC9D,CAACC,IAAM,CAAC,IAAI,CAACpD,aAAa,CAACqC,oBAAoB,CAACe;QAGlD,IAAIJ,mBAAmBhB,MAAM,KAAK,GAAG;YACnClC,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;YACzB;QACF;QAEAV,QAAQC,GAAG,CAACQ,cAAK,CAACQ,IAAI,CAAC;QACvBjB,QAAQC,GAAG,CAACQ,cAAK,CAACU,IAAI,CAAC;QAEvB,MAAMgB,WAAW,MAAMoB,IAAAA,6BAAa,EAAe;YACjDC,SAAS;YACTC,SAASP,mBAAmBQ,GAAG,CAAC,CAACJ,IAAO,CAAA;oBACtCb,MAAM,GAAGJ,8BAAiB,CAACiB,EAAE,CAACb,IAAI,CAAC,GAAG,EAAEJ,8BAAiB,CAACiB,EAAE,CAAC1B,WAAW,EAAE;oBAC1EkB,OAAOQ;gBACT,CAAA;QACF;QAEA,IAAInB,aAAa,MAAM;YACrBnC,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;YACzB;QACF;QAEA,MAAM0B,OAAOC,8BAAiB,CAACF,SAAS;QAExC,IAAIN,SAAgD,CAAC;QAErD,IAAIM,aAAa,UAAU;YACzB,MAAMwB,UAAU,MAAMC,IAAAA,4BAAY,EAAC;gBACjCJ,SAAS;gBACTK,SAASzB,KAAK0B,cAAc;YAC9B;YACA,IAAIH,YAAY,MAAM;gBACpB3D,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;gBACzB;YACF;YACAmB,SAAS;gBAAE8B;YAAQ;QACrB,OAAO;YACL3D,QAAQC,GAAG,CAACQ,cAAK,CAACU,IAAI,CAAC,CAAC,0BAA0B,EAAEiB,KAAK2B,UAAU,EAAE;YAErE,MAAMC,YAAY,MAAMJ,IAAAA,4BAAY,EAAC;gBACnCJ,SAAS,CAAC,aAAa,EAAEpB,KAAKK,IAAI,CAAC,CAAC,CAAC;gBACrCwB,UAAU,CAACC;oBACT,MAAMC,QAAQD,EAAEE,IAAI;oBACpB,IAAID,MAAMjC,MAAM,IAAI,GAAG,OAAO;oBAC9B,IAAI,QAAQmC,IAAI,CAACF,QAAQ,OAAO;oBAChC,OAAO;gBACT;YACF;YAEA,IAAIH,cAAc,MAAM;gBACtBhE,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;gBACzB;YACF;YACA,MAAM4D,SAASN,UAAUI,IAAI;YAE7B,MAAMG,YAAY,MAAMC,IAAAA,8BAAc,EAAC;gBACrChB,SAAS;gBACTK,SAAS;YACX;YAEA,IAAIU,cAAc,MAAM;gBACtBvE,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;gBACzB;YACF;YAEA,IAAIiD;YACJ,IAAIY,WAAW;gBACbZ,UAAU,MAAMC,IAAAA,4BAAY,EAAC;oBAC3BJ,SAAS;oBACTK,SAASzB,KAAK0B,cAAc;gBAC9B;gBACA,IAAIH,YAAY,MAAM;oBACpB3D,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;oBACzB;gBACF;YACF;YAEAmB,SAAS;gBAAEyC;gBAAQX;YAAQ;QAC7B;QAEA,MAAM,IAAI,CAACzD,aAAa,CAACuE,WAAW,CAACtC,UAAUN;QAC/C7B,QAAQC,GAAG,CAACQ,cAAK,CAACS,KAAK,CAAC,CAAC,aAAa,EAAEkB,KAAKK,IAAI,CAAC,0BAA0B,CAAC;IAC/E;IAEA,MAAc1C,4BAA2C;QACvD,MAAM,IAAI,CAACG,aAAa,CAACoB,UAAU;QAEnC,MAAMoD,sBAAsB,IAAI,CAACxE,aAAa,CAAC+B,sBAAsB;QACrE,IAAIyC,oBAAoBxC,MAAM,KAAK,GAAG;YACpClC,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;YACzB;QACF;QAEAV,QAAQC,GAAG,CAACQ,cAAK,CAACU,IAAI,CAAC;QAEvB,MAAMgB,WAAW,MAAMoB,IAAAA,6BAAa,EAAe;YACjDC,SAAS;YACTC,SAASiB,oBAAoBhB,GAAG,CAAC,CAACJ,IAAO,CAAA;oBACvCb,MAAMJ,8BAAiB,CAACiB,EAAE,CAACb,IAAI;oBAC/BK,OAAOQ;gBACT,CAAA;QACF;QAEA,IAAInB,aAAa,MAAM;YACrBnC,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;YACzB;QACF;QAEA,MAAMiE,gBAAgB,MAAMH,IAAAA,8BAAc,EAAC;YACzChB,SAAS,CAAC,+BAA+B,EAAEnB,8BAAiB,CAACF,SAAS,CAACM,IAAI,CAAC,CAAC,CAAC;YAC9EoB,SAAS;QACX;QAEA,IAAIc,kBAAkB,QAAQ,CAACA,eAAe;YAC5C3E,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;YACzB;QACF;QAEA,MAAMmB,SAAS,IAAI,CAAC3B,aAAa,CAAC4B,SAAS;QAC3C,OAAOD,OAAOG,SAAS,CAACG,SAAS;QACjC,MAAM,IAAI,CAACjC,aAAa,CAAC0E,UAAU,CAAC/C;QACpC7B,QAAQC,GAAG,CAACQ,cAAK,CAACS,KAAK,CAAC,CAAC,wBAAwB,CAAC;IACpD;IAEA,MAAcpB,sBAAqC;QACjD,MAAM,IAAI,CAACI,aAAa,CAACoB,UAAU;QAEnC,MAAM4B,qBAAqB,IAAI,CAAChD,aAAa,CAAC+B,sBAAsB;QACpE,IAAIiB,mBAAmBhB,MAAM,KAAK,GAAG;YACnClC,QAAQC,GAAG,CACTQ,cAAK,CAACsB,GAAG,CAAC;YAEZ;QACF;QAEA/B,QAAQC,GAAG,CAACQ,cAAK,CAACQ,IAAI,CAAC;QACvBjB,QAAQC,GAAG,CAACQ,cAAK,CAACU,IAAI,CAAC;QAEvB,MAAMuB,UAAU,MAAMa,IAAAA,6BAAa,EAAe;YAChDC,SAAS;YACTC,SAASd,2BAAc,CAACe,GAAG,CAAC,CAACJ,IAAO,CAAA;oBAClCb,MAAM,GAAGa,EAAE3B,KAAK,CAAC,GAAG,EAAE2B,EAAE1B,WAAW,EAAE;oBACrCkB,OAAOQ,EAAER,KAAK;gBAChB,CAAA;QACF;QAEA,IAAIJ,YAAY,MAAM;YACpB1C,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;YACzB;QACF;QAEA,MAAMyB,WAAW,MAAMoB,IAAAA,6BAAa,EAAe;YACjDC,SAAS;YACTC,SAASP,mBAAmBQ,GAAG,CAAC,CAACJ,IAAO,CAAA;oBACtCb,MAAMJ,8BAAiB,CAACiB,EAAE,CAACb,IAAI;oBAC/BK,OAAOQ;gBACT,CAAA;QACF;QAEA,IAAInB,aAAa,MAAM;YACrBnC,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;YACzB;QACF;QAEA,MAAM0B,OAAOC,8BAAiB,CAACF,SAAS;QAExC,MAAM0C,aAAa,MAAML,IAAAA,8BAAc,EAAC;YACtChB,SAAS,CAAC,iCAAiC,EAAEpB,KAAKK,IAAI,CAAC,CAAC,CAAC;YACzDoB,SAAS;QACX;QAEA,IAAIgB,eAAe,MAAM;YACvB7E,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;YACzB;QACF;QAEA,IAAIuC;QAEJ,IAAI4B,YAAY;YACd5B,QAAQ,MAAMM,IAAAA,6BAAa,EAAS;gBAClCC,SAAS;gBACTC,SAAS;uBACJrB,KAAK0C,aAAa,CAACpB,GAAG,CAAC,CAACqB,IAAO,CAAA;4BAAEtC,MAAMsC;4BAAGjC,OAAOiC;wBAAE,CAAA;oBACtD;wBAAEtC,MAAM;wBAAqBK,OAAO;oBAAa;iBAClD;YACH;YAEA,IAAIG,UAAU,MAAM;gBAClBjD,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;gBACzB;YACF;YAEA,IAAIuC,UAAU,cAAc;gBAC1BA,QAAQ,MAAMW,IAAAA,4BAAY,EAAC;oBACzBJ,SAAS;oBACTK,SAASzB,KAAK0C,aAAa,CAAC,EAAE;gBAChC;gBACA,IAAI7B,UAAU,MAAM;oBAClBjD,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;oBACzB;gBACF;YACF;QACF,OAAO;YACLuC,QAAQ,MAAMW,IAAAA,4BAAY,EAAC;gBACzBJ,SAAS;gBACTK,SAASzB,KAAK0C,aAAa,CAAC,EAAE;YAChC;YACA,IAAI7B,UAAU,MAAM;gBAClBjD,QAAQC,GAAG,CAACQ,cAAK,CAACC,MAAM,CAAC;gBACzB;YACF;QACF;QAEA,MAAM,IAAI,CAACR,aAAa,CAAC8E,QAAQ,CAACtC,SAAS;YACzCP;YACAc;QACF;QAEA,MAAMgC,eAAetC,2BAAc,CAACuC,IAAI,CAAC,CAAC5B,IAAMA,EAAER,KAAK,KAAKJ,UAAUf;QACtE3B,QAAQC,GAAG,CACTQ,cAAK,CAACS,KAAK,CAAC,CAAC,iBAAiB,EAAE+D,aAAa,eAAe,EAAEhC,MAAM,EAAE,CAAC;IAE3E;IAzYA,YACE,AAAiB/C,aAAmC,EACpD,AAAiBR,WAA8B,CAC/C;aAFiBQ,gBAAAA;aACAR,cAAAA;IAChB;AAuYL"}
@@ -111,16 +111,21 @@ let InitConfigService = class InitConfigService {
111
111
  };
112
112
  }
113
113
  console.log(_chalk.default.gray(` → Obtenha sua API key em: ${meta.websiteUrl}`));
114
- const apiKey = await (0, _promptswithesc.inputWithEsc)({
114
+ const apiKeyRaw = await (0, _promptswithesc.inputWithEsc)({
115
115
  message: `API Key para ${meta.name}:`,
116
116
  validate: (value)=>{
117
- if (!value || value.trim().length < 10) {
117
+ const clean = value.trim();
118
+ if (!clean || clean.length < 10) {
118
119
  return 'Por favor, insira uma API key válida';
119
120
  }
121
+ if (/[\s%]/.test(clean)) {
122
+ return 'API key contém caracteres inválidos (espaços ou %)';
123
+ }
120
124
  return true;
121
125
  }
122
126
  });
123
- if (apiKey === null) return null;
127
+ if (apiKeyRaw === null) return null;
128
+ const apiKey = apiKeyRaw.trim();
124
129
  const useCustomUrl = await (0, _promptswithesc.confirmWithEsc)({
125
130
  message: 'Usar URL de API customizada (ex: OpenRouter, proxy)?',
126
131
  default: false