kward 0.79.0 → 0.80.1

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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -0
  3. data/CHANGELOG.md +65 -1
  4. data/Gemfile.lock +2 -2
  5. data/README.md +31 -38
  6. data/doc/agent-tools.md +9 -10
  7. data/doc/api.md +3 -3
  8. data/doc/authentication.md +79 -110
  9. data/doc/code-search.md +1 -1
  10. data/doc/composer.md +1 -1
  11. data/doc/configuration.md +69 -26
  12. data/doc/context-budgeting.md +6 -6
  13. data/doc/context-tools.md +2 -2
  14. data/doc/editor.md +7 -7
  15. data/doc/extensibility.md +7 -29
  16. data/doc/files.md +6 -6
  17. data/doc/getting-started.md +2 -2
  18. data/doc/git.md +8 -2
  19. data/doc/lifecycle-hooks.md +5 -4
  20. data/doc/local-models.md +2 -2
  21. data/doc/mcp.md +5 -5
  22. data/doc/permissions.md +13 -4
  23. data/doc/plugins.md +39 -4
  24. data/doc/prompt-templates.md +105 -0
  25. data/doc/providers.md +140 -0
  26. data/doc/releasing.md +10 -2
  27. data/doc/rpc.md +54 -31
  28. data/doc/sandboxing.md +22 -0
  29. data/doc/security.md +22 -7
  30. data/doc/session-management.md +2 -4
  31. data/doc/skills.md +2 -0
  32. data/doc/tabs.md +37 -0
  33. data/doc/telegram.md +138 -0
  34. data/doc/transports.md +209 -0
  35. data/doc/usage.md +11 -3
  36. data/doc/web-search.md +3 -3
  37. data/doc/workspace-tools.md +2 -2
  38. data/examples/plugins/stardate_footer.rb +10 -0
  39. data/examples/plugins/telegram/plugin.rb +39 -0
  40. data/examples/plugins/telegram/telegram_api.rb +136 -0
  41. data/examples/plugins/telegram/telegram_transport.rb +304 -0
  42. data/lib/kward/agent.rb +11 -6
  43. data/lib/kward/ansi.rb +1 -0
  44. data/lib/kward/auth/api_key_store.rb +99 -0
  45. data/lib/kward/cli/auth_commands.rb +72 -13
  46. data/lib/kward/cli/commands.rb +7 -0
  47. data/lib/kward/cli/git.rb +31 -8
  48. data/lib/kward/cli/memory_commands.rb +2 -2
  49. data/lib/kward/cli/plugins.rb +1 -0
  50. data/lib/kward/cli/prompt_interface.rb +44 -1
  51. data/lib/kward/cli/rendering.rb +6 -2
  52. data/lib/kward/cli/runtime_helpers.rb +5 -2
  53. data/lib/kward/cli/sessions.rb +1 -1
  54. data/lib/kward/cli/settings.rb +97 -33
  55. data/lib/kward/cli/slash_commands.rb +1 -1
  56. data/lib/kward/cli/tabs.rb +103 -37
  57. data/lib/kward/cli/transports.rb +67 -0
  58. data/lib/kward/cli/worktrees.rb +360 -0
  59. data/lib/kward/cli.rb +22 -0
  60. data/lib/kward/compactor.rb +7 -2
  61. data/lib/kward/config_files.rb +51 -12
  62. data/lib/kward/conversation.rb +13 -7
  63. data/lib/kward/git_worktree_manager.rb +291 -0
  64. data/lib/kward/hooks/audit_log.rb +5 -2
  65. data/lib/kward/model/azure_openai_config.rb +54 -0
  66. data/lib/kward/model/catalog.rb +113 -0
  67. data/lib/kward/model/client.rb +225 -20
  68. data/lib/kward/model/model_info.rb +49 -0
  69. data/lib/kward/model/payloads.rb +63 -4
  70. data/lib/kward/model/provider_catalog.rb +114 -0
  71. data/lib/kward/model/sources.rb +70 -0
  72. data/lib/kward/model/stream_parser.rb +83 -13
  73. data/lib/kward/permissions/policy.rb +18 -4
  74. data/lib/kward/plugin_chat_runtime.rb +374 -0
  75. data/lib/kward/plugin_registry.rb +99 -19
  76. data/lib/kward/private_file.rb +9 -3
  77. data/lib/kward/prompt_interface/approval_prompt.rb +2 -0
  78. data/lib/kward/prompt_interface/composer_renderer.rb +1 -5
  79. data/lib/kward/prompt_interface/editor/auto_indent.rb +46 -0
  80. data/lib/kward/prompt_interface/editor/buffer.rb +18 -4
  81. data/lib/kward/prompt_interface/editor/controller.rb +7 -7
  82. data/lib/kward/prompt_interface/editor/modes/vibe.rb +2 -2
  83. data/lib/kward/prompt_interface/editor/renderer.rb +8 -8
  84. data/lib/kward/prompt_interface/editor/state.rb +3 -9
  85. data/lib/kward/prompt_interface/editor/syntax_highlighter.rb +219 -19
  86. data/lib/kward/prompt_interface/file_overlay.rb +2 -2
  87. data/lib/kward/prompt_interface/git_prompt.rb +7 -3
  88. data/lib/kward/prompt_interface/interactive/controller.rb +4 -4
  89. data/lib/kward/prompt_interface/interactive/renderer.rb +4 -1
  90. data/lib/kward/prompt_interface/interactive/state.rb +2 -2
  91. data/lib/kward/prompt_interface/project_browser.rb +25 -6
  92. data/lib/kward/prompt_interface/runtime_state.rb +22 -6
  93. data/lib/kward/prompt_interface/screen.rb +3 -0
  94. data/lib/kward/prompt_interface/selection_prompt.rb +7 -1
  95. data/lib/kward/prompt_interface/transcript_buffer.rb +24 -2
  96. data/lib/kward/prompt_interface.rb +53 -12
  97. data/lib/kward/prompts/commands.rb +1 -1
  98. data/lib/kward/prompts/templates.rb +11 -6
  99. data/lib/kward/prompts.rb +6 -5
  100. data/lib/kward/rpc/auth_manager.rb +112 -152
  101. data/lib/kward/rpc/config_manager.rb +46 -6
  102. data/lib/kward/rpc/plugin_chat_manager.rb +55 -196
  103. data/lib/kward/rpc/prompt_bridge.rb +8 -4
  104. data/lib/kward/rpc/redactor.rb +1 -1
  105. data/lib/kward/rpc/server.rb +60 -10
  106. data/lib/kward/rpc/session_manager.rb +109 -30
  107. data/lib/kward/session_store.rb +84 -24
  108. data/lib/kward/skills/registry.rb +16 -11
  109. data/lib/kward/tab_driver.rb +6 -3
  110. data/lib/kward/telemetry/logger.rb +5 -2
  111. data/lib/kward/tools/git_commit.rb +39 -0
  112. data/lib/kward/tools/registry.rb +7 -2
  113. data/lib/kward/tools/tool_call.rb +1 -0
  114. data/lib/kward/transport/gateway.rb +253 -0
  115. data/lib/kward/transport/host.rb +343 -0
  116. data/lib/kward/transport/manager.rb +179 -0
  117. data/lib/kward/transport/plugin_chat_gateway.rb +186 -0
  118. data/lib/kward/transport/runtime.rb +41 -0
  119. data/lib/kward/transport/store.rb +101 -0
  120. data/lib/kward/transport.rb +204 -0
  121. data/lib/kward/version.rb +1 -1
  122. data/lib/kward/workspace_factory.rb +19 -2
  123. data/templates/default/fulldoc/html/js/kward.js +2 -0
  124. data/templates/default/kward_navigation.rb +7 -2
  125. data/templates/default/layout/html/setup.rb +4 -0
  126. metadata +26 -1
