kward 0.83.0 → 0.85.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 (193) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -15
  3. data/CONTRIBUTING.md +74 -0
  4. data/Gemfile.lock +8 -2
  5. data/README.md +21 -1
  6. data/Rakefile +46 -2
  7. data/SECURITY.md +31 -0
  8. data/doc/agent-tools.md +13 -1
  9. data/doc/api.md +21 -2
  10. data/doc/composer.md +2 -2
  11. data/doc/configuration.md +95 -25
  12. data/doc/editor.md +28 -13
  13. data/doc/extensibility.md +2 -1
  14. data/doc/files.md +8 -4
  15. data/doc/getting-started.md +3 -0
  16. data/doc/git.md +3 -1
  17. data/doc/pan.md +25 -15
  18. data/doc/permissions.md +4 -4
  19. data/doc/platform-support.md +48 -0
  20. data/doc/plugins.md +464 -15
  21. data/doc/rpc.md +154 -16
  22. data/doc/sandboxing.md +11 -5
  23. data/doc/security.md +10 -3
  24. data/doc/session-management.md +5 -4
  25. data/doc/shell.md +62 -45
  26. data/doc/tabs.md +6 -2
  27. data/doc/transports.md +15 -0
  28. data/doc/troubleshooting.md +12 -2
  29. data/doc/usage.md +9 -6
  30. data/doc/workspace-tools.md +9 -0
  31. data/examples/plugins/space_invaders.rb +1 -1
  32. data/examples/plugins/stardate_footer.rb +2 -2
  33. data/examples/plugins/telegram/plugin.rb +1 -1
  34. data/kward.gemspec +5 -4
  35. data/lib/kward/agent.rb +30 -14
  36. data/lib/kward/cli/auth_commands.rb +34 -13
  37. data/lib/kward/cli/commands.rb +83 -62
  38. data/lib/kward/cli/compaction.rb +9 -3
  39. data/lib/kward/cli/doctor.rb +39 -17
  40. data/lib/kward/cli/hook_commands.rb +22 -12
  41. data/lib/kward/cli/interactive_turn.rb +48 -7
  42. data/lib/kward/cli/plugins.rb +81 -12
  43. data/lib/kward/cli/project_skills_commands.rb +8 -4
  44. data/lib/kward/cli/prompt_interface.rb +52 -5
  45. data/lib/kward/cli/rendering.rb +18 -9
  46. data/lib/kward/cli/runtime_helpers.rb +228 -71
  47. data/lib/kward/cli/sessions.rb +9 -5
  48. data/lib/kward/cli/settings/menus.rb +745 -0
  49. data/lib/kward/cli/settings/model.rb +327 -0
  50. data/lib/kward/cli/settings.rb +6 -1055
  51. data/lib/kward/cli/slash_commands.rb +56 -17
  52. data/lib/kward/cli/tabs.rb +244 -33
  53. data/lib/kward/cli/tool_summaries.rb +14 -0
  54. data/lib/kward/{cli_transcript_formatter.rb → cli/transcript_formatter.rb} +14 -7
  55. data/lib/kward/cli/worktrees.rb +65 -2
  56. data/lib/kward/cli.rb +70 -30
  57. data/lib/kward/compactor.rb +18 -7
  58. data/lib/kward/config/core.rb +389 -0
  59. data/lib/kward/config/extensions.rb +96 -0
  60. data/lib/kward/config/prompts.rb +313 -0
  61. data/lib/kward/config/settings.rb +250 -0
  62. data/lib/kward/config_files.rb +14 -994
  63. data/lib/kward/conversation.rb +31 -2
  64. data/lib/kward/image_attachments.rb +1 -1
  65. data/lib/kward/model/client.rb +36 -24
  66. data/lib/kward/model/copilot_models.rb +2 -2
  67. data/lib/kward/model/model_info.rb +20 -3
  68. data/lib/kward/{openrouter_model_cache.rb → model/openrouter_model_cache.rb} +3 -3
  69. data/lib/kward/model/payloads.rb +12 -3
  70. data/lib/kward/model/provider_catalog.rb +5 -0
  71. data/lib/kward/model/stream_parser.rb +20 -4
  72. data/lib/kward/model/typesafe_client.rb +78 -0
  73. data/lib/kward/pan/index.html.erb +3 -3
  74. data/lib/kward/pan/server.rb +33 -10
  75. data/lib/kward/permissions/policy.rb +6 -2
  76. data/lib/kward/plugin_registry.rb +2 -659
  77. data/lib/kward/plugins/actions.rb +453 -0
  78. data/lib/kward/plugins/chat_contract.rb +121 -0
  79. data/lib/kward/{plugin_chat_runtime.rb → plugins/chat_runtime.rb} +62 -18
  80. data/lib/kward/plugins/host.rb +232 -0
  81. data/lib/kward/plugins/registry.rb +1190 -0
  82. data/lib/kward/plugins/resources.rb +206 -0
  83. data/lib/kward/plugins/turn_request.rb +36 -0
  84. data/lib/kward/plugins/ui.rb +219 -0
  85. data/lib/kward/prompt_interface/composer_renderer.rb +44 -40
  86. data/lib/kward/prompt_interface/composer_state.rb +33 -24
  87. data/lib/kward/prompt_interface/editor/auto_indent.rb +24 -22
  88. data/lib/kward/prompt_interface/editor/controller.rb +30 -33
  89. data/lib/kward/prompt_interface/editor/endwise.rb +13 -4
  90. data/lib/kward/prompt_interface/editor/markdown_code_block.rb +136 -0
  91. data/lib/kward/prompt_interface/editor/modes/vibe.rb +289 -44
  92. data/lib/kward/prompt_interface/editor/renderer.rb +108 -6
  93. data/lib/kward/prompt_interface/editor/runner.rb +362 -0
  94. data/lib/kward/prompt_interface/editor/runner_state.rb +78 -0
  95. data/lib/kward/prompt_interface/editor/scratchpad_languages.rb +74 -0
  96. data/lib/kward/prompt_interface/editor/scratchpad_runner.rb +182 -0
  97. data/lib/kward/prompt_interface/editor/state.rb +11 -11
  98. data/lib/kward/prompt_interface/editor/syntax_highlighter.rb +68 -6
  99. data/lib/kward/prompt_interface/editor/vibe_state.rb +3 -3
  100. data/lib/kward/prompt_interface/file_overlay.rb +71 -15
  101. data/lib/kward/prompt_interface/key_handler.rb +67 -0
  102. data/lib/kward/prompt_interface/layout.rb +1 -1
  103. data/lib/kward/prompt_interface/overlay_renderer.rb +7 -5
  104. data/lib/kward/prompt_interface/plugin_ui_requests.rb +82 -0
  105. data/lib/kward/prompt_interface/project_browser.rb +415 -14
  106. data/lib/kward/prompt_interface/runtime_state.rb +56 -2
  107. data/lib/kward/prompt_interface/screen.rb +11 -4
  108. data/lib/kward/prompt_interface/selection_prompt.rb +3 -1
  109. data/lib/kward/prompt_interface/slash_overlay.rb +19 -4
  110. data/lib/kward/prompt_interface/transcript_renderer.rb +12 -7
  111. data/lib/kward/prompt_interface.rb +151 -27
  112. data/lib/kward/prompts/commands.rb +3 -2
  113. data/lib/kward/prompts.rb +1 -1
  114. data/lib/kward/{adaptive_pty_output_sink.rb → pty/adaptive_output_sink.rb} +1 -1
  115. data/lib/kward/pty/detached_run.rb +44 -0
  116. data/lib/kward/{interactive_pty_runner.rb → pty/interactive_runner.rb} +104 -30
  117. data/lib/kward/{local_command_runner.rb → pty/local_command_runner.rb} +1 -1
  118. data/lib/kward/{local_pty_command_runner.rb → pty/local_pty_runner.rb} +3 -9
  119. data/lib/kward/{pty_output_sink.rb → pty/output_sink.rb} +52 -0
  120. data/lib/kward/{pty_transcript_normalizer.rb → pty/transcript_normalizer.rb} +1 -1
  121. data/lib/kward/rpc/plugin_chat_manager.rb +30 -10
  122. data/lib/kward/rpc/prompt_bridge.rb +25 -0
  123. data/lib/kward/rpc/server.rb +91 -12
  124. data/lib/kward/rpc/session_manager.rb +147 -44
  125. data/lib/kward/rpc/session_tree_rows.rb +2 -2
  126. data/lib/kward/rpc/tool_metadata.rb +1 -1
  127. data/lib/kward/rpc/transcript_normalizer.rb +7 -3
  128. data/lib/kward/sandbox/command_runner.rb +1 -1
  129. data/lib/kward/{session_catalog.rb → sessions/catalog.rb} +1 -1
  130. data/lib/kward/{session_store.rb → sessions/store.rb} +9 -9
  131. data/lib/kward/{session_tree_nodes.rb → sessions/tree_nodes.rb} +3 -3
  132. data/lib/kward/{session_tree_renderer.rb → sessions/tree_renderer.rb} +4 -4
  133. data/lib/kward/{session_tree_tool_display.rb → sessions/tree_tool_display.rb} +1 -1
  134. data/lib/kward/{ekwsh.rb → shell/kwsh.rb} +38 -19
  135. data/lib/kward/shell/kwshrc.rb +233 -0
  136. data/lib/kward/{persistent_shell_session.rb → shell/persistent_session.rb} +121 -28
  137. data/lib/kward/{shell_prompt.rb → shell/prompt.rb} +2 -0
  138. data/lib/kward/{shell_prompt_session.rb → shell/prompt_session.rb} +1 -1
  139. data/lib/kward/skills/trust_store.rb +1 -1
  140. data/lib/kward/tabs/driver.rb +194 -0
  141. data/lib/kward/{tab_store.rb → tabs/store.rb} +2 -2
  142. data/lib/kward/{ansi.rb → terminal/ansi.rb} +110 -10
  143. data/lib/kward/{clipboard.rb → terminal/clipboard.rb} +1 -1
  144. data/lib/kward/{terminal_image_support.rb → terminal/image_support.rb} +1 -1
  145. data/lib/kward/{terminal_keys.rb → terminal/keys.rb} +12 -0
  146. data/lib/kward/terminal/text.rb +121 -0
  147. data/lib/kward/text_matcher.rb +18 -0
  148. data/lib/kward/tools/base.rb +18 -0
  149. data/lib/kward/tools/context_for_task.rb +15 -6
  150. data/lib/kward/tools/edit_file.rb +9 -6
  151. data/lib/kward/tools/git_commit.rb +13 -7
  152. data/lib/kward/tools/list_directory.rb +4 -4
  153. data/lib/kward/tools/open_editor.rb +41 -0
  154. data/lib/kward/tools/plugin_tool.rb +41 -0
  155. data/lib/kward/tools/prepare_shell_command.rb +1 -1
  156. data/lib/kward/tools/read_file.rb +7 -6
  157. data/lib/kward/tools/registry.rb +109 -17
  158. data/lib/kward/tools/run_shell_command.rb +10 -8
  159. data/lib/kward/tools/search/code.rb +1 -1
  160. data/lib/kward/tools/summarize_file_structure.rb +5 -5
  161. data/lib/kward/tools/tool_call.rb +3 -1
  162. data/lib/kward/tools/typesafe_evaluate.rb +81 -0
  163. data/lib/kward/tools/workspace_targets.rb +58 -0
  164. data/lib/kward/tools/write_file.rb +9 -6
  165. data/lib/kward/{export_path.rb → transcripts/export_path.rb} +1 -1
  166. data/lib/kward/{markdown_transcript.rb → transcripts/markdown_transcript.rb} +2 -2
  167. data/lib/kward/transport/contracts.rb +200 -0
  168. data/lib/kward/transport/gateway.rb +79 -35
  169. data/lib/kward/transport/plugin_chat_gateway.rb +3 -2
  170. data/lib/kward/transport.rb +1 -200
  171. data/lib/kward/version.rb +1 -1
  172. data/lib/kward/{workspace_factory.rb → workspace/factory.rb} +2 -2
  173. data/lib/kward/{project_files.rb → workspace/files.rb} +2 -2
  174. data/lib/kward/{git_worktree_manager.rb → workspace/git_worktree_manager.rb} +28 -0
  175. data/lib/kward/{workspace.rb → workspace/workspace.rb} +3 -3
  176. data/templates/default/kward_navigation.rb +1 -0
  177. data/templates/default/layout/html/footer.erb +10 -0
  178. data/templates/default/layout/html/headers.erb +23 -0
  179. data/templates/default/layout/html/layout.erb +2 -2
  180. data/templates/default/layout/html/setup.rb +41 -2
  181. metadata +94 -47
  182. data/lib/kward/scratchpad_runner.rb +0 -56
  183. data/lib/kward/tab_driver.rb +0 -90
  184. /data/lib/kward/{editor_prompt.rb → cli/editor_prompt.rb} +0 -0
  185. /data/lib/kward/{editor_prompt_session.rb → cli/editor_prompt_session.rb} +0 -0
  186. /data/lib/kward/{diff_view_mode.rb → prompt_interface/editor/diff_view_mode.rb} +0 -0
  187. /data/lib/kward/{editor_mode.rb → prompt_interface/editor/editor_mode.rb} +0 -0
  188. /data/lib/kward/{session_diff.rb → sessions/diff.rb} +0 -0
  189. /data/lib/kward/{session_naming.rb → sessions/naming.rb} +0 -0
  190. /data/lib/kward/{session_trash.rb → sessions/trash.rb} +0 -0
  191. /data/lib/kward/{terminal_sequences.rb → terminal/sequences.rb} +0 -0
  192. /data/lib/kward/{transcript_export.rb → transcripts/transcript_export.rb} +0 -0
  193. /data/lib/kward/{path_guard.rb → workspace/path_guard.rb} +0 -0
