fantasy-cli 1.2.6

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 (112) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +456 -0
  4. data/bin/gsd +8 -0
  5. data/bin/gsd-core-darwin-amd64 +0 -0
  6. data/bin/gsd-core-darwin-arm64 +0 -0
  7. data/bin/gsd-core-linux-amd64 +0 -0
  8. data/bin/gsd-core-linux-arm64 +0 -0
  9. data/bin/gsd-core-windows-amd64.exe +0 -0
  10. data/bin/gsd-core-windows-arm64.exe +0 -0
  11. data/bin/gsd-core.exe +0 -0
  12. data/lib/gsd/agents/coordinator.rb +195 -0
  13. data/lib/gsd/agents/task_manager.rb +158 -0
  14. data/lib/gsd/agents/worker.rb +162 -0
  15. data/lib/gsd/agents.rb +30 -0
  16. data/lib/gsd/ai/chat.rb +486 -0
  17. data/lib/gsd/ai/cli.rb +248 -0
  18. data/lib/gsd/ai/command_parser.rb +97 -0
  19. data/lib/gsd/ai/commands/base.rb +42 -0
  20. data/lib/gsd/ai/commands/clear.rb +20 -0
  21. data/lib/gsd/ai/commands/context.rb +30 -0
  22. data/lib/gsd/ai/commands/cost.rb +30 -0
  23. data/lib/gsd/ai/commands/export.rb +42 -0
  24. data/lib/gsd/ai/commands/help.rb +61 -0
  25. data/lib/gsd/ai/commands/model.rb +67 -0
  26. data/lib/gsd/ai/commands/reset.rb +22 -0
  27. data/lib/gsd/ai/config.rb +256 -0
  28. data/lib/gsd/ai/context.rb +324 -0
  29. data/lib/gsd/ai/cost_tracker.rb +361 -0
  30. data/lib/gsd/ai/git_context.rb +169 -0
  31. data/lib/gsd/ai/history.rb +384 -0
  32. data/lib/gsd/ai/providers/anthropic.rb +429 -0
  33. data/lib/gsd/ai/providers/base.rb +282 -0
  34. data/lib/gsd/ai/providers/lmstudio.rb +279 -0
  35. data/lib/gsd/ai/providers/ollama.rb +336 -0
  36. data/lib/gsd/ai/providers/openai.rb +396 -0
  37. data/lib/gsd/ai/providers/openrouter.rb +429 -0
  38. data/lib/gsd/ai/reference_resolver.rb +225 -0
  39. data/lib/gsd/ai/repl.rb +349 -0
  40. data/lib/gsd/ai/streaming.rb +438 -0
  41. data/lib/gsd/ai/ui.rb +429 -0
  42. data/lib/gsd/buddy/cli.rb +284 -0
  43. data/lib/gsd/buddy/gacha.rb +148 -0
  44. data/lib/gsd/buddy/renderer.rb +108 -0
  45. data/lib/gsd/buddy/species.rb +190 -0
  46. data/lib/gsd/buddy/stats.rb +156 -0
  47. data/lib/gsd/buddy.rb +28 -0
  48. data/lib/gsd/cli.rb +455 -0
  49. data/lib/gsd/commands.rb +198 -0
  50. data/lib/gsd/config.rb +183 -0
  51. data/lib/gsd/error.rb +188 -0
  52. data/lib/gsd/frontmatter.rb +123 -0
  53. data/lib/gsd/go/bridge.rb +173 -0
  54. data/lib/gsd/history.rb +76 -0
  55. data/lib/gsd/milestone.rb +75 -0
  56. data/lib/gsd/output.rb +184 -0
  57. data/lib/gsd/phase.rb +102 -0
  58. data/lib/gsd/plugins/base.rb +92 -0
  59. data/lib/gsd/plugins/cli.rb +330 -0
  60. data/lib/gsd/plugins/config.rb +164 -0
  61. data/lib/gsd/plugins/hooks.rb +132 -0
  62. data/lib/gsd/plugins/installer.rb +158 -0
  63. data/lib/gsd/plugins/loader.rb +122 -0
  64. data/lib/gsd/plugins/manager.rb +187 -0
  65. data/lib/gsd/plugins/marketplace.rb +142 -0
  66. data/lib/gsd/plugins/sandbox.rb +114 -0
  67. data/lib/gsd/plugins/search.rb +131 -0
  68. data/lib/gsd/plugins/validator.rb +157 -0
  69. data/lib/gsd/plugins.rb +48 -0
  70. data/lib/gsd/profile.rb +127 -0
  71. data/lib/gsd/research.rb +85 -0
  72. data/lib/gsd/roadmap.rb +90 -0
  73. data/lib/gsd/skills/bundled/commit.md +58 -0
  74. data/lib/gsd/skills/bundled/debug.md +28 -0
  75. data/lib/gsd/skills/bundled/explain.md +41 -0
  76. data/lib/gsd/skills/bundled/plan.md +42 -0
  77. data/lib/gsd/skills/bundled/verify.md +26 -0
  78. data/lib/gsd/skills/loader.rb +189 -0
  79. data/lib/gsd/state.rb +102 -0
  80. data/lib/gsd/template.rb +106 -0
  81. data/lib/gsd/tools/ask_user_question.rb +179 -0
  82. data/lib/gsd/tools/base.rb +204 -0
  83. data/lib/gsd/tools/bash.rb +246 -0
  84. data/lib/gsd/tools/file_edit.rb +297 -0
  85. data/lib/gsd/tools/file_read.rb +199 -0
  86. data/lib/gsd/tools/file_write.rb +153 -0
  87. data/lib/gsd/tools/glob.rb +202 -0
  88. data/lib/gsd/tools/grep.rb +227 -0
  89. data/lib/gsd/tools/gsd_frontmatter.rb +165 -0
  90. data/lib/gsd/tools/gsd_phase.rb +140 -0
  91. data/lib/gsd/tools/gsd_roadmap.rb +108 -0
  92. data/lib/gsd/tools/gsd_state.rb +143 -0
  93. data/lib/gsd/tools/gsd_template.rb +157 -0
  94. data/lib/gsd/tools/gsd_verify.rb +159 -0
  95. data/lib/gsd/tools/registry.rb +103 -0
  96. data/lib/gsd/tools/task.rb +235 -0
  97. data/lib/gsd/tools/todo_write.rb +290 -0
  98. data/lib/gsd/tools/web.rb +260 -0
  99. data/lib/gsd/tui/app.rb +366 -0
  100. data/lib/gsd/tui/auto_complete.rb +79 -0
  101. data/lib/gsd/tui/colors.rb +111 -0
  102. data/lib/gsd/tui/command_palette.rb +126 -0
  103. data/lib/gsd/tui/header.rb +38 -0
  104. data/lib/gsd/tui/input_box.rb +199 -0
  105. data/lib/gsd/tui/spinner.rb +40 -0
  106. data/lib/gsd/tui/status_bar.rb +51 -0
  107. data/lib/gsd/tui.rb +17 -0
  108. data/lib/gsd/validator.rb +216 -0
  109. data/lib/gsd/verify.rb +175 -0
  110. data/lib/gsd/version.rb +5 -0
  111. data/lib/gsd/workstream.rb +91 -0
  112. metadata +231 -0
