fantasy-cli 1.2.11 → 1.2.14

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9d3e9147f450f7556df6f5bc25422413cb7d931602a891f6fa44760bf0c9199
4
- data.tar.gz: 46a0e41b9cc69c9898b7041e11ad6c0c05370f8cb41330bfec0d21080f6e1cee
3
+ metadata.gz: 5adcd4b07f5da2256106aa2df3bc5ad67ab64d3b62d69dbfb316edc266bf90be
4
+ data.tar.gz: 2115dd7040fff7fe0fcd20bda97b6e28b7462bc06b3e77bf4e3f738870b5e558
5
5
  SHA512:
6
- metadata.gz: 6ff5b96ebe17b99f51c2c74a325fe1289be0ccaddd96a30ebd06565ee58b2186aede2d6bc3b12b1402b54aa15b517c37e54c450c2e76c281abc51af6f010875f
7
- data.tar.gz: 815b60e5ef7e357f2b83e954af91261e392660df8d92e59c4276c0513ddaa1a849d2541a3f973e43c3f3aeef4a6d13b19c43795e98384a721f189dfb8de1dcd7
6
+ metadata.gz: 85abb14e63e9ae8c6aec9ea4e84995c4c9d26f2410f92630fb0335fa5b40d5e325b4530415b2ed3e983d54cf19b0376160eb820efab5c3e3907e367d3a466f33
7
+ data.tar.gz: 78e547cdc205b0638de16917d78fd6499060a73095ac4d3a35bb12cce1ec049c75e279da8f8d052b59961e75bb7dd232c934679bed0d401847edb74a05642b81
data/lib/gsd/tui/app.rb CHANGED
@@ -8,6 +8,7 @@ require 'gsd/tui/status_bar'
8
8
  require 'gsd/tui/auto_complete'
9
9
  require 'gsd/tui/command_palette'
10
10
  require 'gsd/tui/spinner'
11
+ require 'gsd/ai/config'
11
12
 
12
13
  module Gsd
13
14
  module TUI
@@ -54,7 +55,7 @@ module Gsd
54
55
  end
55
56
  print Colors::HOME
56
57
 
57
- @output << { type: :system, text: 'Welcome to Fantasy CLI v1.2.0!' }
58
+ @output << { type: :system, text: "Welcome to Fantasy CLI v#{Gsd::VERSION}!" }
58
59
  @output << { type: :system, text: 'Press Ctrl+P for commands, Ctrl+Q to quit.' }
59
60
 
60
61
  full_render
@@ -171,9 +172,6 @@ module Gsd
171
172
 
172
173
  # Input box
173
174
  lines << @input_box.render
174
-
175
- # Agent selector
176
- lines << render_agent_selector
177
175
  end
178
176
 
179
177
  # Status bar
@@ -310,6 +308,12 @@ module Gsd
310
308
  text = @input_box.submit
311
309
  return if text.strip.empty?
312
310
 
311
+ # Check for slash commands
312
+ if text.start_with?('/')
313
+ handle_slash_command(text)
314
+ return
315
+ end
316
+
313
317
  @history << text
314
318
  @history_index = @history.length
315
319
  @output << { type: :user, text: text }
@@ -325,6 +329,70 @@ module Gsd
325
329
  @spinner.stop
326
330
  end
327
331
 
332
+ # Handle slash commands like /api
333
+ def handle_slash_command(text)
334
+ parts = text.split
335
+ command = parts[0]
336
+ args = parts[1..]
337
+
338
+ case command
339
+ when '/api'
340
+ handle_api_command(args)
341
+ else
342
+ @output << { type: :error, text: "Unknown command: #{command}" }
343
+ end
344
+ end
345
+
346
+ # Handle /api subcommands
347
+ def handle_api_command(args)
348
+ config_cli = Gsd::AI::ConfigCLI.new(cwd: Dir.pwd)
349
+ subcommand = args[0]
350
+
351
+ case subcommand
352
+ when 'set'
353
+ provider = args[1]
354
+ key = args[2]
355
+ if provider && key
356
+ config_cli.set_key(provider, key)
357
+ @output << { type: :system, text: "✅ API key for #{provider} configured" }
358
+ else
359
+ @output << { type: :error, text: "Usage: /api set <provider> <key>" }
360
+ end
361
+ when 'get'
362
+ provider = args[1]
363
+ if provider
364
+ key = config_cli.get_key(provider)
365
+ if key
366
+ masked = "#{key[0..10]}..."
367
+ @output << { type: :system, text: "#{provider}: #{masked}" }
368
+ else
369
+ @output << { type: :error, text: "❌ API key for #{provider} not configured" }
370
+ end
371
+ else
372
+ @output << { type: :error, text: "Usage: /api get <provider>" }
373
+ end
374
+ when 'list', nil
375
+ @output << { type: :system, text: "🔑 API Keys Status:" }
376
+ providers = %w[anthropic openai openrouter ollama lmstudio groq gemini]
377
+ providers.each do |provider|
378
+ key = config_cli.get_key(provider)
379
+ status = key ? '✅' : '❌'
380
+ @output << { type: :system, text: " #{status} #{provider}" }
381
+ end
382
+ when 'remove', 'rm'
383
+ provider = args[1]
384
+ if provider
385
+ config_cli.remove_key(provider)
386
+ @output << { type: :system, text: "✅ API key for #{provider} removed" }
387
+ else
388
+ @output << { type: :error, text: "Usage: /api remove <provider>" }
389
+ end
390
+ else
391
+ @output << { type: :error, text: "Unknown /api subcommand: #{subcommand}" }
392
+ @output << { type: :system, text: "Usage: /api {set|get|list|remove} [args]" }
393
+ end
394
+ end
395
+
328
396
  def handle_up_arrow