@@ -133,6 +133,16 @@ module Kward
133
133
  run_git(path, "diff", "--name-only", "--diff-filter=U").lines(chomp: true)
134
134
  end
135
135
 
136
+ def merge_conflict_marker_paths(path, cached: true)
137
+ arguments = ["diff"]
138
+ arguments << "--cached" if cached
139
+ arguments << "--check"
140
+ output, _status = capture_git(path, *arguments)
141
+ output.lines.filter_map do |line|
142
+ line[/\A(.+?):\d+: leftover conflict marker/, 1]
143
+ end.uniq
144
+ end
145
+
136
146
  def abort_merge(path)
137
147
  raise Error, "No merge is in progress." unless merge_in_progress?(path)
138
148
 
@@ -140,6 +150,24 @@ module Kward
140
150
  true
141
151
  end
142
152
 
153
+ def continue_merge(path)
154
+ raise Error, "No merge is in progress." unless merge_in_progress?(path)
155
+
156
+ run_git(path, "add", "--all")
157
+ conflicts = unmerged_paths(path)
158
+ unless conflicts.empty?
159
+ raise Error, "Merge still has unresolved conflicts: #{conflicts.join(", ")}"
160
+ end
161
+
162
+ marker_paths = merge_conflict_marker_paths(path)
163
+ unless marker_paths.empty?
164
+ raise Error, "Merge still contains conflict markers: #{marker_paths.join(", ")}"
165
+ end
166
+
167
+ run_git(path, "commit", "--no-edit")
168
+ true
169
+ end
170
+
143
171
  def create(repository_root:, origin_root:, path:, branch:, base: "HEAD")