@@ -0,0 +1,41 @@
1
+ require "stringio"
2
+ require_relative "../config_files"
3
+ require_relative "../rpc/server"
4
+ require_relative "gateway"
5
+ require_relative "manager"
6
+ require_relative "plugin_chat_gateway"
7
+
8
+ module Kward
9
+ module Transport
10
+ # Builds the Kward runtime needed by foreground transport processes.
11
+ class Runtime
12
+ attr_reader :manager
13
+
14
+ def initialize(client:)
15
+ @server = RPC::Server.new(
16
+ input: StringIO.new,
17
+ output: StringIO.new,
18
+ error_output: $stderr,
19
+ client: client
20
+ )
21
+ @manager = Manager.new(
22
+ registry: @server.session_manager.plugin_registry,
23
+ gateway: lambda { |transport_id|
24
+ Gateway.new(session_manager: @server.session_manager, transport_id: transport_id)
25
+ },
26
+ plugin_chat_gateway: lambda { |transport_id|
27
+ PluginChatGateway.new(runtime: @server.plugin_chat_manager.runtime, transport_id: transport_id)
28
+ },
29
+ config_root: ConfigFiles.config_dir,
30
+ config_provider: ->(transport_id) { ConfigFiles.transport_config(transport_id) }
31
+ )
32
+ end
33
+
34
+ def shutdown
35
+ @manager.shutdown
36
+ @server.shutdown
37
+ nil
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,101 @@
1
+ require "fileutils"
2
+ require "json"
3
+ require "thread"
4
+ require "time"
5
+ require_relative "../config_files"
6
+ require_relative "../deep_copy"
7
+ require_relative "../private_file"
8
+
9
+ module Kward
10
+ module Transport
11
+ # Small private JSON store scoped to one transport plugin.
12
+ class Store
13
+ KEY_PATTERN = /\A[A-Za-z0-9][A-Za-z0-9:._-]*\z/.freeze
14
+ DEFAULT_MAX_PROCESSED_KEYS = 10_000
15
+
16
+ attr_reader :transport_id
17
+
18
+ def initialize(transport_id, root: ConfigFiles.config_dir)
19
+ @transport_id = validate_key(transport_id, "transport id")
20
+ @path = File.join(File.expand_path(root), "transports", @transport_id, "state.json")
21
+ @mutex = Mutex.new
22
+ @values, @processed = load_state
23
+ end
24
+
25
+ def get(key)
26
+ key = validate_key(key, "storage key")
27
+ @mutex.synchronize { copy(@values[key]) }
28
+ end
29
+
30
+ def put(key, value)
31
+ key = validate_key(key, "storage key")
32
+ @mutex.synchronize do
33
+ @values[key] = copy(value)
34
+ persist
35
+ end
36
+ value
37
+ end
38
+
39
+ def delete(key)
40
+ key = validate_key(key, "storage key")
41
+ @mutex.synchronize do
42
+ present = @values.key?(key)
43
+ value = @values.delete(key)
44
+ persist if present
45
+ copy(value)
46
+ end
47
+ end
48
+
49
+ # Claims an external event key. Returns false when the key was already
50
+ # claimed, making duplicate webhook and polling deliveries harmless.
51
+ def claim(key, max_keys: DEFAULT_MAX_PROCESSED_KEYS)
52
+ key = validate_key(key, "idempotency key")
53
+ max_keys = Integer(max_keys)
54
+ raise ArgumentError, "max_keys must be positive" unless max_keys.positive?
55
+
56
+ @mutex.synchronize do
57
+ return false if @processed.key?(key)
58
+
59
+ @processed[key] = Time.now.utc.iso8601
60
+ @processed.shift while @processed.length > max_keys
61
+ persist
62
+ true
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def load_state
69
+ return [{}, {}] unless File.file?(@path)
70
+
71
+ state = JSON.parse(File.read(@path))
72
+ values = state.fetch("values", {})
73
+ processed = state.fetch("processed", {})
74
+ unless values.is_a?(Hash) && processed.is_a?(Hash)
75
+ raise JSON::ParserError, "transport state must contain JSON objects"
76
+ end
77
+
78
+ [values, processed]
79
+ rescue JSON::ParserError => e
80
+ raise "Invalid transport state #{@path}: #{e.message}"
81
+ end
82
+
83
+ def persist
84
+ PrivateFile.write_json(@path, "values" => @values, "processed" => @processed)
85
+ end
86
+
87
+ def validate_key(value, name)
88
+ value = value.to_s
89
+ raise ArgumentError, "#{name} is required" unless value.match?(KEY_PATTERN)
90
+
91
+ value
92
+ end
93
+
94
+ def copy(value)
95
+ return nil if value.nil?
96
+
97
+ DeepCopy.dup(value)
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,204 @@
1
+ require "logger"
2
+ require_relative "deep_copy"
3
+
4
+ # Namespace for frontend-neutral external transport contracts.
5
+ module Kward
6
+ module Transport
7
+ STREAMING_MODES = %i[native edit aggregate none].freeze
8
+
9
+ Actor = Data.define(:id, :display_name, :metadata)
10
+ Attachment = Data.define(:name, :mime_type, :data, :url, :metadata)
11
+ ConversationKey = Data.define(:transport_id, :external_id)
12
+ InboundMessage = Data.define(
13
+ :conversation,
14
+ :message_id,
15
+ :actor,
16
+ :text,
17
+ :attachments,
18
+ :reply_context,
19
+ :idempotency_key,
20
+ :metadata
21
+ )
22
+ TurnEvent = Data.define(:type, :session_id, :turn_id, :sequence, :payload)
23
+ InteractionRequest = Data.define(
24
+ :id,
25
+ :session_id,
26
+ :turn_id,
27
+ :kind,
28
+ :prompt,
29
+ :choices,
30
+ :expires_at,
31
+ :metadata
32
+ )
33
+ Capabilities = Data.define(:inbound, :outbound, :streaming, :limits)
34
+ ExecutionProfile = Data.define(
35
+ :id,
36
+ :tool_mode,
37
+ :allowed_tools,
38
+ :disabled_tools,
39
+ :plugin_commands,
40
+ :approval_mode,
41
+ :memory,
42
+ :attachments,
43
+ :workspace_mode,
44
+ :prompt_context
45
+ )
46
+
47
+ TOOL_MODES = %i[all none allowlist].freeze
48
+ APPROVAL_MODES = %i[default ask deny].freeze
49
+ MEMORY_MODES = %i[default none].freeze
50
+ WORKSPACE_MODES = %i[session fixed].freeze
51
+
52
+ module_function
53
+
54
+ def actor(id:, display_name: nil, metadata: {})
55
+ Actor.new(
56
+ id: required_string(id, "actor id"),
57
+ display_name: optional_string(display_name),
58
+ metadata: frozen_copy(metadata)
59
+ )
60
+ end
61
+
62
+ def attachment(name: nil, mime_type:, data: nil, url: nil, metadata: {})
63
+ raise ArgumentError, "attachment requires data or url" if data.nil? && url.nil?
64
+ raise ArgumentError, "attachment cannot contain both data and url" unless data.nil? || url.nil?
65
+
66
+ Attachment.new(
67
+ name: optional_string(name),
68
+ mime_type: required_string(mime_type, "attachment MIME type"),
69
+ data: data&.dup&.freeze,
70
+ url: url && required_string(url, "attachment URL"),
71
+ metadata: frozen_copy(metadata)
72
+ )
73
+ end
74
+
75
+ def conversation_key(transport_id:, external_id:)
76
+ ConversationKey.new(
77
+ transport_id: required_string(transport_id, "transport id"),
78
+ external_id: required_string(external_id, "external conversation id")
79
+ )
80
+ end
81
+
82
+ def inbound_message(conversation:, message_id:, actor:, text: "", attachments: [], reply_context: {}, idempotency_key:, metadata: {})
83
+ unless conversation.is_a?(ConversationKey)
84
+ raise ArgumentError, "conversation must be a Transport::ConversationKey"
85
+ end
86
+ unless actor.is_a?(Actor)
87
+ raise ArgumentError, "actor must be a Transport::Actor"
88
+ end
89
+
90
+ InboundMessage.new(
91
+ conversation: conversation,
92
+ message_id: required_string(message_id, "message id"),
93
+ actor: actor,
94
+ text: text.to_s.freeze,
95
+ attachments: frozen_copy(Array(attachments)),
96
+ reply_context: frozen_copy(reply_context),
97
+ idempotency_key: required_string(idempotency_key, "idempotency key"),
98
+ metadata: frozen_copy(metadata)
99
+ )
100
+ end
101
+
102
+ def turn_event(type:, session_id:, turn_id:, sequence:, payload: {})
103
+ TurnEvent.new(
104
+ type: required_string(type, "turn event type"),
105
+ session_id: required_string(session_id, "session id"),
106
+ turn_id: required_string(turn_id, "turn id"),
107
+ sequence: Integer(sequence),
108
+ payload: frozen_copy(payload)
109
+ )
110
+ end
111
+
112
+ def interaction_request(id:, session_id:, turn_id:, kind:, prompt:, choices: [], expires_at: nil, metadata: {})
113
+ InteractionRequest.new(
114
+ id: required_string(id, "interaction id"),
115
+ session_id: required_string(session_id, "session id"),
116
+ turn_id: required_string(turn_id, "turn id"),
117
+ kind: required_string(kind, "interaction kind"),
118
+ prompt: required_string(prompt, "interaction prompt"),
119
+ choices: frozen_copy(Array(choices)),
120
+ expires_at: expires_at,
121
+ metadata: frozen_copy(metadata)
122
+ )
123
+ end
124
+
125
+ def execution_profile(
126
+ id:,
127
+ tool_mode: :all,
128
+ allowed_tools: nil,
129
+ disabled_tools: nil,
130
+ plugin_commands: true,
131
+ approval_mode: :default,
132
+ memory: :default,
133
+ attachments: true,
134
+ workspace_mode: :session,
135
+ prompt_context: nil
136
+ )
137
+ id = required_string(id, "execution profile id")
138
+ tool_mode = tool_mode.to_sym
139
+ approval_mode = approval_mode.to_sym
140
+ memory = memory.to_sym
141
+ workspace_mode = workspace_mode.to_sym
142
+ raise ArgumentError, "unsupported tool mode: #{tool_mode}" unless TOOL_MODES.include?(tool_mode)
143
+ raise ArgumentError, "unsupported approval mode: #{approval_mode}" unless APPROVAL_MODES.include?(approval_mode)
144
+ raise ArgumentError, "unsupported memory mode: #{memory}" unless MEMORY_MODES.include?(memory)
145
+ raise ArgumentError, "unsupported workspace mode: #{workspace_mode}" unless WORKSPACE_MODES.include?(workspace_mode)
146
+ raise ArgumentError, "allowlist tool mode requires allowed_tools" if tool_mode == :allowlist && Array(allowed_tools).empty?
147
+ raise ArgumentError, "none tool mode cannot define allowed_tools" if tool_mode == :none && allowed_tools
148
+ raise ArgumentError, "allowed_tools and disabled_tools cannot both be set" if allowed_tools && disabled_tools
149
+
150
+ ExecutionProfile.new(
151
+ id: id,
152
+ tool_mode: tool_mode,
153
+ allowed_tools: frozen_symbols(allowed_tools),
154
+ disabled_tools: frozen_symbols(disabled_tools),
155
+ plugin_commands: !!plugin_commands,
156
+ approval_mode: approval_mode,
157
+ memory: memory,
158
+ attachments: !!attachments,
159
+ workspace_mode: workspace_mode,
160
+ prompt_context: prompt_context.nil? ? nil : prompt_context.to_s.freeze
161
+ )
162
+ end
163
+
164
+ def capabilities(inbound: [], outbound: [], streaming: :none, limits: {})
165
+ streaming = streaming.to_sym
166
+ raise ArgumentError, "unsupported streaming mode: #{streaming}" unless STREAMING_MODES.include?(streaming)
167
+
168
+ Capabilities.new(
169
+ inbound: frozen_symbols(inbound),
170
+ outbound: frozen_symbols(outbound),
171
+ streaming: streaming,
172
+ limits: frozen_copy(limits)
173
+ )
174
+ end
175
+
176
+ def required_string(value, name)
177
+ value = value.to_s
178
+ raise ArgumentError, "#{name} is required" if value.empty?
179
+
180
+ value.freeze
181
+ end
182
+ private_class_method :required_string
183
+
184
+ def optional_string(value)
185
+ value.nil? ? nil : value.to_s.freeze
186
+ end
187
+ private_class_method :optional_string
188
+
189
+ def frozen_symbols(values)
190
+ Array(values).map { |value| value.to_sym }.uniq.freeze
191
+ end
192
+ private_class_method :frozen_symbols
193
+
194
+ def frozen_copy(value)
195
+ DeepCopy.freeze(DeepCopy.dup(value))
196
+ end
197
+ private_class_method :frozen_copy
198
+ end
199
+ end
200
+
201
+ require_relative "transport/store"
202
+ require_relative "transport/host"
203
+ require_relative "transport/manager"
204
+ require_relative "transport/gateway"
data/lib/kward/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # Namespace for the Kward CLI agent runtime.
2
2
  module Kward
