kward 0.76.0 → 0.77.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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +8 -1
  3. data/CHANGELOG.md +36 -0
  4. data/Gemfile.lock +2 -2
  5. data/README.md +12 -4
  6. data/doc/agent-tools.md +0 -3
  7. data/doc/api.md +4 -0
  8. data/doc/composer.md +219 -0
  9. data/doc/configuration.md +75 -27
  10. data/doc/editor.md +18 -2
  11. data/doc/files.md +1 -1
  12. data/doc/getting-started.md +4 -0
  13. data/doc/git.md +2 -2
  14. data/doc/lifecycle-hooks.md +2 -14
  15. data/doc/pan.md +167 -0
  16. data/doc/rpc.md +0 -22
  17. data/doc/security.md +180 -0
  18. data/doc/usage.md +15 -32
  19. data/lib/kward/ansi.rb +2 -2
  20. data/lib/kward/cancellation.rb +2 -2
  21. data/lib/kward/cli/commands.rb +1 -3
  22. data/lib/kward/cli/interactive_turn.rb +0 -17
  23. data/lib/kward/cli/plugins.rb +2 -7
  24. data/lib/kward/cli/prompt_interface.rb +1 -0
  25. data/lib/kward/cli/runtime_helpers.rb +0 -38
  26. data/lib/kward/cli/sessions.rb +14 -5
  27. data/lib/kward/cli/settings.rb +22 -0
  28. data/lib/kward/cli/slash_commands.rb +1 -561
  29. data/lib/kward/cli/tabs.rb +14 -2
  30. data/lib/kward/cli.rb +1 -17
  31. data/lib/kward/compactor.rb +3 -3
  32. data/lib/kward/config_files.rb +18 -0
  33. data/lib/kward/ekwsh.rb +0 -4
  34. data/lib/kward/hooks/catalog.rb +0 -5
  35. data/lib/kward/image_attachments.rb +1 -1
  36. data/lib/kward/pan/index.html.erb +459 -64
  37. data/lib/kward/pan/kward_logo.png +0 -0
  38. data/lib/kward/pan/server.rb +248 -23
  39. data/lib/kward/plugin_registry.rb +18 -0
  40. data/lib/kward/prompt_interface/editor/auto_indent.rb +31 -23
  41. data/lib/kward/prompt_interface/editor/modes/vibe.rb +72 -3
  42. data/lib/kward/prompt_interface/layout.rb +0 -4
  43. data/lib/kward/prompt_interface/project_browser.rb +40 -1
  44. data/lib/kward/prompt_interface/runtime_state.rb +4 -0
  45. data/lib/kward/prompt_interface/selection_prompt.rb +0 -1
  46. data/lib/kward/prompt_interface/transcript_renderer.rb +0 -12
  47. data/lib/kward/prompt_interface.rb +18 -1
  48. data/lib/kward/prompts/commands.rb +1 -3
  49. data/lib/kward/prompts.rb +20 -0
  50. data/lib/kward/rpc/server.rb +13 -41
  51. data/lib/kward/rpc/session_manager.rb +75 -25
  52. data/lib/kward/rpc/tool_event_normalizer.rb +2 -0
  53. data/lib/kward/rpc/tool_metadata.rb +23 -0
  54. data/lib/kward/rpc/transcript_normalizer.rb +4 -0
  55. data/lib/kward/session_store.rb +55 -16
  56. data/lib/kward/skills/registry.rb +21 -1
  57. data/lib/kward/tools/base.rb +14 -0
  58. data/lib/kward/tools/registry.rb +11 -16
  59. data/lib/kward/tools/search/code.rb +1 -1
  60. data/lib/kward/tools/search/web.rb +1 -1
  61. data/lib/kward/tools/tool_call.rb +0 -4
  62. data/lib/kward/transcript_export.rb +1 -1
  63. data/lib/kward/version.rb +1 -1
  64. data/templates/default/kward_navigation.rb +5 -1
  65. data/templates/default/layout/html/layout.erb +0 -2
  66. metadata +5 -12
  67. data/lib/kward/workers/git_guard.rb +0 -93
  68. data/lib/kward/workers/job.rb +0 -99
  69. data/lib/kward/workers/live_view.rb +0 -49
  70. data/lib/kward/workers/manager.rb +0 -328
  71. data/lib/kward/workers/queue_runner.rb +0 -166
  72. data/lib/kward/workers/queue_store.rb +0 -112
  73. data/lib/kward/workers/store.rb +0 -72
  74. data/lib/kward/workers/tool_policy.rb +0 -23
  75. data/lib/kward/workers/worker.rb +0 -82
  76. data/lib/kward/workers/write_lock.rb +0 -38
  77. data/lib/kward/workers.rb +0 -10
@@ -37,7 +37,7 @@ module Kward
37
37
 
38
38
  Cut = Struct.new(:first_kept_index, :messages_to_summarize, :turn_prefix_messages, :split_turn, :preserved_messages, :preserved_start_index, keyword_init: true)
39
39
 
40
- # Interactive settings menu actions mixed into the CLI frontend.
40
+ # Configuration for manual and automatic conversation compaction.
41
41
  class Settings
42
42
  DEFAULT_ENABLED = true
43
43
  DEFAULT_RESERVE_TOKENS = 16_384
@@ -731,7 +731,7 @@ module Kward
731
731
  SummarizationFailed = Compaction::SummarizationFailed
732
732
 
733
733
  AUTO_COMPACTION_GUARD_RATIO = 0.10
734
- AUTO_COMPACTION_EXTRA_GUARD_CAP = 12_000
734
+ AUTO_COMPACTION_EXTRA_GUARD_FLOOR = 12_000
735
735
 
