@nimbuslab/cli 0.15.0 → 0.16.0

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.
@@ -11,6 +11,24 @@ const USER_MEMORY = join(HOME, ".claude", "USER_MEMORY.md")
11
11
  const LOLA_MEMORY_URL = "https://lola.nimbuslab.com.br/sse"
12
12
  const LOLA_MEMORY_NAME = "lola-memory"
13
13
 
14
+ // Gemini CLI
15
+ const GEMINI_DIR = join(HOME, ".gemini")
16
+ const GEMINI_SETTINGS = join(GEMINI_DIR, "GEMINI.md")
17
+
18
+ // Tipos de agent
19
+ type AgentType = "claude" | "gemini" | "all"
20
+
21
+ // Helpers de detecção
22
+ function hasClaudeCLI(): boolean {
23
+ const result = Bun.spawnSync(["which", "claude"], { stdout: "pipe" })
24
+ return result.exitCode === 0
25
+ }
26
+
27
+ function hasGeminiCLI(): boolean {
28
+ const result = Bun.spawnSync(["which", "gemini"], { stdout: "pipe" })
29
+ return result.exitCode === 0
30
+ }
31
+
14
32
  async function installLolaMemoryMCP(): Promise<void> {
15
33
  console.log()
16
34
  console.log(pc.cyan(" Configurando lola-memory MCP..."))
@@ -61,261 +79,206 @@ async function installLolaMemoryMCP(): Promise<void> {
61
79
  console.log(pc.dim(" memory_stats - Ver estatisticas"))
62
80
  }
63
81
 
64
- async function installLola(): Promise<void> {
65
- console.log()
66
- console.log(pc.cyan(" Lola - Code Agent da nimbuslab"))
67
- console.log(pc.dim(" ==============================="))
82
+ // ============================================
83
+ // GEMINI CLI
84
+ // ============================================
85
+
86
+ async function installGeminiCLI(): Promise<boolean> {
68
87
  console.log()
88
+ console.log(pc.cyan(" Instalando Gemini CLI..."))
69
89
 
70
- const isUpdate = existsSync(LOLA_DIR)
90
+ const result = Bun.spawnSync(["npm", "install", "-g", "@google/gemini-cli"], {
91
+ stdout: "inherit",
92
+ stderr: "inherit",
93
+ })
71
94
 
72
- if (isUpdate) {
73
- console.log(pc.dim(` Lola ja instalada em ${LOLA_DIR}`))
74
- console.log(pc.cyan(" Atualizando..."))
95
+ if (result.exitCode !== 0) {
96
+ console.log(pc.red(" Erro ao instalar Gemini CLI"))
97
+ console.log(pc.dim(" Tente manualmente: npm install -g @google/gemini-cli"))
98
+ return false
99
+ }
75
100
 
76
- // Verificar se tem mudancas locais
77
- const statusCheck = Bun.spawnSync(["git", "status", "--porcelain"], {
78
- cwd: LOLA_DIR,
79
- stdout: "pipe",
80
- })
81
- const hasLocalChanges = statusCheck.stdout.toString().trim().length > 0
101
+ console.log(pc.green(" Gemini CLI instalado!"))
102
+ return true
103
+ }
82
104
 
83
- // Stash se tiver mudancas locais
84
- if (hasLocalChanges) {
85
- console.log(pc.dim(" Salvando mudancas locais..."))
86
- Bun.spawnSync(["git", "stash", "--quiet"], {
87
- cwd: LOLA_DIR,
88
- stdout: "pipe",
89
- stderr: "pipe",
90
- })
91
- }
105
+ async function installGeminiMCP(): Promise<void> {
106
+ console.log()
107
+ console.log(pc.cyan(" Configurando MCP no Gemini..."))
92
108
 
93
- // Pull
94
- const result = Bun.spawnSync(["git", "pull", "--quiet"], {
95
- cwd: LOLA_DIR,
96
- stdout: "inherit",
97
- stderr: "inherit",
98
- })
109
+ const settingsPath = join(GEMINI_DIR, "settings.json")
99
110
 
100
- // Restaurar mudancas locais se tinha
101
- if (hasLocalChanges) {
102
- console.log(pc.dim(" Restaurando mudancas locais..."))
103
- const stashPop = Bun.spawnSync(["git", "stash", "pop", "--quiet"], {
104
- cwd: LOLA_DIR,
105
- stdout: "pipe",
106
- stderr: "pipe",
107
- })
111
+ // Criar diretório se não existir
112
+ if (!existsSync(GEMINI_DIR)) {
113
+ await Bun.$`mkdir -p ${GEMINI_DIR}`
114
+ }
108
115
 
109
- if (stashPop.exitCode !== 0) {
110
- console.log(pc.yellow(" Aviso: conflito ao restaurar mudancas locais"))
111
- console.log(pc.dim(" Verifique ~/.lola e resolva manualmente: git stash pop"))
112
- }
116
+ // Ler settings existente ou criar novo
117
+ let settings: Record<string, unknown> = {}
118
+ if (existsSync(settingsPath)) {
119
+ try {
120
+ const content = await Bun.file(settingsPath).text()
121
+ settings = JSON.parse(content)
122
+ } catch {
123
+ // Se falhar, começa do zero
113
124
  }
125
+ }
114
126
 
115
- if (result.exitCode !== 0) {
116
- console.log(pc.red(" Erro ao atualizar Lola"))
117
- process.exit(1)
118
- }
127
+ // Verificar se tem lola-memory configurado
128
+ const mcpServers = (settings.mcpServers || {}) as Record<string, unknown>
129
+ if (mcpServers[LOLA_MEMORY_NAME]) {
130
+ console.log(pc.green(" MCP lola-memory ja configurado no Gemini"))
131
+ return
132
+ }
119
133
 
120
- console.log(pc.green(" Atualizado!"))
121
- } else {
122
- console.log(pc.cyan(` Instalando Lola em ${LOLA_DIR}...`))
134
+ // Adicionar lola-memory
135
+ mcpServers[LOLA_MEMORY_NAME] = {
136
+ url: LOLA_MEMORY_URL
137
+ }
138
+ settings.mcpServers = mcpServers
123
139
 
124
- const result = Bun.spawnSync(["git", "clone", "--quiet", LOLA_REPO, LOLA_DIR], {
125
- stdout: "inherit",
126
- stderr: "inherit",
127
- })
140
+ // Salvar
141
+ await Bun.write(settingsPath, JSON.stringify(settings, null, 2))
142
+ console.log(pc.green(" MCP lola-memory adicionado ao Gemini!"))
143
+ }
128
144
 
129
- if (result.exitCode !== 0) {
130
- console.log(pc.red(" Erro ao clonar repositorio"))
131
- console.log(pc.dim(" Verifique se tem acesso ao repo nimbuslab/lola"))
132
- process.exit(1)
133
- }
145
+ async function installGeminiSystemPrompt(): Promise<void> {
146
+ console.log()
147
+ console.log(pc.cyan(" Configurando GEMINI.md..."))
134
148
 
135
- console.log(pc.green(" Instalado!"))
149
+ // Criar diretório se não existir
150
+ if (!existsSync(GEMINI_DIR)) {
151
+ await Bun.$`mkdir -p ${GEMINI_DIR}`
136
152
  }
137
153
 
138
- // Criar comando lola
139
- const isWindows = process.platform === "win32"
154
+ // Copiar o agent da Lola (adaptar claude.md para gemini)
140
155
  const lolaAgent = join(LOLA_DIR, "agents", "claude.md")
141
156
 
157
+ if (!existsSync(lolaAgent)) {
158
+ console.log(pc.yellow(" Agent Lola nao encontrado"))
159
+ console.log(pc.dim(" Rode 'nimbus lola install' primeiro"))
160
+ return
161
+ }
162
+
163
+ // Ler o agent do Claude
164
+ let content = await Bun.file(lolaAgent).text()
165
+
166
+ // Remover frontmatter do Claude (não suportado no Gemini)
167
+ content = content.replace(/^---[\s\S]*?---\n/, "")
168
+
169
+ // Adaptar menções específicas
170
+ content = content.replace(/Claude Code/g, "Gemini CLI")
171
+ content = content.replace(/Claude CLI/g, "Gemini CLI")
172
+
173
+ // Adicionar header para Gemini
174
+ const geminiContent = `# Lola - Code Agent (Gemini)
175
+
176
+ > Este arquivo configura a Lola para o Gemini CLI
177
+ > Gerado automaticamente por: nimbus lola install
178
+
179
+ ---
180
+
181
+ ${content}`
182
+
183
+ await Bun.write(GEMINI_SETTINGS, geminiContent)
184
+ console.log(pc.green(" GEMINI.md criado!"))
185
+ }
186
+
187
+ async function createGeminiCommand(): Promise<void> {
188
+ const isWindows = process.platform === "win32"
189
+ const lolaAgent = GEMINI_SETTINGS
190
+
142
191
  console.log()
143
- console.log(pc.cyan(" Configurando comando lola..."))
192
+ console.log(pc.cyan(" Configurando comando lola-gemini..."))
144
193
 
145
194
  if (isWindows) {
146
195
  // Windows: adicionar função ao PowerShell profile
147
- // PowerShell 5.x usa WindowsPowerShell, PowerShell 7+ usa PowerShell
148
- const ps5ProfileDir = join(HOME, "Documents", "WindowsPowerShell")
149
196
  const ps7ProfileDir = join(HOME, "Documents", "PowerShell")
150
197
  const profileName = "Microsoft.PowerShell_profile.ps1"
198
+ const profilePath = join(ps7ProfileDir, profileName)
151
199
 
152
- const lolaFunction = `
153
- # Lola - Code Agent da nimbuslab
154
- function lola {
200
+ const lolaGeminiFunction = `
201
+ # Lola (Gemini) - Code Agent da nimbuslab
202
+ function lola-gemini {
155
203
  param([Parameter(ValueFromRemainingArguments=$true)]$args)
156
- $agent = "$env:USERPROFILE\\.lola\\agents\\claude.md"
157
- if (Test-Path $agent) {
158
- claude --append-system-prompt-file $agent @args
159
- } else {
160
- Write-Host "Agente Lola nao encontrado. Rode: nimbus lola install"
161
- }
204
+ gemini @args
162
205
  }
163
206
  `
164
207
 
165
- // Adicionar função em ambos os profiles (PS 5.x e 7+)
166
- const profiles = [
167
- { dir: ps5ProfileDir, name: "PowerShell 5.x" },
168
- { dir: ps7ProfileDir, name: "PowerShell 7+" },
169
- ]
170
-
171
- let addedToAny = false
172
-
173
- for (const { dir, name } of profiles) {
174
- const profilePath = join(dir, profileName)
175
-
176
- // Criar diretório se não existir
177
- if (!existsSync(dir)) {
178
- await Bun.$`mkdir -p ${dir}`
179
- }
180
-
181
- // Verificar se já tem a função no profile
182
- let profileContent = ""
183
- if (existsSync(profilePath)) {
184
- profileContent = await Bun.file(profilePath).text()
185
- }
208
+ if (!existsSync(ps7ProfileDir)) {
209
+ await Bun.$`mkdir -p ${ps7ProfileDir}`
210
+ }
186
211
 
187
- if (!profileContent.includes("function lola")) {
188
- await Bun.write(profilePath, profileContent + lolaFunction)
189
- console.log(pc.green(` Funcao lola adicionada ao ${name} profile`))
190
- addedToAny = true
191
- }
212
+ let profileContent = ""
213
+ if (existsSync(profilePath)) {
214
+ profileContent = await Bun.file(profilePath).text()
192
215
  }
193
216
 
194
- if (addedToAny) {
195
- console.log(pc.yellow(" Reinicie o PowerShell para usar o comando 'lola'"))
196
- console.log()
197
- console.log(pc.yellow(" IMPORTANTE (Windows):"))
198
- console.log(pc.dim(" Se o comando 'lola' nao funcionar, execute primeiro:"))
199
- console.log(pc.cyan(" Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser"))
200
- console.log(pc.dim(" Isso habilita execucao de scripts no PowerShell."))
217
+ if (!profileContent.includes("function lola-gemini")) {
218
+ await Bun.write(profilePath, profileContent + lolaGeminiFunction)
219
+ console.log(pc.green(" Funcao lola-gemini adicionada ao PowerShell"))
201
220
  } else {
202
- console.log(pc.green(" Funcao lola ja existe nos profiles do PowerShell"))
221
+ console.log(pc.green(" Funcao lola-gemini ja existe"))
203
222
  }
204
223
  } else {
205
224
  // Linux/macOS: criar script em ~/.local/bin
206
225
  const binDir = join(HOME, ".local", "bin")
207
- const lolaScript = join(binDir, "lola")
226
+ const lolaGeminiScript = join(binDir, "lola-gemini")
208
227
 
209
- if (!existsSync(lolaScript)) {
228
+ if (!existsSync(lolaGeminiScript)) {
210
229
  await Bun.$`mkdir -p ${binDir}`
211
230
 
212
231
  const unixScript = `#!/bin/bash
213
- # lola - Code Agent da nimbuslab
214
- LOLA_AGENT="${lolaAgent}"
232
+ # lola-gemini - Code Agent da nimbuslab (Gemini)
215
233
 
216
234
  if [[ "\$1" == "-h" || "\$1" == "--help" ]]; then
217
- echo "lola - Code Agent da nimbuslab"
218
- echo "Uso: lola [args]"
219
- echo " lola Abre Claude CLI com a Lola"
220
- echo " lola --resume Resume sessao anterior"
235
+ echo "lola-gemini - Code Agent da nimbuslab (Gemini)"
236
+ echo "Uso: lola-gemini [args]"
237
+ echo " lola-gemini Abre Gemini CLI com a Lola"
221
238
  exit 0
222
239
  fi
223
240
 
224
- if [[ -f "\$LOLA_AGENT" ]]; then
225
- exec claude --append-system-prompt-file "\$LOLA_AGENT" "\$@"
226
- else
227
- echo "Agente Lola nao encontrado: \$LOLA_AGENT"
228
- echo "Rode: nimbus lola install"
229
- exit 1
230
- fi
241
+ exec gemini "\$@"
231
242
  `
232
- await Bun.write(lolaScript, unixScript)
233
- await Bun.$`chmod +x ${lolaScript}`
243
+ await Bun.write(lolaGeminiScript, unixScript)
244
+ await Bun.$`chmod +x ${lolaGeminiScript}`
234
245
 
235
- console.log(pc.green(` Script lola criado em ${lolaScript}`))
236
-
237
- // Verificar se ~/.local/bin está no PATH
238
- const pathEnv = process.env.PATH || ""
239
- if (!pathEnv.includes(".local/bin")) {
240
- console.log()
241
- console.log(pc.yellow(" IMPORTANTE: Adicione ~/.local/bin ao seu PATH"))
242
- console.log(pc.dim(" Adicione ao seu ~/.bashrc ou ~/.zshrc:"))
243
- console.log(pc.dim(" export PATH=\"$HOME/.local/bin:$PATH\""))
244
- }
246
+ console.log(pc.green(` Script lola-gemini criado em ${lolaGeminiScript}`))
245
247
  } else {
246
- console.log(pc.green(" Script lola ja existe"))
248
+ console.log(pc.green(" Script lola-gemini ja existe"))
247
249
  }
248
250
  }
251
+ }
249
252
 
250
- // Instalar MCP lola-memory
251
- await installLolaMemoryMCP()
252
-
253
- // Verificar USER_MEMORY.md
254
- const claudeDir = join(HOME, ".claude")
255
- if (!existsSync(USER_MEMORY)) {
256
- console.log()
257
- console.log(pc.cyan(" Configurando USER_MEMORY.md..."))
258
-
259
- // Pegar info do git automaticamente
260
- const gitUserResult = Bun.spawnSync(["git", "config", "user.name"], { stdout: "pipe" })
261
- const gitEmailResult = Bun.spawnSync(["git", "config", "user.email"], { stdout: "pipe" })
262
-
263
- const gitUser = gitUserResult.stdout.toString().trim() || "Dev"
264
- const gitEmail = gitEmailResult.stdout.toString().trim() || ""
265
- const hostname = process.env.HOSTNAME || process.env.COMPUTERNAME || "local"
266
- const today = new Date().toISOString().split("T")[0]
267
-
268
- await Bun.$`mkdir -p ${claudeDir}`
269
-
270
- const content = `# User Memory
271
-
272
- Memoria persistente para sessoes Claude Code
273
-
274
- ---
275
-
276
- ## Dev
277
-
278
- **Nome:** ${gitUser}
279
- **Email:** ${gitEmail}
280
- **Maquina:** ${hostname}
281
- **Instalacao:** ${today}
282
-
283
- ---
284
-
285
- ## Configuracoes da Lola
286
-
287
- \`\`\`
288
- lola_profile: millennial
289
- \`\`\`
290
-
291
- ---
253
+ async function setupGemini(): Promise<void> {
254
+ // Verificar/instalar Gemini CLI
255
+ if (!hasGeminiCLI()) {
256
+ const installed = await installGeminiCLI()
257
+ if (!installed) return
258
+ } else {
259
+ console.log(pc.green(" Gemini CLI ja instalado"))
260
+ }
292
261
 
293
- ## Ultima Sessao
262
+ // Configurar MCP
263
+ await installGeminiMCP()
294
264
 
295
- (sera preenchido automaticamente)
265
+ // Configurar GEMINI.md
266
+ await installGeminiSystemPrompt()
296
267
 
297
- ---
298
- `
299
- await Bun.write(USER_MEMORY, content)
300
- console.log(pc.green(` USER_MEMORY.md criado para ${gitUser}!`))
301
- }
268
+ // Criar comando lola-gemini
269
+ await createGeminiCommand()
302
270
 
303
271
  console.log()
304
- console.log(pc.green(" Instalacao concluida!"))
305
- console.log()
306
- console.log(pc.bold(" Para usar a Lola:"))
307
- console.log(pc.dim(" lola ") + pc.white("# Iniciar sessao"))
308
- console.log()
309
- console.log(pc.bold(" lola-memory (conhecimento compartilhado):"))
310
- console.log(pc.dim(" remember \"query\" ") + pc.white("# Buscar conhecimento"))
311
- console.log(pc.dim(" learn \"content\" ") + pc.white("# Salvar conhecimento"))
312
- console.log(pc.dim(" memory_stats ") + pc.white("# Ver estatisticas"))
272
+ console.log(pc.green(" Gemini configurado!"))
313
273
  console.log()
314
- console.log(pc.bold(" Para mudar perfil, edite ~/.claude/USER_MEMORY.md:"))
315
- console.log(pc.dim(" lola_profile: millennial|genz|profissional|nerd|chill"))
274
+ console.log(pc.bold(" Para usar:"))
275
+ console.log(pc.dim(" lola-gemini ") + pc.white("# Iniciar sessao com Gemini"))
276
+ console.log(pc.dim(" gemini ") + pc.white("# Gemini puro (sem Lola)"))
316
277
  console.log()
278
+ console.log(pc.dim(" Na primeira execucao, faca login com sua conta Google."))
317
279
  }
318
280
 
281
+
319
282
  async function suggestImprovement(message: string): Promise<void> {
320
283
  if (!message) {
321
284
  console.log(pc.red(" Erro: forneça uma mensagem"))
@@ -427,7 +390,7 @@ async function onboardDev(): Promise<void> {
427
390
  if (!existsSync(LOLA_DIR)) {
428
391
  console.log(pc.yellow(" Lola nao instalada. Instalando primeiro..."))
429
392
  console.log()
430
- await installLola()
393
+ await installLolaBase()
431
394
  console.log()
432
395
  }
433
396
 
@@ -684,11 +647,328 @@ async function runQuiz(): Promise<void> {
684
647
  console.log()
685
648
  }
686
649
 
650
+ async function installInteractive(): Promise<void> {
651
+ console.log()
652
+ console.log(pc.cyan(" Lola - Code Agent da nimbuslab"))
653
+ console.log(pc.dim(" ==============================="))
654
+ console.log()
655
+
656
+ // Detectar CLIs instaladas
657
+ const hasClaude = hasClaudeCLI()
658
+ const hasGemini = hasGeminiCLI()
659
+
660
+ console.log(pc.dim(" Detectando agents..."))
661
+ console.log(pc.dim(` Claude CLI: ${hasClaude ? pc.green("instalado") : pc.yellow("nao encontrado")}`))
662
+ console.log(pc.dim(` Gemini CLI: ${hasGemini ? pc.green("instalado") : pc.yellow("nao encontrado")}`))
663
+ console.log()
664
+
665
+ // Perguntar qual agent configurar
666
+ const agentChoice = await p.select({
667
+ message: "Qual agent deseja configurar?",
668
+ options: [
669
+ {
670
+ value: "all",
671
+ label: "Todos (Recomendado)",
672
+ hint: "Configura Claude e Gemini",
673
+ },
674
+ {
675
+ value: "claude",
676
+ label: "Apenas Claude",
677
+ hint: hasClaude ? "Ja instalado" : "Sera instalado",
678
+ },
679
+ {
680
+ value: "gemini",
681
+ label: "Apenas Gemini",
682
+ hint: hasGemini ? "Ja instalado" : "Sera instalado",
683
+ },
684
+ ],
685
+ })
686
+
687
+ if (p.isCancel(agentChoice)) {
688
+ p.cancel("Instalacao cancelada")
689
+ process.exit(0)
690
+ }
691
+
692
+ const choice = agentChoice as AgentType
693
+
694
+ // Instalar ~/.lola primeiro (necessário para ambos)
695
+ await installLolaBase()
696
+
697
+ // Configurar agents escolhidos
698
+ if (choice === "claude" || choice === "all") {
699
+ console.log()
700
+ console.log(pc.bgBlue(pc.white(" CLAUDE ")))
701
+ await setupClaude()
702
+ }
703
+
704
+ if (choice === "gemini" || choice === "all") {
705
+ console.log()
706
+ console.log(pc.bgMagenta(pc.white(" GEMINI ")))
707
+ await setupGemini()
708
+ }
709
+
710
+ // Resumo final
711
+ console.log()
712
+ console.log(pc.green(" ==============================="))
713
+ console.log(pc.green(" Instalacao concluida!"))
714
+ console.log(pc.green(" ==============================="))
715
+ console.log()
716
+
717
+ if (choice === "claude" || choice === "all") {
718
+ console.log(pc.dim(" lola ") + pc.white("# Claude com Lola"))
719
+ }
720
+ if (choice === "gemini" || choice === "all") {
721
+ console.log(pc.dim(" lola-gemini ") + pc.white("# Gemini com Lola"))
722
+ }
723
+ console.log()
724
+ console.log(pc.bold(" lola-memory (compartilhado entre agents):"))
725
+ console.log(pc.dim(" remember, learn, memory_stats"))
726
+ console.log()
727
+ }
728
+
729
+ async function installLolaBase(): Promise<void> {
730
+ console.log()
731
+ console.log(pc.cyan(" Instalando base Lola (~/.lola)..."))
732
+
733
+ const isUpdate = existsSync(LOLA_DIR)
734
+
735
+ if (isUpdate) {
736
+ console.log(pc.dim(` Lola ja instalada em ${LOLA_DIR}`))
737
+ console.log(pc.dim(" Atualizando..."))
738
+
739
+ // Verificar se tem mudancas locais
740
+ const statusCheck = Bun.spawnSync(["git", "status", "--porcelain"], {
741
+ cwd: LOLA_DIR,
742
+ stdout: "pipe",
743
+ })
744
+ const hasLocalChanges = statusCheck.stdout.toString().trim().length > 0
745
+
746
+ // Stash se tiver mudancas locais
747
+ if (hasLocalChanges) {
748
+ console.log(pc.dim(" Salvando mudancas locais..."))
749
+ Bun.spawnSync(["git", "stash", "--quiet"], {
750
+ cwd: LOLA_DIR,
751
+ stdout: "pipe",
752
+ stderr: "pipe",
753
+ })
754
+ }
755
+
756
+ // Pull
757
+ const result = Bun.spawnSync(["git", "pull", "--quiet"], {
758
+ cwd: LOLA_DIR,
759
+ stdout: "inherit",
760
+ stderr: "inherit",
761
+ })
762
+
763
+ // Restaurar mudancas locais se tinha
764
+ if (hasLocalChanges) {
765
+ console.log(pc.dim(" Restaurando mudancas locais..."))
766
+ const stashPop = Bun.spawnSync(["git", "stash", "pop", "--quiet"], {
767
+ cwd: LOLA_DIR,
768
+ stdout: "pipe",
769
+ stderr: "pipe",
770
+ })
771
+
772
+ if (stashPop.exitCode !== 0) {
773
+ console.log(pc.yellow(" Aviso: conflito ao restaurar mudancas locais"))
774
+ console.log(pc.dim(" Verifique ~/.lola e resolva manualmente: git stash pop"))
775
+ }
776
+ }
777
+
778
+ if (result.exitCode !== 0) {
779
+ console.log(pc.red(" Erro ao atualizar Lola"))
780
+ process.exit(1)
781
+ }
782
+
783
+ console.log(pc.green(" Atualizado!"))
784
+ } else {
785
+ console.log(pc.dim(` Clonando em ${LOLA_DIR}...`))
786
+
787
+ const result = Bun.spawnSync(["git", "clone", "--quiet", LOLA_REPO, LOLA_DIR], {
788
+ stdout: "inherit",
789
+ stderr: "inherit",
790
+ })
791
+
792
+ if (result.exitCode !== 0) {
793
+ console.log(pc.red(" Erro ao clonar repositorio"))
794
+ console.log(pc.dim(" Verifique se tem acesso ao repo nimbuslab/lola"))
795
+ process.exit(1)
796
+ }
797
+
798
+ console.log(pc.green(" Instalado!"))
799
+ }
800
+ }
801
+
802
+ async function setupClaude(): Promise<void> {
803
+ if (!hasClaudeCLI()) {
804
+ console.log(pc.yellow(" Claude CLI nao encontrado"))
805
+ console.log(pc.dim(" Instale: https://claude.ai/download"))
806
+ console.log(pc.dim(" Depois rode 'nimbus lola install' novamente"))
807
+ return
808
+ }
809
+
810
+ console.log(pc.green(" Claude CLI encontrado"))
811
+
812
+ // Criar comando lola
813
+ const isWindows = process.platform === "win32"
814
+ const lolaAgent = join(LOLA_DIR, "agents", "claude.md")
815
+
816
+ console.log()
817
+ console.log(pc.cyan(" Configurando comando lola..."))
818
+
819
+ if (isWindows) {
820
+ const ps5ProfileDir = join(HOME, "Documents", "WindowsPowerShell")
821
+ const ps7ProfileDir = join(HOME, "Documents", "PowerShell")
822
+ const profileName = "Microsoft.PowerShell_profile.ps1"
823
+
824
+ const lolaFunction = `
825
+ # Lola - Code Agent da nimbuslab
826
+ function lola {
827
+ param([Parameter(ValueFromRemainingArguments=$true)]$args)
828
+ $agent = "$env:USERPROFILE\\.lola\\agents\\claude.md"
829
+ if (Test-Path $agent) {
830
+ claude --append-system-prompt-file $agent @args
831
+ } else {
832
+ Write-Host "Agente Lola nao encontrado. Rode: nimbus lola install"
833
+ }
834
+ }
835
+ `
836
+
837
+ const profiles = [
838
+ { dir: ps5ProfileDir, name: "PowerShell 5.x" },
839
+ { dir: ps7ProfileDir, name: "PowerShell 7+" },
840
+ ]
841
+
842
+ let addedToAny = false
843
+
844
+ for (const { dir, name } of profiles) {
845
+ const profilePath = join(dir, profileName)
846
+
847
+ if (!existsSync(dir)) {
848
+ await Bun.$`mkdir -p ${dir}`
849
+ }
850
+
851
+ let profileContent = ""
852
+ if (existsSync(profilePath)) {
853
+ profileContent = await Bun.file(profilePath).text()
854
+ }
855
+
856
+ if (!profileContent.includes("function lola")) {
857
+ await Bun.write(profilePath, profileContent + lolaFunction)
858
+ console.log(pc.green(` Funcao lola adicionada ao ${name} profile`))
859
+ addedToAny = true
860
+ }
861
+ }
862
+
863
+ if (addedToAny) {
864
+ console.log(pc.yellow(" Reinicie o PowerShell para usar o comando 'lola'"))
865
+ } else {
866
+ console.log(pc.green(" Funcao lola ja existe"))
867
+ }
868
+ } else {
869
+ const binDir = join(HOME, ".local", "bin")
870
+ const lolaScript = join(binDir, "lola")
871
+
872
+ if (!existsSync(lolaScript)) {
873
+ await Bun.$`mkdir -p ${binDir}`
874
+
875
+ const unixScript = `#!/bin/bash
876
+ # lola - Code Agent da nimbuslab
877
+ LOLA_AGENT="${lolaAgent}"
878
+
879
+ if [[ "\$1" == "-h" || "\$1" == "--help" ]]; then
880
+ echo "lola - Code Agent da nimbuslab"
881
+ echo "Uso: lola [args]"
882
+ echo " lola Abre Claude CLI com a Lola"
883
+ echo " lola --resume Resume sessao anterior"
884
+ exit 0
885
+ fi
886
+
887
+ if [[ -f "\$LOLA_AGENT" ]]; then
888
+ exec claude --append-system-prompt-file "\$LOLA_AGENT" "\$@"
889
+ else
890
+ echo "Agente Lola nao encontrado: \$LOLA_AGENT"
891
+ echo "Rode: nimbus lola install"
892
+ exit 1
893
+ fi
894
+ `
895
+ await Bun.write(lolaScript, unixScript)
896
+ await Bun.$`chmod +x ${lolaScript}`
897
+
898
+ console.log(pc.green(` Script lola criado em ${lolaScript}`))
899
+
900
+ const pathEnv = process.env.PATH || ""
901
+ if (!pathEnv.includes(".local/bin")) {
902
+ console.log()
903
+ console.log(pc.yellow(" IMPORTANTE: Adicione ~/.local/bin ao seu PATH"))
904
+ console.log(pc.dim(" export PATH=\"$HOME/.local/bin:$PATH\""))
905
+ }
906
+ } else {
907
+ console.log(pc.green(" Script lola ja existe"))
908
+ }
909
+ }
910
+
911
+ // Instalar MCP lola-memory
912
+ await installLolaMemoryMCP()
913
+
914
+ // Verificar USER_MEMORY.md
915
+ const claudeDir = join(HOME, ".claude")
916
+ if (!existsSync(USER_MEMORY)) {
917
+ console.log()
918
+ console.log(pc.cyan(" Configurando USER_MEMORY.md..."))
919
+
920
+ const gitUserResult = Bun.spawnSync(["git", "config", "user.name"], { stdout: "pipe" })
921
+ const gitEmailResult = Bun.spawnSync(["git", "config", "user.email"], { stdout: "pipe" })
922
+
923
+ const gitUser = gitUserResult.stdout.toString().trim() || "Dev"
924
+ const gitEmail = gitEmailResult.stdout.toString().trim() || ""
925
+ const hostname = process.env.HOSTNAME || process.env.COMPUTERNAME || "local"
926
+ const today = new Date().toISOString().split("T")[0]
927
+
928
+ await Bun.$`mkdir -p ${claudeDir}`
929
+
930
+ const content = `# User Memory
931
+
932
+ Memoria persistente para sessoes Claude Code
933
+
934
+ ---
935
+
936
+ ## Dev
937
+
938
+ **Nome:** ${gitUser}
939
+ **Email:** ${gitEmail}
940
+ **Maquina:** ${hostname}
941
+ **Instalacao:** ${today}
942
+
943
+ ---
944
+
945
+ ## Configuracoes da Lola
946
+
947
+ \`\`\`
948
+ lola_profile: millennial
949
+ \`\`\`
950
+
951
+ ---
952
+
953
+ ## Ultima Sessao
954
+
955
+ (sera preenchido automaticamente)
956
+
957
+ ---
958
+ `
959
+ await Bun.write(USER_MEMORY, content)
960
+ console.log(pc.green(` USER_MEMORY.md criado para ${gitUser}!`))
961
+ }
962
+
963
+ console.log()
964
+ console.log(pc.green(" Claude configurado!"))
965
+ }
966
+
687
967
  export async function lola(args: string[]) {
688
968
  const subcommand = args[0]
689
969
 
690
970
  if (!subcommand || subcommand === "install" || subcommand === "sync") {
691
- await installLola()
971
+ await installInteractive()
692
972
  } else if (subcommand === "onboard") {
693
973
  await onboardDev()
694
974
  } else if (subcommand === "quiz") {