3
3
  # Current gem version.
4
- VERSION = "0.79.0"
4
+ VERSION = "0.80.1"
5
5
  end
@@ -8,10 +8,27 @@ module Kward
8
8
  module WorkspaceFactory
9
9
  module_function
10
10
 
11
- def build(root:, guardrails: true, config: ConfigFiles.read_config)
11
+ def build(root:, guardrails: true, config: ConfigFiles.read_config, strict: false)
12
12
  policy = ConfigFiles.sandbox_policy(root, config)
13
+ policy = strict_policy(root, policy) if strict
13
14
  runner = Sandbox::RunnerFactory.build(policy)
14
- Workspace.new(root:, guardrails:, command_runner: runner)
15
+ if strict && !runner.capabilities.filesystem_enforced?
16
+ reason = runner.capabilities.reason || "filesystem enforcement is unavailable"
17
+ raise Sandbox::UnavailableError, "Strict workspace sandbox is unavailable: #{reason}"
18
+ end
19
+
20
+ Workspace.new(root:, guardrails: strict ? true : guardrails, command_runner: runner)
21
+ end
22
+
23
+ def strict_policy(root, configured_policy)
24
+ Sandbox::Policy.new(
25
+ mode: "workspace_write",
26
+ network: configured_policy.network,
27
+ workspace_root: root,
28
+ writable_roots: [],
29
+ protect_git_metadata: configured_policy.protect_git_metadata?
30
+ )
15
31
  end
