kward 0.71.0 → 0.72.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.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -1
  3. data/Gemfile.lock +2 -2
  4. data/README.md +4 -0
  5. data/doc/agent-tools.md +15 -6
  6. data/doc/authentication.md +22 -1
  7. data/doc/code-search.md +42 -2
  8. data/doc/configuration.md +106 -3
  9. data/doc/context-budgeting.md +136 -0
  10. data/doc/context-tools.md +16 -3
  11. data/doc/editor.md +394 -0
  12. data/doc/extensibility.md +16 -7
  13. data/doc/files.md +100 -0
  14. data/doc/getting-started.md +25 -18
  15. data/doc/git.md +122 -0
  16. data/doc/memory.md +24 -4
  17. data/doc/personas.md +34 -5
  18. data/doc/plugins.md +72 -1
  19. data/doc/releasing.md +37 -9
  20. data/doc/rpc.md +74 -4
  21. data/doc/session-management.md +35 -1
  22. data/doc/shell.md +286 -0
  23. data/doc/tabs.md +122 -0
  24. data/doc/troubleshooting.md +77 -1
  25. data/doc/usage.md +53 -7
  26. data/doc/web-search.md +12 -4
  27. data/doc/workspace-tools.md +51 -12
  28. data/examples/plugins/space_invaders.rb +377 -0
  29. data/lib/kward/agent.rb +1 -1
  30. data/lib/kward/cli/commands.rb +33 -2
  31. data/lib/kward/cli/git.rb +150 -0
  32. data/lib/kward/cli/interactive_turn.rb +73 -9
  33. data/lib/kward/cli/plugins.rb +54 -4
  34. data/lib/kward/cli/prompt_interface.rb +32 -1
  35. data/lib/kward/cli/runtime_helpers.rb +133 -3
  36. data/lib/kward/cli/sessions.rb +2 -2
  37. data/lib/kward/cli/settings.rb +218 -9
  38. data/lib/kward/cli/slash_commands.rb +415 -2
  39. data/lib/kward/cli/tabs.rb +695 -0
  40. data/lib/kward/cli.rb +158 -26
  41. data/lib/kward/config_files.rb +123 -1
  42. data/lib/kward/context_budget_meter.rb +44 -0
  43. data/lib/kward/conversation.rb +12 -4
  44. data/lib/kward/editor_mode.rb +25 -0
  45. data/lib/kward/ekwsh.rb +362 -0
  46. data/lib/kward/plugin_registry.rb +61 -0
  47. data/lib/kward/project_files.rb +52 -0
  48. data/lib/kward/prompt_history.rb +82 -0
  49. data/lib/kward/prompt_interface/composer_controller.rb +69 -1
  50. data/lib/kward/prompt_interface/composer_renderer.rb +109 -13
  51. data/lib/kward/prompt_interface/composer_state.rb +96 -27
  52. data/lib/kward/prompt_interface/editor/auto_close_pairs.rb +123 -0
  53. data/lib/kward/prompt_interface/editor/auto_indent.rb +509 -0
  54. data/lib/kward/prompt_interface/editor/buffer.rb +109 -0
  55. data/lib/kward/prompt_interface/editor/controller.rb +1018 -0
  56. data/lib/kward/prompt_interface/editor/endwise.rb +321 -0
  57. data/lib/kward/prompt_interface/editor/file_marker.rb +40 -0
  58. data/lib/kward/prompt_interface/editor/indent_navigation.rb +61 -0
  59. data/lib/kward/prompt_interface/editor/kill_ring.rb +78 -0
  60. data/lib/kward/prompt_interface/editor/modes/emacs.rb +259 -0
  61. data/lib/kward/prompt_interface/editor/modes/modern.rb +353 -0
  62. data/lib/kward/prompt_interface/editor/modes/vibe.rb +1962 -0
  63. data/lib/kward/prompt_interface/editor/renderer.rb +243 -0
  64. data/lib/kward/prompt_interface/editor/search.rb +76 -0
  65. data/lib/kward/prompt_interface/editor/selections.rb +120 -0
  66. data/lib/kward/prompt_interface/editor/state.rb +1249 -0
  67. data/lib/kward/prompt_interface/editor/status_text.rb +23 -0
  68. data/lib/kward/prompt_interface/editor/syntax_highlighter.rb +420 -0
  69. data/lib/kward/prompt_interface/editor/undo_history.rb +46 -0
  70. data/lib/kward/prompt_interface/editor/vibe_state.rb +44 -0
  71. data/lib/kward/prompt_interface/file_overlay.rb +211 -0
  72. data/lib/kward/prompt_interface/git_prompt.rb +299 -0
  73. data/lib/kward/prompt_interface/interactive/controller.rb +186 -0
  74. data/lib/kward/prompt_interface/interactive/renderer.rb +71 -0
  75. data/lib/kward/prompt_interface/interactive/state.rb +62 -0
  76. data/lib/kward/prompt_interface/key_handler.rb +387 -35
  77. data/lib/kward/prompt_interface/overlay_renderer.rb +21 -2
  78. data/lib/kward/prompt_interface/project_browser.rb +524 -0
  79. data/lib/kward/prompt_interface/question_prompt.rb +98 -50
  80. data/lib/kward/prompt_interface/runtime_state.rb +43 -0
  81. data/lib/kward/prompt_interface/screen.rb +16 -0
  82. data/lib/kward/prompt_interface/selection_prompt.rb +7 -13
  83. data/lib/kward/prompt_interface/stream_state.rb +7 -0
  84. data/lib/kward/prompt_interface/transcript_buffer.rb +6 -0
  85. data/lib/kward/prompt_interface.rb +286 -8
  86. data/lib/kward/prompts/commands.rb +5 -0
  87. data/lib/kward/prompts.rb +2 -0
  88. data/lib/kward/rpc/server.rb +42 -3
  89. data/lib/kward/rpc/session_manager.rb +35 -47
  90. data/lib/kward/rpc/session_tree_rows.rb +9 -115
  91. data/lib/kward/rpc/tool_event_normalizer.rb +1 -1
  92. data/lib/kward/session_store.rb +44 -0
  93. data/lib/kward/session_tree_nodes.rb +136 -0
  94. data/lib/kward/session_tree_renderer.rb +9 -131
  95. data/lib/kward/tab_store.rb +47 -0
  96. data/lib/kward/text_boundary.rb +25 -0
  97. data/lib/kward/tools/context_budget_stats.rb +54 -0
  98. data/lib/kward/tools/context_for_task.rb +202 -0
  99. data/lib/kward/tools/read_file.rb +8 -4
  100. data/lib/kward/tools/registry.rb +62 -16
  101. data/lib/kward/tools/tool_call.rb +10 -0
  102. data/lib/kward/version.rb +1 -1
  103. data/lib/kward/workers/git_guard.rb +68 -0
  104. data/lib/kward/workers/live_view.rb +49 -0
  105. data/lib/kward/workers/manager.rb +288 -0
  106. data/lib/kward/workers/store.rb +72 -0
  107. data/lib/kward/workers/tool_policy.rb +23 -0
  108. data/lib/kward/workers/worker.rb +82 -0
  109. data/lib/kward/workers/write_lock.rb +38 -0
  110. data/lib/kward/workers.rb +7 -0
  111. data/lib/kward/workspace.rb +110 -24
  112. data/templates/default/fulldoc/html/css/kward.css +107 -36
  113. data/templates/default/kward_navigation.rb +12 -1
  114. data/templates/default/layout/html/layout.erb +4 -2
  115. data/templates/default/layout/html/setup.rb +6 -0
  116. metadata +53 -1
