kward 0.66.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.
- checksums.yaml +7 -0
- data/.yardopts +9 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +90 -0
- data/LICENSE +21 -0
- data/README.md +101 -0
- data/Rakefile +20 -0
- data/doc/authentication.md +105 -0
- data/doc/code-search.md +56 -0
- data/doc/configuration.md +310 -0
- data/doc/extensibility.md +186 -0
- data/doc/getting-started.md +127 -0
- data/doc/memory.md +192 -0
- data/doc/plugins.md +223 -0
- data/doc/releasing.md +36 -0
- data/doc/rpc.md +635 -0
- data/doc/usage.md +179 -0
- data/doc/web-search.md +28 -0
- data/exe/kward +5 -0
- data/kward.gemspec +33 -0
- data/lib/kward/agent.rb +234 -0
- data/lib/kward/ansi.rb +276 -0
- data/lib/kward/auth/file.rb +11 -0
- data/lib/kward/auth/github_oauth.rb +222 -0
- data/lib/kward/auth/openai_oauth.rb +323 -0
- data/lib/kward/auth/openrouter_api_key.rb +40 -0
- data/lib/kward/cancellation.rb +54 -0
- data/lib/kward/cli.rb +2122 -0
- data/lib/kward/clipboard.rb +84 -0
- data/lib/kward/compactor.rb +998 -0
- data/lib/kward/config_files.rb +564 -0
- data/lib/kward/conversation.rb +148 -0
- data/lib/kward/events.rb +13 -0
- data/lib/kward/export_path.rb +28 -0
- data/lib/kward/image_attachments.rb +331 -0
- data/lib/kward/markdown_transcript.rb +72 -0
- data/lib/kward/memory/manager.rb +652 -0
- data/lib/kward/message_access.rb +42 -0
- data/lib/kward/model/chat_invocation.rb +23 -0
- data/lib/kward/model/client.rb +875 -0
- data/lib/kward/model/context_overflow.rb +55 -0
- data/lib/kward/model/context_usage.rb +104 -0
- data/lib/kward/model/model_info.rb +188 -0
- data/lib/kward/model/retry_message.rb +11 -0
- data/lib/kward/model/stream_parser.rb +205 -0
- data/lib/kward/pan/index.html.erb +143 -0
- data/lib/kward/pan/server.rb +397 -0
- data/lib/kward/plugin_registry.rb +327 -0
- data/lib/kward/private_file.rb +18 -0
- data/lib/kward/prompt_interface.rb +2437 -0
- data/lib/kward/prompts/commands.rb +50 -0
- data/lib/kward/prompts/templates.rb +60 -0
- data/lib/kward/prompts.rb +58 -0
- data/lib/kward/resources/avatar_kward_logo.rb +48 -0
- data/lib/kward/resources/pixel_logo.rb +230 -0
- data/lib/kward/rpc/auth_manager.rb +265 -0
- data/lib/kward/rpc/config_manager.rb +58 -0
- data/lib/kward/rpc/prompt_bridge.rb +104 -0
- data/lib/kward/rpc/redactor.rb +47 -0
- data/lib/kward/rpc/server.rb +639 -0
- data/lib/kward/rpc/session_manager.rb +1122 -0
- data/lib/kward/rpc/tool_event_normalizer.rb +68 -0
- data/lib/kward/rpc/tool_metadata.rb +80 -0
- data/lib/kward/rpc/transcript_normalizer.rb +307 -0
- data/lib/kward/rpc/transport.rb +58 -0
- data/lib/kward/session_diff.rb +125 -0
- data/lib/kward/session_store.rb +493 -0
- data/lib/kward/skills/registry.rb +76 -0
- data/lib/kward/starter_pack_installer.rb +110 -0
- data/lib/kward/steering.rb +56 -0
- data/lib/kward/telemetry/logger.rb +195 -0
- data/lib/kward/telemetry/stats.rb +466 -0
- data/lib/kward/tools/ask_user_question.rb +107 -0
- data/lib/kward/tools/base.rb +45 -0
- data/lib/kward/tools/code_search.rb +65 -0
- data/lib/kward/tools/edit_file.rb +41 -0
- data/lib/kward/tools/list_directory.rb +21 -0
- data/lib/kward/tools/read_file.rb +30 -0
- data/lib/kward/tools/read_skill.rb +27 -0
- data/lib/kward/tools/registry.rb +117 -0
- data/lib/kward/tools/run_shell_command.rb +28 -0
- data/lib/kward/tools/search/code.rb +445 -0
- data/lib/kward/tools/search/web.rb +747 -0
- data/lib/kward/tools/tool_call.rb +87 -0
- data/lib/kward/tools/web_search.rb +48 -0
- data/lib/kward/tools/write_file.rb +29 -0
- data/lib/kward/transcript_export.rb +40 -0
- data/lib/kward/version.rb +4 -0
- data/lib/kward/workspace.rb +377 -0
- data/lib/kward.rb +6 -0
- data/lib/main.rb +3 -0
- metadata +232 -0
data/doc/memory.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Memory
|
|
2
|
+
|
|
3
|
+
Kward has an opt-in structured memory system for interactive sessions. Memory is designed to be inspectable, explainable, and removable. It is disabled by default.
|
|
4
|
+
|
|
5
|
+
Memory is not used for one-shot prompts such as `kward "..."`.
|
|
6
|
+
|
|
7
|
+
Use memory when you want Kward to remember stable preferences, recurring project facts, or personal workflow habits across interactive sessions. Leave it disabled when you want every session to start clean.
|
|
8
|
+
|
|
9
|
+
## Enable or disable memory
|
|
10
|
+
|
|
11
|
+
In interactive chat:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
/memory enable
|
|
15
|
+
/memory disable
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Enabling memory stores this config in `~/.kward/config.json`:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"memory": {
|
|
23
|
+
"enabled": true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
When memory is disabled, Kward does not inject retrieved memories into the prompt.
|
|
29
|
+
|
|
30
|
+
## Auto-summary
|
|
31
|
+
|
|
32
|
+
Memory auto-summary is off by default. When both memory and auto-summary are enabled, Kward quietly runs the same learning flow as `/memory summarize` after each completed interactive agent turn, when it is ready for the next user prompt:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
/memory auto-summary enable
|
|
36
|
+
/memory auto-summary disable
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The config value is stored as:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"memory": {
|
|
44
|
+
"enabled": true,
|
|
45
|
+
"auto_summary": true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Auto-summary does not run when memory is disabled and is not used for one-shot prompts.
|
|
51
|
+
|
|
52
|
+
## Memory layers
|
|
53
|
+
|
|
54
|
+
### Core memories
|
|
55
|
+
|
|
56
|
+
Core memories are explicit user instructions. They are high-trust and persistent until removed. Add them only when you intentionally want Kward to remember something:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
/memory core "Prefer small, focused patches with tests."
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Core memories are stored as human-readable JSON in:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
~/.kward/memory/core.json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Soft memories
|
|
69
|
+
|
|
70
|
+
Soft memories are contextual hints, such as workflow preferences or recurring project facts. They are confidence-based and treated as non-authoritative. Add one manually with:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
/memory add "This workspace usually uses Minitest."
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Soft memories are stored as JSON Lines in:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
~/.kward/memory/soft.jsonl
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Kward can also infer soft memories when auto-summary is enabled, or when you explicitly ask it to summarize/learn from the current session:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
/memory summarize
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The v1 inference is conservative and heuristic-based, with optional model-based reformulation when summarization has an available client. Kward refuses to automatically persist inferred emotional, intimate, romantic, or dependency-forming memories.
|
|
89
|
+
|
|
90
|
+
### Session memories
|
|
91
|
+
|
|
92
|
+
Session memories record memories learned during the current conversation so Kward can avoid learning the same item again when summarizing or resuming the session. They are stored with the session JSONL file, but they are not injected into the prompt as a separate memory layer and are not automatically promoted into core memories.
|
|
93
|
+
|
|
94
|
+
## Inspect, explain, and remove memory
|
|
95
|
+
|
|
96
|
+
List memories:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
/memory list
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Inspect memory state and file paths:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
/memory inspect
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Explain why memories were retrieved for the most recent interactive turn:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
/memory why
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Forget a memory:
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
/memory forget core_001
|
|
118
|
+
/memory forget soft_001
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
For core memories, forget removes the record. For soft memories, forget marks the record inactive and redacts its stored text, tags, confidence, and hit count so inactive audit metadata can remain without retaining the memory content.
|
|
122
|
+
|
|
123
|
+
Promote a soft memory to a core memory:
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
/memory promote soft_001
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Promotion creates a new core memory and marks the soft memory forgotten.
|
|
130
|
+
|
|
131
|
+
## Retrieval behavior
|
|
132
|
+
|
|
133
|
+
For each interactive turn, Kward selectively retrieves memories using:
|
|
134
|
+
|
|
135
|
+
- scope: `global` and `workspace:<canonical path>`
|
|
136
|
+
- core memories first
|
|
137
|
+
- soft-memory text or tag overlap with the current input; soft memories without overlap are not injected
|
|
138
|
+
- soft-memory confidence
|
|
139
|
+
- soft-memory recency/TTL, updated when a soft memory is retrieved
|
|
140
|
+
- hard limits on injected memory count
|
|
141
|
+
|
|
142
|
+
Retrieved memories are injected into the system prompt as a bounded block similar to:
|
|
143
|
+
|
|
144
|
+
```text
|
|
145
|
+
<kward_memory>
|
|
146
|
+
Core Memories:
|
|
147
|
+
- [core_001] ...
|
|
148
|
+
|
|
149
|
+
Relevant Soft Memories:
|
|
150
|
+
- [soft_001] ...
|
|
151
|
+
|
|
152
|
+
Rules:
|
|
153
|
+
- Core memories override soft memories.
|
|
154
|
+
- Soft memories are contextual hints, not guaranteed facts.
|
|
155
|
+
</kward_memory>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Kward never injects every stored memory.
|
|
159
|
+
|
|
160
|
+
## Storage and audit trail
|
|
161
|
+
|
|
162
|
+
Default files:
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
~/.kward/memory/core.json
|
|
166
|
+
~/.kward/memory/soft.jsonl
|
|
167
|
+
~/.kward/memory/events.jsonl
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`events.jsonl` records minimal audit events such as enable, disable, add, forget, promote, retrieve, and summarize. Audit events use IDs, scopes, tags, and timestamps rather than full memory text where practical. Forgotten soft memories keep inactive metadata in `soft.jsonl`, but their stored text is replaced with `[forgotten]`.
|
|
171
|
+
|
|
172
|
+
If `KWARD_CONFIG_PATH` is set, memory files live beside that config file instead of under `~/.kward`.
|
|
173
|
+
|
|
174
|
+
## RPC methods
|
|
175
|
+
|
|
176
|
+
The experimental RPC backend exposes dedicated memory methods:
|
|
177
|
+
|
|
178
|
+
- `memory/status`
|
|
179
|
+
- `memory/enable`
|
|
180
|
+
- `memory/disable`
|
|
181
|
+
- `memory/autoSummary/enable`
|
|
182
|
+
- `memory/autoSummary/disable`
|
|
183
|
+
- `memory/list`
|
|
184
|
+
- `memory/add`
|
|
185
|
+
- `memory/addCore`
|
|
186
|
+
- `memory/forget`
|
|
187
|
+
- `memory/promote`
|
|
188
|
+
- `memory/inspect`
|
|
189
|
+
- `memory/why`
|
|
190
|
+
- `memory/summarize`
|
|
191
|
+
|
|
192
|
+
See [RPC protocol](rpc.md) for method details.
|
data/doc/plugins.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Plugins
|
|
2
|
+
|
|
3
|
+
Plugins are Kward's trusted local extension system. They let you add project or personal workflow features without changing Kward itself.
|
|
4
|
+
|
|
5
|
+
A plugin can:
|
|
6
|
+
|
|
7
|
+
- add interactive slash commands,
|
|
8
|
+
- expose commands through the RPC backend,
|
|
9
|
+
- render a custom terminal footer,
|
|
10
|
+
- inject concise prompt context into future model requests,
|
|
11
|
+
- observe live transcript events such as assistant output, tool calls, and retries.
|
|
12
|
+
|
|
13
|
+
Plugins are plain Ruby files. They run inside the Kward process with your local user permissions, so install only plugins you trust.
|
|
14
|
+
|
|
15
|
+
Use a prompt template when reusable text is enough. Use a skill when you need reusable instructions. Use a plugin when you need local Ruby behavior, file or network integration, custom commands, or transcript observers.
|
|
16
|
+
|
|
17
|
+
## Where plugins live
|
|
18
|
+
|
|
19
|
+
Kward loads top-level Ruby files from:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
~/.kward/plugins/*.rb
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Plugins are intentionally **not** loaded from the current workspace, from a project repository, or from a custom `KWARD_CONFIG_PATH` directory. This keeps plugin loading tied to the local user account rather than to whatever project Kward is currently inspecting.
|
|
26
|
+
|
|
27
|
+
If a legacy plugin directory exists beside a custom config path, Kward warns and ignores it.
|
|
28
|
+
|
|
29
|
+
## A first plugin
|
|
30
|
+
|
|
31
|
+
Create the plugin directory:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
mkdir -p ~/.kward/plugins
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then create `~/.kward/plugins/hello.rb`:
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
Kward.plugin do |plugin|
|
|
41
|
+
plugin.command "hello", description: "Say hello", argument_hint: "[name]" do |args, ctx|
|
|
42
|
+
name = args.strip.empty? ? "captain" : args.strip
|
|
43
|
+
ctx.say("Hello, #{name}.")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Start Kward and run:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
/hello Kai
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Plugin commands appear in interactive slash completion and in RPC command listings.
|
|
55
|
+
|
|
56
|
+
## Slash commands
|
|
57
|
+
|
|
58
|
+
Register a command with `plugin.command`:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
Kward.plugin do |plugin|
|
|
62
|
+
plugin.command "session-info", description: "Show session details" do |_args, ctx|
|
|
63
|
+
ctx.say("Session: #{ctx.session_name || ctx.session_id || 'unnamed'}")
|
|
64
|
+
ctx.say("Path: #{ctx.session_path || 'not saved'}")
|
|
65
|
+
ctx.say("Workspace: #{ctx.workspace_root}")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Command names:
|
|
71
|
+
|
|
72
|
+
- do not include the leading `/`,
|
|
73
|
+
- must start with a letter or number,
|
|
74
|
+
- may contain letters, numbers, `_`, and `-`,
|
|
75
|
+
- cannot replace built-in commands or prompt-template commands.
|
|
76
|
+
|
|
77
|
+
If a plugin command conflicts with a reserved or duplicate command, Kward skips it and prints a warning.
|
|
78
|
+
|
|
79
|
+
Command handlers receive:
|
|
80
|
+
|
|
81
|
+
- `args`: the raw text after the command name,
|
|
82
|
+
- `ctx`: a plugin context object.
|
|
83
|
+
|
|
84
|
+
Use `ctx.say(message)` for user-visible output.
|
|
85
|
+
|
|
86
|
+
## Prompt context
|
|
87
|
+
|
|
88
|
+
Plugins can add concise context to future system prompts:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
Kward.plugin do |plugin|
|
|
92
|
+
plugin.prompt_context do |ctx|
|
|
93
|
+
next unless File.exist?(File.join(ctx.workspace_root, "Gemfile"))
|
|
94
|
+
|
|
95
|
+
"Workspace note: this project uses Ruby. Prefer bundle exec for project commands."
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Prompt context is injected after personas and before skills/workspace instructions. Keep it short and stable. Long or noisy prompt context will be sent repeatedly to the model and can reduce useful context space.
|
|
101
|
+
|
|
102
|
+
If plugin state changes and the active conversation should rebuild its system message, call:
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
ctx.refresh_system_message!
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
from a command or event handler.
|
|
109
|
+
|
|
110
|
+
## Custom footer
|
|
111
|
+
|
|
112
|
+
A plugin can render one custom footer for the terminal UI:
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
Kward.plugin do |plugin|
|
|
116
|
+
plugin.footer do |ctx|
|
|
117
|
+
name = ctx.session_name || "unnamed"
|
|
118
|
+
messages = ctx.transcript.messages.length
|
|
119
|
+
"#{name} • #{messages} messages"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Only one footer renderer is active. If multiple plugins register footers, the later one replaces the earlier one and Kward prints a warning.
|
|
125
|
+
|
|
126
|
+
Footer errors are caught and printed as warnings so they do not break the session.
|
|
127
|
+
|
|
128
|
+
## Transcript events
|
|
129
|
+
|
|
130
|
+
Plugins can observe live transcript stream events:
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
Kward.plugin do |plugin|
|
|
134
|
+
plugin.on_transcript_event do |event, ctx|
|
|
135
|
+
next unless event.type == "assistant_delta"
|
|
136
|
+
|
|
137
|
+
File.open(File.join(ctx.workspace_root, ".assistant-stream.log"), "a") do |file|
|
|
138
|
+
file.write(event.payload[:delta])
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Supported event types include:
|
|
145
|
+
|
|
146
|
+
- `reasoning_delta`
|
|
147
|
+
- `assistant_delta`
|
|
148
|
+
- `assistant_message`
|
|
149
|
+
- `model_retry`
|
|
150
|
+
- `turn_steered`
|
|
151
|
+
- `tool_call`
|
|
152
|
+
- `tool_result`
|
|
153
|
+
- `answer`
|
|
154
|
+
|
|
155
|
+
Event payloads are deep-frozen copies. Treat them as read-only.
|
|
156
|
+
|
|
157
|
+
Transcript-event handler errors are caught and printed as warnings.
|
|
158
|
+
|
|
159
|
+
## Plugin context API
|
|
160
|
+
|
|
161
|
+
Plugin handlers receive a `ctx` object with:
|
|
162
|
+
|
|
163
|
+
- `ctx.args` - raw command arguments for contexts that have them.
|
|
164
|
+
- `ctx.workspace_root` - active workspace path.
|
|
165
|
+
- `ctx.transcript.messages` - deep-frozen copy of active conversation messages.
|
|
166
|
+
- `ctx.say(message)` - emit output to the active frontend when available.
|
|
167
|
+
- `ctx.session_id` - current persisted session ID when available.
|
|
168
|
+
- `ctx.session_name` - current session name when available.
|
|
169
|
+
- `ctx.session_path` - current session file path when available.
|
|
170
|
+
- `ctx.refresh_system_message!` - rebuild the active conversation system message.
|
|
171
|
+
|
|
172
|
+
The transcript is read-only by design. Plugins should use Kward APIs exposed through the context rather than mutating conversation internals.
|
|
173
|
+
|
|
174
|
+
## RPC support
|
|
175
|
+
|
|
176
|
+
Plugins are available to both the CLI and the experimental RPC backend.
|
|
177
|
+
|
|
178
|
+
RPC clients can:
|
|
179
|
+
|
|
180
|
+
- list plugin commands through `commands/list`,
|
|
181
|
+
- run plugin commands through `commands/run`,
|
|
182
|
+
- run plugin slash commands through `turns/start` input such as `/hello Kai`.
|
|
183
|
+
|
|
184
|
+
When a plugin command is run as a turn, Kward emits command output through normal turn events without calling the model.
|
|
185
|
+
|
|
186
|
+
## Security model
|
|
187
|
+
|
|
188
|
+
Plugins are trusted local Ruby code. A plugin can read and write files, run commands, make network requests, and access process environment variables just like any Ruby code running as your user.
|
|
189
|
+
|
|
190
|
+
Recommended practices:
|
|
191
|
+
|
|
192
|
+
- Install plugins only from sources you trust.
|
|
193
|
+
- Keep plugins in your personal `~/.kward/plugins` directory.
|
|
194
|
+
- Do not place secrets directly in plugin files if they will be shared.
|
|
195
|
+
- Prefer user-specific config or environment variables for credentials.
|
|
196
|
+
- Keep prompt context concise and avoid injecting secrets into model prompts.
|
|
197
|
+
- Be careful when writing transcript observers that persist conversation content.
|
|
198
|
+
|
|
199
|
+
## Complete example
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
Kward.plugin do |plugin|
|
|
203
|
+
plugin.command "last-message", description: "Show transcript size" do |_args, ctx|
|
|
204
|
+
ctx.say("Messages: #{ctx.transcript.messages.length}")
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
plugin.footer do |ctx|
|
|
208
|
+
"#{ctx.session_name || 'unnamed'} • #{ctx.transcript.messages.length} messages"
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
plugin.prompt_context do |_ctx|
|
|
212
|
+
"Project background: prefer small, focused changes."
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
plugin.on_transcript_event do |event, ctx|
|
|
216
|
+
next unless event.type == "assistant_delta"
|
|
217
|
+
|
|
218
|
+
File.open(File.join(ctx.workspace_root, ".assistant-stream.log"), "a") do |file|
|
|
219
|
+
file.write(event.payload[:delta])
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
```
|
data/doc/releasing.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Releasing Kward
|
|
2
|
+
|
|
3
|
+
Release steps that can be completed before publishing:
|
|
4
|
+
|
|
5
|
+
1. Update `CHANGELOG.md` for the version.
|
|
6
|
+
2. Update `Kward::VERSION` in `lib/kward/version.rb`.
|
|
7
|
+
3. Run the test suite:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bundle exec rake test
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
4. Generate documentation:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bundle exec rake rdoc
|
|
17
|
+
bundle exec yard doc
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
5. Build the gem locally:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
gem build kward.gemspec
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
6. Inspect the packaged files and confirm no local config, sessions, logs, or secrets are included.
|
|
27
|
+
7. Install the built gem locally and smoke test the `kward` executable.
|
|
28
|
+
|
|
29
|
+
RubyGems setup before the first public release:
|
|
30
|
+
|
|
31
|
+
1. Create or sign in to a RubyGems.org account.
|
|
32
|
+
2. Enable multi-factor authentication for the account.
|
|
33
|
+
3. Confirm the `kward` gem name is available.
|
|
34
|
+
4. Add final homepage, source code, changelog, documentation, and bug tracker metadata to `kward.gemspec` once the public repository URLs are final.
|
|
35
|
+
5. Prefer RubyGems trusted publishing for automated releases so long-lived API keys do not need to be stored in CI secrets.
|
|
36
|
+
6. Push the built gem or publish through the trusted publishing workflow.
|