32
+ private_class_method :strict_policy
16
33
  end
17
34
  end
@@ -4,6 +4,7 @@ const guideLinks = {
4
4
  'doc/usage.md': 'file.usage.html',
5
5
  'doc/configuration.md': 'file.configuration.html',
6
6
  'doc/authentication.md': 'file.authentication.html',
7
+ 'doc/providers.md': 'file.providers.html',
7
8
  'doc/sandboxing.md': 'file.sandboxing.html',
8
9
  'doc/troubleshooting.md': 'file.troubleshooting.html',
9
10
  'doc/session-management.md': 'file.session-management.html',
@@ -19,6 +20,7 @@ const guideLinks = {
19
20
  'doc/code-search.md': 'file.code-search.html',
20
21
  'doc/context-tools.md': 'file.context-tools.html',
21
22
  'doc/rpc.md': 'file.rpc.html',
23
+ 'doc/transports.md': 'file.transports.html',
22
24
  'doc/releasing.md': 'file.releasing.html'
23
25
  }
24
26
 
@@ -5,10 +5,12 @@ module KwardDocsNavigationData
5
5
  [
6
6
  "Start here",
7
7
  [
8
+ ["Overview", "file.README.html"],
8
9
  ["Getting started", "file.getting-started.html"],
9
10
  ["Usage", "file.usage.html"],
10
11
  ["Configuration", "file.configuration.html"],
11
12
  ["Authentication", "file.authentication.html"],
13
+ ["Model providers", "file.providers.html"],
12
14
  ["Security and trust", "file.security.html"],
13
15
  ["Troubleshooting", "file.troubleshooting.html"]
14
16
  ]
@@ -22,8 +24,8 @@ module KwardDocsNavigationData
22
24
  ["Memory", "file.memory.html"],
23
25
  ["Personas", "file.personas.html"],
24
26
  ["Skills", "file.skills.html"],
25
- ["Pan mode", "file.pan.html"],
26
- ["Local models", "file.local-models.html"]
27
+ ["Prompt templates", "file.prompt-templates.html"],
28
+ ["Pan mode", "file.pan.html"]
27
29
  ]
28
30
  ],
