Commit Graph

193 Commits

Author SHA1 Message Date
Ed Zynda d79eb1f0fa refactor(pkg/kit): use fantasy type aliases for LLM types with clean SDK names
Replace concrete LLMMessage/LLMUsage/LLMResponse/LLMFilePart structs with
type aliases to charm.land/fantasy types, exposing them under clean
LLM-prefixed names. This gives SDK consumers full access to rich message
parts (tool calls, reasoning, tool results) without importing fantasy
directly.

Key changes:
- LLM types are now aliases: LLMMessage=fantasy.Message, etc.
- Added aliases for all part types: LLMTextPart, LLMToolCallPart, etc.
- Re-exported constructors: NewLLMUserMessage, NewLLMSystemMessage
- Removed lossy conversion helpers (llm_convert.go, fantasyMsgsToKit)
- Updated all internal packages to use aliases consistently
- Added ACP smoke test script and prompt template
- Fixed lint issues: unused vars, modernize min() usage
2026-03-31 14:26:49 +03:00
Ed Zynda e7f11487b9 remove CompactRenderer and --compact flag
The compact display mode was purely a UI concern that added complexity
without providing unique value. Anyone wanting compact-style formatting
can implement it as an extension using the Renderer interface.

- Delete internal/ui/compact_renderer.go
- Remove renderToolBodyCompact and all compact tool body renderers from
  tool_renderers.go
- Simplify NewCLI(debug bool) — drop compact parameter
- Simplify NewStreamComponent(width, modelName) — drop compactMode parameter
- Remove CompactMode from AppModelOptions, app.Options, CLISetupOptions
- Remove Compact from internal/config/config.go
- Remove --compact flag, var, and viper binding from cmd/root.go
- Update format.go: remove CompactRenderer interface compile-time check
  and clean up comments
2026-03-31 13:01:30 +03:00
Ed Zynda 8eb0fa855a Fix ACP file attachment support
- Implement proper handling for all ACP content block types:
  - ContentBlockText: extracts text content
  - ContentBlockImage: decodes base64 to LLMFilePart
  - ContentBlockAudio: decodes base64 to LLMFilePart
  - ContentBlockResource: handles text and binary embedded resources
  - ContentBlockResourceLink: reads files from disk

- Text files are now included inline in the message (not as FilePart)
  to avoid OpenAI API errors. Only binary files (images, audio, PDFs)
  are sent as FilePart attachments.

- Add fallback MIME types when not provided by client
- Add default prompt text when user attaches files without text
- Add comprehensive debug logging for content extraction
- Enable debug logging in ACP command when --debug flag is used
2026-03-30 20:28:14 +03:00
Ed Zynda 6d424554ad Add KIT logo above startup info in TUI
- Display kitBanner() before PrintStartupInfo() when running Kit normally
- The ASCII art banner with KITT scanner lights now appears at the top
  of the screen, before Model, Context, Skills information
- Maintains consistent styling with the existing usage/help screen
2026-03-30 16:57:27 +03:00
Ed Zynda c91225629d fix: handle custom provider model persistence and bare model names
Two related fixes for --provider-url handling:

1. Don't restore custom/* models from preferences without --provider-url
   - When user runs with --provider-url, model defaults to custom/custom
   - If they switch models, custom/custom gets persisted to preferences
   - On next run without --provider-url, restoring custom/custom fails
   - Now we skip restoring custom/* models when no --provider-url is provided

2. Auto-prefix bare model names with custom/ when --provider-url is set
   - Users often provide just the model name (e.g., qwen3.5-35b-a3b)
   - This failed with 'invalid model format' error
   - Now auto-prefixed with custom/ for OpenAI-compatible endpoints
2026-03-30 16:12:16 +03:00
Ed Zynda 5aa6c9e116 chore: fix all golangci-lint v2 issues
- Fix gofmt formatting issues in 7 files
- Replace atomic.AddUint64 with atomic.Uint64 type (modernize)
- Replace for i := 0; i < count; i++ with for i := range count (modernize)
- Replace strings.Split with strings.SplitSeq (modernize)
- Replace deprecated GetFantasyProviders with GetLLMProviders
- Replace deprecated GetFantasyMessages with GetLLMMessages
- Replace deprecated ConvertFromFantasyMessage with ConvertFromLLMMessage
- Replace deprecated FromFantasyMessage with FromLLMMessage
- Replace deprecated ToFantasyMessages with ToLLMMessages
- Remove 2 unused formatToolArgs functions
2026-03-29 14:36:03 +03:00
Ed Zynda 971521f534 Group Extension* methods behind ExtensionAPI interface
- Create ExtensionAPI interface with all extension-related methods
- Add extensionAPI type that wraps *Kit and implements the interface
- Add Kit.Extensions() method to access the ExtensionAPI
- Remove ~30 Extension* methods from Kit (breaking SDK change)
- Update all internal callers (cmd/, internal/acpserver/) to use Extensions().Method()
- Extensions themselves unaffected (use kit/ext API via Yaegi)

This cleans up the Kit API surface while maintaining full extension functionality.
2026-03-29 13:19:51 +03:00
Ed Zynda 3f08bf2424 pkg/kit: SDK quality-of-life improvements
Replace var function aliases with proper func wrappers (types.go)
- ParseModelString, CreateProvider, GetGlobalRegistry, LoadSystemPrompt
  were package-level vars, making them reassignable and rendering oddly
  in go doc. Now plain func wrappers with matching signatures.

Fix Subagent() double-error return convention
- Was returning both (*SubagentResult{Error: err}, err) simultaneously.
  Now returns (nil, err) on failure, consistent with Go conventions.
- Removed SubagentResult.Error field; errors come from the error return.
- Updated all call sites in cmd/root.go, internal/acpserver, and kit.go.

Fix NavigateTo/SummarizeBranch/CollapseBranch string-encoded errors
- All three returned "" or an error string instead of error values,
  making it impossible to distinguish success from failure in SummarizeBranch
  (empty string meant both "no content" and "LLM failed").
- NavigateTo: string -> error
- SummarizeBranch: string -> (string, error)
- CollapseBranch: string -> error
- Updated cmd/root.go bridge closures to use err != nil and err.Error().

Remove duplicate GetSessionFilePath (use GetSessionPath)
- GetSessionPath (sessions.go) and GetSessionFilePath (kit.go) were
  identical. Removed GetSessionFilePath; updated cmd/root.go and
  internal/acpserver to call GetSessionPath directly.
2026-03-29 12:51:04 +03:00
Ed Zynda b0991c7aa6 tui: simplify rendering, fix correctness issues, remove dead code
## Dead code removal
- Delete slash_command_input.go (352 lines, never instantiated)
- Remove FormatCompactLine, StyleCompactSymbol/Label/Content from
  enhanced_styles.go (zero call sites)
- Remove getTheme() alias in messages.go; standardize on GetTheme()
  across compact_renderer.go (8 sites) and tool_renderers.go (14 sites)

## BubbleTea correctness
- Fix child model discards: all m.stream.Update() and m.input.Update()
  calls now store the returned model via type-assertion (13 sites)
- Fix Init(): remove vestigial nil guards; StreamComponent.Init() always
  returns nil so only m.input.Init() is needed
- Fix /clear divergence: remove silent InputComponent /clear handler so
  parent AppModel handles it with the proper system message (one path)

## Architecture / maintainability
- Unify slash-command dispatch from two-pass (exact + prefix) to single
  parse: strings.Cut once, GetCommandByName on name, pass args to
  handleSlashCommand(sc, args); eliminates 3 separate dispatch sites
- Add noopCmd package-level var replacing three inline func()tea.Msg{nil}
  sentinel returns
- Remove stale TAS-15/16/17 comments from interface declarations
- Deduplicate headerProviderForUI / footerProviderForUI in cmd/root.go
  into a shared headerFooterProviderForUI helper (removes ~28 duplicated lines)

## Performance
- Cache glamour.TermRenderer keyed by width in styles.go; invalidate on
  theme change — eliminates full goldmark parser re-init every flush tick
- Add styleMarginBottom1 package-level var replacing 9 per-frame
  lipgloss.NewStyle().MarginBottom(1) allocations
- Add layoutDirty flag: replace 9 distributeHeight() calls in Update()
  with m.layoutDirty=true; flush once in View() — guarantees exactly one
  layout measurement per frame instead of N (reduces double-render)
- Add WidgetUpdateEvent coalescing in app.NotifyWidgetUpdate() via
  atomic.Bool + 16ms debounce; prevents fast extension tickers from
  flooding BubbleTea's message queue with redundant re-render triggers

## Concurrency safety
- Convert all NotifyWidgetUpdate() call sites in cmd/root.go to
  go appInstance.NotifyWidgetUpdate() (16 sites) — eliminates deadlock
  risk when called synchronously from inside BubbleTea's Update() handler
2026-03-29 11:34:16 +03:00
Ed Zynda 4caa8ba3dc Bridge SDK features to extension system: tree navigation, skills, templates, model resolution
This commit bridges 4 categories of internal SDK capabilities to the extension
system, enabling extensions like pi-prompt-template-model to be built with
minimal custom code.

New Extension APIs:

Tree Navigation (Phase 1):
- GetTreeNode, GetCurrentBranch, GetChildren - Navigate conversation tree
- NavigateTo - Branch/fork to specific entries
- SummarizeBranch - LLM-based branch summarization
- CollapseBranch - Fresh context primitive for context management

Skill Loading (Phase 2):
- LoadSkill, LoadSkillsFromDir - Load skill files with YAML frontmatter
- DiscoverSkills - Auto-discover from standard locations
- InjectSkillAsContext, InjectRawSkillAsContext - Pre-load skills

Template Parsing (Phase 3):
- ParseTemplate, RenderTemplate - {{variable}} substitution
- ParseArguments, SimpleParseArguments - CLI-style arg parsing (, , )
- EvaluateModelConditional, RenderWithModelConditionals - Model conditionals

Model Resolution (Phase 4):
- ResolveModelChain - Fallback chain resolution
- GetModelCapabilities - Query model specs
- CheckModelAvailable, GetCurrentProvider, GetCurrentModelID

Files Modified:
- internal/extensions/api.go - New types and Context methods
- internal/extensions/symbols.go - Export to Yaegi
- internal/extensions/runner.go - No-op stubs
- pkg/kit/sessions.go - Tree navigation bridge
- pkg/kit/skills.go - Skill loading bridge
- pkg/kit/template_bridge.go - NEW - Template & model resolution
- cmd/root.go - Wire to extension Context

Examples Added:
- conversation-manager.go - Tree nav, branch collapse, fresh context loops
- prompt-templates.go - Frontmatter templates with model switching
- bridge_demo.go - All new APIs demonstration

Documentation Updated:
- README.md - New capabilities and examples
- www/pages/extensions/capabilities.md - Full API docs
- www/pages/extensions/examples.md - New example category
- skills/kit-extensions/SKILL.md - Extension developer docs
2026-03-28 12:00:19 +03:00
Ed Zynda b6ecc36ea1 refactor(ui): improve message spacing and styling consistency
- Add bottom margin to startup header (KVGroup)
- Add bottom margin to thinking/reasoning blocks
- Fix thinking block footer to appear on new line without extra spacing
- Update spawn_subagent tool output to use bash-style formatting
- Add blank line after extension startup messages for visual separation
2026-03-27 21:15:41 +03:00
Ed Zynda f12e195390 refactor(ui): replace custom message rendering with herald typography library
- Replace MessageRenderer with herald-based implementation
- Use herald alerts (Note, Tip, Warning, Caution) for message types
- Use blockquote for thinking/reasoning content
- Use KVGroup for startup info display
- Add margin-bottom to all message types for visual separation
- Simplify Read tool with herald CodeBlock and line numbers
- Add detectLanguage helper for syntax highlighting
- Capture extension startup messages and print after startup banner
- Remove ~200 lines of custom rendering code
2026-03-27 20:54:43 +03:00
Ed Zynda bbf1106e27 Add OpenAI ChatGPT/Codex OAuth authentication alongside Anthropic auth
Implements OAuth authentication for OpenAI ChatGPT Plus/Pro (Codex) similar to pi:

- Add OpenAICredentials type with OAuth and API key support
- Add OpenAI OAuth client with correct endpoints (auth.openai.com)
- Implement PKCE-based OAuth flow with local callback server on :1455
- Add login/logout/status commands for openai provider
- Support both ChatGPT/Codex OAuth tokens (chatgpt.com/backend-api) and
  regular OpenAI API keys (api.openai.com)
- Extract and store ChatGPT account ID from JWT token
- Add custom HTTP transport with required Codex headers:
  - chatgpt-account-id, originator, OpenAI-Beta: responses=experimental
- Update provider selection to use correct endpoint based on auth type

Usage:
  kit auth login openai    # OAuth with ChatGPT account
  kit auth logout openai
  kit auth status

The implementation follows the same patterns as the existing Anthropic OAuth
support, with automatic token refresh and secure credential storage in
~/.config/.kit/credentials.json
2026-03-26 14:50:15 +03:00
Ed Zynda be55bc03f1 Add mid-turn steering with Ctrl+S 2026-03-26 12:10:14 +03:00
Ed Zynda 7a2de4cc3c fix: update token counting when switching models mid-session
When switching models (e.g., via /model command or ctx.SetModel), the usage
tracker now updates its model info to reflect the new model's:
- Pricing for cost calculations
- Context limits for percentage display
- OAuth status (to show bash costs when using OAuth creds)

Previously, token costs and context percentages continued using the old
model's settings after a switch, causing incorrect display for:
- Users switching from paid to free/OAuth models
- Users switching between models with different pricing

Changes:
- Add UpdateModelInfo() method to UsageTracker
- Call UpdateModelInfo() in both SetModel callbacks (extension and UI)
- Add auth import for OAuth detection in root.go
2026-03-25 18:09:36 +03:00
Ed Zynda 329cd4ea4a feat: Add custom models via config file
Allow users to define custom models in ~/.kit.yml under the customModels
section. These models are automatically merged into the custom provider.

Example config:
  customModels:
    my-model:
      name: "My Custom Model"
      reasoning: true
      temperature: true
      cost:
        input: 0.002
        output: 0.004
      limit:
        context: 128000
        output: 32000

Usage:
  kit --model custom/my-model "Hello"
  kit --provider-url "http://localhost:8080" --model custom/my-model "Hello"

Note: When --provider-url is specified without --model, kit defaults to
custom/custom. When --provider-url is specified WITH a custom model from
config, that model is used.

Bug fixes:
- Fixed kit.New() re-loading config file and overriding CLI-specified config
- Fixed models command to reload registry for custom models
2026-03-24 14:19:49 +03:00
Ed Zynda fc054f50e8 Add custom/custom stub model for --provider-url
When users pass --provider-url without --model, automatically default
to custom/custom instead of the saved model preference. This lets users
point kit at any OpenAI-compatible endpoint without needing a provider/model
pair from the database.

The custom/custom model has:
- Zero cost (input/output = 0)
- 262K context window, 65K output limit
- Reasoning and temperature support
- Routes through openaicompat fantasy provider
2026-03-24 13:28:23 +03:00
Ed Zynda d8f1b32885 Remove --skill flag from skill subcommand to install all skills
The skill command now runs 'npx skills add mark3labs/kit' without
filtering to a single skill, installing both available skills:

1. Extensions - creating Kit extensions
2. SDK - building with the Kit Go SDK
2026-03-23 17:54:53 +03:00
Ed Zynda 017eb99d44 feat: add Pi-style prompt templates
Add user-defined prompt templates that expand into full prompts with
shell-style argument substitution.

Features:
- Templates loaded from ~/.kit/prompts/*.md and .kit/prompts/*.md
- YAML frontmatter support for description
- Argument placeholders: $1, $2, $@, $ARGUMENTS, ${@:N}, ${@:N:L}
- Autocomplete integration (templates appear as /name commands)
- CLI flags: --prompt-template and --no-prompt-templates
- First-match-wins collision handling with logged diagnostics

Example template:
---
description: Review code for issues
---
Review the following code for bugs and security issues.
Focus on $1 specifically.

Usage: /review error handling
2026-03-22 19:09:15 +03:00
Ed Zynda f7c8e7757b feat: persist model selection and thinking level across sessions
Model and thinking level choices now survive restarts, matching the
existing theme persistence pattern. Selections are saved to
~/.config/kit/preferences.yml and restored on next launch.

Precedence: CLI flag > config file > saved preference > default

Changes:
- Extended preferences struct with model and thinking_level fields
- Refactored preferences.go to shared load/save helpers (DRY)
- Added SaveModelPreference/LoadModelPreference
- Added SaveThinkingLevelPreference/LoadThinkingLevelPreference
- Persist on /model, model selector, /thinking, and Shift+Tab cycle
- Restore at startup in runNormalMode when no explicit flag/config
- Added modelFlagChanged/thinkingFlagChanged to detect explicit flags
- Comprehensive tests for all preference operations
2026-03-22 13:52:06 +03:00
Ed Zynda 3b14814740 feat: persist theme selection across sessions
Theme choices via /theme or ctx.SetTheme() were previously lost on
restart. Now the selected theme name is saved to
~/.config/kit/preferences.yml and restored on next launch.

Precedence: .kit.yml theme > preferences.yml > default (kitt).

- Add internal/ui/preferences.go with atomic save/load
- ApplyTheme() now persists; ApplyThemeWithoutSave() for startup
- Fallback to saved preference in cmd/root.go init()
2026-03-21 21:01:25 +03:00
Ed Zynda 4e66c0b4f7 feat: add session management features (picker, history, /name, /export, /import)
Fill session management gaps compared to pi:
- TUI session picker (/resume, --resume flag) with search, scope/filter
  toggles, delete, right-aligned metadata, and background-highlighted cursor
- Prompt history navigation via up/down arrows (100-entry ring buffer)
- /name <name> command now functional (was stubbed as not implemented)
- /export [path] exports session JSONL to file
- /import <path> loads session from JSONL file
- Remove deprecated unused App.runQueueItem method
2026-03-20 18:08:48 +03:00
Ed Zynda 95abb6fa6e feat: add extension API for programmatic theme registration and switching
Add RegisterTheme, SetTheme, and ListThemes to the extension Context,
allowing extensions to create custom themes at runtime and switch
between them. Uses ThemeColor/ThemeColorConfig concrete structs (no
interfaces) for Yaegi safety.

Include neon-theme.go example extension demonstrating the API.
2026-03-20 13:03:23 +03:00
Ed Zynda 13060a20f9 feat: add KITT-inspired theme system with unified markdown colors
Replace the Catppuccin color palette with a Knight Rider KITT-inspired
theme — scanner reds, amber dashboard glows, and dark cockpit tones.
No blues or bright greens; the entire palette stays in the warm
red/amber/gray family.

Unify the theme system by folding the standalone MarkdownTheme config
into the main Theme struct, eliminating the separate config path.
Replace all hardcoded lipgloss.Color() calls across input, overlay,
and CLI components with semantic theme references so every color
responds to theme customization.
2026-03-19 18:04:56 +03:00
Ed Zynda 54717e32bc refactor: Auto-show multi-select when repo has multiple extensions
Remove --select flag. Multi-select now appears automatically when a repo
contains more than one extension. Add --all flag to skip selection.
2026-03-18 16:53:42 +03:00
Ed Zynda 5b214b9fdf refactor: Use huh for CLI prompts, fix extension discovery in mixed repos
- Replace custom multi-select with huh.NewMultiSelect for kit install --select
- Replace raw bufio prompts in cmd/auth.go with huh.NewConfirm and huh.NewInput
- Fix extension discovery to use opinionated conventions (only scan root,
  extensions/, ext/, examples/extensions/ directories, skip cmd/internal/pkg/)
- Fix loader to use same convention-based scanning for installed git repos
- Fix errcheck lint warning in loader.go
2026-03-18 16:49:48 +03:00
Ed Zynda c5e6ca6e4d feat: Add kit install command for git-based extension distribution
Add comprehensive extension installation system for Kit:

Features:
- kit install <git-url> - Install extensions from git repos
- kit install <url> --local - Install to project .kit/git/ directory
- kit install <url> --select - Interactive selection for multi-extension repos
- kit install <url> --update - Update installed extensions
- kit install <url> --uninstall - Remove installed extensions
- Version pinning via @ref (tags, branches, commits)
- Support multiple URL formats (shorthand, git:, https, ssh)

Implementation:
- internal/extensions/installer.go - Git clone, checkout, validation
- internal/extensions/manifest.go - Package tracking with Include filtering
- internal/extensions/loader.go - Respect Include field when loading
- cmd/install.go - Cobra command with interactive prompts
- PromptMultiSelectConfig API - Multi-select prompts for extensions

Storage:
- Global: ~/.local/share/kit/git/<host>/<owner>/<repo>/
- Project: .kit/git/<host>/<owner>/<repo>/
- Manifests: packages.json tracking installed packages

Examples:
- Reorganized examples/extensions/ with README.md
- Added status-tools/ multi-file extension example
- Created comprehensive install guide in SKILL.md

Testing:
- Added installer_test.go with 15+ test cases
- All tests pass, build clean

Closes #extension-distribution
2026-03-18 16:21:31 +03:00
Ed Zynda 41d5f5e0fb feat: add OnEvent callback for real-time subagent event streaming
Add SubagentEvent type to extension API and OnEvent field to
SubagentConfig so extensions can watch subagent tool calls, text
chunks, reasoning deltas, and turn lifecycle events in real time.

The SDK's Kit.Subagent() already had OnEvent via kit.SubagentConfig.
This wires it through to the extension layer with a concrete
SubagentEvent struct (Yaegi-safe) and bridges SDK events to it
in both cmd/root.go and the ACP server.
2026-03-16 13:06:53 +03:00
Ed Zynda 8831b49b51 feat: in-process subagents replace subprocess spawning
Subagents now run as child Kit instances in the same process instead of
spawning a kit binary subprocess. This removes the binary dependency,
eliminates JSON serialization overhead, and enables SDK-only consumers
to use subagents without installing the kit CLI.

- Add Kit.Subagent() method for in-process subagent execution
- Add SubagentConfig/SubagentResult types to the SDK
- Add context-based SubagentSpawnFunc injection so core spawn_subagent
  tool calls back to Kit.Subagent() without an import cycle
- Add SubagentTools() bundle (all core tools minus spawn_subagent)
- Add viperInitMu for thread-safe concurrent kit.New() calls
- Wire extension ctx.SpawnSubagent and ACP server to use in-process
- Child Kit gets parent's model as fallback, in-memory or persisted
  session, and no extensions (preventing recursive loading)
2026-03-16 11:39:59 +03:00
Ed Zynda c94edc929b feat: add rich tool metadata to SDK and extension events (Gaps 1-8)
Thread ToolCallID, ToolKind, ParsedArgs, FileDiff metadata, StopReason,
SessionID, and StructuredMessages across the SDK event bus, extension
wrapper, app bridge, hooks, and ACP server layers.

- Gap 1: ToolCallID from Fantasy's ToolCallContent threaded end-to-end
- Gap 2: ToolKind via static lookup (execute/edit/read/search/agent)
- Gap 3+4: FileDiffInfo with DiffBlocks via fantasy.ToolResponse.Metadata
- Gap 5: StopReason from Fantasy FinishReason on TurnEndEvent/TurnResult
- Gap 6: Subagent sessions now opt-out (NoSession); SessionID in JSON output
- Gap 7: GetStructuredMessages() returns typed ContentParts
- Gap 8: ParsedArgs map[string]any on tool events for convenience

Edit/write tools attach structured diff metadata. ACP server uses real
ToolCallIDs. Extension and SDK events kept in sync with matching fields.
2026-03-16 11:10:05 +03:00
Ed Zynda fefbf19b42 fix(acp): default mcpServers to empty array for clients that omit it 2026-03-15 11:57:30 +03:00
Ed Zynda 93905d4d77 fix(acp): remove startup message from stdio output 2026-03-15 11:38:31 +03:00
Ed Zynda bbd8975ca0 feat: add first-class subagent support for task delegation
Implement 4-phase subagent system enabling LLM and extensions to spawn,
manage, and orchestrate child Kit instances for parallel task execution.

- Phase 1: SDK API with SpawnSubagent() for extensions
- Phase 2: spawn_subagent core tool for LLM usage
- Phase 3: Session hierarchy with ParentSessionID tracking
- Phase 4: Provider pooling for concurrent model access

New files:
- internal/extensions/subagent.go: SpawnSubagent implementation
- internal/core/subagent.go: Core tool definition
- internal/models/pool.go: Provider pool for concurrency
- examples/extensions/subagent-test.go: Test extension
- openspec/subagent-support.md: Design specification
2026-03-09 23:07:27 +03:00
Ed Zynda e613a07773 feat: add ACP server mode (kit acp)
Implement Agent Client Protocol server allowing ACP-compatible clients
(e.g. OpenCode) to drive Kit as a remote coding agent over stdio.

- internal/acpserver/agent.go: acp.Agent implementation bridging Kit's
  LLM execution, tool system, and event bus to ACP session updates
- internal/acpserver/session.go: session registry mapping ACP sessions
  to persisted Kit JSONL tree sessions
- cmd/acp.go: cobra subcommand wiring stdio JSON-RPC connection
- Add acp-go-sdk dependency, update README with ACP docs
2026-03-09 21:41:10 +03:00
Ed Zynda 1d3b4f8d56 feat: add skill subcommand to install kit-extensions skill via skills.sh 2026-03-09 14:24:09 +03:00
Ed Zynda f3ea18ae3a feat: add thinking model support with configurable reasoning levels
Add extended thinking/reasoning support for Anthropic and OpenAI models:

- ThinkingLevel type (off/minimal/low/medium/high) with token budgets
- Stream reasoning deltas via OnReasoningDelta through SDK→TUI event pipeline
- Render thinking blocks in StreamComponent (muted italic, collapsible)
- ctrl+t toggles thinking visibility, shift+tab cycles thinking level
- /thinking slash command with tab-completion for level names
- --thinking-level CLI flag and config file support
- Map ThinkingLevel to OpenAI ReasoningEffort for Responses API
- Auto-bump Anthropic max_tokens when thinking budget exceeds it
- Fix ResponseCompleteEvent prematurely resetting stream in streaming mode
- Status bar displays current thinking level
2026-03-07 21:27:46 +03:00
Ed Zynda 4577d218d3 feat: add /model slash command with interactive fuzzy-finding selector
Add /model command that allows switching LLM models mid-session.
When invoked without arguments, opens a full-screen selector overlay
showing only models with configured API keys, with inline fuzzy search,
cursor navigation, and current model indicator. When invoked with an
argument (e.g. /model anthropic/claude-haiku-4-5), switches directly.

Also upgrades all Go dependencies to latest versions.
2026-03-06 18:50:32 +03:00
Ed Zynda 57250a3a3d refactor: remove --prompt flag, positional args are the only way
Drop the --prompt/-p flag entirely. Non-interactive mode is now
triggered by passing positional arguments:

  kit "Explain this"
  kit @file.go "Review this" --json
  kit @a.go @b.go --quiet

Updated extension examples (kit-kit.go, subagent-widget.go) to pass
the prompt as a positional arg. Updated AGENTS.md and README.md.
2026-03-05 19:03:47 +03:00
Ed Zynda 7e1686e572 feat: positional args as primary non-interactive mode, hide --prompt
Positional args are now the main way to run non-interactive mode:

  kit "Explain this codebase"
  kit @code.ts @test.ts "Review these files"
  kit @go.mod "What module?" --quiet

--prompt is hidden but still works for subprocess compat (extensions
spawn kit with --prompt internally). Updated --quiet/--json/--no-exit
error messages to reference the new positional arg pattern.
2026-03-05 19:00:51 +03:00
Ed Zynda 4a8b10cde7 feat: support Pi-style positional @file args
Enables: kit @code.ts @test.ts "Review these files"

Positional args starting with @ are treated as file attachments —
their content is read and prepended to the prompt. Remaining
positional args are joined as the prompt text. Works alongside
--prompt flag (files prepended, extra text appended).
2026-03-05 18:57:00 +03:00
Ed Zynda cc5611eff7 feat: support @file references in non-interactive mode (--prompt) 2026-03-05 18:54:17 +03:00
Ed Zynda 51c70b63a7 feat: add @file autocomplete and context attachment
Type @ in the input to trigger a fuzzy file picker popup. Files are
discovered via git ls-files (with os.ReadDir fallback), scored by
fuzzy match, and displayed in the existing autocomplete popup.

Tab/Enter inserts the selected path; directories keep the popup open
for drilling. On submit, @file tokens are expanded into XML-wrapped
file content before being sent to the agent. No CWD restriction —
supports ~/, ../, and absolute paths.
2026-03-05 18:46:25 +03:00
Ed Zynda aede76d807 feat: add TUI suspend, custom message rendering, and extension hot-reload
- ctx.SuspendTUI(callback): releases terminal for interactive subprocesses
  (vim, shell, htop), automatically restores TUI when callback returns.
  Uses BubbleTea v2 ReleaseTerminal/RestoreTerminal.

- api.RegisterMessageRenderer(config) + ctx.RenderMessage(name, content):
  named render functions for branded/styled extension output. Renderers
  receive content and terminal width, return ANSI-styled strings.

- ctx.ReloadExtensions(): hot-reloads all extensions from disk. Emits
  SessionShutdown to old extensions, reloads source, emits SessionStart
  to new. Event handlers, commands, renderers, shortcuts update immediately.
  TUI command list refreshes via WidgetUpdateEvent. Extension tools are
  NOT updated (baked into agent at creation, documented limitation).

New example extensions: interactive-shell.go, branded-output.go, dev-reload.go
2026-03-02 19:32:19 +03:00
Ed Zynda 9e1df38836 feat: add keyboard shortcuts, tool context, and ToolCallEvent source field
- RegisterShortcut(ShortcutDef, handler) for global keyboard shortcuts
  that fire across all non-modal app states (after ctrl+c, before
  component dispatch). Handlers run in goroutines for safe blocking calls.
- ToolContext with IsCancelled/OnProgress for rich tool execution;
  ExecuteWithContext on ToolDef takes priority over simple Execute.
- Source field on ToolCallEvent (currently "llm", forward-compatible
  with future user-initiated tool calls).
- Fix missing //go:build ignore on context-inject.go.
- Update plan-mode.go to register ctrl+alt+p shortcut.
2026-03-02 19:04:37 +03:00
Ed Zynda 8f5efee837 feat: add session before-hooks (OnBeforeFork, OnBeforeSessionSwitch) and compaction event (OnBeforeCompact)
Add three new extension events that allow extensions to gate destructive
session operations and compaction:

- OnBeforeFork: fires before branching in the tree selector; handler can
  cancel with reason (e.g. dirty-repo guard)
- OnBeforeSessionSwitch: fires before /new resets the session branch;
  handler can cancel with reason
- OnBeforeCompact: fires before context compaction (auto or manual);
  handler receives token stats and IsAutomatic flag, can cancel

Includes SDK hook registry (beforeCompact), extension bridge, UI
callbacks threaded through AppModelOptions, and two example extensions:
- confirm-destructive.go: git dirty check + fork confirmation
- compact-notify.go: compaction notification + auto-compact gating
2026-03-02 16:35:00 +03:00
Ed Zynda c40dc2f4fb feat: add argument tab-completion for extension slash commands
Extensions can now provide a Complete function on CommandDef that supplies
argument suggestions. When the user types a command name followed by a space,
the input popup switches to argument-completion mode, calling Complete with
the partial text and displaying matching suggestions.
2026-03-02 15:37:52 +03:00
Ed Zynda 37e82781b1 feat: add OnModelChange event and ctx.Exit(); remove Gap/Pi references from comments 2026-03-02 14:49:51 +03:00
Ed Zynda 23c16bb197 feat: add tool mgmt, model mgmt, options, event bus, LLM completion, steer mode, and 10 example extensions
Phase 2+3 extension API additions:
- Tool management: GetAllTools, SetActiveTools (plan-mode support)
- Model management: SetModel, GetAvailableModels, ModelChangedEvent
- Extension options: RegisterOption, GetOption, SetOption (env/config/default)
- Inter-extension event bus: OnCustomEvent, EmitCustomEvent
- Direct LLM completion: ctx.Complete with streaming/blocking modes
- Steer delivery mode: CancelAndSend for interrupt-and-redirect

New example extensions (10):
- plan-mode.go: read-only exploration with /plan toggle
- summarize.go: conversation summarization via ctx.Complete
- bookmark.go: persistent bookmarks via AppendEntry/GetEntries
- auto-commit.go: auto-commit on exit using last assistant message
- permission-gate.go: confirm dangerous bash commands
- protected-paths.go: block writes to .env, .git/, secrets/
- notify.go: desktop notifications on agent completion
- inline-bash.go: !{cmd} expansion in prompts
- pirate.go: system prompt persona injection
- project-rules.go: load .kit/rules/*.md into system prompt

Always-wrap tools through runner for SetActiveTools disabled-tool checking.
Removed phase1/phase2 test extensions from examples.
2026-03-02 14:31:35 +03:00
Ed Zynda 9449f1fcdf feat: add session management, persistence, editor text, and status bar APIs for extensions
Implement Phase 1 extension API gaps identified in the pi-mono gap analysis:

- Gap 1: Session Management API (GetMessages, GetSessionPath) — read-only
  access to conversation history from extensions
- Gap 2: Session Persistence (AppendEntry, GetEntries) — custom extension
  data survives across session restarts via new ExtensionDataEntry type
- Gap 10: SetEditorText — extensions can pre-fill the input editor
- Gap M3: Keyed Status Bar (SetStatus, RemoveStatus) — multiple extensions
  can place independent entries in the TUI status bar, ordered by priority
2026-03-02 01:33:56 +03:00
Ed Zynda dc59cfc81e feat: add --json output mode for --prompt and update subagent extensions
Add a --json flag that outputs structured JSON (response, model, usage,
messages with typed parts) when used with --prompt. Update kit-kit and
subagent-widget extensions to use --json for cleaner subprocess output
parsing instead of raw text heuristics.
2026-03-01 21:16:34 +03:00