736
736
  # Creates an object for conversation compaction.
737
737
  def initialize(conversation:, client:, tool_result_summarizer: nil, settings: nil, summarizer: nil)
@@ -805,7 +805,7 @@ module Kward
805
805
  def self.auto_compaction_reserve_tokens(context_window:, configured_reserve_tokens:)
806
806
  context_window_i = context_window.to_i
807
807
  dynamic_guard = (context_window_i * AUTO_COMPACTION_GUARD_RATIO).to_i
808
- [configured_reserve_tokens.to_i, dynamic_guard, AUTO_COMPACTION_EXTRA_GUARD_CAP].max
808
+ [configured_reserve_tokens.to_i, dynamic_guard, AUTO_COMPACTION_EXTRA_GUARD_FLOOR].max
809
809
  end
810
810
 
811
811
  def compaction_messages(custom_instructions = nil)
@@ -24,7 +24,9 @@ module Kward
24
24
  # Keep path decisions here. Higher-level code should ask `ConfigFiles` for
25
25
  # config, prompt, skill, plugin, cache, memory, and session locations instead of
26
26
  # reconstructing `~/.kward` paths independently.
27
+ # @api public
27
28
  module ConfigFiles
29
+ # Raised when a user configuration file cannot be parsed.
28
30
  class ConfigError < StandardError
29
31
  attr_reader :path, :format, :detail
30
32
 
@@ -39,6 +41,7 @@ module Kward
39
41
  MAX_SKILL_FILE_BYTES = 100_000
40
42
  MAX_PROMPT_FILE_BYTES = 32 * 1024
41
43
  DEFAULT_OVERLAY_SETTINGS = { "alignment" => "center", "width" => "maximum" }.freeze
44
+ PROJECT_BROWSER_ICON_THEMES = %w[off nerd-font].freeze
42
45
  DEFAULT_PERSONAS = {
43
46
  "characters" => [
44
47
  {
@@ -87,10 +90,12 @@ module Kward
87
90
  File.expand_path(ENV["KWARD_CONFIG_PATH"] || File.join(config_dir, "config.json"))
88
91
  end
89
92
 
93
+ # @return [String] directory containing reusable local caches
90
94
  def cache_dir
91
95
  File.join(config_dir, "cache")
92
96
  end
93
97
 
98
+ # @return [String] embedded-shell YAML config path
94
99
  def ekwsh_config_path
95
100
  File.join(config_dir, "ekwsh.yml")
96
101
  end
@@ -103,6 +108,9 @@ module Kward
103
108
  File.join(config_dir, "trusted_workspace_hooks.json")
104
109
  end
105
110
 
111
+ # Returns a fresh default config suitable for first-run persistence.
112
+ #
113
+ # @return [Hash] deep-mutable config defaults
106
114
  def default_config
107
115
  {
108
116
  "personas" => JSON.parse(JSON.generate(DEFAULT_PERSONAS)),
@@ -124,6 +132,9 @@ module Kward
124
132
  "diff_view" => "auto"
125
133
  },
126
134
  "overlay" => DEFAULT_OVERLAY_SETTINGS.dup,
135
+ "project_browser" => {
136
+ "icons" => "off"
137
+ },
127
138
  "web_search" => {
128
139
  "enabled" => true,
129
140
  "provider" => "auto",
@@ -409,6 +420,13 @@ module Kward
409
420
  settings
410
421
  end
411
422
 
423
+ # Returns the project browser icon theme, or off when unset or invalid.
424
+ def project_browser_icon_theme(config = read_config)
425
+ browser = config["project_browser"].is_a?(Hash) ? config["project_browser"] : {}
426
+ theme = browser["icons"].to_s
427
+ PROJECT_BROWSER_ICON_THEMES.include?(theme) ? theme : "off"
428
+ end
429
+
412
430
  # Returns whether the composer should show busy-state keyboard help.
413
431
  def composer_busy_help?(config = read_config)
414
432
  composer = config["composer"].is_a?(Hash) ? config["composer"] : {}
data/lib/kward/ekwsh.rb CHANGED
@@ -551,9 +551,5 @@ module Kward
551
551
  ANSI.sanitize_transcript(text)
552
552
  end
553
553
 
554
- def clean_output(value)
555
- text = clean_chunk(value)
556
- text.end_with?("\n") || text.empty? ? text : "#{text}\n"
557
- end
558
554
  end
559
555
  end
@@ -45,11 +45,6 @@ module Kward
45
45
  EventDefinition.new(name: "git_stage_after", failure_policy: "warn"),
46
46
  EventDefinition.new(name: "git_commit_before", failure_policy: "deny"),
47
47
  EventDefinition.new(name: "git_commit_after", failure_policy: "warn"),
48
- EventDefinition.new(name: "worker_job_create", failure_policy: "warn"),
49
- EventDefinition.new(name: "worker_job_start_before", failure_policy: "warn"),
50
- EventDefinition.new(name: "worker_job_start_after", failure_policy: "warn"),
51
- EventDefinition.new(name: "worker_job_ready_for_review", failure_policy: "warn"),
52
- EventDefinition.new(name: "worker_job_failed", failure_policy: "warn")
53
48
  ].each_with_object({}) { |definition, result| result[definition.name] = definition }.freeze
54
49
 
55
50
  module_function
@@ -1,5 +1,5 @@
1
1
  require "base64"
2
- require "cgi"
2
+ require "cgi/escape"
3
3
  require "shellwords"
4
4
  require "tmpdir"
5
5
  require "uri"