kward 0.84.0 → 0.85.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/Gemfile.lock +2 -2
- data/README.md +2 -2
- data/doc/agent-tools.md +13 -1
- data/doc/api.md +17 -2
- data/doc/composer.md +1 -1
- data/doc/configuration.md +27 -4
- data/doc/extensibility.md +2 -1
- data/doc/git.md +3 -1
- data/doc/pan.md +6 -0
- data/doc/permissions.md +4 -4
- data/doc/plugins.md +464 -15
- data/doc/rpc.md +154 -16
- data/doc/sandboxing.md +11 -5
- data/doc/security.md +7 -1
- data/doc/session-management.md +5 -4
- data/doc/tabs.md +6 -2
- data/doc/transports.md +15 -0
- data/doc/usage.md +4 -1
- data/doc/workspace-tools.md +9 -0
- data/examples/plugins/space_invaders.rb +1 -1
- data/examples/plugins/stardate_footer.rb +2 -2
- data/examples/plugins/telegram/plugin.rb +1 -1
- data/lib/kward/agent.rb +24 -11
- data/lib/kward/cli/compaction.rb +9 -3
- data/lib/kward/cli/plugins.rb +81 -12
- data/lib/kward/cli/prompt_interface.rb +25 -5
- data/lib/kward/cli/rendering.rb +3 -0
- data/lib/kward/cli/runtime_helpers.rb +121 -27
- data/lib/kward/cli/sessions.rb +9 -5
- data/lib/kward/cli/settings/menus.rb +745 -0
- data/lib/kward/cli/settings/model.rb +327 -0
- data/lib/kward/cli/settings.rb +6 -1055
- data/lib/kward/cli/slash_commands.rb +45 -4
- data/lib/kward/cli/tabs.rb +167 -27
- data/lib/kward/{cli_transcript_formatter.rb → cli/transcript_formatter.rb} +3 -3
- data/lib/kward/cli/worktrees.rb +65 -2
- data/lib/kward/cli.rb +26 -24
- data/lib/kward/compactor.rb +18 -7
- data/lib/kward/config/core.rb +389 -0
- data/lib/kward/config/extensions.rb +96 -0
- data/lib/kward/config/prompts.rb +313 -0
- data/lib/kward/config/settings.rb +250 -0
- data/lib/kward/config_files.rb +14 -1008
- data/lib/kward/conversation.rb +31 -2
- data/lib/kward/image_attachments.rb +1 -1
- data/lib/kward/model/client.rb +2 -2
- data/lib/kward/model/copilot_models.rb +2 -2
- data/lib/kward/model/model_info.rb +20 -3
- data/lib/kward/{openrouter_model_cache.rb → model/openrouter_model_cache.rb} +3 -3
- data/lib/kward/model/payloads.rb +12 -3
- data/lib/kward/model/typesafe_client.rb +78 -0
- data/lib/kward/pan/server.rb +10 -7
- data/lib/kward/permissions/policy.rb +6 -2
- data/lib/kward/plugin_registry.rb +2 -659
- data/lib/kward/plugins/actions.rb +453 -0
- data/lib/kward/plugins/chat_contract.rb +121 -0
- data/lib/kward/{plugin_chat_runtime.rb → plugins/chat_runtime.rb} +62 -18
- data/lib/kward/plugins/host.rb +232 -0
- data/lib/kward/plugins/registry.rb +1190 -0
- data/lib/kward/plugins/resources.rb +206 -0
- data/lib/kward/plugins/turn_request.rb +36 -0
- data/lib/kward/plugins/ui.rb +219 -0
- data/lib/kward/prompt_interface/composer_renderer.rb +1 -1
- data/lib/kward/prompt_interface/composer_state.rb +1 -1
- data/lib/kward/prompt_interface/editor/controller.rb +1 -1
- data/lib/kward/prompt_interface/editor/runner.rb +1 -1
- data/lib/kward/prompt_interface/editor/state.rb +1 -1
- data/lib/kward/prompt_interface/layout.rb +1 -1
- data/lib/kward/prompt_interface/overlay_renderer.rb +1 -1
- data/lib/kward/prompt_interface/plugin_ui_requests.rb +82 -0
- data/lib/kward/prompt_interface/runtime_state.rb +6 -1
- data/lib/kward/prompt_interface/screen.rb +9 -2
- data/lib/kward/prompt_interface.rb +60 -11
- data/lib/kward/prompts/commands.rb +2 -1
- data/lib/kward/{adaptive_pty_output_sink.rb → pty/adaptive_output_sink.rb} +1 -1
- data/lib/kward/{interactive_pty_runner.rb → pty/interactive_runner.rb} +2 -2
- data/lib/kward/{local_command_runner.rb → pty/local_command_runner.rb} +1 -1
- data/lib/kward/{local_pty_command_runner.rb → pty/local_pty_runner.rb} +3 -9
- data/lib/kward/{pty_output_sink.rb → pty/output_sink.rb} +9 -4
- data/lib/kward/{pty_transcript_normalizer.rb → pty/transcript_normalizer.rb} +1 -1
- data/lib/kward/rpc/plugin_chat_manager.rb +30 -10
- data/lib/kward/rpc/prompt_bridge.rb +25 -0
- data/lib/kward/rpc/server.rb +91 -12
- data/lib/kward/rpc/session_manager.rb +147 -44
- data/lib/kward/rpc/session_tree_rows.rb +2 -2
- data/lib/kward/rpc/tool_metadata.rb +1 -1
- data/lib/kward/sandbox/command_runner.rb +1 -1
- data/lib/kward/{session_catalog.rb → sessions/catalog.rb} +1 -1
- data/lib/kward/{session_store.rb → sessions/store.rb} +9 -9
- data/lib/kward/{session_tree_nodes.rb → sessions/tree_nodes.rb} +3 -3
- data/lib/kward/{session_tree_renderer.rb → sessions/tree_renderer.rb} +4 -4
- data/lib/kward/{session_tree_tool_display.rb → sessions/tree_tool_display.rb} +1 -1
- data/lib/kward/{kwsh.rb → shell/kwsh.rb} +3 -3
- data/lib/kward/{persistent_shell_session.rb → shell/persistent_session.rb} +3 -3
- data/lib/kward/{shell_prompt_session.rb → shell/prompt_session.rb} +1 -1
- data/lib/kward/skills/trust_store.rb +1 -1
- data/lib/kward/tabs/driver.rb +194 -0
- data/lib/kward/{tab_store.rb → tabs/store.rb} +2 -2
- data/lib/kward/{clipboard.rb → terminal/clipboard.rb} +1 -1
- data/lib/kward/{terminal_image_support.rb → terminal/image_support.rb} +1 -1
- data/lib/kward/tools/base.rb +18 -0
- data/lib/kward/tools/context_for_task.rb +15 -6
- data/lib/kward/tools/edit_file.rb +9 -6
- data/lib/kward/tools/git_commit.rb +13 -7
- data/lib/kward/tools/list_directory.rb +4 -4
- data/lib/kward/tools/plugin_tool.rb +41 -0
- data/lib/kward/tools/prepare_shell_command.rb +1 -1
- data/lib/kward/tools/read_file.rb +7 -6
- data/lib/kward/tools/registry.rb +96 -13
- data/lib/kward/tools/run_shell_command.rb +10 -8
- data/lib/kward/tools/search/code.rb +1 -1
- data/lib/kward/tools/summarize_file_structure.rb +5 -5
- data/lib/kward/tools/tool_call.rb +2 -1
- data/lib/kward/tools/typesafe_evaluate.rb +81 -0
- data/lib/kward/tools/workspace_targets.rb +58 -0
- data/lib/kward/tools/write_file.rb +9 -6
- data/lib/kward/{export_path.rb → transcripts/export_path.rb} +1 -1
- data/lib/kward/{markdown_transcript.rb → transcripts/markdown_transcript.rb} +2 -2
- data/lib/kward/transport/contracts.rb +200 -0
- data/lib/kward/transport/gateway.rb +79 -35
- data/lib/kward/transport/plugin_chat_gateway.rb +3 -2
- data/lib/kward/transport.rb +1 -200
- data/lib/kward/version.rb +1 -1
- data/lib/kward/{workspace_factory.rb → workspace/factory.rb} +2 -2
- data/lib/kward/{git_worktree_manager.rb → workspace/git_worktree_manager.rb} +28 -0
- data/lib/kward/{workspace.rb → workspace/workspace.rb} +3 -3
- data/templates/default/fulldoc/html/css/kward.css +125 -0
- data/templates/default/fulldoc/html/images/kward_screen_1.png +0 -0
- data/templates/default/fulldoc/html/setup.rb +1 -1
- data/templates/default/layout/html/layout.erb +16 -4
- metadata +67 -48
- data/lib/kward/tab_driver.rb +0 -90
- data/templates/default/fulldoc/html/images/kward_workflow.svg +0 -52
- /data/lib/kward/{editor_prompt.rb → cli/editor_prompt.rb} +0 -0
- /data/lib/kward/{editor_prompt_session.rb → cli/editor_prompt_session.rb} +0 -0
- /data/lib/kward/{diff_view_mode.rb → prompt_interface/editor/diff_view_mode.rb} +0 -0
- /data/lib/kward/{editor_mode.rb → prompt_interface/editor/editor_mode.rb} +0 -0
- /data/lib/kward/{markdown_code_block.rb → prompt_interface/editor/markdown_code_block.rb} +0 -0
- /data/lib/kward/{scratchpad_languages.rb → prompt_interface/editor/scratchpad_languages.rb} +0 -0
- /data/lib/kward/{scratchpad_runner.rb → prompt_interface/editor/scratchpad_runner.rb} +0 -0
- /data/lib/kward/{detached_run.rb → pty/detached_run.rb} +0 -0
- /data/lib/kward/{session_diff.rb → sessions/diff.rb} +0 -0
- /data/lib/kward/{session_naming.rb → sessions/naming.rb} +0 -0
- /data/lib/kward/{session_trash.rb → sessions/trash.rb} +0 -0
- /data/lib/kward/{kwshrc.rb → shell/kwshrc.rb} +0 -0
- /data/lib/kward/{shell_prompt.rb → shell/prompt.rb} +0 -0
- /data/lib/kward/{ansi.rb → terminal/ansi.rb} +0 -0
- /data/lib/kward/{terminal_keys.rb → terminal/keys.rb} +0 -0
- /data/lib/kward/{terminal_sequences.rb → terminal/sequences.rb} +0 -0
- /data/lib/kward/{terminal_text.rb → terminal/text.rb} +0 -0
- /data/lib/kward/{transcript_export.rb → transcripts/transcript_export.rb} +0 -0
- /data/lib/kward/{project_files.rb → workspace/files.rb} +0 -0
- /data/lib/kward/{path_guard.rb → workspace/path_guard.rb} +0 -0
data/doc/rpc.md
CHANGED
|
@@ -15,7 +15,7 @@ A typical client launches the server, sends `initialize`, creates or resumes a s
|
|
|
15
15
|
| Connect and negotiate capabilities | [Launch](#Launch), [Framing](#Framing), and [Initialization](#Initialization) |
|
|
16
16
|
| Open, resume, branch, or export a conversation | [Session methods](#Session_methods) |
|
|
17
17
|
| Send input and render a response | [Turn methods](#Turn_methods) and [Turn notifications](#Turn_notifications) |
|
|
18
|
-
| Handle tool approval or structured
|
|
18
|
+
| Handle tool approval or structured plugin UI | [Tool approval bridge](#Tool_approval_bridge) and [Structured UI bridge](#Structured_UI_bridge) |
|
|
19
19
|
| Show model, runtime, auth, or configuration controls | [Runtime methods](#Runtime_methods), [Model methods](#Model_methods), and [Config and auth methods](#Config_and_auth_methods) |
|
|
20
20
|
| Discover tools, MCP servers, prompts, skills, or plugins | [Tool and prompt methods](#Tool_and_prompt_methods) |
|
|
21
21
|
|
|
@@ -65,8 +65,10 @@ Read `capabilities` at runtime instead of assuming every feature is available. I
|
|
|
65
65
|
- `transcript`: Kward transcript format support, including normalized messages, image/tool support, compaction summaries, and restored assistant reasoning as Pi-compatible `thinking` content blocks.
|
|
66
66
|
- `sessions`: explicit RPC session mode, JSONL persistence, and methods for listing, auto-resume, live-session discovery, linear forking, compaction, and labeled tree navigation with branch summaries. Import is unsupported. Live session updates are also unsupported but reserve the `session/updated` notification name. Git worktree bindings are reported as interactive-TUI-only.
|
|
67
67
|
- `turns`: asynchronous turns, per-session concurrency, active and recent turn lists, busy-input steering when the provider supports it, queued follow-ups, best-effort cancellation, and recent in-memory event replay. Per-turn options cover model, reasoning, tool scope, and tool approval, with structured client context for editor integrations.
|
|
68
|
-
- `
|
|
69
|
-
- `
|
|
68
|
+
- `plugins`: the supported plugin API version and public `id`, `version`, and `apiVersion` metadata for identified plugins. Private plugin configuration is never included.
|
|
69
|
+
- `pluginTools`: model-callable tools registered by trusted local plugins, including the registered count, `tools/list` discovery, execution-profile filtering, and permission-policy enforcement.
|
|
70
|
+
- `pluginChats`: optional plugin-owned chats. The capability lists opted-in chat types and methods. Versioned types report declared attachment, steering, and transcript-paging capabilities. Clients must explicitly subscribe before receiving `pluginChat/event` notifications; plugin chats are independent from workspace sessions. A type may also report `transport: true` when a trusted external transport is allowed to target it; RPC opt-in and external transport opt-in remain separate.
|
|
71
|
+
- `events`: the `turn/event` contract, assistant and reasoning events, typed plugin-command results, normalized tool metadata, tool updates and results, diff support, workspace guardrail status, focused-context and context-budget statistics tools, and explicitly unsupported shell changed-file and session-update flags.
|
|
70
72
|
- `attachments`: supported input attachment contract for `turns/start`, with accepted base64 image MIME types and a stable max byte value.
|
|
71
73
|
- `models`: model listing, refresh, selection, and exposed metadata across providers. Scoped model selection is not supported.
|
|
72
74
|
- `runtime`: runtime state, message-count statistics, and OpenAI/Codex context usage. Kward does not yet compute cumulative token or cost statistics.
|
|
@@ -74,12 +76,13 @@ Read `capabilities` at runtime instead of assuming every feature is available. I
|
|
|
74
76
|
- `runtimeSettings`: live `runtime/updateSetting` support for `defaultModel` and `defaultThinkingLevel`, plus `runtime/reload`.
|
|
75
77
|
- `auth`: available providers and authentication methods, private API-key storage, sanitized status, and logout. OpenAI and Anthropic OAuth are supported; Copilot OAuth is CLI-only, OpenRouter PKCE is not implemented, and xAI has no supported stable third-party flow.
|
|
76
78
|
- `memory`: opt-in structured memory support, interactive prompt injection only, JSON/JSONL local storage, and dedicated `memory/*` methods.
|
|
77
|
-
- `commands`: supported `commands/list` capability for prompt, skill, and plugin command sources, plus plugin execution through `commands/run` or plugin slash turns.
|
|
79
|
+
- `commands`: supported `commands/list` capability for prompt, skill, and plugin command sources, plus plugin execution through `commands/run` or plugin slash turns. Plugin commands may advertise validated JSON Schema arguments, shell-style text parsing, and structured results while legacy raw-string commands remain supported.
|
|
80
|
+
- `pluginActions`: namespaced typed actions discovered through `pluginActions/list` and synchronously invoked through `pluginActions/run`. They use object arguments and structured results, are not local TUI commands, and cannot make blocking UI requests.
|
|
78
81
|
- `skillCapture`: capture a reviewed personal `SKILL.md` from any saved session’s active branch through `skills/captureSessions`, `skills/captureDraft`, and `skills/saveCapturedDraft`.
|
|
79
82
|
- `projectSkillTrust`: explicitly unsupported over RPC. RPC clients cannot answer the interactive Allow/Deny/Review decision, so project skills remain skipped unless the global `skills.trust_project` override is enabled.
|
|
80
83
|
- `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
84
|
- `startupResources`: supported startup resource listing for context, skills, prompts, and plugins.
|
|
82
|
-
- `extensionUi`: question
|
|
85
|
+
- `extensionUi`: structured question support plus plugin `select`, `confirm`, `input`, `progress`, and `notify` UI through `ui/request`, `ui/answerRequest`, `ui/progress`, and `ui/notification`; plugin footer updates use `ui/footer`. Editor, widget, custom-canvas, and raw terminal-input primitives remain explicitly unsupported.
|
|
83
86
|
- `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
87
|
- `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
88
|
- `export`: supported transcript export formats. Currently `markdown` and `html`; default is `markdown`.
|
|
@@ -294,7 +297,11 @@ Returns `{ "session": {}, "editorText": "...", "cancelled": false, "aborted": fa
|
|
|
294
297
|
|
|
295
298
|
## Plugin chat methods
|
|
296
299
|
|
|
297
|
-
Plugin chats are optional trusted-plugin capabilities, not Kward workspace
|
|
300
|
+
Plugin chats are optional trusted-plugin capabilities, not Kward workspace
|
|
301
|
+
sessions. When `initialize.capabilities.pluginChats.supported` is true, use
|
|
302
|
+
`pluginChats/list` to discover available types. Types using the versioned chat
|
|
303
|
+
contract also report `apiVersion` and `capabilities` with `attachments`,
|
|
304
|
+
`steering`, and `transcriptPaging`; legacy types omit those fields.
|
|
298
305
|
|
|
299
306
|
### `pluginChats/open`
|
|
300
307
|
|
|
@@ -330,7 +337,10 @@ Params:
|
|
|
330
337
|
- `input`;
|
|
331
338
|
- `attachments`: optional base64 image attachments using the same MIME and size limits as `turns/start`.
|
|
332
339
|
|
|
333
|
-
Queues a plugin-chat turn and returns `{ id, chatId, status, ... }`. Plugin chat
|
|
340
|
+
Queues a plugin-chat turn and returns `{ id, chatId, status, ... }`. Plugin chat
|
|
341
|
+
turns are serialized per chat and do not use workspace sessions, agents, or
|
|
342
|
+
model overrides. A versioned chat whose declared `attachments` capability omits
|
|
343
|
+
`image` rejects image attachments before invoking its driver.
|
|
334
344
|
|
|
335
345
|
### `pluginChats/turns/cancel`, `pluginChats/turns/status`, `pluginChats/turns/events`, `pluginChats/turns/list`, `pluginChats/turns/listActive`
|
|
336
346
|
|
|
@@ -439,6 +449,7 @@ Known event types:
|
|
|
439
449
|
- `toolCall`
|
|
440
450
|
- `toolUpdate`
|
|
441
451
|
- `toolResult`
|
|
452
|
+
- `pluginCommandResult`
|
|
442
453
|
- `answer`
|
|
443
454
|
- `turnCancelRequested`
|
|
444
455
|
- `error`
|
|
@@ -462,6 +473,10 @@ Lifecycle payloads include `status` for `turnQueued`, `turnStarted`, and `turnFi
|
|
|
462
473
|
|
|
463
474
|
`toolResult` additionally includes `result` with `content`, `isError`, optional unified `diff`, optional `changedFiles`, and `images`. Failed or declined tools set `isError: true`.
|
|
464
475
|
|
|
476
|
+
A typed plugin slash command emits `pluginCommandResult` with `command` and a
|
|
477
|
+
structured `result` containing optional `message` and `data` fields. It then
|
|
478
|
+
emits the usual text events when the command produced user-facing output.
|
|
479
|
+
|
|
465
480
|
Examples:
|
|
466
481
|
|
|
467
482
|
- `edit_file`: `toolName: "edit"`, `args: { "path": "...", "edits": [{ "oldText": "...", "newText": "..." }] }`.
|
|
@@ -490,11 +505,11 @@ Params:
|
|
|
490
505
|
|
|
491
506
|
Denied tools are returned to the model as error-like tool results instead of executing the local operation.
|
|
492
507
|
|
|
493
|
-
## UI
|
|
508
|
+
## Structured UI bridge
|
|
494
509
|
|
|
495
|
-
Kward supports
|
|
510
|
+
Kward supports model questions and frontend-neutral plugin UI over RPC. The `extensionUi` capability reports the notification and answer method for each operation. `question` continues to use `ui/question` and `ui/answerQuestion`; plugin `select`, `confirm`, and `input` requests use `ui/request` and `ui/answerRequest`. Non-blocking plugin updates use `ui/progress` and `ui/notification`, while plugin footers use `ui/footer`. Editor, widget, custom-canvas, and raw terminal-input primitives remain explicitly unsupported.
|
|
496
511
|
|
|
497
|
-
Question requests are validated before notification. Kward accepts 1-4 questions, each with 2-4 options, and rejects unsupported `multiSelect` or option `preview` requests.
|
|
512
|
+
Question requests are validated before notification. Kward accepts 1-4 questions, each with 2-4 options, and rejects unsupported `multiSelect` or option `preview` requests. Plugin selections accept at most 100 options, and plugin text input is bounded to 16,384 bytes.
|
|
498
513
|
|
|
499
514
|
When the model calls `ask_user_question`, RPC emits a `ui/question` notification:
|
|
500
515
|
|
|
@@ -506,16 +521,37 @@ When the model calls `ask_user_question`, RPC emits a `ui/question` notification
|
|
|
506
521
|
}
|
|
507
522
|
```
|
|
508
523
|
|
|
509
|
-
When
|
|
524
|
+
When loaded Kward plugins contribute footer status, RPC emits `ui/footer` after
|
|
525
|
+
session creation/resume/clone, after each completed turn, and when the status
|
|
526
|
+
changes during its periodic refresh:
|
|
510
527
|
|
|
511
528
|
```json
|
|
512
529
|
{
|
|
513
530
|
"sessionId": "...",
|
|
514
|
-
"text": "
|
|
531
|
+
"text": "Bridge · 2 messages",
|
|
532
|
+
"segments": [
|
|
533
|
+
{
|
|
534
|
+
"id": "com.example.session/session",
|
|
535
|
+
"text": "Bridge",
|
|
536
|
+
"tooltip": "Current Kward session",
|
|
537
|
+
"priority": "high",
|
|
538
|
+
"order": 10
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
"id": "com.example.session/messages",
|
|
542
|
+
"text": "2 messages",
|
|
543
|
+
"priority": "low",
|
|
544
|
+
"order": 20
|
|
545
|
+
}
|
|
546
|
+
]
|
|
515
547
|
}
|
|
516
548
|
```
|
|
517
549
|
|
|
518
|
-
|
|
550
|
+
`text` is the combined fallback for clients that do not render segments.
|
|
551
|
+
`segments` remains display-ordered and lets richer clients show tooltips or
|
|
552
|
+
apply their own width policy. An empty `text` with an empty `segments` array
|
|
553
|
+
clears the client footer. The `extensionUi.footer` capability advertises
|
|
554
|
+
segment, tooltip, and priority support.
|
|
519
555
|
|
|
520
556
|
The UI must respond with `ui/answerQuestion`:
|
|
521
557
|
|
|
@@ -525,6 +561,40 @@ Params:
|
|
|
525
561
|
- `questionRequestId`
|
|
526
562
|
- `answers`: answer array returned to the tool.
|
|
527
563
|
|
|
564
|
+
When a plugin calls `ctx.ui.select`, `ctx.ui.confirm`, or `ctx.ui.input` during an asynchronous plugin-command turn or plugin tool call, RPC emits:
|
|
565
|
+
|
|
566
|
+
```json
|
|
567
|
+
{
|
|
568
|
+
"method": "ui/request",
|
|
569
|
+
"params": {
|
|
570
|
+
"sessionId": "...",
|
|
571
|
+
"requestId": "...",
|
|
572
|
+
"kind": "select",
|
|
573
|
+
"payload": {
|
|
574
|
+
"title": "Environment",
|
|
575
|
+
"message": "Choose a target",
|
|
576
|
+
"options": [
|
|
577
|
+
{ "label": "Staging", "value": "staging", "description": "Deploy for testing." }
|
|
578
|
+
]
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
Answer it with `ui/answerRequest`:
|
|
585
|
+
|
|
586
|
+
```json
|
|
587
|
+
{
|
|
588
|
+
"sessionId": "...",
|
|
589
|
+
"requestId": "...",
|
|
590
|
+
"value": "staging"
|
|
591
|
+
}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
For `confirm`, `value` must be a boolean. For `input`, it is a string or `null` when cancelled. For `select`, it is one of the advertised option values or `null`. Submit interactive plugin commands through `turns/start`; synchronous `commands/run` deliberately reports blocking plugin UI as unavailable so the RPC reader never waits for an answer it cannot read.
|
|
595
|
+
|
|
596
|
+
`ctx.ui.progress` emits `ui/progress` with `sessionId`, stable `id`, `message`, optional `percent`, and `done`. `ctx.ui.notify` emits `ui/notification` with `sessionId`, `message`, and `level` (`info`, `success`, `warning`, or `error`). These notifications do not require answers.
|
|
597
|
+
|
|
528
598
|
## Runtime methods
|
|
529
599
|
|
|
530
600
|
### `runtime/state`
|
|
@@ -737,11 +807,11 @@ Params:
|
|
|
737
807
|
|
|
738
808
|
Returns current tool schemas. The existing model-facing schema shape is preserved: each entry still has `type: "function"` and `function` with `name`, `description`, and `parameters`. Entries also include additive metadata for UI discovery:
|
|
739
809
|
|
|
740
|
-
- `metadata.source`: one of practical source labels such as `builtin`, `mcp`, `web`, `skill`, `ui`, or `unknown`.
|
|
810
|
+
- `metadata.source`: one of practical source labels such as `builtin`, `plugin`, `mcp`, `web`, `skill`, `ui`, or `unknown`.
|
|
741
811
|
- `metadata.displayName`: human-readable tool label.
|
|
742
812
|
- MCP tools also include `metadata.serverName` and `metadata.remoteName`. The callable name remains sanitized with a double underscore, for example `github__search_issues`, while `displayName` is `github.search_issues`.
|
|
743
813
|
|
|
744
|
-
Clients that only read `tools[].function` remain compatible.
|
|
814
|
+
Clients that only read `tools[].function` remain compatible. Model-callable tools registered by trusted local plugins appear here with `metadata.source: "plugin"` and follow the same per-session execution-profile filtering as built-in tools.
|
|
745
815
|
|
|
746
816
|
### `mcp/status`
|
|
747
817
|
|
|
@@ -766,7 +836,74 @@ Params:
|
|
|
766
836
|
|
|
767
837
|
- `sessionId`: active RPC session ID.
|
|
768
838
|
|
|
769
|
-
Returns frontend-neutral slash command metadata for configured prompt templates, skills, and plugins. Prompt command names omit the leading slash. Skill command names use `skill:<name>`. Plugin command names omit the leading slash and include `executable: true`. Builtin terminal-only commands are omitted. Prompt commands can be submitted directly to `turns/start` as slash commands or expanded first with `prompts/expand`; plugin commands can be submitted to `turns/start` or run explicitly with `commands/run`.
|
|
839
|
+
Returns frontend-neutral slash command metadata for configured prompt templates, skills, and plugins. Prompt command names omit the leading slash. Skill command names use `skill:<name>`. Plugin command names omit the leading slash and include `executable: true`. Typed plugin entries additionally include `typed: true`, their strict object `schema`, declared `positionals`, and `pluginId` when the plugin has stable identity. Builtin terminal-only commands are omitted. Prompt commands can be submitted directly to `turns/start` as slash commands or expanded first with `prompts/expand`; plugin commands can be submitted to `turns/start` or run explicitly with `commands/run`.
|
|
840
|
+
|
|
841
|
+
### `commands/run`
|
|
842
|
+
|
|
843
|
+
Params:
|
|
844
|
+
|
|
845
|
+
- `sessionId`: active RPC session ID.
|
|
846
|
+
- `name`: plugin command name, with or without the leading slash.
|
|
847
|
+
- `arguments`: shell-style text or, for typed commands, an object matching the advertised schema.
|
|
848
|
+
|
|
849
|
+
Legacy plugin commands return their existing string-or-null `result`. Typed
|
|
850
|
+
commands return `result` as an object containing optional user-facing `message`
|
|
851
|
+
and JSON-compatible `data`; text emitted through `ctx.say` remains in `output`.
|
|
852
|
+
Blocking structured UI requests are unavailable on this synchronous path. Use a
|
|
853
|
+
slash-command `turns/start` call when the command needs interactive UI.
|
|
854
|
+
|
|
855
|
+
Plugin commands can also stage a model response with `ctx.request_turn(system: text)`.
|
|
856
|
+
Submit these through `turns/start`, for example:
|
|
857
|
+
|
|
858
|
+
```json
|
|
859
|
+
{"sessionId":"session-id","input":"/iddqd Answer in French and explain the current design."}
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
The same turn emits the normal model, tool, answer, error, and completion events.
|
|
863
|
+
The host retains cancellation, execution-profile restrictions, and tool approvals.
|
|
864
|
+
The instructions supplement the system prompt for this turn only; they are not
|
|
865
|
+
submitted as user text and are not reactivated by restoring the session.
|
|
866
|
+
`commands/run` and `pluginActions/run` reject model-turn requests. Discover this
|
|
867
|
+
contract under `initialize.capabilities.commands.modelTurns`, including the
|
|
868
|
+
65,536-byte limit, `scope: "turn"`, and `synchronous: false`.
|
|
869
|
+
`inputRole: "system"` describes Kward's internal instruction role;
|
|
870
|
+
`codexInputRole: "developer"` reports the Codex subscription backend's supported
|
|
871
|
+
wire role. Codex receives the command as a new ordered developer message, while
|
|
872
|
+
direct OpenAI Responses receives an ordered system message. Base instructions
|
|
873
|
+
stay separate from these turn-scoped input messages.
|
|
874
|
+
|
|
875
|
+
The invocation is saved as a user-visible history entry with `display_content`
|
|
876
|
+
and `plugin_system_turn` metadata (command, plugin ID, instruction text, request ID,
|
|
877
|
+
and scope). Later model requests omit these history entries; compaction uses an
|
|
878
|
+
informational placeholder, not the expired instructions. Anthropic and Gemini
|
|
879
|
+
use separate system fields rather than ordered system messages and require
|
|
880
|
+
existing dialogue; a system-only request in an empty session fails explicitly
|
|
881
|
+
rather than inserting a synthetic user prompt.
|
|
882
|
+
|
|
883
|
+
### `pluginActions/list`
|
|
884
|
+
|
|
885
|
+
Params:
|
|
886
|
+
|
|
887
|
+
- `sessionId`: active RPC session ID.
|
|
888
|
+
|
|
889
|
+
Returns identified-plugin actions with `id`, local `name`, `pluginId`,
|
|
890
|
+
`description`, and strict object `schema`. Action IDs use
|
|
891
|
+
`<plugin-id>/<action-name>`.
|
|
892
|
+
|
|
893
|
+
### `pluginActions/run`
|
|
894
|
+
|
|
895
|
+
Params:
|
|
896
|
+
|
|
897
|
+
- `sessionId`: active RPC session ID.
|
|
898
|
+
- `id`: complete namespaced action ID.
|
|
899
|
+
- `arguments`: object matching the action schema; defaults to an empty object.
|
|
900
|
+
|
|
901
|
+
Returns `action`, `output`, and a structured `result` with optional `message` and
|
|
902
|
+
`data`. Actions run synchronously and therefore expose notifications and progress
|
|
903
|
+
but not blocking questions, selections, confirmations, or input. They are
|
|
904
|
+
rejected when the session execution profile disables plugin commands. Actions
|
|
905
|
+
are intentionally not exposed in local slash completion; a plugin should also
|
|
906
|
+
register a typed command when it needs a human-facing TUI entry point.
|
|
770
907
|
|
|
771
908
|
### `skills/captureSessions`, `skills/captureDraft`, and `skills/saveCapturedDraft`
|
|
772
909
|
|
|
@@ -884,4 +1021,5 @@ Returns login status for a login ID.
|
|
|
884
1021
|
- RPC is intended for a trusted local UI and can read/write files, run shell commands, update secrets, and use OAuth.
|
|
885
1022
|
- Workspace roots may be any existing local directory accessible to the process.
|
|
886
1023
|
- Tool execution matches current CLI behavior; mutating tools are not approval-gated by RPC.
|
|
1024
|
+
- `commands/run` and `pluginActions/run` execute trusted local plugin code. Action schemas validate data shape but are not an authorization boundary; use execution profiles to disable plugin operations for restricted sessions.
|
|
887
1025
|
- Responses and diagnostics redact secret-looking fields, but clients should still avoid logging full protocol traffic unless necessary.
|
data/doc/sandboxing.md
CHANGED
|
@@ -67,9 +67,12 @@ after changing the mode.
|
|
|
67
67
|
|
|
68
68
|
An active worktree-backed tab uses a strict `workspace_write` policy for its
|
|
69
69
|
model-requested command workers, regardless of the global `sandbox.mode` or
|
|
70
|
-
`tools.workspace_guardrails` settings. The writable root is exactly the
|
|
71
|
-
worktree and no configured additional writable roots are carried into the
|
|
72
|
-
|
|
70
|
+
`tools.workspace_guardrails` settings. The default writable root is exactly the
|
|
71
|
+
linked worktree and no configured additional writable roots are carried into the
|
|
72
|
+
tab. When a workspace tool explicitly selects the verified `origin` target,
|
|
73
|
+
Kward uses a separate strict command worker whose writable root is exactly that
|
|
74
|
+
original worktree. Arbitrary target paths are not accepted. The configured
|
|
75
|
+
child-network setting is preserved.
|
|
73
76
|
|
|
74
77
|
If the current platform cannot provide filesystem enforcement, Kward refuses to
|
|
75
78
|
activate the worktree instead of falling back to an unrestricted command
|
|
@@ -82,8 +85,11 @@ This does not contain the user-directed `/shell`, `!command`, `/capture`, or
|
|
|
82
85
|
model-requested shell commands still cannot write Git metadata. Active worktree tabs additionally
|
|
83
86
|
expose a narrow `git_commit` tool for explicit agent-requested commits; it runs
|
|
84
87
|
through the trusted host-side Git workflow rather than widening the shell
|
|
85
|
-
sandbox. The
|
|
86
|
-
|
|
88
|
+
sandbox. The verified original worktree is available as `target: "origin"` on
|
|
89
|
+
core workspace tools so an agent can inspect and resolve merge conflicts without
|
|
90
|
+
switching tabs. Selecting that target does not add an approval layer; the normal
|
|
91
|
+
configured tool-permission policy applies equally to both worktrees. The
|
|
92
|
+
interactive `/git` flow remains available for manual review and commit.
|
|
87
93
|
|
|
88
94
|
## Platform support
|
|
89
95
|
|
data/doc/security.md
CHANGED
|
@@ -87,7 +87,7 @@ See [Lifecycle hooks](lifecycle-hooks.md) for policy examples and [RPC protocol]
|
|
|
87
87
|
|
|
88
88
|
## Opt-in permission policy
|
|
89
89
|
|
|
90
|
-
`permissions.enabled` is off by default. When enabled, Kward can allow, ask, or deny model-requested file changes, shell commands, web tools, and
|
|
90
|
+
`permissions.enabled` is off by default. When enabled, Kward can allow, ask, or deny model-requested file changes, shell commands, web tools, MCP tools, and plugin tools before execution. The interactive CLI uses an approval overlay; an unavailable approval bridge fails closed. The policy is not a sandbox: after Kward permits a shell command, it still runs with the permissions of your user account. See [Permissions](permissions.md) for workflows, modes, rules, and limits.
|
|
91
91
|
|
|
92
92
|
## Know what you are trusting
|
|
93
93
|
|
|
@@ -113,6 +113,11 @@ They can read files and environment variables, write files, run commands, and
|
|
|
113
113
|
make network requests. Kward intentionally does not load plugins from a
|
|
114
114
|
workspace directory.
|
|
115
115
|
|
|
116
|
+
Identified-plugin configuration and state remain local to the active config
|
|
117
|
+
directory. RPC capability reports include only plugin IDs and versions, never
|
|
118
|
+
plugin configuration or secret values. Treat `host.logger` output as
|
|
119
|
+
user-visible diagnostics and never write credentials to it.
|
|
120
|
+
|
|
116
121
|
### MCP servers
|
|
117
122
|
|
|
118
123
|
Configured MCP servers are local child processes. Their tools can expose application state such as browser pages, console messages, network traffic, or screenshots. Kward currently supports local stdio servers, but local transport does not make an untrusted server safe.
|
|
@@ -168,6 +173,7 @@ Kward keeps user data under `~/.kward` by default, or mostly beside `KWARD_CONFI
|
|
|
168
173
|
| Memory | `~/.kward/memory/` | Off by default; directory `0700` and files `0600`. |
|
|
169
174
|
| Telemetry logs | `~/.kward/logs/` | Off by default; redacted metadata, not intentional prompt or file-content logging. |
|
|
170
175
|
| Plugins | `~/.kward/plugins/` | Trusted Ruby code, not private data storage. |
|
|
176
|
+
| Plugin state | `~/.kward/plugin_state/` | Namespaced by stable plugin ID; state files use mode `0600`. |
|
|
171
177
|
| Hook audit log and trust records | `~/.kward/logs/`, `~/.kward/trusted_workspace_hooks.json` | Audit records use redacted metadata rather than raw event values. |
|
|
172
178
|
|
|
173
179
|
Private file modes help on normal Unix-like systems but do not protect data from your own account, privileged users, backups, malware, or a compromised machine. Session exports are written to the path you choose and should be protected separately.
|
data/doc/session-management.md
CHANGED
|
@@ -25,13 +25,13 @@ To automatically resume the last active session for the current workspace on sta
|
|
|
25
25
|
|
|
26
26
|
## A normal session workflow
|
|
27
27
|
|
|
28
|
-
Start a chat and give
|
|
28
|
+
Start a chat and give the current session and tab a useful name:
|
|
29
29
|
|
|
30
30
|
```text
|
|
31
|
-
/
|
|
31
|
+
/name oauth cleanup
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
`/
|
|
34
|
+
`/name` requires a name and updates both the active session and its tab label. It can also be used while the active tab's agent is running; it is unavailable in plugin tabs. Use `/rename` when you only want to rename the session. Use `/session name` without an argument to clear the current session name.
|
|
35
35
|
|
|
36
36
|
Work normally:
|
|
37
37
|
|
|
@@ -227,7 +227,8 @@ This is useful when you want to confirm which session you are in or check whethe
|
|
|
227
227
|
| Need | Use |
|
|
228
228
|
| --- | --- |
|
|
229
229
|
| Continue earlier work | `/session` or `/resume` |
|
|
230
|
-
| Give the current session a better name | `/
|
|
230
|
+
| Give the current session and tab a better name | `/name <name>` |
|
|
231
|
+
| Give only the current session a better name | `/rename <name>` |
|
|
231
232
|
| Clear the current session name | `/session name` |
|
|
232
233
|
| Keep the current state but try another future | `/clone` |
|
|
233
234
|
| Start a separate session from before an earlier prompt | `/fork` |
|
data/doc/tabs.md
CHANGED
|
@@ -59,11 +59,13 @@ Inspect, merge, or remove the binding explicitly:
|
|
|
59
59
|
/tab worktree remove
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
`/tab worktree merge` merges the active worktree's clean, committed branch directly into the branch currently checked out in its original workspace. Kward shows the source and target revisions and requires confirmation. Both worktrees must be clean. If Git reports conflicts, Kward leaves the original workspace in its normal merge state
|
|
62
|
+
`/tab worktree merge` merges the active worktree's clean, committed branch directly into the branch currently checked out in its original workspace. Kward shows the source and target revisions and requires confirmation. Both worktrees must be clean. If Git reports conflicts, Kward leaves the original workspace in its normal merge state while keeping the current tab on the linked branch. The composer shows the target branch and conflict count. Run `/tab worktree merge resolve` (or `/worktree merge resolve`) to start an agent turn that inspects and edits the verified original workspace with `target: "origin"`; the turn leaves committing for review. After the conflicts are resolved, run `/tab worktree merge continue` to stage the resolutions and complete the merge, or use `/tab worktree merge abort` to cancel it.
|
|
63
63
|
|
|
64
64
|
Removal refuses a dirty worktree and keeps its branch. A worktree that is missing or no longer points at the recorded branch is restored as unavailable rather than silently falling back to the original workspace.
|
|
65
65
|
|
|
66
|
-
Worktree tabs are available for normal session tabs, not plugin-owned tabs. Kward's file tools, `@`/`$` completion, `/files` browser, integrated editor, and model-requested shell workers use the active worktree root
|
|
66
|
+
Worktree tabs are available for normal session tabs, not plugin-owned tabs. Kward's file tools, `@`/`$` completion, `/files` browser, integrated editor, and model-requested shell workers use the active worktree root by default. Core model workspace tools advertise an optional `target` selector in an active worktree tab: `active` keeps the normal linked-worktree root, while `origin` selects only that tab's verified original repository worktree. Selecting `origin` does not add a separate approval prompt; the normal configured tool-permission policy applies equally to both targets. Paths remain relative to the selected root, and arbitrary filesystem targets are never accepted.
|
|
67
|
+
|
|
68
|
+
Both targets retain strict workspace guardrails and separate command sandboxes. The user-directed `/shell`, `!command`, `/capture`, and `/pty` features remain host-process operations and are not contained by the model command sandbox; use them only when that is intentional. Generic shell Git writes remain protected. When explicitly asked to commit, the agent can use `git_commit` for the active worktree or set `target: "origin"` for the original worktree; use the interactive `/git` flow when you want to review and commit changes yourself.
|
|
67
69
|
|
|
68
70
|
## Common workflow
|
|
69
71
|
|
|
@@ -98,6 +100,8 @@ Tabs keep the conversations separate, so context from one tab does not automatic
|
|
|
98
100
|
| `/tab worktree detach` | Return to the original workspace while keeping the linked worktree and branch |
|
|
99
101
|
| `/tab worktree status` | Show the current tab's worktree binding and Git status |
|
|
100
102
|
| `/tab worktree merge` | Merge the current worktree branch into the branch checked out in its original workspace |
|
|
103
|
+
| `/tab worktree merge resolve` | Ask the agent to resolve an in-progress merge in the original workspace from the same tab |
|
|
104
|
+
| `/tab worktree merge continue` | Stage resolutions and complete an in-progress merge after confirmation |
|
|
101
105
|
| `/tab worktree merge abort` | Abort a conflicted worktree merge in the original workspace |
|
|
102
106
|
| `/tab worktree remove` | Remove a clean linked worktree and keep its branch |
|
|
103
107
|
| `/worktree …` | Alias for `/tab worktree …` on the active tab |
|
data/doc/transports.md
CHANGED
|
@@ -104,6 +104,13 @@ Plugin-chat drivers may accept a `context:` keyword on `submit`. Transport turns
|
|
|
104
104
|
provide the authenticated actor there. Existing drivers that do not accept the
|
|
105
105
|
keyword continue to work, but cannot use actor-specific context.
|
|
106
106
|
|
|
107
|
+
The plugin-chat factory host reports `surface: :transport`, the stable chat type
|
|
108
|
+
ID and scope key, immutable plugin configuration, scoped durable storage, secret
|
|
109
|
+
lookup, logging, declared chat capabilities, and managed cleanup. Storage is
|
|
110
|
+
isolated by plugin, chat type, and external conversation scope. Versioned chat
|
|
111
|
+
contracts also reject attachments not declared by that chat type before calling
|
|
112
|
+
the driver.
|
|
113
|
+
|
|
107
114
|
Plugin-chat transport IDs, turn events, transcript storage, and authorization
|
|
108
115
|
remain separate from normal workspace sessions. A plugin's `singleton: :global`
|
|
109
116
|
setting also means that all transport conversations share that one plugin
|
|
@@ -119,6 +126,14 @@ API.
|
|
|
119
126
|
Transports that cannot support interactive approvals must use an explicit
|
|
120
127
|
configured fallback policy; they must not leave an agent turn waiting forever.
|
|
121
128
|
|
|
129
|
+
Structured plugin UI requests use the same transport-neutral interaction path.
|
|
130
|
+
Plugin `question`, `select`, `confirm`, and `input` calls arrive with matching
|
|
131
|
+
interaction kinds, prompts, choices, and metadata, and answers are routed back to the
|
|
132
|
+
waiting plugin handler. An adapter may support only a subset, but it must cancel
|
|
133
|
+
or answer unsupported requests rather than leaving the turn blocked. Plugin
|
|
134
|
+
notifications and progress remain local to the RPC/TUI UI bridge for now and
|
|
135
|
+
are not transport interaction requests.
|
|
136
|
+
|
|
122
137
|
## Storage and routing
|
|
123
138
|
|
|
124
139
|
Transport plugins receive namespaced durable storage for state such as:
|
data/doc/usage.md
CHANGED
|
@@ -136,11 +136,14 @@ Slash commands run local actions in the current session. Most do not send a prom
|
|
|
136
136
|
| `/tab close` | close the active tab. |
|
|
137
137
|
| `/tab new` | open a new tab. |
|
|
138
138
|
| `/tab name <label>` | rename the active tab label. |
|
|
139
|
+
| `/name <name>` | rename the active session and tab together; available while the tab's agent is running. |
|
|
139
140
|
| `/tab worktree` | create or activate the active session tab's linked Git worktree. |
|
|
140
141
|
| `/tab worktree activate` | explicitly create or activate the active session tab's linked Git worktree. |
|
|
141
142
|
| `/tab worktree detach` | return to the original workspace while keeping the linked worktree and branch. |
|
|
142
143
|
| `/tab worktree status` | inspect the active tab's worktree binding and changes. |
|
|
143
144
|
| `/tab worktree merge` | merge a clean worktree branch into the branch checked out in its original workspace. |
|
|
145
|
+
| `/tab worktree merge resolve` | ask the agent to resolve an in-progress merge in the original workspace from the same tab. |
|
|
146
|
+
| `/tab worktree merge continue` | stage resolutions and complete an in-progress merge after confirmation. |
|
|
144
147
|
| `/tab worktree merge abort` | abort a conflicted worktree merge in the original workspace. |
|
|
145
148
|
| `/tab worktree remove` | remove a clean linked worktree while keeping its branch. |
|
|
146
149
|
| `/worktree …` | alias for `/tab worktree …` on the active tab. |
|
|
@@ -191,7 +194,7 @@ Use sessions when work spans more than one terminal sitting, or when you want to
|
|
|
191
194
|
Typical flow:
|
|
192
195
|
|
|
193
196
|
```text
|
|
194
|
-
/
|
|
197
|
+
/name oauth cleanup
|
|
195
198
|
# work with Kward
|
|
196
199
|
/export oauth-notes.md
|
|
197
200
|
/exit
|
data/doc/workspace-tools.md
CHANGED
|
@@ -21,6 +21,15 @@ Important behavior:
|
|
|
21
21
|
- Edits use exact text replacement, so accidental partial or fuzzy changes fail instead of guessing.
|
|
22
22
|
- With sandboxing off (the default), shell commands run as your operating-system user from the workspace. Enable [command sandboxing](sandboxing.md) to apply an OS boundary to model-requested `run_shell_command` workers. Command output is capped at 128 KB.
|
|
23
23
|
|
|
24
|
+
### Worktree targets
|
|
25
|
+
|
|
26
|
+
In an active linked-worktree tab, `list_directory`, `read_file`, `write_file`, `edit_file`, `run_shell_command`, `summarize_file_structure`, and `context_for_task` also advertise an optional `target` argument:
|
|
27
|
+
|
|
28
|
+
- `active` is the default linked worktree.
|
|
29
|
+
- `origin` is the tab's verified original repository worktree.
|
|
30
|
+
|
|
31
|
+
Kward supplies this fixed role map from the tab binding; the model cannot provide an arbitrary filesystem root. Selecting `origin` does not add a separate approval prompt, so the agent can complete a requested inspect/edit/test/commit workflow without interruption. The normal configured tool-permission policy still applies equally to both targets. Each target keeps its own path guard and strict shell sandbox.
|
|
32
|
+
|
|
24
33
|
## Reading the workspace
|
|
25
34
|
|
|
26
35
|
### `list_directory`
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# The game renders colored sprites and particle-burst explosions inside the
|
|
16
16
|
# composer canvas region using the interactive mode API.
|
|
17
17
|
|
|
18
|
-
Kward.plugin do |plugin|
|
|
18
|
+
Kward.plugin(id: "com.kward.example.space-invaders", version: "1.0.0", api: 1) do |plugin|
|
|
19
19
|
plugin.interactive_command "invaders", rows: 18, fps: 30, description: "Space Invaders arcade game" do |ui, ctx|
|
|
20
20
|
game = SpaceInvadersGame.new(width: ui.width, height: ui.height)
|
|
21
21
|
ui.on_tick { |ui| game.tick(ui) }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Displays the current Federation stardate in Kward's interactive footer.
|
|
2
|
-
Kward.plugin do |plugin|
|
|
3
|
-
plugin.
|
|
2
|
+
Kward.plugin(id: "com.kward.example.stardate-footer", version: "1.0.0", api: 1) do |plugin|
|
|
3
|
+
plugin.status "stardate", priority: :low do |_ctx|
|
|
4
4
|
now = Time.now.utc
|
|
5
5
|
reference = Time.utc(1987, 7, 15)
|
|
6
6
|
stardate = 41_000 + ((now - reference) / (365.25 * 24 * 60 * 60) * 1_000)
|
data/lib/kward/agent.rb
CHANGED
|
@@ -3,6 +3,7 @@ require_relative "model/chat_invocation"
|
|
|
3
3
|
require_relative "compactor"
|
|
4
4
|
require_relative "model/context_overflow"
|
|
5
5
|
require_relative "conversation"
|
|
6
|
+
require_relative "plugins/turn_request"
|
|
6
7
|
require_relative "events"
|
|
7
8
|
require_relative "deep_copy"
|
|
8
9
|
require_relative "hooks"
|
|
@@ -41,9 +42,9 @@ module Kward
|
|
|
41
42
|
|
|
42
43
|
attr_reader :conversation, :tool_registry
|
|
43
44
|
|
|
44
|
-
# Adds
|
|
45
|
+
# Adds user input or scopes a plugin system request, then runs a normal turn.
|
|
45
46
|
#
|
|
46
|
-
# @param input [String] text
|
|
47
|
+
# @param input [String, PluginTurnRequest] user text or host-staged system instructions
|
|
47
48
|
# @param display_input [String, nil] alternate text kept for transcripts
|
|
48
49
|
# @yieldparam event [Object] streamed turn event for frontends
|
|
49
50
|
# @return [String] final assistant answer
|
|
@@ -52,19 +53,31 @@ module Kward
|
|
|
52
53
|
status = "completed"
|
|
53
54
|
error = nil
|
|
54
55
|
cancellation&.raise_if_cancelled!
|
|
55
|
-
|
|
56
|
+
system_turn = input if input.is_a?(PluginTurnRequest)
|
|
57
|
+
display_input ||= system_turn.to_s if system_turn
|
|
58
|
+
input = system_turn.system if system_turn
|
|
59
|
+
turn_start = run_hook("turn_start", payload: { input: input, display_input: display_input, input_role: system_turn ? "system" : "user" })
|
|
56
60
|
return hook_denied_answer(turn_start) if turn_start.denied?
|
|
57
61
|
|
|
58
62
|
input = turn_start.payload[:input] || turn_start.payload["input"] || input
|
|
59
63
|
display_input = turn_start.payload[:display_input] || turn_start.payload["display_input"] || display_input
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
if system_turn
|
|
65
|
+
system_turn = PluginTurnRequest.new(system: input, command: system_turn.command, plugin_id: system_turn.plugin_id, id: system_turn.id)
|
|
66
|
+
end
|
|
67
|
+
@conversation.with_system_turn(system_turn) do
|
|
68
|
+
@conversation.refresh_system_message_if_workspace_agents_changed!
|
|
69
|
+
if system_turn
|
|
70
|
+
@conversation.append_system_turn(system_turn)
|
|
71
|
+
else
|
|
72
|
+
@conversation.append_user(input, display_content: display_input)
|
|
73
|
+
end
|
|
74
|
+
run_hook("turn_context_build_before", payload: { message_count: @conversation.messages.length })
|
|
75
|
+
auto_compact_if_needed
|
|
76
|
+
run_hook("turn_context_build_after", payload: { message_count: @conversation.messages.length })
|
|
77
|
+
answer = run_turn(on_reasoning_delta: on_reasoning_delta, on_retry: on_retry, cancellation: cancellation, steering: steering, options: options, tool_registry: tool_registry, &block)
|
|
78
|
+
run_hook("turn_end", payload: { input: input, answer: answer })
|
|
79
|
+
answer
|
|
80
|
+
end
|
|
68
81
|
rescue StandardError => e
|
|
69
82
|
status = "failed"
|
|
70
83
|
error = e
|
data/lib/kward/cli/compaction.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Kward
|
|
|
6
6
|
module CompactionCommands
|
|
7
7
|
private
|
|
8
8
|
|
|
9
|
-
def compact_context(agent, argument)
|
|
9
|
+
def compact_context(agent, argument, cancellation: nil)
|
|
10
10
|
before = run_lifecycle_hook("session_compact_before", conversation: agent.conversation, payload: { instructions: argument.to_s })
|
|
11
11
|
if before.denied? || before.approval_required?
|
|
12
12
|
runtime_output("Declined: #{before.decision.message || "session compaction denied"}")
|
|
@@ -17,16 +17,22 @@ module Kward
|
|
|
17
17
|
conversation: agent.conversation,
|
|
18
18
|
client: @client,
|
|
19
19
|
tool_result_summarizer: lambda { |tool_call, content| tool_result_summary(tool_call, content) }
|
|
20
|
-
).compact(custom_instructions: argument)
|
|
20
|
+
).compact(custom_instructions: argument, cancellation: cancellation)
|
|
21
21
|
run_lifecycle_hook("session_compact_after", conversation: agent.conversation, payload: { old_message_count: result.old_message_count, new_message_count: result.new_message_count })
|
|
22
22
|
runtime_output("Compacted context: #{result.old_message_count} messages -> #{result.new_message_count} messages.")
|
|
23
|
-
|
|
23
|
+
result.summary
|
|
24
24
|
rescue Compactor::NothingToCompact, Compactor::AlreadyCompacted, Compactor::EmptySummary => e
|
|
25
25
|
runtime_output(e.message)
|
|
26
|
+
rescue Cancellation::CancelledError
|
|
27
|
+
raise
|
|
26
28
|
rescue StandardError => e
|
|
27
29
|
runtime_output("Compaction error: #{e.message}")
|
|
28
30
|
end
|
|
29
31
|
|
|
32
|
+
def render_compaction_summary(summary)
|
|
33
|
+
render_transcript_block("Assistant", summary)
|
|
34
|
+
end
|
|
35
|
+
|
|
30
36
|
end
|
|
31
37
|
end
|
|
32
38
|
end
|