kward 0.82.0 → 0.83.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 +4 -4
- data/CHANGELOG.md +28 -0
- data/Gemfile.lock +2 -2
- data/doc/agent-tools.md +1 -0
- data/doc/composer.md +1 -1
- data/doc/configuration.md +18 -3
- data/doc/editor.md +20 -10
- data/doc/files.md +4 -3
- data/doc/permissions.md +1 -0
- data/doc/releasing.md +12 -4
- data/doc/rpc.md +2 -2
- data/doc/sandboxing.md +5 -1
- data/doc/security.md +1 -1
- data/doc/shell.md +40 -16
- data/doc/tabs.md +3 -0
- data/doc/usage.md +3 -2
- data/lib/kward/agent.rb +1 -0
- data/lib/kward/auth/anthropic_oauth.rb +7 -7
- data/lib/kward/cli/interactive_turn.rb +101 -19
- data/lib/kward/cli/runtime_helpers.rb +156 -14
- data/lib/kward/cli/slash_commands.rb +12 -1
- data/lib/kward/cli/tabs.rb +12 -5
- data/lib/kward/cli.rb +10 -0
- data/lib/kward/compaction/token_estimator.rb +12 -6
- data/lib/kward/config_files.rb +17 -0
- data/lib/kward/editor_prompt.rb +46 -0
- data/lib/kward/editor_prompt_session.rb +28 -0
- data/lib/kward/ekwsh.rb +70 -10
- data/lib/kward/model/client.rb +1 -17
- data/lib/kward/model/model_info.rb +3 -2
- data/lib/kward/model/payloads.rb +0 -2
- data/lib/kward/persistent_shell_session.rb +750 -0
- data/lib/kward/project_files.rb +18 -5
- data/lib/kward/prompt_interface/composer_renderer.rb +1 -1
- data/lib/kward/prompt_interface/editor/auto_indent.rb +3 -0
- data/lib/kward/prompt_interface/editor/controller.rb +69 -0
- data/lib/kward/prompt_interface/editor/modes/modern.rb +4 -0
- data/lib/kward/prompt_interface/editor/modes/vibe.rb +10 -4
- data/lib/kward/prompt_interface/editor/renderer.rb +1 -0
- data/lib/kward/prompt_interface/editor/state.rb +11 -0
- data/lib/kward/prompt_interface/editor/word_completion.rb +124 -0
- data/lib/kward/prompt_interface/file_overlay.rb +21 -7
- data/lib/kward/prompt_interface/key_handler.rb +8 -0
- data/lib/kward/prompt_interface/project_browser.rb +30 -5
- data/lib/kward/prompt_interface/runtime_state.rb +5 -1
- data/lib/kward/prompt_interface.rb +76 -0
- data/lib/kward/prompts/commands.rb +1 -0
- data/lib/kward/rpc/auth_manager.rb +1 -1
- data/lib/kward/rpc/server.rb +2 -1
- data/lib/kward/shell_prompt.rb +50 -0
- data/lib/kward/shell_prompt_session.rb +58 -0
- data/lib/kward/terminal_keys.rb +1 -0
- data/lib/kward/tools/prepare_shell_command.rb +28 -0
- data/lib/kward/tools/registry.rb +63 -5
- data/lib/kward/tools/replace_editor_buffer.rb +30 -0
- data/lib/kward/tools/run_shell_command.rb +24 -6
- data/lib/kward/version.rb +1 -1
- data/templates/default/layout/html/layout.erb +1 -1
- metadata +9 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 678c9e9bb188e6c3d065dfde6b97c9ec5c31b29b178b40d69b0397b5200eb2a8
|
|
4
|
+
data.tar.gz: 3e09cb3d11ff6018ecc75e3eb31e8745e72e534dba7a4c3711a488451d353fcc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7f4247a32300deff0906c95c10d7312aa6303108956596f16d9f2c6d2d4fc444b5ef377751f47dbd2157b041710d855c44a981a1a22f8a562c79203afe8b65ed
|
|
7
|
+
data.tar.gz: d93d09126d221c05d7ef0e931f46ccfaa4a84450e6eb5695dbea653d8b9de99bb27bc7fb070b323c74160477fd328f0be3cd972d544b45e3ea90ffbeb79cb087
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,33 @@ All notable changes to Kward will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.83.0] - 2026-08-28
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Added `?` shell prompts for transient, context-aware assistance inside `/shell`, including shared shell-state commands and prepare-without-execute command drafts.
|
|
12
|
+
- Added `Ctrl+.` in Modern editor mode to open an in-editor prompt line for communicating with the dedicated editor agent.
|
|
13
|
+
- Added Vibe `:prompt <instruction>` support, allowing the agent to inspect and replace the active in-memory editor buffer without saving it automatically.
|
|
14
|
+
- Added current-buffer word completion to the integrated editor, with repeated Tab presses cycling nearby matches and existing smart indentation retained when no match exists.
|
|
15
|
+
- Added Claude Opus 5 to the Anthropic model picker with its 1M context window and high-reasoning metadata.
|
|
16
|
+
- Added an `i` toggle to the `/files` browser for showing Git-ignored files, which remain hidden by default.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- `/shell` now keeps one persistent local shell process per tab so shell variables, functions, aliases, and directory changes are shared by user and agent commands.
|
|
21
|
+
- Shell-agent turns use a transient per-tab context and receive only bounded, sanitized output after an explicit `?` request; ordinary shell output remains outside model context.
|
|
22
|
+
- Shell-agent transcript output is now retained as bounded, tab-local runtime state so it survives tab switches without entering session history.
|
|
23
|
+
- Vibe editor-agent turns now use an isolated, configurable model/reasoning context, remain visible with a status-line spinner, and stay out of normal chat transcripts and session history.
|
|
24
|
+
- Removed the obsolete GPT-5.6 Luna Responses Lite compatibility workaround so Luna requests retain Kward's identity and standard Codex payload.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Made persistent shell command cancellation and timeouts recover by restarting an unresponsive embedded shell, and stabilized raw-input coverage across platforms.
|
|
29
|
+
- Restored full-screen Git pagers and immediate key/Ctrl+C forwarding for interactive `/shell` commands by removing Kward's ambient `GIT_PAGER=cat` default and putting host input in raw mode during persistent-shell handoff, while keeping paging suppressed for captured and shell-agent commands.
|
|
30
|
+
- Fixed Claude subscription OAuth authorization and token-exchange requests by removing unsupported subscription scopes and the nonstandard `code` query parameter, and by forwarding the OAuth state to the token endpoint.
|
|
31
|
+
- Installed and enabled Bubblewrap during release verification so Linux worktree tests use the same sandbox setup as normal CI, added manual recovery for existing release tags, and made publication wait for and attach the canonical RubyGems artifact after trusted-publishing attestation.
|
|
32
|
+
- Fixed automatic context compaction so Codex response items are included in token estimates and long tool-call turns are checked before each model request.
|
|
33
|
+
|
|
7
34
|
## [0.82.0] - 2026-08-23
|
|
8
35
|
|
|
9
36
|
### Added
|
|
@@ -91,6 +118,7 @@ All notable changes to Kward will be documented in this file.
|
|
|
91
118
|
- Added Git worktree bindings for normal interactive session tabs. `/tab worktree` can move a tab into a strict linked-worktree workspace after research, preserve its transcript, warn about dirty origin changes, and keep the branch available when explicitly detached.
|
|
92
119
|
- Added the active worktree `git_commit` model tool, allowing explicitly requested agent commits through the trusted host-side Git workflow without widening the shell sandbox.
|
|
93
120
|
- Added `/tab worktree merge` for explicitly merging a clean worktree branch into the branch checked out in its original workspace, plus `/tab worktree merge abort` for conflicted merges.
|
|
121
|
+
- Added `/worktree` as a concise alias for `/tab worktree` on the active tab.
|
|
94
122
|
- Added `j`/`k` keyboard navigation to the `/files` project browser.
|
|
95
123
|
- Added `h`/`l` keyboard navigation for collapsing and expanding `/files` directories.
|
|
96
124
|
- Added `j`/`k` keyboard navigation to the `/git` changed-file overlay.
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
kward (0.
|
|
4
|
+
kward (0.83.0)
|
|
5
5
|
base64
|
|
6
6
|
nokogiri
|
|
7
7
|
tiktoken_ruby
|
|
@@ -146,7 +146,7 @@ CHECKSUMS
|
|
|
146
146
|
html-proofer (5.2.1) sha256=fdd958a7cbf9c3255fb96fe7cfc4e611f64e2706e469488a3326309ad007d2fd
|
|
147
147
|
io-event (1.16.2) sha256=9f9cb0a96ea5c3850a672606c65f27bc96d7621399ef6196acbfe2be0cd1279c
|
|
148
148
|
json (2.19.9) sha256=9b9025b7cdddafa38d316eca0b2358488e42d417045c1b90d216a9fefe46b79a
|
|
149
|
-
kward (0.
|
|
149
|
+
kward (0.83.0)
|
|
150
150
|
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
151
151
|
metrics (0.15.0) sha256=61ded5bac95118e995b1bc9ed4a5f19bc9814928a312a85b200abbdac9039072
|
|
152
152
|
minitest (6.0.6) sha256=153ea36d1d987a62942382b61075745042a2b3123b1cd48f4c3675af9cc7d6f1
|
data/doc/agent-tools.md
CHANGED
|
@@ -15,6 +15,7 @@ Tools also enforce important boundaries:
|
|
|
15
15
|
| Category | Tools | Guide |
|
|
16
16
|
| --- | --- | --- |
|
|
17
17
|
| Workspace tools | `list_directory`, `read_file`, `context_for_task`, `context_budget_stats`, `summarize_file_structure`, `write_file`, `edit_file`, `run_shell_command` | [Workspace tools](workspace-tools.md) |
|
|
18
|
+
| Shell prompt tools | `run_shell_command`, `prepare_shell_command` (available only to the transient `?` shell assistant) | [Embedded shell](shell.md) |
|
|
18
19
|
| Web tools | `web_search`, `fetch_content`, `fetch_raw` | [Web search](web-search.md) |
|
|
19
20
|
| Code search | `code_search` | [Code search](code-search.md) |
|
|
20
21
|
| Context and interaction tools | `read_skill`, `retrieve_tool_output`, `ask_user_question` | [Context tools](context-tools.md) |
|
data/doc/composer.md
CHANGED
|
@@ -213,4 +213,4 @@ If rendering becomes corrupted after resize or after an external program writes
|
|
|
213
213
|
|
|
214
214
|
You can also press `Ctrl+L`; it rebuilds the durable current-tab view without deleting the conversation transcript, removing transient shell output. If a shortcut never reaches Kward, prefer its slash-command equivalent or change `composer.tab_keybindings` in `/settings`.
|
|
215
215
|
|
|
216
|
-
External commands inside `/shell` and one-shot `!command` input receive an interactive PTY by default. They begin inline above a frozen composer, then switch to full-terminal passthrough if they emit screen-oriented or unknown terminal controls; full-screen programs such as Vim or `less` can therefore temporarily own the terminal. Use `capture <command>` inside `/shell` or `/capture <command>` from the normal composer for bounded, sanitized transcript output.
|
|
216
|
+
External commands inside `/shell` and one-shot `!command` input receive an interactive PTY by default. They begin inline above a frozen composer, then switch to full-terminal passthrough if they emit screen-oriented or unknown terminal controls; full-screen programs such as Vim or `less` can therefore temporarily own the terminal. While Kward owns the shell composer, a leading `?` asks the transient shell assistant; it receives only bounded, sanitized output from the latest command. Use `capture <command>` inside `/shell` or `/capture <command>` from the normal composer for bounded, sanitized transcript output.
|
data/doc/configuration.md
CHANGED
|
@@ -184,9 +184,9 @@ aliases:
|
|
|
184
184
|
gd: "git diff --color=always"
|
|
185
185
|
```
|
|
186
186
|
|
|
187
|
-
`env` values are applied when shell mode starts, after Kward's conservative color defaults. Keys must look like environment variable names (`A_Z`, digits after the first character, and underscores); invalid keys are ignored. Values are converted to strings.
|
|
187
|
+
`env` values are applied when shell mode starts, after Kward's conservative color defaults. `/shell` keeps one persistent local interactive shell process per tab. Keys must look like environment variable names (`A_Z`, digits after the first character, and underscores); invalid keys are ignored. Values are converted to strings.
|
|
188
188
|
|
|
189
|
-
`aliases` expand the first word of a command once. For example, `ll lib` runs `ls -la lib`. Configured aliases are available both inside `/shell` and after the normal composer's `!` prefix, including command-name Tab completion. Built-in
|
|
189
|
+
`aliases` expand the first word of a command once. For example, `ll lib` runs `ls -la lib`. Configured aliases are available both inside `/shell` and after the normal composer's `!` prefix, including command-name Tab completion. Built-in shell commands such as `cd`, `pwd`, `export`, `unset`, `alias`, `capture`, `clear`, `pty`, and `exit` take precedence over aliases inside `/shell`. External commands receive an interactive PTY by default. Prefix a submitted line with `?` inside `/shell` to ask the transient shell assistant about the current command output or state. An alias value can begin with `capture` when its `/shell` output should use the configured timeout, output limit, and transcript sanitization. Leading-`!` alias invocations are always interactive, so Kward removes a leading `capture` or legacy `pty` mode marker from the expanded alias before execution. Run `alias` inside `ekwsh` to list configured aliases. Aliases created at runtime with that built-in belong only to the current `/shell` session and are not available to `!command` input.
|
|
190
190
|
|
|
191
191
|
## Provider and model settings
|
|
192
192
|
|
|
@@ -248,7 +248,7 @@ Defaults:
|
|
|
248
248
|
- Copilot: `gpt-5-mini`
|
|
249
249
|
- Reasoning effort: `medium`
|
|
250
250
|
|
|
251
|
-
The Anthropic model choices include `claude-fable-5`,
|
|
251
|
+
The Anthropic model choices include `claude-fable-5`, `claude-opus-5`, and `claude-sonnet-5`. Fable and Opus availability depends on the logged-in account and organization. Selecting a model without access returns an Anthropic provider error. Kward keeps Sonnet 5 as its default because it supports both Pro and Max subscriptions; select Opus 5 explicitly when it is available on the account.
|
|
252
252
|
|
|
253
253
|
The interactive `/model` picker reads cached OpenRouter models when available. Run `kward openrouter refresh` to fetch text-capable models available to the configured OpenRouter API key and cache them under `~/.kward/cache/openrouter_models.json`. Run `kward openrouter list` to inspect the cached model ids.
|
|
254
254
|
|
|
@@ -393,6 +393,21 @@ The built-in TUI file editor supports three keybinding modes. Modern is the defa
|
|
|
393
393
|
|
|
394
394
|
`mode` can be `modern`, `emacs`, or `vibe`. The old `default` value is still accepted as an alias for `modern`. You can change this from `/settings` → Interface → Editor mode; newly opened editor buffers pick up the setting immediately.
|
|
395
395
|
|
|
396
|
+
Vibe `:prompt` uses a dedicated transient editor agent. Configure its model and reasoning effort under `editor.agent` when it should differ from the active tab:
|
|
397
|
+
|
|
398
|
+
```json
|
|
399
|
+
{
|
|
400
|
+
"editor": {
|
|
401
|
+
"agent": {
|
|
402
|
+
"model": "gpt-5.5",
|
|
403
|
+
"reasoning_effort": "medium"
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
These settings use the active tab's provider. If either value is omitted, Kward falls back to the active tab's value and then the client default. Editor-agent prompts and tool activity are kept out of the normal transcript and session history; the editor remains visible with a spinner while the transient turn runs.
|
|
410
|
+
|
|
396
411
|
The integrated Git and session diff viewers support unified and side-by-side layouts:
|
|
397
412
|
|
|
398
413
|
```json
|
data/doc/editor.md
CHANGED
|
@@ -43,7 +43,7 @@ For a nested project tree, run:
|
|
|
43
43
|
/files
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
In the tree browser, use `↑`/`↓` to move, `←`/`→` to collapse or expand directories, `Enter` to toggle a directory or open a file, `Tab` or `/` to search, `@` to insert the selected file as an `@path` mention, and `Esc` to close. When you open a file from `/files`, quitting the editor returns to the browser at the same position.
|
|
46
|
+
In the tree browser, use `↑`/`↓` to move, `←`/`→` to collapse or expand directories, `Enter` to toggle a directory or open a file, `Tab` or `/` to search, `i` to show or hide Git-ignored files, `@` to insert the selected file as an `@path` mention, and `Esc` to close. When you open a file from `/files`, quitting the editor returns to the browser at the same position.
|
|
47
47
|
|
|
48
48
|
For an unsaved buffer, open a scratchpad:
|
|
49
49
|
|
|
@@ -85,21 +85,26 @@ $doc/editor.md
|
|
|
85
85
|
1. Type `$doc/editor.md` in the composer.
|
|
86
86
|
2. Pick the file from the matching results, or press `Enter` if the path is already complete.
|
|
87
87
|
3. Edit the file.
|
|
88
|
-
4.
|
|
89
|
-
5.
|
|
90
|
-
6.
|
|
88
|
+
4. In Vibe normal mode, use `:prompt <instruction>` to ask the agent to update the current in-memory buffer. In Modern mode, press `Ctrl+.` and type the instruction in the editor prompt line. For example, `write a HelloWorld class`.
|
|
89
|
+
5. The editor stays visible while the agent works; its status line shows a spinner. Review the generated buffer and save with `Ctrl+S` in Modern mode, `C-x C-s` in Emacs mode, or `:w` in Vibe mode. For an unsaved scratchpad in Vibe mode, use `:w filename`.
|
|
90
|
+
6. Quit with `Ctrl+Q`, `C-x C-c`, or `:q`.
|
|
91
|
+
7. Continue chatting with Kward.
|
|
91
92
|
|
|
92
93
|
## What the editor supports
|
|
93
94
|
|
|
94
95
|
The editor is intentionally compact, but it covers the basics you need for quick changes:
|
|
95
96
|
|
|
96
97
|
- Syntax highlighting for common languages, including Ruby, ERB templates, Crystal, Elixir, Julia, JavaScript, TypeScript, JSON, Markdown, YAML, Shell, Makefile, HTML, CSS, SCSS, Python, Go, Rust, Java, C#, C, C++, Swift, Kotlin, Lua, and SQL. ERB highlights template HTML outside ERB tags and Ruby inside `<% ... %>` tags. Unknown file types render as plain text.
|
|
97
|
-
-
|
|
98
|
+
- Current-buffer word completion. After a partial word, Tab completes from words elsewhere in the active buffer; repeated Tab presses cycle nearby matches. Completion is case-sensitive and recognizes letters, numbers, and underscores. No project files or external sources are searched.
|
|
99
|
+
- Auto-indent, enabled by default. New lines inherit indentation. When word completion does not apply, Tab jumps to the expected indentation or the next indentation stop. Shift+Tab moves indentation back, obvious closing tokens are re-indented, and Backspace in leading whitespace removes one indentation unit when possible. ERB recognizes common inline Ruby control tags and HTML opening tags when calculating the next indentation. For Ruby, Crystal, Elixir, Julia, Lua, Makefiles, and shell scripts, Enter after a block opener inserts the matching closing keyword; Ctrl+Enter also works from the middle of the line in terminals that report modified Enter keys.
|
|
98
100
|
- Undo and redo, with up to 100 history entries per buffer.
|
|
99
101
|
- Incremental search forward and backward.
|
|
100
102
|
- Selection, copy, cut, and paste. Copy and cut also write to the terminal clipboard through OSC 52 when the terminal supports it.
|
|
101
103
|
- A line-number gutter and a status line that shows the current mode and prompts.
|
|
102
104
|
- Soft-wrap, enabled by default so long lines wrap within the editor width instead of scrolling sideways. Disable it with `editor.soft_wrap: false`.
|
|
105
|
+
- Vibe `:prompt <instruction>` and Modern `Ctrl+.` prompt lines send the complete current buffer and document metadata to a dedicated, transient editor agent. The agent can replace the in-memory buffer through an explicit editor tool; it does not save files automatically.
|
|
106
|
+
- Editor prompts and their tool activity are not added to the normal chat transcript or session history.
|
|
107
|
+
- The editor remains visible and locked for editing while the agent runs. Its status line displays progress and a spinner; `Ctrl+C` cancels the request.
|
|
103
108
|
|
|
104
109
|
## Choosing an editor mode
|
|
105
110
|
|
|
@@ -122,12 +127,16 @@ You can also configure it in `config.json`:
|
|
|
122
127
|
```json
|
|
123
128
|
{
|
|
124
129
|
"editor": {
|
|
125
|
-
"mode": "modern"
|
|
130
|
+
"mode": "modern",
|
|
131
|
+
"agent": {
|
|
132
|
+
"model": "gpt-5.5",
|
|
133
|
+
"reasoning_effort": "medium"
|
|
134
|
+
}
|
|
126
135
|
}
|
|
127
136
|
}
|
|
128
137
|
```
|
|
129
138
|
|
|
130
|
-
`mode` can be `modern`, `emacs`, or `vibe`. The old `default` value is still accepted as an alias for `modern`.
|
|
139
|
+
`mode` can be `modern`, `emacs`, or `vibe`. The optional `editor.agent.model` and `editor.agent.reasoning_effort` settings configure the dedicated Vibe editor agent. They use the active tab's provider. When either value is omitted, it falls back to the active tab's setting and then the client default. Editor-agent turns use a dedicated system prompt and are not persisted in the active tab transcript. The old `default` value is still accepted as an alias for `modern`.
|
|
131
140
|
|
|
132
141
|
To disable auto-indent or auto-close pairs:
|
|
133
142
|
|
|
@@ -156,6 +165,7 @@ Modern mode is the default and is the easiest place to start. It uses common ter
|
|
|
156
165
|
| --------------------- | ------------------------------------------------- |
|
|
157
166
|
| `Ctrl+S` | Save |
|
|
158
167
|
| `Ctrl+Q` | Quit; press again to discard unsaved changes |
|
|
168
|
+
| `Ctrl+.` | Open the editor-agent prompt line |
|
|
159
169
|
| `/` | Search forward |
|
|
160
170
|
| `?` | Search backward |
|
|
161
171
|
| `Ctrl+C` | Copy selection, or cancel search |
|
|
@@ -192,7 +202,7 @@ Modern mode is the default and is the easiest place to start. It uses common ter
|
|
|
192
202
|
| `Home` / `End` | Move to start / end of line |
|
|
193
203
|
| `PageUp` / `PageDown` | Scroll |
|
|
194
204
|
| `Enter` | Insert newline, or confirm search |
|
|
195
|
-
| `Tab` |
|
|
205
|
+
| `Tab` | Complete a buffer word, or smart-indent when no match exists |
|
|
196
206
|
| `Shift+Tab` | Move indentation back by one stop |
|
|
197
207
|
| `Backspace` | Delete before cursor |
|
|
198
208
|
| `Delete` | Delete character at cursor |
|
|
@@ -233,7 +243,7 @@ Emacs mode is for users who prefer classic Emacs-style non-modal editing. Save a
|
|
|
233
243
|
| `Home` / `End` | Move to start / end of line |
|
|
234
244
|
| `PageUp` / `PageDown` | Scroll |
|
|
235
245
|
| `Enter` | Insert newline, or confirm search |
|
|
236
|
-
| `Tab` |
|
|
246
|
+
| `Tab` | Complete a buffer word, or smart-indent when no match exists |
|
|
237
247
|
| `Shift+Tab` | Move indentation back by one stop |
|
|
238
248
|
| `Backspace` | Delete before cursor |
|
|
239
249
|
| `Delete` / `C-d` | Delete character at cursor |
|
|
@@ -370,7 +380,7 @@ Vibe insert mode also supports readline-style shortcuts for efficient editing wi
|
|
|
370
380
|
| ---------------- | ---------------------------------------- |
|
|
371
381
|
| type text | Insert characters |
|
|
372
382
|
| `Enter` | Insert newline |
|
|
373
|
-
| `Tab` |
|
|
383
|
+
| `Tab` | Complete a buffer word, or smart-indent when no match exists |
|
|
374
384
|
| `Shift+Tab` | Move indentation back by one stop |
|
|
375
385
|
| `Backspace` | Delete before cursor |
|
|
376
386
|
| `Delete` | Delete character at cursor |
|
data/doc/files.md
CHANGED
|
@@ -24,7 +24,7 @@ Inside a Git repository, `/files` uses Git's project view:
|
|
|
24
24
|
git ls-files --cached --others --exclude-standard
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
That means tracked files and normal untracked files appear, while ignored files stay out of the list.
|
|
27
|
+
That means tracked files and normal untracked files appear by default, while ignored files stay out of the list. Press `i` in the tree view to show or hide Git-ignored files; Kward remembers this choice for the workspace.
|
|
28
28
|
|
|
29
29
|
Outside Git, Kward scans the workspace directory and skips common noisy directories such as `.git`, `.yardoc`, `_yardoc`, `node_modules`, `rdoc`, `tmp`, and `vendor/bundle`.
|
|
30
30
|
|
|
@@ -39,6 +39,7 @@ Outside Git, Kward scans the workspace directory and skips common noisy director
|
|
|
39
39
|
| `Tab` | Start or stop search |
|
|
40
40
|
| `/` | Start search |
|
|
41
41
|
| `Backspace` | Delete the last search character |
|
|
42
|
+
| `i` | Show or hide Git-ignored files |
|
|
42
43
|
| `Esc` | Leave search; press again to close the browser |
|
|
43
44
|
| `Q` | Close an image preview |
|
|
44
45
|
| `+` / `-` | Zoom an image preview in / out |
|
|
@@ -90,7 +91,7 @@ See [Integrated editor](editor.md) for editor modes, save/quit keys, search, sel
|
|
|
90
91
|
|
|
91
92
|
## Remembered state
|
|
92
93
|
|
|
93
|
-
Kward remembers the expanded folders
|
|
94
|
+
Kward remembers the expanded folders, selected path, and Git-ignored file visibility for each workspace. The next time you open `/files` in the same project, it restores the browser close to where you left it.
|
|
94
95
|
|
|
95
96
|
Search itself is temporary. Closing search returns to the normal tree, and closing the browser leaves your chat session intact.
|
|
96
97
|
|
|
@@ -103,4 +104,4 @@ Image previews are read-only and replace the file-list overlay while leaving the
|
|
|
103
104
|
- `/files` is only available in the interactive prompt.
|
|
104
105
|
- It opens files inside the current workspace.
|
|
105
106
|
- It is a focused project browser, not a full file manager: it does not rename, move, copy, or delete files.
|
|
106
|
-
- Ignored Git files are
|
|
107
|
+
- Ignored Git files are hidden by default when Git can provide the file list; press `i` in the tree view to show them.
|
data/doc/permissions.md
CHANGED
|
@@ -176,6 +176,7 @@ The policy runs before Kward dispatches a model-requested tool. It does not cons
|
|
|
176
176
|
- a permitted shell command can access files, processes, credentials, and network services available to your user account;
|
|
177
177
|
- command-text rules are useful review controls, not a reliable way to enforce network destinations or all subprocess behavior;
|
|
178
178
|
- direct commands that you type yourself—`!command`, `/capture`, `/shell`, and `/pty`—are treated as your actions and are outside this first policy scope;
|
|
179
|
+
- commands run by the transient `?` shell assistant go through the normal permission and hook checks but deliberately use the user-owned `/shell` process, so the command sandbox cannot contain them;
|
|
179
180
|
- plugins, hooks, and MCP servers are trusted local extensions with their own process access.
|
|
180
181
|
|
|
181
182
|
For sensitive work, use a restricted operating-system account, container, virtual machine, or disposable checkout. [Command sandboxing](sandboxing.md) is a separate, opt-in operating-system boundary for model-requested `run_shell_command` workers. It can add filesystem and child-network restrictions, but does not cover Kward's host process, extensions, or direct interactive commands.
|
data/doc/releasing.md
CHANGED
|
@@ -60,13 +60,21 @@ If preparation fails before the commit, the command restores the version, lockfi
|
|
|
60
60
|
A pushed `v*` tag starts `.github/workflows/release.yml`. The workflow:
|
|
61
61
|
|
|
62
62
|
1. Checks that the tag, gem version, and changelog heading agree.
|
|
63
|
-
2.
|
|
63
|
+
2. Installs and enables Bubblewrap, then runs the full test suite and generated-documentation checks against Ruby 3.4 using the same Linux sandbox setup as normal CI.
|
|
64
64
|
3. Builds the gem and verifies its packaged files.
|
|
65
65
|
4. Publishes through RubyGems trusted publishing.
|
|
66
|
-
5.
|
|
67
|
-
6. Creates `Kward VERSION` as a GitHub Release using that version's changelog section and attaches the verified
|
|
66
|
+
5. Downloads the canonical published gem from RubyGems.org, waiting for propagation when necessary, and verifies its checksum against the RubyGems API.
|
|
67
|
+
6. Creates `Kward VERSION` as a GitHub Release using that version's changelog section and attaches the verified RubyGems artifact.
|
|
68
68
|
|
|
69
|
-
The publishing job uses the protected `release` environment. If RubyGems.org already has the version after a partially completed workflow, a rerun
|
|
69
|
+
The publishing job uses the protected `release` environment. If RubyGems.org already has the version after a partially completed workflow, a rerun downloads and verifies the canonical published gem before continuing. This also accommodates trusted-publishing attestations that can change the published gem bytes. For an existing GitHub Release, the workflow downloads and compares the gem, uploads it when missing, and publishes an unfinished draft. This makes normal workflow reruns safe without silently replacing mismatched artifacts.
|
|
70
|
+
|
|
71
|
+
If the workflow itself needs a fix after a tag has already been pushed, commit and push the fix to `main`, then recover the existing tag with the updated workflow:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
gh workflow run Release --ref main -f tag=v0.82.0
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Manual recovery still checks out and verifies the tagged source before publishing. The `release` environment permits automatic version-tag runs and manual recovery runs from `main` only.
|
|
70
78
|
|
|
71
79
|
Follow the run from the repository's **Actions → Release** page. Installation can be checked after publication with:
|
|
72
80
|
|
data/doc/rpc.md
CHANGED
|
@@ -80,11 +80,11 @@ Read `capabilities` at runtime instead of assuming every feature is available. I
|
|
|
80
80
|
- `mcp`: local stdio MCP server support through the shared `mcpServers` config. RPC exposes MCP tools to turns and advertises discovery with `methods: ["tools/list", "mcp/status"]`, `toolMetadata: true`, and `serverStatus: true`. It does not support MCP resources, prompts, sampling, or Streamable HTTP.
|
|
81
81
|
- `startupResources`: supported startup resource listing for context, skills, prompts, and plugins.
|
|
82
82
|
- `extensionUi`: question bridge support via `ui/question` and `ui/answerQuestion`, plus plugin footer updates via `ui/footer`; other UI primitives are explicitly unsupported.
|
|
83
|
-
- `composer`: composer-only UI features. Interactive session diff totals are explicitly unsupported over RPC (`composer.sessionDiff.supported: false`) because RPC clients already receive per-tool diff results and no live composer status payload is exposed. Clipboard copy is also unsupported over RPC (`composer.copy.supported: false`) because UI clients own clipboard access.
|
|
83
|
+
- `composer`: composer-only UI features. Interactive session diff totals are explicitly unsupported over RPC (`composer.sessionDiff.supported: false`) because RPC clients already receive per-tool diff results and no live composer status payload is exposed. Clipboard copy is also unsupported over RPC (`composer.copy.supported: false`) because UI clients own clipboard access. Vibe editor prompts are unsupported over RPC (`composer.editorPrompt.supported: false`) because RPC has no live integrated editor buffer.
|
|
84
84
|
- `security`: trusted-local behavior and optional per-turn tool approval. By default, RPC turns have no workspace mutation guard or tool approval, so shell commands and file changes can run. Clients can inspect file-tool guardrails through `capabilities.events.tools.workspaceGuardrails` and `runtime/state.workspaceGuardrailsEnabled`. `security.sandbox` reports the command sandbox mode, enforcement backend, and filesystem and network capabilities; session pinning and one-time elevation are unsupported. See [Command sandboxing](sandboxing.md) for the boundary and its limits.
|
|
85
85
|
- `export`: supported transcript export formats. Currently `markdown` and `html`; default is `markdown`.
|
|
86
86
|
- `starterPack`: explicitly unsupported (`supported: false`, reason `cliOnlyInstallCommand`). Use `kward init` from the shell.
|
|
87
|
-
- `shell`: explicitly unsupported (`supported: false`, reason `interactiveTuiOnly`) because `/shell`, `!command`, `/capture`, and PTY handoff require the local TUI. Model-requested `run_shell_command` tools remain bounded, captured, and noninteractive over RPC.
|
|
87
|
+
- `shell`: explicitly unsupported (`supported: false`, reason `interactiveTuiOnly`) because `/shell`, its transient `?` shell assistant, `!command`, `/capture`, and PTY handoff require the local TUI. Model-requested `run_shell_command` tools remain bounded, captured, and noninteractive over RPC.
|
|
88
88
|
- `logging`: local redacted telemetry, its directory and enabled categories, `logging/stats` and `logging/tokenCsv`, bucketed `usageCsv` support, JSONL storage, and 10 MB rotation with manual retention. Logs contain redacted metadata only. Configuration uses the `logging` key and `KWARD_LOGGING` environment prefix.
|
|
89
89
|
|
|
90
90
|
### `shutdown`
|
data/doc/sandboxing.md
CHANGED
|
@@ -106,12 +106,16 @@ this interface.
|
|
|
106
106
|
## Boundaries and limits
|
|
107
107
|
|
|
108
108
|
The current implementation protects **model-requested command workers only**.
|
|
109
|
+
The transient `?` shell assistant is intentionally not one of those workers: its
|
|
110
|
+
`run_shell_command` calls use the active user-owned `/shell` process so shell
|
|
111
|
+
state can persist.
|
|
112
|
+
|
|
109
113
|
It does not sandbox:
|
|
110
114
|
|
|
111
115
|
- the Kward Ruby host process;
|
|
112
116
|
- model-provider, search-provider, or RPC traffic;
|
|
113
117
|
- trusted Ruby plugins;
|
|
114
|
-
- MCP servers, lifecycle hooks, `/shell`, `!command`, `/capture`, or `/pty`.
|
|
118
|
+
- MCP servers, lifecycle hooks, `/shell`, `?` shell-agent commands, `!command`, `/capture`, or `/pty`.
|
|
115
119
|
|
|
116
120
|
Sandboxed command workers receive a minimal environment: Kward preserves only
|
|
117
121
|
basic terminal, locale, and path variables, then supplies a private `HOME` and
|
data/doc/security.md
CHANGED
|
@@ -57,7 +57,7 @@ Kward's built-in file tools normally resolve paths inside the active workspace.
|
|
|
57
57
|
These protections reduce accidental edits. They do not contain the whole process:
|
|
58
58
|
|
|
59
59
|
- With `sandbox.mode: off` (the default), `run_shell_command`, `!command`, `/capture`, `/shell`, and `/pty` run with your user permissions.
|
|
60
|
-
- A non-off [command sandbox](sandboxing.md) restricts only model-requested `run_shell_command` workers and their descendants. It does not cover `!command`, `/capture`, `/shell`, or `/pty
|
|
60
|
+
- A non-off [command sandbox](sandboxing.md) restricts only model-requested `run_shell_command` workers and their descendants. It does not cover `!command`, `/capture`, `/shell`, or `/pty`, including commands that the transient `?` shell assistant runs through the user's persistent `/shell` process.
|
|
61
61
|
- External `/shell` commands, `!command`, and `/pty` receive an interactive PTY. Kward forwards a conservative set of line-oriented controls into the inline region, then grants full-terminal passthrough when a child emits screen-oriented or unknown controls. Full passthrough bypasses transcript control-sequence sanitization, so run only commands you trust with terminal access. `capture <command>` and `/capture <command>` sanitize their captured output.
|
|
62
62
|
- Plugins, command hooks, and MCP servers are local processes with the same general operating-system access.
|
|
63
63
|
- Read-before-edit applies to Kward's file tools, not to arbitrary shell commands or extension code.
|
data/doc/shell.md
CHANGED
|
@@ -4,6 +4,7 @@ Kward lets you run your own shell commands without leaving the interactive TUI.
|
|
|
4
4
|
|
|
5
5
|
- **For one quick command, use `!command`.** It runs from the active workspace and returns you to the normal composer when it finishes.
|
|
6
6
|
- **For a longer stretch of shell work, use `/shell`.** It keeps its directory, environment, aliases, and history between commands.
|
|
7
|
+
- **To ask Kward for help from inside `/shell`, prefix the request with `?`.** It can inspect the latest shell output, run an explicitly requested state change, or prepare a command in the shell prompt for your confirmation.
|
|
7
8
|
- **For bounded output in the transcript view, use `/capture <command>`.** Inside `/shell`, use `capture <command>` for the same kind of readable output while keeping the shell's current state.
|
|
8
9
|
|
|
9
10
|
Ordinary `!command` input and external commands inside `/shell` receive an interactive PTY. Pagers, Vim, SSH, REPLs, password prompts, and other interactive tools therefore work without a `pty` prefix.
|
|
@@ -20,7 +21,7 @@ Prefix a command with `!` in the normal composer:
|
|
|
20
21
|
|
|
21
22
|
The command runs from the active workspace root and begins in an inline PTY region above a frozen composer. Line-oriented output, single-line carriage-return progress, and synchronized-output update brackets scroll the transcript area naturally while keyboard input belongs to the child process. If the child emits alternate-screen, clear-screen, absolute cursor, or unknown terminal controls, Kward conservatively hides the composer and switches permanently to full-terminal passthrough for the rest of that command. Pagers and full-screen applications therefore retain the complete terminal without relying on a command-name allowlist.
|
|
22
23
|
|
|
23
|
-
When an inline command exits without reading input, safe output is mirrored into the transient transcript view so a repaint cannot hide it. Carriage-return and horizontal-cursor progress redraws are reduced to their final visible lines, while an unterminated synchronized-output update is closed before Kward redraws. If the child reads input, Kward retains only output captured before the first forwarded input byte; this prevents echoed passwords, OTPs, or other input from entering tab state.
|
|
24
|
+
When an inline command exits without reading input, safe output is mirrored into the transient transcript view so a repaint cannot hide it. Carriage-return and horizontal-cursor progress redraws are reduced to their final visible lines, while an unterminated synchronized-output update is closed before Kward redraws. If the child reads input, Kward retains only output captured before the first forwarded input byte; this prevents echoed passwords, OTPs, or other input from entering tab state. Output from one-off commands is never added to the AI conversation or sent to the model.
|
|
24
25
|
|
|
25
26
|
Shell output can leave transient text in the transcript area. **After the command finishes, press Ctrl+L to redraw the durable conversation and clear that transient `!command` output.** While an interactive command is still running, the composer remains frozen and keyboard input—including Ctrl+L and Kward's tab shortcuts—belongs to the child process.
|
|
26
27
|
|
|
@@ -90,6 +91,29 @@ Leave shell mode with `exit`, `logout`, or Ctrl+D on an empty prompt.
|
|
|
90
91
|
|
|
91
92
|
`cd` changes only the embedded shell's directory. It does not change Kward's workspace root or the directory used by the model's other tools.
|
|
92
93
|
|
|
94
|
+
## Ask the shell agent
|
|
95
|
+
|
|
96
|
+
While `/shell` is active, start a submitted line with `?` to ask the transient shell assistant:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
? why did the last command fail?
|
|
100
|
+
? show me which process is listening on port 3000
|
|
101
|
+
? prepare a command to find Ruby files changed today
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The assistant receives the current shell directory, the last command, its exit status, and bounded output from that command. Output is sent to the model only because you explicitly asked with `?`; it is sanitized and bounded before being included, and shell-agent turns are not added to the normal session history.
|
|
105
|
+
|
|
106
|
+
If you explicitly ask the assistant to change shell state, it can use the active shell session:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
? cd into test
|
|
110
|
+
? set RAILS_ENV to test
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For a suggestion or prepared command, the assistant uses `prepare_shell_command`. The command is placed in the shell composer but is not run until you press `Enter`. Running a command directly and preparing one are deliberately separate actions.
|
|
114
|
+
|
|
115
|
+
The shell assistant cannot safely run commands that require terminal input. Ask it to prepare those commands instead. The local `/shell` session keeps one interactive shell process alive, so directory changes, variables, functions, aliases, and other shell state persist between commands. The one-off `!command` and `/capture` workflows remain separate. SSH remains available through the normal interactive PTY handoff, but shell-agent prompting resumes after that SSH session exits.
|
|
116
|
+
|
|
93
117
|
## Interactive and captured commands
|
|
94
118
|
|
|
95
119
|
External commands inside `/shell` are interactive by default:
|
|
@@ -101,7 +125,7 @@ ruby
|
|
|
101
125
|
ssh example.com
|
|
102
126
|
```
|
|
103
127
|
|
|
104
|
-
Kward gives each command the terminal, forwards keyboard input, and restores the shell prompt when the command exits. It prints the submitted command but no PTY start message or exit-status summary. The line-oriented Git commands `git fetch`, `git ls-remote`, `git push`, `git remote`, and `git status` keep the shell prompt visible as a frozen display. Safe, line-oriented output from commands that did not read keyboard input is kept in the transient transcript view; full-screen and genuinely interactive output stays terminal-owned.
|
|
128
|
+
Kward gives each command the terminal, forwards keyboard input, and restores the shell prompt when the command exits. Interactive commands inherit your normal pager configuration, so commands such as `git log` can open `less` in full-screen mode. Kward suppresses Git paging only for noninteractive shell-agent and `capture` executions. It prints the submitted command but no PTY start message or exit-status summary. The line-oriented Git commands `git fetch`, `git ls-remote`, `git push`, `git remote`, and `git status` keep the shell prompt visible as a frozen display. Safe, line-oriented output from commands that did not read keyboard input is kept in the transient transcript view; full-screen and genuinely interactive output stays terminal-owned.
|
|
105
129
|
|
|
106
130
|
Use `capture` inside `/shell` when you want ordinary, readable output in Kward's transcript area instead of direct terminal control:
|
|
107
131
|
|
|
@@ -141,7 +165,7 @@ Each Kward tab owns its `/shell` state. Switching away and back restores that ta
|
|
|
141
165
|
|
|
142
166
|
Shell commands use a separate, workspace-scoped history rather than the normal chat-prompt history. Configure its size with `history_limit` in `ekwsh.yml`.
|
|
143
167
|
|
|
144
|
-
Kward's tab shortcuts work at the shell prompt and while a captured command is running. During an interactive command, the child owns every key; exit or interrupt it before switching Kward tabs.
|
|
168
|
+
Kward's tab shortcuts work at the shell prompt and while a captured command is running. During an interactive command, the child owns every key; exit or interrupt it before switching Kward tabs. Bounded output from shell-agent `?` turns is also retained in the tab's transient runtime view, so it is restored when you switch away and back without being added to session history. Ctrl+L clears this transient shell and shell-agent output.
|
|
145
169
|
|
|
146
170
|
## Completion
|
|
147
171
|
|
|
@@ -179,7 +203,7 @@ When several candidates match, repeated Tab presses cycle through them and wrap
|
|
|
179
203
|
|
|
180
204
|
## Built-ins
|
|
181
205
|
|
|
182
|
-
|
|
206
|
+
The persistent `/shell` process handles these commands in-session so their state can persist:
|
|
183
207
|
|
|
184
208
|
| Built-in | What it does |
|
|
185
209
|
| --- | --- |
|
|
@@ -232,12 +256,12 @@ aliases:
|
|
|
232
256
|
|
|
233
257
|
| Setting | Default | What it does |
|
|
234
258
|
| --- | --- | --- |
|
|
235
|
-
| `shell` | `/bin/sh` |
|
|
236
|
-
| `timeout_seconds` | `300` | Maximum runtime for one captured command. |
|
|
237
|
-
| `max_output_bytes` | `1048576` | Maximum output retained for one captured command. |
|
|
259
|
+
| `shell` | `/bin/sh` | Absolute executable path for the persistent `/shell` process and interactive shell commands. |
|
|
260
|
+
| `timeout_seconds` | `300` | Maximum runtime for one captured or shell-agent command. |
|
|
261
|
+
| `max_output_bytes` | `1048576` | Maximum output retained for one captured or shell-agent command. |
|
|
238
262
|
| `history_limit` | `1000` | Maximum shell-history entries per workspace. |
|
|
239
263
|
|
|
240
|
-
Invalid or relative `shell` paths fall back to `/bin/sh`. These timeout and output limits apply
|
|
264
|
+
Invalid or relative `shell` paths fall back to `/bin/sh`. These timeout and output limits apply to `capture` inside `/shell` and shell-agent commands, not user-owned interactive commands or the separate `/capture` slash command.
|
|
241
265
|
|
|
242
266
|
### Environment
|
|
243
267
|
|
|
@@ -253,7 +277,7 @@ TERM=xterm-256color # only when TERM is missing or dumb
|
|
|
253
277
|
|
|
254
278
|
It does not force color. Set `FORCE_COLOR`, `CLICOLOR_FORCE`, or a command-specific option such as `--color=always` when needed.
|
|
255
279
|
|
|
256
|
-
When rbenv is available, Kward adds its shims and bin directories to `PATH` and supplies `RBENV_ROOT` if it was missing
|
|
280
|
+
When rbenv is available, Kward adds its shims and bin directories to `PATH` and supplies `RBENV_ROOT` if it was missing before starting `/shell`. The configured interactive shell may also load its normal startup files.
|
|
257
281
|
|
|
258
282
|
### Aliases
|
|
259
283
|
|
|
@@ -281,17 +305,17 @@ Aliases are intentionally simple: they do not expand recursively and are not she
|
|
|
281
305
|
|
|
282
306
|
## Terminal output and safety
|
|
283
307
|
|
|
284
|
-
Interactive commands write directly to your terminal so full-screen tools can work. When a command does not read keyboard input and emits only line-oriented text plus safe color sequences, Kward mirrors that output into the transient transcript view after the command exits. Other interactive output is not sanitized and may contain terminal control sequences, so run only commands you trust with terminal access.
|
|
308
|
+
Interactive commands write directly to your terminal so full-screen tools can work. When a command does not read keyboard input and emits only line-oriented text plus safe color sequences, Kward mirrors that output into the transient transcript view after the command exits. Other interactive output is not sanitized and may contain terminal control sequences, so run only commands you trust with terminal access. Safe bounded output is included in a shell-agent request only when you explicitly use `?`; it is never sent to the model for ordinary shell commands.
|
|
285
309
|
|
|
286
310
|
Commands run with `capture` inside `/shell` preserve safe ANSI color and style sequences while removing cursor movement, clear-screen controls, title changes, alternate-screen controls, and similar sequences that could damage the TUI transcript.
|
|
287
311
|
|
|
288
312
|
## Limitations
|
|
289
313
|
|
|
290
|
-
|
|
314
|
+
The local `/shell` session is persistent, but it is not a complete terminal emulator or a remote-shell protocol:
|
|
291
315
|
|
|
292
|
-
-
|
|
293
|
-
-
|
|
294
|
-
-
|
|
295
|
-
- there is no login-shell readline integration,
|
|
316
|
+
- the one-off `!command` and `/capture` workflows do not share `/shell` state,
|
|
317
|
+
- shell state is held by the live process and is not serialized across Kward restarts,
|
|
318
|
+
- a stopped or unresponsive command can still require Ctrl+C or shell-session cleanup,
|
|
296
319
|
- full-screen terminal state is not retained after an interactive command exits,
|
|
297
|
-
-
|
|
320
|
+
- while an interactive SSH session owns the terminal, Kward cannot safely intercept `?` or provide remote cwd/completion context; shell-agent prompting resumes after SSH exits,
|
|
321
|
+
- safe line-oriented output may remain in the transient TUI transcript; only bounded safe output from an explicit `?` request enters the transient shell-agent context and none of it is added to the normal session history.
|
data/doc/tabs.md
CHANGED
|
@@ -39,6 +39,8 @@ A normal session tab can be activated in a linked Git worktree after you have re
|
|
|
39
39
|
|
|
40
40
|
```text
|
|
41
41
|
/tab worktree
|
|
42
|
+
# or
|
|
43
|
+
/worktree
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
When enabled, Kward keeps the same tab and transcript but rebuilds its agent against a new worktree. The tab label includes the worktree branch. The worktree is created from `HEAD`, so Kward warns when the original workspace is dirty and leaves those existing changes in the original checkout; it does not copy them automatically. `/tab worktree activate` is an explicit alias for the same action.
|
|
@@ -98,6 +100,7 @@ Tabs keep the conversations separate, so context from one tab does not automatic
|
|
|
98
100
|
| `/tab worktree merge` | Merge the current worktree branch into the branch checked out in its original workspace |
|
|
99
101
|
| `/tab worktree merge abort` | Abort a conflicted worktree merge in the original workspace |
|
|
100
102
|
| `/tab worktree remove` | Remove a clean linked worktree and keep its branch |
|
|
103
|
+
| `/worktree …` | Alias for `/tab worktree …` on the active tab |
|
|
101
104
|
| `/tab move left` | Move the current tab one slot left |
|
|
102
105
|
| `/tab move right` | Move the current tab one slot right |
|
|
103
106
|
| `/tab move <number>` | Move the current tab to a numbered position |
|
data/doc/usage.md
CHANGED
|
@@ -78,7 +78,7 @@ For several commands, enter the embedded Kward shell:
|
|
|
78
78
|
/shell
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
`/shell` opens `ekwsh`, a Kward-native command mode
|
|
81
|
+
`/shell` opens `ekwsh`, a Kward-native command mode with one persistent local shell process. It preserves state such as the current directory, environment variables, functions, and aliases between commands. Prefix a line with `?` inside `/shell` to ask a transient shell assistant about the latest output, execute an explicit state change, or prepare a command without running it. External commands receive an interactive PTY by default, so `git log`, `less`, Vim, SSH, and REPLs work without a prefix. Use `capture <command>` inside `/shell` or `/capture <command>` from the normal composer for bounded, transcript-friendly output. See [Embedded shell](shell.md) for built-ins, completion, configuration, ANSI handling, PTY passthrough, and limitations.
|
|
82
82
|
|
|
83
83
|
## Shell commands
|
|
84
84
|
|
|
@@ -123,7 +123,7 @@ Slash commands run local actions in the current session. Most do not send a prom
|
|
|
123
123
|
| `/git` | review uncommitted changes, stage files, and commit. |
|
|
124
124
|
| `/diff` | open the file changes recorded in the current session. |
|
|
125
125
|
| `/files` | browse project files in a nested tree and open them in the editor. |
|
|
126
|
-
| `/shell` | run stateful workspace commands with interactive PTY support
|
|
126
|
+
| `/shell` | run stateful workspace commands with interactive PTY support and ask the shell agent with `?`. |
|
|
127
127
|
| `/capture <command>` | run a bounded one-shot command and retain its output in the transcript. |
|
|
128
128
|
| `/pty <command>` | explicitly hand the terminal to an interactive command; retained for compatibility with existing workflows. |
|
|
129
129
|
| `/settings` | configure models, accounts, memory, interface, tools, context, personalization, and logging. |
|
|
@@ -143,6 +143,7 @@ Slash commands run local actions in the current session. Most do not send a prom
|
|
|
143
143
|
| `/tab worktree merge` | merge a clean worktree branch into the branch checked out in its original workspace. |
|
|
144
144
|
| `/tab worktree merge abort` | abort a conflicted worktree merge in the original workspace. |
|
|
145
145
|
| `/tab worktree remove` | remove a clean linked worktree while keeping its branch. |
|
|
146
|
+
| `/worktree …` | alias for `/tab worktree …` on the active tab. |
|
|
146
147
|
| `/session` | open the saved sessions picker or continue a previous session by path. |
|
|
147
148
|
| `/resume` | alias for `/session`. |
|
|
148
149
|
| `/session name <name>` | name or clear the current session. |
|
data/lib/kward/agent.rb
CHANGED
|
@@ -84,6 +84,7 @@ module Kward
|
|
|
84
84
|
end
|
|
85
85
|
loop do
|
|
86
86
|
cancellation&.raise_if_cancelled!
|
|
87
|
+
auto_compact_if_needed
|
|
87
88
|
begin
|
|
88
89
|
message = chat(on_reasoning_delta: on_reasoning_delta, on_retry: on_retry, cancellation: cancellation, steering: steering, options: options, tool_registry: tool_registry) do |event|
|
|
89
90
|
yield event if block_given?
|
|
@@ -17,7 +17,7 @@ module Kward
|
|
|
17
17
|
DEFAULT_PORT = 53_692
|
|
18
18
|
CALLBACK_PATH = "/callback"
|
|
19
19
|
DEFAULT_CLIENT_ID = Base64.decode64("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl")
|
|
20
|
-
SCOPE = "
|
|
20
|
+
SCOPE = "user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload"
|
|
21
21
|
|
|
22
22
|
attr_reader :auth_path
|
|
23
23
|
|
|
@@ -60,7 +60,7 @@ module Kward
|
|
|
60
60
|
end
|
|
61
61
|
raise "Missing authorization code" if code.to_s.empty?
|
|
62
62
|
|
|
63
|
-
complete_login_flow(code: code, redirect_uri: redirect_uri, code_verifier: pkce[:verifier])
|
|
63
|
+
complete_login_flow(code: code, redirect_uri: redirect_uri, code_verifier: pkce[:verifier], state: state)
|
|
64
64
|
auth_path
|
|
65
65
|
ensure
|
|
66
66
|
server&.close unless server&.closed?
|
|
@@ -68,7 +68,6 @@ module Kward
|
|
|
68
68
|
|
|
69
69
|
def authorization_url(redirect_uri:, code_challenge:, state:)
|
|
70
70
|
query = URI.encode_www_form(
|
|
71
|
-
code: "true",
|
|
72
71
|
client_id: client_id,
|
|
73
72
|
response_type: "code",
|
|
74
73
|
redirect_uri: redirect_uri,
|
|
@@ -98,8 +97,8 @@ module Kward
|
|
|
98
97
|
wait_for_callback(server, expected_state: expected_state, timeout_seconds: timeout_seconds)
|
|
99
98
|
end
|
|
100
99
|
|
|
101
|
-
def complete_login_flow(code:, redirect_uri:, code_verifier:)
|
|
102
|
-
tokens = exchange_code_for_tokens(code: code, redirect_uri: redirect_uri, code_verifier: code_verifier)
|
|
100
|
+
def complete_login_flow(code:, redirect_uri:, code_verifier:, state:)
|
|
101
|
+
tokens = exchange_code_for_tokens(code: code, redirect_uri: redirect_uri, code_verifier: code_verifier, state: state)
|
|
103
102
|
save_auth(tokens: tokens)
|
|
104
103
|
tokens
|
|
105
104
|
end
|
|
@@ -192,13 +191,14 @@ module Kward
|
|
|
192
191
|
oauth_callback_server(port_env: "KWARD_ANTHROPIC_OAUTH_PORT", default_port: DEFAULT_PORT)
|
|
193
192
|
end
|
|
194
193
|
|
|
195
|
-
def exchange_code_for_tokens(code:, redirect_uri:, code_verifier:)
|
|
194
|
+
def exchange_code_for_tokens(code:, redirect_uri:, code_verifier:, state:)
|
|
196
195
|
response = post_json(TOKEN_URL,
|
|
197
196
|
grant_type: "authorization_code",
|
|
198
197
|
client_id: client_id,
|
|
199
198
|
code: code,
|
|
200
199
|
redirect_uri: redirect_uri,
|
|
201
|
-
code_verifier: code_verifier
|
|
200
|
+
code_verifier: code_verifier,
|
|
201
|
+
state: state)
|
|
202
202
|
parse_successful_json(response, "Anthropic OAuth token exchange")
|
|
203
203
|
end
|
|
204
204
|
|