144
172
  repository_root = canonical_existing_path(repository_root)
145
173
  origin_root = canonical_existing_path(origin_root)
@@ -1,7 +1,7 @@
1
1
  require "pathname"
2
- require_relative "local_command_runner"
3
- require_relative "sandbox"
4
- require_relative "session_diff"
2
+ require_relative "../pty/local_command_runner"
3
+ require_relative "../sandbox"
4
+ require_relative "../sessions/diff"
5
5
 
6
6
  require_relative "path_guard"
7
7
 
@@ -12,6 +12,7 @@ module KwardDocsNavigationData
12
12
  ["Authentication", "file.authentication.html"],
13
13
  ["Model providers", "file.providers.html"],
14
14
  ["Security and trust", "file.security.html"],
15
+ ["Platform support", "file.platform-support.html"],
15
16
  ["Troubleshooting", "file.troubleshooting.html"]
16
17
  ]
17
18
  ],
@@ -0,0 +1,10 @@
1
+ <div id="footer">
2
+ <% if home_page? %>
3
+ Kward is open source software released under the
4
+ <a href="https://github.com/kaiwood/kward/blob/main/LICENSE">MIT License</a>.
5
+ <% else %>
6
+ Generated with
7
+ <a href="https://yardoc.org" title="YARD documentation tool" target="_parent">YARD</a>
8
+ <%= YARD::VERSION %>.
9
+ <% end %>
10
+ </div>
@@ -0,0 +1,23 @@
1
+ <meta charset="<%= charset %>">
2
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
3
+ <title><%= h docs_page_title %></title>
4
+ <meta name="description" content="<%= h docs_page_description %>">
5
+ <meta name="theme-color" content="#070b07">
6
+ <link rel="canonical" href="<%= h docs_canonical_url %>">
7
+ <link rel="icon" type="image/png" href="<%= url_for('images/kward_logo.png') %>">
8
+ <meta property="og:type" content="website">
9
+ <meta property="og:site_name" content="Kward">
10
+ <meta property="og:title" content="<%= h docs_page_title %>">
11
+ <meta property="og:description" content="<%= h docs_page_description %>">
12
+ <meta property="og:url" content="<%= h docs_canonical_url %>">
13
+ <meta property="og:image" content="https://kaiwood.github.io/kward/images/kward_logo.png">
14
+ <meta name="twitter:card" content="summary">
15
+ <meta name="twitter:title" content="<%= h docs_page_title %>">
16
+ <meta name="twitter:description" content="<%= h docs_page_description %>">
17
+ <% stylesheets.each do |stylesheet| %>
18
+ <link rel="stylesheet" href="<%= mtime_url(stylesheet) %>" type="text/css">
19
+ <% end %>
20
+ <%= erb :script_setup %>
21
+ <% javascripts.each do |javascript| %>
22
+ <script type="text/javascript" charset="utf-8" src="<%= mtime_url(javascript) %>"></script>
23
+ <% end %>
@@ -96,7 +96,7 @@
96
96
  </h1>