329
397
  return if @history.empty?
330
398
 
@@ -375,24 +443,6 @@ module Gsd
375
443
  'NORMAL'
376
444
  end
377
445
  end
378
-
379
- def render_agent_selector
380
- t = Colors.theme
381
- accent = t[:accent]
382
- white = t[:text]
383
- dim = t[:dim]
384
- reset = Colors::RESET
385
-
386
- parts = @agents.each_with_index.map do |agent, idx|
387
- if idx == @selected_agent
388
- "#{accent}[#{reset}#{white}#{agent}#{reset}#{accent}]#{reset}"
389
- else
390
- "#{dim}[#{agent}]#{reset}"
391
- end
392
- end
393
-
394
- " #{parts.join(' ')}"
395
- end
396
446
  end
397
447
  end
398
448
  end
@@ -14,6 +14,18 @@ module Gsd
14
14
  get-phase analyze
15
15
  ].freeze
16
16
 
17
+ SLASH_COMMANDS = %w[
18
+ /api
19
+ /api set
20
+ /api get
21
+ /api list
22
+ /api remove
23
+ /help
24
+ /quit
25
+ /q
26
+ /clear
27
+ ].freeze
28
+
17
29
  def initialize
18
30
  @suggestions = []
19
31
  @selected_index = 0
@@ -22,7 +34,12 @@ module Gsd
22
34
  def update(text)
23
35
  return [] if text.strip.empty?
24
36
 
25
- @suggestions = COMMANDS.select { |cmd| cmd.start_with?(text.downcase) }
37
+ # Detectar comandos slash
38
+ if text.start_with?('/')
39
+ @suggestions = SLASH_COMMANDS.select { |cmd| cmd.start_with?(text.downcase) }
40
+ else
41
+ @suggestions = COMMANDS.select { |cmd| cmd.start_with?(text.downcase) }
42
+ end
26
43
  @selected_index = 0
27
44
  @suggestions
28
45
  end
@@ -55,15 +72,33 @@ module Gsd
55
72
  dim = t[:dim]
56
73
  reset = Colors::RESET
57
74
 
58
- display = @suggestions.first(3).map.with_index do |sug, i|
75
+ # Build display with proper ANSI handling
76
+ parts = @suggestions.first(3).map.with_index do |sug, i|
77
+ # Truncate suggestion text first (before adding ANSI)
78
+ truncated = sug[0...width]
59
79
  if i == @selected_index
60
- " #{bg}#{selected_fg} #{sug} #{reset}"
80
+ " #{bg}#{selected_fg} #{truncated} #{reset}"
61
81
  else
62
- " #{dim}#{sug}#{reset}"
82
+ " #{dim}#{truncated}#{reset}"
63
83
  end
64
- end.join(' ')
65
-
66
- display[0...width]
84
+ end
85
+
86
+ result = parts.join(' ')
87
+ # Strip ANSI codes to check visible length
88
+ visible_length = result.gsub(/\e\[\d+m/, '').length
89
+ if visible_length > width
90
+ # Find safe truncation point by stripping ANSI, truncating, then adding reset
91
+ stripped = result.gsub(/\e\[\d+m/, '')
92
+ # Account for the extra spaces from join(' ')
93
+ num_items = [parts.length, 3].min
94
+ extra_spaces = (num_items - 1) * 2
95
+ safe_width = width - extra_spaces - 1
96
+ safe_stripped = stripped[0...safe_width]
97
+ # Return stripped version to avoid broken ANSI
98
+ safe_stripped + reset
99
+ else
100
+ result
101
+ end
67
102
  end
68
103
 
69
104
  def has_suggestions?
data/lib/gsd/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gsd
4
- VERSION = '1.2.11'
4
+ VERSION = '1.2.14'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fantasy-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.11
4
+ version: 1.2.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fantasy Team