29
31
  [
@@ -52,7 +54,10 @@ module KwardDocsNavigationData
52
54
  "Integrate",
53
55
  [
54
56
  ["MCP servers", "file.mcp.html"],
57
+ ["Local models", "file.local-models.html"],
55
58
  ["RPC protocol", "file.rpc.html"],
59
+ ["Transports", "file.transports.html"],
60
+ ["Telegram transport", "file.telegram.html"],
56
61
  ["Releasing", "file.releasing.html"]
57
62
  ]
58
63
  ],
@@ -29,6 +29,7 @@ module KwardDocsNavigation
29
29
  "doc/usage.md" => "file.usage.html",
30
30
  "doc/configuration.md" => "file.configuration.html",
31
31
  "doc/authentication.md" => "file.authentication.html",
32
+ "doc/providers.md" => "file.providers.html",
32
33
  "doc/permissions.md" => "file.permissions.html",
33
34
  "doc/sandboxing.md" => "file.sandboxing.html",
34
35
  "doc/troubleshooting.md" => "file.troubleshooting.html",
@@ -41,6 +42,7 @@ module KwardDocsNavigation
41
42
  "doc/memory.md" => "file.memory.html",
42
43
  "doc/personas.md" => "file.personas.html",
43
44
  "doc/skills.md" => "file.skills.html",