97
97
  <p class="kward-lede">Kward is a general-purpose coding agent written in Ruby: terminal-native, project-aware, pipeable, and designed around your workflow.</p>
98
98
  <div class="kward-actions">
99
- <a class="kward-primary-button" href="<%= url_for('file.README.html') %>">Get Started ›</a>
99
+ <a class="kward-primary-button" href="<%= url_for('file.getting-started.html') %>">Get Started ›</a>
100
100
  <a class="kward-secondary-button" href="https://github.com/kaiwood/kward" target="_blank" rel="noopener noreferrer">View on GitHub</a>
101
101
  </div>
102
102
  <p class="kward-supports">Supports <span>OpenAI</span>, <span>Anthropic</span>, <span>OpenRouter</span> &amp; more.</p>
@@ -110,7 +110,7 @@
110
110
  <article><strong>⌘</strong><h2>Project-aware agent loop</h2><p>Inspect, reason, patch, verify.</p></article>
111
111
  <article><strong>▤</strong><h2>Unix filter mode</h2><p>Pipe diffs, logs, and code through Kward.</p></article>
112
112
  <article><strong>▰</strong><h2>Branchable sessions</h2><p>Resume, rewind, fork, compact, export.</p></article>
113
- <article><strong>⌗</strong><h2>Builtin shell and editor</h2><p>Run commands and edit files safely in the workspace.</p></article>
113
+ <article><strong>⌗</strong><h2>Built-in shell and editor</h2><p>Run commands and edit files safely in the workspace.</p></article>
114
114
  <article><strong>◎</strong><h2>Live source intelligence</h2><p>Search the web and read public repos.</p></article>
115
115
  <article><strong>✣</strong><h2>Ruby-native extensions</h2><p>Shape Kward with plugins, skills, and prompts.</p></article>
116
116
  </section>
@@ -24,16 +24,23 @@ module KwardDocsNavigation
24
24
  end
25
25
  end
26
26
  ].freeze