@@ -0,0 +1,71 @@
1
+ # Namespace for the Kward CLI agent runtime.
2
+ module Kward
3
+ # Interactive terminal UI used by the CLI frontend.
4
+ class PromptInterface
5
+ # Renderer for interactive mode canvas frames. Draws the canvas buffer into
6
+ # the composer region using the same boxed-row infrastructure as the editor.
7
+ module InteractiveRenderer
8
+ private
9
+
10
+ def interactive_active_locked?
11
+ !@interactive_state.nil?
12
+ end
13
+
14
+ def interactive_layout(width, height = screen_height)
15
+ state = @interactive_state
16
+ controller = state[:controller]
17
+ rows = [interactive_top_border(width, state)]
18
+ content_width = [width - 4, 1].max
19
+ canvas_width = [content_width - 2, 1].max
20
+
21
+ controller.cells.each do |cell_row|
22
+ line = cell_row[0, canvas_width].map do |cell|
23
+ char = cell[:char]
24
+ colors = cell[:colors]
25
+ colors.empty? ? char : colored(char, *colors)
26
+ end.join
27
+ rows << box_content_row(visible_ljust(line, content_width), content_width)
28
+ end
29
+
30
+ rows << footer_row(content_width, interactive_status_text(state))
31
+ rows.concat(interactive_bottom_rows(width))
32
+ cursor_row = 1
33
+ cursor_col = 2
34
+ [rows, cursor_row, cursor_col]
35
+ end
36
+
37
+ def interactive_top_border(width, state)
38
+ title = visible_truncate(state[:title].to_s, [width - 4, 1].max)
39
+ plain_title = ANSI.strip(title)
40
+ "#{colored("╭", :primary_green)} #{title} #{colored("─" * [width - plain_title.length - 4, 0].max, :primary_green)}#{colored("╮", :primary_green)}"
41
+ end
42
+
43
+ def interactive_status_text(state)
44
+ fps = state[:controller].fps
45
+ "Interactive · #{fps.to_i}fps · Ctrl+C exits"
46
+ end
47
+
48
+ def interactive_bottom_rows(width)
49
+ @tabs.empty? ? [bottom_border(width)] : tab_border_rows(width)
50
+ end
51
+
52
+ def tick_interactive_locked
53
+ return false unless interactive_active_locked?
54
+
55
+ controller = @interactive_state[:controller]
56
+ return false if controller.exited?
57
+
58
+ now = monotonic_now
59
+ interval = 1.0 / controller.fps
60
+ elapsed = now - @last_interactive_tick
61
+ return false if elapsed < interval
62
+
63
+ steps = (elapsed / interval).floor
64
+ @last_interactive_tick += steps * interval
65
+ result = controller.invoke_tick
66
+ controller.exit if result == :exit
67
+ true
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,62 @@
1
+ # Namespace for the Kward CLI agent runtime.
2
+ module Kward
3
+ # Interactive terminal UI used by the CLI frontend.
4
+ class PromptInterface
5
+ # State lifecycle for interactive mode. Manages entering and exiting the
6
+ # canvas-based render loop, including composer snapshot save/restore.
7
+ module InteractiveState
8
+ private
9
+
10
+ def interactive_canvas_width
11
+ [screen_width - 6, 1].max
12
+ end
13
+
14
+ def route_interactive_key(key)
15
+ return false unless interactive_active_locked?
16
+
17
+ interactive_key = interactive_csi_u_key(key)
18
+ unless interactive_key == false
19
+ return force_interactive_exit if interactive_key == :force_exit
20
+
21
+ @interactive_state[:controller].push_key(interactive_key)
22
+ return true
23
+ end
24
+
25
+ name = key_name_for(key) if key.is_a?(String) && key.length >= 1
26
+ return force_interactive_exit if key == "\x03" || name == :escape
27
+
28
+ @interactive_state[:controller].push_key(name || key)
29
+ true
30
+ end
31
+
32
+ def interactive_csi_u_key(key)
33
+ sequence = parse_csi_u_key(key)
34
+ return false unless sequence
35
+
36
+ code = sequence[:code]
37
+ modifier = sequence[:modifier]
38
+ queue_pending_keys(sequence[:remaining]) if sequence[:remaining] && !sequence[:remaining].empty?
39
+
40
+ return :force_exit if code == 27 || (code.to_i.chr.downcase == "c" && ctrl_modifier?(modifier))
41
+ return :return if code == 13
42
+ return :backspace if [8, 127].include?(code)
43
+ return :space if code == 32 && !ctrl_modifier?(modifier) && !alt_modifier?(modifier) && !super_modifier?(modifier)
44
+
45
+ text = csi_u_printable_text(sequence)
46
+ return text if text
47
+
48
+ false
49
+ end
50
+
51
+ def force_interactive_exit
52
+ @interactive_state[:controller].force_exit
53
+ true
54
+ end
55
+
56
+ def handle_interactive_key(key)
57
+ route_interactive_key(key)
58
+ nil
59
+ end
60
+ end
61
+ end
62
+ end