45
+ "doc/local-models.md" => "file.local-models.html",
44
46
  "doc/extensibility.md" => "file.extensibility.html",
45
47
  "doc/plugins.md" => "file.plugins.html",
46
48
  "doc/lifecycle-hooks.md" => "file.lifecycle-hooks.html",
@@ -51,6 +53,8 @@ module KwardDocsNavigation
51
53
  "doc/code-search.md" => "file.code-search.html",
52
54
  "doc/context-tools.md" => "file.context-tools.html",
53
55
  "doc/rpc.md" => "file.rpc.html",
56
+ "doc/transports.md" => "file.transports.html",
57
+ "doc/telegram.md" => "file.telegram.html",
54
58
  "doc/releasing.md" => "file.releasing.html"
55
59
  }.freeze
56
60
 
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.79.0
4
+ version: 0.80.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kai Wood
@@ -146,6 +146,8 @@ files:
146
146
  - doc/permissions.md
147
147
  - doc/personas.md
148
148
  - doc/plugins.md
149
+ - doc/prompt-templates.md
150
+ - doc/providers.md
149
151
  - doc/releasing.md
150
152
  - doc/rpc.md
151
153
  - doc/sandboxing.md
@@ -154,17 +156,24 @@ files:
154
156
  - doc/shell.md