27
+ DOCS_LINK_TITLES = (
28
+ [["Overview", GUIDE_OVERVIEW], ["Advanced", EXTENSION_OVERVIEW], ["API Docs", API_OVERVIEW]] +
29
+ (GUIDE_GROUPS + EXTENSION_GROUPS + API_GROUPS).flat_map { |_title, items| items }
30
+ ).to_h { |label, link| [link, label] }.freeze
27
31
  GUIDE_FILE_LINKS = {
28
32
  "doc/getting-started.md" => "file.getting-started.html",
29
33
  "doc/usage.md" => "file.usage.html",
30
34
  "doc/configuration.md" => "file.configuration.html",
31
35
  "doc/authentication.md" => "file.authentication.html",
32
36
  "doc/providers.md" => "file.providers.html",
37
+ "doc/security.md" => "file.security.html",
38
+ "doc/platform-support.md" => "file.platform-support.html",
33
39
  "doc/permissions.md" => "file.permissions.html",
34
40
  "doc/sandboxing.md" => "file.sandboxing.html",
35
41
  "doc/troubleshooting.md" => "file.troubleshooting.html",
36
42
  "doc/session-management.md" => "file.session-management.html",
43
+ "doc/composer.md" => "file.composer.html",
37
44
  "doc/tabs.md" => "file.tabs.html",
38
45
  "doc/files.md" => "file.files.html",
39
46
  "doc/editor.md" => "file.editor.html",
@@ -42,6 +49,9 @@ module KwardDocsNavigation
42
49
  "doc/memory.md" => "file.memory.html",
43
50
  "doc/personas.md" => "file.personas.html",
44
51
  "doc/skills.md" => "file.skills.html",
52
+ "doc/prompt-templates.md" => "file.prompt-templates.html",
53
+ "doc/pan.md" => "file.pan.html",
54
+ "doc/mcp.md" => "file.mcp.html",
45
55
  "doc/local-models.md" => "file.local-models.html",
46
56
  "doc/extensibility.md" => "file.extensibility.html",
47
57
  "doc/plugins.md" => "file.plugins.html",
@@ -79,7 +89,7 @@ module KwardDocsNavigation
79
89
  title: title,
80
90
  path: source,
81
91
  url: url_for(link),
82
- text: content.gsub(/[`*_#>\[\]()]/, " ").gsub(/\s+/, " ").strip
92
+ text: content.gsub(/<[^>]+>/, " ").gsub(/[`*_#>\[\]()]/, " ").gsub(/\s+/, " ").strip
83
93
  }
84
94
  end
85
95
  end
@@ -111,6 +121,35 @@ module KwardDocsNavigation
111
121
  options.index && readme_file?
112
122
  end
113
123
 
124
+ def docs_page_title
125
+ return "Kward — Ruby Coding Agent for Your Terminal" if home_page?
126
+
127
+ page = DOCS_LINK_TITLES[docs_output_path] || @page_title.to_s.sub(/\AFile:\s*/, "")
128
+ "#{page} | Kward Docs"
129
+ end
130
+
131
+ def docs_page_description
132
+ if home_page?
133
+ "Kward is an extensible Ruby coding agent for inspecting code, editing files, running tests, and resuming work from your terminal."
134
+ else
135
+ "Documentation for Kward, the extensible Ruby coding agent for your terminal."
136
+ end
137
+ end
138
+
139
+ def docs_canonical_url
140
+ return "https://kaiwood.github.io/kward/" if home_page?
141
+
142
+ "https://kaiwood.github.io/kward/#{docs_output_path}"
143
+ end
144
+
145
+ def docs_output_path
146
+ if defined?(@file) && @file
147
+ GUIDE_FILE_LINKS[@file.filename.to_s] || API_FILE_LINKS[@file.filename.to_s] || current_docs_path
148
+ else
149
+ current_docs_path
150
+ end
151
+ end
152
+
114
153
  def guide_page?
115
154
  (readme_file? && !options.index) || guide_file? || GUIDE_LINKS.include?(current_docs_path)
116
155
  end
@@ -133,7 +172,7 @@ module KwardDocsNavigation
133
172
  GUIDE_FILE_LINKS.merge(API_FILE_LINKS).each do |source, target|
134
173
  html = html.gsub(%(href="#{source}"), %(href="#{target}"))
135
174
  end
136
- html
175
+ html.gsub(%(src="templates/default/fulldoc/html/images/), %(src="images/))
137
176
  end
138
177
  end
139
178
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kward
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.83.0
4
+ version: 0.85.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kai Wood
@@ -107,8 +107,22 @@ dependencies:
107
107
  - - ">="
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
- description: Kward is a Ruby CLI coding agent with local workspace tools, configurable
111
- prompts, web search, sessions, and an experimental JSON-RPC backend.
110
+ - !ruby/object:Gem::Dependency
111
+ name: unicode-display_width
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ description: Kward is an extensible Ruby coding agent with workspace tools, resumable
125
+ sessions, multiple model providers, a local browser UI, and JSON-RPC integrations.
112
126
  email:
113
127
  - kai.wood@icloud.com
114
128
  executables:
@@ -118,11 +132,13 @@ extra_rdoc_files: []
118
132
  files:
119
133
  - ".yardopts"
120
134
  - CHANGELOG.md
135
+ - CONTRIBUTING.md
121
136
  - Gemfile
122
137
  - Gemfile.lock
123
138
  - LICENSE
124
139
  - README.md
125
140
  - Rakefile
141
+ - SECURITY.md
126
142
  - doc/agent-tools.md
127
143
  - doc/api.md
128
144
  - doc/authentication.md
@@ -143,6 +159,7 @@ files:
143
159
  - doc/pan.md
144
160
  - doc/permissions.md
145
161
  - doc/personas.md
162
+ - doc/platform-support.md
146
163
  - doc/plugins.md
147
164
  - doc/prompt-templates.md
148
165
  - doc/providers.md
@@ -168,9 +185,7 @@ files:
168
185
  - exe/kward
169
186
  - kward.gemspec
170
187
  - lib/kward.rb
171
- - lib/kward/adaptive_pty_output_sink.rb
172
188
  - lib/kward/agent.rb
173
- - lib/kward/ansi.rb
174
189
  - lib/kward/auth/anthropic_oauth.rb
175
190
  - lib/kward/auth/api_key_store.rb
176
191
  - lib/kward/auth/file.rb
@@ -184,6 +199,8 @@ files:
184
199
  - lib/kward/cli/commands.rb
185
200
  - lib/kward/cli/compaction.rb
186
201
  - lib/kward/cli/doctor.rb
202
+ - lib/kward/cli/editor_prompt.rb
203
+ - lib/kward/cli/editor_prompt_session.rb
187
204
  - lib/kward/cli/git.rb
188
205
  - lib/kward/cli/hook_commands.rb
189
206
  - lib/kward/cli/interactive_turn.rb
@@ -197,31 +214,29 @@ files:
197
214
  - lib/kward/cli/runtime_helpers.rb
198
215
  - lib/kward/cli/sessions.rb
199
216
  - lib/kward/cli/settings.rb
217
+ - lib/kward/cli/settings/menus.rb
218
+ - lib/kward/cli/settings/model.rb
200
219
  - lib/kward/cli/slash_commands.rb
201
220
  - lib/kward/cli/stats.rb
202
221
  - lib/kward/cli/sysprompt.rb
203
222
  - lib/kward/cli/tabs.rb
204
223
  - lib/kward/cli/tool_summaries.rb
224
+ - lib/kward/cli/transcript_formatter.rb
205
225
  - lib/kward/cli/transports.rb
206
226
  - lib/kward/cli/worktrees.rb
207
- - lib/kward/cli_transcript_formatter.rb
208
- - lib/kward/clipboard.rb
209
227
  - lib/kward/compaction/file_operation_tracker.rb
210
228
  - lib/kward/compaction/token_estimator.rb
211
229
  - lib/kward/compactor.rb
230
+ - lib/kward/config/core.rb
231
+ - lib/kward/config/extensions.rb
232
+ - lib/kward/config/prompts.rb
233
+ - lib/kward/config/settings.rb
212
234
  - lib/kward/config_files.rb
213
235
  - lib/kward/context_budget_meter.rb
214
236
  - lib/kward/conversation.rb
215
237
  - lib/kward/deep_copy.rb
216
- - lib/kward/diff_view_mode.rb
217
- - lib/kward/editor_mode.rb
218
- - lib/kward/editor_prompt.rb
219
- - lib/kward/editor_prompt_session.rb
220
- - lib/kward/ekwsh.rb
221
238
  - lib/kward/events.rb
222
- - lib/kward/export_path.rb
223
239
  - lib/kward/frontmatter.rb
224
- - lib/kward/git_worktree_manager.rb
225
240
  - lib/kward/hooks.rb
226
241
  - lib/kward/hooks/audit_log.rb
227
242
  - lib/kward/hooks/catalog.rb
@@ -234,10 +249,6 @@ files:
234
249
  - lib/kward/hooks/matcher.rb
235
250
  - lib/kward/http.rb
236
251
  - lib/kward/image_attachments.rb
237
- - lib/kward/interactive_pty_runner.rb
238
- - lib/kward/local_command_runner.rb
239
- - lib/kward/local_pty_command_runner.rb
240
- - lib/kward/markdown_transcript.rb
241
252
  - lib/kward/mcp/client.rb
242
253
  - lib/kward/mcp/server_config.rb
243
254
  - lib/kward/mcp/stdio_transport.rb
@@ -253,22 +264,27 @@ files:
253
264
  - lib/kward/model/context_usage.rb
254
265
  - lib/kward/model/copilot_models.rb
255
266
  - lib/kward/model/model_info.rb
267
+ - lib/kward/model/openrouter_model_cache.rb
256
268
  - lib/kward/model/payloads.rb
257
269
  - lib/kward/model/provider_catalog.rb
258
270
  - lib/kward/model/retry_message.rb
259
271
  - lib/kward/model/sources.rb
260
272
  - lib/kward/model/stream_parser.rb
261
- - lib/kward/openrouter_model_cache.rb
273
+ - lib/kward/model/typesafe_client.rb
262
274
  - lib/kward/pan/index.html.erb
263
275
  - lib/kward/pan/kward_logo.png
264
276
  - lib/kward/pan/server.rb
265
- - lib/kward/path_guard.rb
266
277
  - lib/kward/permissions/policy.rb
267
- - lib/kward/persistent_shell_session.rb
268
- - lib/kward/plugin_chat_runtime.rb
269
278
  - lib/kward/plugin_registry.rb
279
+ - lib/kward/plugins/actions.rb
280
+ - lib/kward/plugins/chat_contract.rb
281
+ - lib/kward/plugins/chat_runtime.rb
282
+ - lib/kward/plugins/host.rb
283
+ - lib/kward/plugins/registry.rb
284
+ - lib/kward/plugins/resources.rb
285
+ - lib/kward/plugins/turn_request.rb
286
+ - lib/kward/plugins/ui.rb
270
287
  - lib/kward/private_file.rb
271
- - lib/kward/project_files.rb
272
288
  - lib/kward/prompt_history.rb
273
289
  - lib/kward/prompt_interface.rb
274
290
  - lib/kward/prompt_interface/approval_prompt.rb
@@ -280,15 +296,22 @@ files:
280
296
  - lib/kward/prompt_interface/editor/auto_indent.rb
281
297
  - lib/kward/prompt_interface/editor/buffer.rb
282
298
  - lib/kward/prompt_interface/editor/controller.rb
299
+ - lib/kward/prompt_interface/editor/diff_view_mode.rb
300
+ - lib/kward/prompt_interface/editor/editor_mode.rb
283
301
  - lib/kward/prompt_interface/editor/endwise.rb
284
302
  - lib/kward/prompt_interface/editor/file_marker.rb
285
303
  - lib/kward/prompt_interface/editor/indent_navigation.rb
286
304
  - lib/kward/prompt_interface/editor/kill_ring.rb
305
+ - lib/kward/prompt_interface/editor/markdown_code_block.rb
287
306
  - lib/kward/prompt_interface/editor/modes/emacs.rb
288
307
  - lib/kward/prompt_interface/editor/modes/modern.rb
289
308
  - lib/kward/prompt_interface/editor/modes/vibe.rb
290
309
  - lib/kward/prompt_interface/editor/modes/vibe_insert_readline.rb
291
310
  - lib/kward/prompt_interface/editor/renderer.rb
311
+ - lib/kward/prompt_interface/editor/runner.rb
312
+ - lib/kward/prompt_interface/editor/runner_state.rb
313
+ - lib/kward/prompt_interface/editor/scratchpad_languages.rb
314
+ - lib/kward/prompt_interface/editor/scratchpad_runner.rb
292
315
  - lib/kward/prompt_interface/editor/search.rb
293
316
  - lib/kward/prompt_interface/editor/selections.rb
294
317
  - lib/kward/prompt_interface/editor/state.rb
@@ -305,6 +328,7 @@ files:
305
328
  - lib/kward/prompt_interface/key_handler.rb
306
329
  - lib/kward/prompt_interface/layout.rb
307
330
  - lib/kward/prompt_interface/overlay_renderer.rb
331
+ - lib/kward/prompt_interface/plugin_ui_requests.rb
308
332
  - lib/kward/prompt_interface/project_browser.rb
309
333
  - lib/kward/prompt_interface/prompt_renderer.rb
310
334
  - lib/kward/prompt_interface/question_prompt.rb
@@ -318,8 +342,13 @@ files:
318
342
  - lib/kward/prompts.rb
319
343
  - lib/kward/prompts/commands.rb
320
344
  - lib/kward/prompts/templates.rb
321
- - lib/kward/pty_output_sink.rb
322
- - lib/kward/pty_transcript_normalizer.rb
345
+ - lib/kward/pty/adaptive_output_sink.rb
346
+ - lib/kward/pty/detached_run.rb
347
+ - lib/kward/pty/interactive_runner.rb
348
+ - lib/kward/pty/local_command_runner.rb
349
+ - lib/kward/pty/local_pty_runner.rb
350
+ - lib/kward/pty/output_sink.rb
351
+ - lib/kward/pty/transcript_normalizer.rb
323
352
  - lib/kward/question_contract.rb
324
353
  - lib/kward/rpc/attachment_normalizer.rb
325
354
  - lib/kward/rpc/auth_manager.rb
@@ -350,31 +379,37 @@ files:
350
379
  - lib/kward/sandbox/policy.rb
351
380
  - lib/kward/sandbox/runner_factory.rb
352
381
  - lib/kward/sandbox/unavailable_runner.rb
353
- - lib/kward/scratchpad_runner.rb
354
- - lib/kward/session_catalog.rb
355
- - lib/kward/session_diff.rb
356
- - lib/kward/session_naming.rb
357
- - lib/kward/session_store.rb
358
- - lib/kward/session_trash.rb
359
- - lib/kward/session_tree_nodes.rb
360
- - lib/kward/session_tree_renderer.rb
361
- - lib/kward/session_tree_tool_display.rb
362
- - lib/kward/shell_prompt.rb
363
- - lib/kward/shell_prompt_session.rb
382
+ - lib/kward/sessions/catalog.rb
383
+ - lib/kward/sessions/diff.rb
384
+ - lib/kward/sessions/naming.rb
385
+ - lib/kward/sessions/store.rb
386
+ - lib/kward/sessions/trash.rb
387
+ - lib/kward/sessions/tree_nodes.rb
388
+ - lib/kward/sessions/tree_renderer.rb
389
+ - lib/kward/sessions/tree_tool_display.rb
390
+ - lib/kward/shell/kwsh.rb
391
+ - lib/kward/shell/kwshrc.rb
392
+ - lib/kward/shell/persistent_session.rb
393
+ - lib/kward/shell/prompt.rb
394
+ - lib/kward/shell/prompt_session.rb
364
395
  - lib/kward/skills/capture.rb
365
396
  - lib/kward/skills/registry.rb
366
397
  - lib/kward/skills/trust_coordinator.rb
367
398
  - lib/kward/skills/trust_store.rb
368
399
  - lib/kward/starter_pack_installer.rb
369
400
  - lib/kward/steering.rb
370
- - lib/kward/tab_driver.rb
371
- - lib/kward/tab_store.rb
401
+ - lib/kward/tabs/driver.rb
402
+ - lib/kward/tabs/store.rb
372
403
  - lib/kward/telemetry/logger.rb
373
404
  - lib/kward/telemetry/stats.rb
374
- - lib/kward/terminal_image_support.rb
375
- - lib/kward/terminal_keys.rb
376
- - lib/kward/terminal_sequences.rb
405
+ - lib/kward/terminal/ansi.rb
406
+ - lib/kward/terminal/clipboard.rb
407
+ - lib/kward/terminal/image_support.rb
408
+ - lib/kward/terminal/keys.rb
409
+ - lib/kward/terminal/sequences.rb
410
+ - lib/kward/terminal/text.rb
377
411
  - lib/kward/text_boundary.rb
412
+ - lib/kward/text_matcher.rb
378
413
  - lib/kward/tool_output_compactor.rb
379
414
  - lib/kward/tools/ask_user_question.rb
380
415
  - lib/kward/tools/base.rb
@@ -387,6 +422,8 @@ files:
387
422
  - lib/kward/tools/git_commit.rb
388
423
  - lib/kward/tools/list_directory.rb
389
424
  - lib/kward/tools/mcp_tool.rb
425
+ - lib/kward/tools/open_editor.rb
426
+ - lib/kward/tools/plugin_tool.rb
390
427
  - lib/kward/tools/prepare_shell_command.rb
391
428
  - lib/kward/tools/read_file.rb
392
429
  - lib/kward/tools/read_skill.rb
@@ -399,10 +436,15 @@ files:
399
436
  - lib/kward/tools/search/web_fetch.rb
400
437
  - lib/kward/tools/summarize_file_structure.rb
401
438
  - lib/kward/tools/tool_call.rb
439
+ - lib/kward/tools/typesafe_evaluate.rb
402
440
  - lib/kward/tools/web_search.rb
441
+ - lib/kward/tools/workspace_targets.rb
403
442
  - lib/kward/tools/write_file.rb
404
- - lib/kward/transcript_export.rb
443
+ - lib/kward/transcripts/export_path.rb
444
+ - lib/kward/transcripts/markdown_transcript.rb
445
+ - lib/kward/transcripts/transcript_export.rb
405
446
  - lib/kward/transport.rb
447
+ - lib/kward/transport/contracts.rb
406
448
  - lib/kward/transport/gateway.rb
407
449
  - lib/kward/transport/host.rb
408
450
  - lib/kward/transport/manager.rb
@@ -411,8 +453,11 @@ files:
411
453
  - lib/kward/transport/store.rb
412
454
  - lib/kward/update_check.rb
413
455
  - lib/kward/version.rb
414
- - lib/kward/workspace.rb
415
- - lib/kward/workspace_factory.rb
456
+ - lib/kward/workspace/factory.rb
457
+ - lib/kward/workspace/files.rb
458
+ - lib/kward/workspace/git_worktree_manager.rb
459
+ - lib/kward/workspace/path_guard.rb
460
+ - lib/kward/workspace/workspace.rb
416
461
  - lib/main.rb
417
462
  - templates/default/fulldoc/html/css/kward.css
418
463
  - templates/default/fulldoc/html/full_list.erb
@@ -422,16 +467,18 @@ files:
422
467
  - templates/default/fulldoc/html/setup.rb
423
468
  - templates/default/kward_navigation.rb
424
469
  - templates/default/layout/html/breadcrumb.erb
470
+ - templates/default/layout/html/footer.erb
471
+ - templates/default/layout/html/headers.erb
425
472
  - templates/default/layout/html/layout.erb
426
473
  - templates/default/layout/html/setup.rb
427
- homepage: https://github.com/kaiwood/kward
474
+ homepage: https://kaiwood.github.io/kward/
428
475
  licenses:
429
476
  - MIT
430
477
  metadata:
431
478
  rubygems_mfa_required: 'true'
432
479
  source_code_uri: https://github.com/kaiwood/kward
433
480
  changelog_uri: https://github.com/kaiwood/kward/blob/main/CHANGELOG.md
434
- documentation_uri: https://github.com/kaiwood/kward#readme
481
+ documentation_uri: https://kaiwood.github.io/kward/
435
482
  bug_tracker_uri: https://github.com/kaiwood/kward/issues
436
483
  rdoc_options: []
437
484
  require_paths:
@@ -449,5 +496,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
449
496
  requirements: []
450
497
  rubygems_version: 3.6.9
451
498
  specification_version: 4
452
- summary: An extendable Ruby CLI coding agent.
499
+ summary: An extensible Ruby coding agent for your terminal.
453
500
  test_files: []
@@ -1,56 +0,0 @@
1
- require "open3"
2
- require "rbconfig"
3
- require "tempfile"
4
-
5
- # Namespace for the Kward CLI agent runtime.
6
- module Kward
7
- # Executes scratchpad buffers and returns transformed buffer content.
8
- module ScratchpadRunner
9
- RUBY_END_MARKER_PATTERN = /^__END__\n?/.freeze
10
-
11
- Result = Struct.new(:buffer, :exit_status, keyword_init: true)
12
-
13
- module_function
14
-
15
- def run(language, content)
16
- case language&.to_sym
17
- when :ruby
18
- run_ruby(content)
19
- else
20
- raise ArgumentError, "Scratchpad language #{language.inspect} is not runnable"
21
- end
22
- end
23
-
24
- def run_ruby(content)
25
- content = content.to_s
26
- output, status = capture_ruby_output(content)
27
- Result.new(buffer: ruby_buffer_with_output(content, output, status.exitstatus), exit_status: status.exitstatus)
28
- end
29
-
30
- def capture_ruby_output(content)
31
- Tempfile.create(["kward-scratchpad", ".rb"]) do |file|
32
- file.write(content)
33
- file.flush
34
- Open3.capture2e(RbConfig.ruby, file.path)
35
- end
36
- end
37
-
38
- def ruby_buffer_with_output(content, output, exit_status)
39
- output = output.to_s
40
- output += "\n" unless output.empty? || output.end_with?("\n")
41
- output += "[exit status: #{exit_status}]\n" unless exit_status.to_i.zero?
42
-
43
- if (match = content.match(RUBY_END_MARKER_PATTERN))
44
- "#{content[0...match.begin(0)]}__END__\n#{output}"
45
- else
46
- "#{content}#{ruby_end_separator(content)}__END__\n#{output}"
47
- end
48
- end
49
-
50
- def ruby_end_separator(content)
51
- return "" if content.empty?
52
-
53
- content.end_with?("\n") ? "\n" : "\n\n"
54
- end
55
- end
56
- end
@@ -1,90 +0,0 @@
1
- # Namespace for the Kward CLI agent runtime.
2
- module Kward
3
- # Adapts a session-backed agent to the tab runtime interface. Plugin tab
4
- # drivers implement the same small surface without becoming Kward sessions.
5
- class SessionTabDriver
6
- attr_reader :session, :agent, :worktree
7
-
8
- def initialize(session:, agent:, worktree: nil)
9
- @session = session
10
- @agent = agent
11
- @worktree = worktree
12
- end
13
-
14
- def messages
15
- agent.conversation.messages
16
- end
17
-
18
- def conversation
19
- agent.conversation
20
- end
21
-
22
- def submit(input, display_input:, cancellation:, steering: nil, &block)
23
- options = { cancellation: cancellation }
24
- options[:display_input] = display_input unless display_input.nil?
25
- options[:steering] = steering if steering
26
- agent.ask(input, **options, &block)
27
- end
28
-
29
- def descriptor
30
- descriptor = { "kind" => "session", "session_path" => session.path }
31
- descriptor["worktree"] = worktree.descriptor if worktree
32
- descriptor
33
- end
34
-
35
- def session?
36
- true
37
- end
38
-
39
- def supports_steering?
40
- true
41
- end
42
-
43
- def assistant_label
44
- nil
45
- end
46
- end
47
-
48
- # Represents a persisted plugin tab whose provider plugin is unavailable.
49
- # Its descriptor is retained so reinstalling the plugin restores the tab.
50
- class UnavailableTabDriver
51
- attr_reader :descriptor
52
-
53
- def initialize(descriptor:, message:)
54
- @descriptor = descriptor
55
- @message = message
56
- end
57
-
58
- def messages
59
- [{ role: "assistant", content: @message }]
60
- end
61
-
62
- def submit(*)
63
- raise @message
64
- end
65
-
66
- def session?
67
- false
68
- end
69
-
70
- def supports_steering?
71
- false
72
- end
73
-
74
- def assistant_label
75
- "Plugin"
76
- end
77
- end
78
-
79
- # Dependencies made available to a plugin tab factory. The host deliberately
80
- # exposes provider transport and frontend-neutral facts, not CLI internals or
81
- # workspace session state.
82
- class PluginTabHost
83
- attr_reader :client, :workspace_root
84
-
85
- def initialize(client:, workspace_root:)
86
- @client = client
87
- @workspace_root = workspace_root
88
- end
89
- end
90
- end