@@ -0,0 +1,349 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'io/console'
4
+
5
+ module Gsd
6
+ module AI
7
+ # REPL Interface - Interface de linha de comando interativa
8
+ #
9
+ # Responsável por:
10
+ # - Input do usuário com readline básico
11
+ # - Output formatado com cores
12
+ # - Comandos especiais do REPL
13
+ class Repl
14
+ attr_reader :chat, :config
15
+
16
+ # Comandos disponíveis no REPL
17
+ COMMANDS = {
18
+ 'quit' => 'Sair do chat',
19
+ 'exit' => 'Sair do chat',
20
+ 'clear' => 'Limpar histórico',
21
+ 'help' => 'Mostrar ajuda',
22
+ 'stats' => 'Mostrar estatísticas',
23
+ 'context' => 'Mostrar contexto atual',
24
+ 'history' => 'Mostrar histórico',
25
+ 'model' => 'Mudar modelo',
26
+ 'provider' => 'Mudar provider',
27
+ 'cost' => 'Mostrar custo acumulado',
28
+ 'cache' => 'Mostrar informações do cache',
29
+ 'reload' => 'Recarregar contexto',
30
+ 'clear-cache' => 'Limpar cache de contexto'
31
+ }.freeze
32
+
33
+ # Inicializa o REPL
34
+ #
35
+ # @param chat [Chat] Instância do chat
36
+ # @param config [Hash] Configurações
37
+ def initialize(chat, config = {})
38
+ @chat = chat
39
+ @config = config
40
+ @verbose = config.fetch(:verbose, false)
41
+ end
42
+
43
+ # Inicia o loop do REPL
44
+ #
45
+ # @return [void]
46
+ def start
47
+ print_banner
48
+ print_help if @config.fetch(:help, false)
49
+
50
+ loop do
51
+ begin
52
+ print_prompt
53
+ input = read_input
54
+
55
+ break if input.nil? || handle_command(input)
56
+ rescue Interrupt
57
+ puts "\n^C"
58
+ next
59
+ rescue => e
60
+ puts "\n❌ Erro: #{e.message}"
61
+ puts e.backtrace.first(5) if @verbose
62
+ end
63
+ end
64
+
65
+ cleanup
66
+ end
67
+
68
+ private
69
+
70
+ # Imprime o banner inicial
71
+ #
72
+ # @return [void]
73
+ def print_banner
74
+ puts "\n" + '=' * 60
75
+ puts '🤖 GSD AI Chat - Interface de Conversa'
76
+ puts '=' * 60
77
+ puts "Provider: #{@chat.provider.class}"
78
+ puts "Modelo: #{@chat.provider.model}"
79
+ puts "Debug: #{@chat.instance_variable_get(:@debug) ? 'ON' : 'OFF'}"
80
+ puts '=' * 60
81
+ puts "Digite 'help' para ver comandos disponíveis"
82
+ puts '=' * 60 + "\n"
83
+ end
84
+
85
+ # Imprime o prompt de input
86
+ #
87
+ # @return [void]
88
+ def print_prompt
89
+ print "\n👤 "
90
+ end
91
+
92
+ # Lê input do usuário
93
+ #
94
+ # @return [String] Input do usuário
95
+ def read_input
96
+ $stdin.gets&.chomp
97
+ end
98
+
99
+ # Processa comandos especiais
100
+ #
101
+ # @param input [String] Input do usuário
102
+ # @return [Boolean] true se deve sair do REPL
103
+ def handle_command(input)
104
+ # Verifica se é um comando especial
105
+ if input.start_with?('/')
106
+ return handle_slash_command(input)
107
+ end
108
+
109
+ # Comandos sem slash
110
+ parts = input.split(/\s+/, 2)
111
+ cmd = parts[0]&.downcase
112
+ args = parts[1]
113
+
114
+ case cmd
115
+ when 'quit', 'exit'
116
+ return true
117
+ when 'clear'
118
+ @chat.clear_history
119
+ puts "🧹 Histórico limpo!"
120
+ when 'help'
121
+ print_help
122
+ when 'stats'
123
+ print_stats
124
+ when 'context'
125
+ print_context
126
+ when 'history'
127
+ print_history
128
+ when 'cache'
129
+ print_cache_info
130
+ when 'reload'
131
+ reload_context
132
+ when 'clear-cache'
133
+ clear_cache
134
+ when 'model'
135
+ change_model(args) if args
136
+ when 'cost'
137
+ print_cost
138
+ when nil, ''
139
+ # Input vazio, ignora
140
+ else
141
+ # Não é um comando, envia para o chat
142
+ handle_chat_message(input)
143
+ end
144
+
145
+ false
146
+ end
147
+
148
+ # Processa comandos com slash
149
+ #
150
+ # @param input [String] Input começando com /
151
+ # @return [Boolean] true se deve sair do REPL
152
+ def handle_slash_command(input)
153
+ parts = input[1..-1].split(/\s+/, 2)
154
+ cmd = parts[0]
155
+ args = parts[1]
156
+
157
+ case cmd
158
+ when 'q', 'quit', 'exit'
159
+ return true
160
+ when 'c', 'clear'
161
+ @chat.clear_history
162
+ puts "🧹 Histórico limpo!"
163
+ when 'h', 'help'
164
+ print_help
165
+ when 's', 'stats'
166
+ print_stats
167
+ when 'ctx', 'context'
168
+ print_context
169
+ when 'hist', 'history'
170
+ print_history
171
+ when 'm', 'model'
172
+ change_model(args) if args
173
+ when 'p', 'provider'
174
+ change_provider(args) if args
175
+ when 'cost'
176
+ print_cost
177
+ when 'v', 'verbose'
178
+ toggle_verbose
179
+ else
180
+ # Não é um comando conhecido, trata como mensagem
181
+ handle_chat_message(input)
182
+ end
183
+
184
+ false
185
+ end
186
+
187
+ # Envia mensagem para o chat e exibe resposta
188
+ #
189
+ # @param message [String] Mensagem do usuário
190
+ # @return [void]
191
+ def handle_chat_message(message)
192
+ print "\n🤖 "
193
+
194
+ # Streaming da resposta
195
+ response = @chat.send(message, stream: true)
196
+
197
+ puts response
198
+ puts "\n" + '-' * 40
199
+ end
200
+
201
+ # Imprime ajuda
202
+ #
203
+ # @return [void]
204
+ def print_help
205
+ puts "\n📖 Comandos disponíveis:"
206
+ puts '-' * 40
207
+
208
+ COMMANDS.each do |cmd, desc|
209
+ puts " /#{cmd.ljust(10)} #{desc}"
210
+ end
211
+
212
+ puts "\nDicas:"
213
+ puts " - Mensagens normais são enviadas para a IA"
214
+ puts " - Use / para comandos especiais"
215
+ puts " - Ctrl+C cancela a resposta atual"
216
+ puts " - Ctrl+D ou /quit sai do chat"
217
+ puts '-' * 40 + "\n"
218
+ end
219
+
220
+ # Imprime estatísticas
221
+ #
222
+ # @return [void]
223
+ def print_stats
224
+ stats = @chat.stats
225
+ puts "\n📊 Estatísticas:"
226
+ puts '-' * 40
227
+ puts " Mensagens: #{stats[:messages_count]}"
228
+ puts " Tokens totais: #{stats[:total_tokens].to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1.').reverse}"
229
+ puts " Custo total: $#{stats[:total_cost].round(4)}"
230
+ puts " Tamanho do contexto: #{stats[:context_size]} KB"
231
+ puts '-' * 40 + "\n"
232
+ end
233
+
234
+ # Imprime contexto atual
235
+ #
236
+ # @return [void]
237
+ def print_context
238
+ context = @chat.context
239
+ puts "\n📁 Contexto atual:"
240
+ puts '-' * 40
241
+
242
+ if context.state
243
+ puts " State:"
244
+ puts " - Current Phase: #{context.state['current_phase']}"
245
+ puts " - Progress: #{context.state['progress']}"
246
+ end
247
+
248
+ puts '-' * 40 + "\n"
249
+ end
250
+
251
+ # Imprime histórico
252
+ #
253
+ # @return [void]
254
+ def print_history
255
+ history = @chat.history
256
+ puts "\n📜 Histórico (últimas 10 mensagens):"
257
+ puts '-' * 40
258
+
259
+ history.messages.last(10).each_with_index do |msg, i|
260
+ role = msg[:role] == 'user' ? '👤' : '🤖'
261
+ content = msg[:content].to_s[0..100]
262
+ content += '...' if msg[:content].to_s.length > 100
263
+ puts " #{i + 1}. #{role} #{content}"
264
+ end
265
+
266
+ puts '-' * 40 + "\n"
267
+ end
268
+
269
+ # Muda o modelo
270
+ #
271
+ # @param model [String] Nome do modelo
272
+ # @return [void]
273
+ def change_model(model)
274
+ @chat.provider.model = model
275
+ puts "✅ Modelo alterado para: #{model}"
276
+ end
277
+
278
+ # Muda o provider
279
+ #
280
+ # @param provider [String] Nome do provider
281
+ # @return [void]
282
+ def change_provider(provider)
283
+ puts "⚠️ Mudança de provider requer reinicialização"
284
+ end
285
+
286
+ # Toggle verbose mode
287
+ #
288
+ # @return [void]
289
+ def toggle_verbose
290
+ @verbose = !@verbose
291
+ puts "✅ Verbose: #{@verbose ? 'ON' : 'OFF'}"
292
+ end
293
+
294
+ # Imprime informações do cache
295
+ #
296
+ # @return [void]
297
+ def print_cache_info
298
+ cache_info = @chat.cache_info
299
+ puts "\n💾 Informações do Cache:"
300
+ puts '-' * 40
301
+ puts " Carregado em: #{cache_info[:loaded_at] || 'N/A'}"
302
+ puts " Idade: #{cache_info[:age_seconds]}s"
303
+ puts " TTL: #{cache_info[:ttl_seconds]}s"
304
+ puts " Expirado: #{cache_info[:expired] ? 'Sim' : 'Não'}"
305
+ puts " Hash: #{cache_info[:hash] ? cache_info[:hash][0..12] + '...' : 'N/A'}"
306
+ puts " Tamanho: #{cache_info[:size_kb].round(2)} KB"
307
+ puts '-' * 40 + "\n"
308
+ end
309
+
310
+ # Recarrega o contexto
311
+ #
312
+ # @return [void]
313
+ def reload_context
314
+ puts "🔄 Recarregando contexto..."
315
+ @chat.reload_context
316
+ puts "✅ Contexto recarregado!"
317
+ print_cache_info
318
+ end
319
+
320
+ # Limpa o cache
321
+ #
322
+ # @return [void]
323
+ def clear_cache
324
+ puts "🧹 Limpando cache..."
325
+ @chat.clear_cache
326
+ puts "✅ Cache limpo!"
327
+ end
328
+
329
+ # Imprime custo
330
+ #
331
+ # @return [void]
332
+ def print_cost
333
+ stats = @chat.stats
334
+ puts "\n💰 Custo acumulado:"
335
+ puts '-' * 40
336
+ puts " Tokens: #{stats[:total_tokens]}"
337
+ puts " Total: $#{stats[:total_cost].round(6)}"
338
+ puts '-' * 40 + "\n"
339
+ end
340
+
341
+ # Cleanup antes de sair
342
+ #
343
+ # @return [void]
344
+ def cleanup
345
+ puts "\n👋 Até logo!"
346
+ end
347
+ end
348
+ end
349
+ end