155
157
  - doc/skills.md
156
158
  - doc/tabs.md
159
+ - doc/telegram.md
160
+ - doc/transports.md
157
161
  - doc/troubleshooting.md
158
162
  - doc/usage.md
159
163
  - doc/web-search.md
160
164
  - doc/workspace-tools.md
161
165
  - examples/plugins/space_invaders.rb
166
+ - examples/plugins/stardate_footer.rb
167
+ - examples/plugins/telegram/plugin.rb
168
+ - examples/plugins/telegram/telegram_api.rb
169
+ - examples/plugins/telegram/telegram_transport.rb
162
170
  - exe/kward
163
171
  - kward.gemspec
164
172
  - lib/kward.rb
165
173
  - lib/kward/agent.rb
166
174
  - lib/kward/ansi.rb
167
175
  - lib/kward/auth/anthropic_oauth.rb
176
+ - lib/kward/auth/api_key_store.rb
168
177
  - lib/kward/auth/file.rb
169
178
  - lib/kward/auth/github_oauth.rb
170
179
  - lib/kward/auth/oauth_helpers.rb
@@ -192,6 +201,8 @@ files:
192
201
  - lib/kward/cli/sysprompt.rb
193
202
  - lib/kward/cli/tabs.rb
194
203
  - lib/kward/cli/tool_summaries.rb
204
+ - lib/kward/cli/transports.rb
205
+ - lib/kward/cli/worktrees.rb
195
206
  - lib/kward/cli_transcript_formatter.rb
196
207
  - lib/kward/clipboard.rb
197
208
  - lib/kward/compaction/file_operation_tracker.rb
@@ -207,6 +218,7 @@ files:
207
218
  - lib/kward/events.rb
208
219
  - lib/kward/export_path.rb
209
220
  - lib/kward/frontmatter.rb
221
+ - lib/kward/git_worktree_manager.rb
210
222
  - lib/kward/hooks.rb
211
223
  - lib/kward/hooks/audit_log.rb
212
224
  - lib/kward/hooks/catalog.rb
@@ -230,6 +242,8 @@ files:
230
242
  - lib/kward/memory/turn_context.rb
231
243
  - lib/kward/message_access.rb
232
244
  - lib/kward/message_text.rb
245
+ - lib/kward/model/azure_openai_config.rb
246
+ - lib/kward/model/catalog.rb
233
247
  - lib/kward/model/chat_invocation.rb
234
248
  - lib/kward/model/client.rb
235
249
  - lib/kward/model/context_overflow.rb
@@ -237,7 +251,9 @@ files:
237
251
  - lib/kward/model/copilot_models.rb
238
252
  - lib/kward/model/model_info.rb
239
253
  - lib/kward/model/payloads.rb
254
+ - lib/kward/model/provider_catalog.rb
240
255
  - lib/kward/model/retry_message.rb
256
+ - lib/kward/model/sources.rb
241
257
  - lib/kward/model/stream_parser.rb
242
258
  - lib/kward/openrouter_model_cache.rb
243
259
  - lib/kward/pan/index.html.erb
@@ -245,6 +261,7 @@ files:
245
261
  - lib/kward/pan/server.rb
246
262
  - lib/kward/path_guard.rb
247
263
  - lib/kward/permissions/policy.rb
264
+ - lib/kward/plugin_chat_runtime.rb
248
265
  - lib/kward/plugin_registry.rb
249
266
  - lib/kward/private_file.rb
250
267
  - lib/kward/project_files.rb
@@ -354,6 +371,7 @@ files:
354
371
  - lib/kward/tools/edit_file.rb
355
372
  - lib/kward/tools/fetch_content.rb
356
373
  - lib/kward/tools/fetch_raw.rb
374
+ - lib/kward/tools/git_commit.rb
357
375
  - lib/kward/tools/list_directory.rb
358
376
  - lib/kward/tools/mcp_tool.rb
359
377
  - lib/kward/tools/read_file.rb
@@ -369,6 +387,13 @@ files:
369
387
  - lib/kward/tools/web_search.rb
370
388
  - lib/kward/tools/write_file.rb
371
389
  - lib/kward/transcript_export.rb
390
+ - lib/kward/transport.rb
391
+ - lib/kward/transport/gateway.rb
392
+ - lib/kward/transport/host.rb
393
+ - lib/kward/transport/manager.rb
394
+ - lib/kward/transport/plugin_chat_gateway.rb
395
+ - lib/kward/transport/runtime.rb
396
+ - lib/kward/transport/store.rb
372
397
  - lib/kward/update_check.rb
373
398
  - lib/kward/version.rb
374
399
  - lib/kward/workspace.rb