Commit Graph

92 Commits

Author SHA1 Message Date
Solomon
99f7d9a4bc feat: Enhance executable resolution by refreshing PATH (#1098)
* Refresh path on executable lookup

* Make resolve_executable_path async

* Handle task attempt start failure gracefully

* clippy fix

* Remove unused to_shell_string

* Lint

---------

Co-authored-by: Alex Netsch <alex@bloop.ai>
2025-11-03 15:57:53 +00:00
Alex Netsch
c59ffdd0ab Bump claude version (#1167) 2025-11-03 12:10:20 +00:00
Louis Knight-Webb
cf078e81d1 Fix profiles (#1122)
* fix profiles

* change warn to error
2025-10-29 12:10:03 +00:00
Alex Netsch
e06dd1f6dc Claude approval refactor (#1080)
* WIP claude approvals

* Use canusetool

* Remove old exitplanmode approvals

* WIP approvals

* types

* Remove bloat

* Cleanup, exit on finish

* Approval messages, cleanup

* Cleanup

* Fix msg types

* Lint fmt

* Cleanup

* Send deny

* add missing timeout to hooks

* FIx timeout issue

* Cleanup

* Error handling, log writer bugs

* Remove deprecated approbal endpoints

* Remove tool matching strategies in favour of only id based matching

* remove register session, parse result at protocol level

* Remove circular peer, remove unneeded trait

* Types
2025-10-28 15:36:47 +00:00
Louis Knight-Webb
a70a7bfbad Diagnose script hang (vibe-kanban) (#1112)
* Done! Applied the fix to [script.rs](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/1761-diagnose-script/crates/executors/src/actions/script.rs):

1. Added `.stdin(std::process::Stdio::null())` - closes stdin so docker compose exec won't wait for input
2. Added `.env("COMPOSE_INTERACTIVE_NO_CLI", "1")` - tells Docker Compose to disable interactive mode

This should fix the hang in production builds. The script will now run in fully non-interactive mode regardless of whether it has a TTY.

* no docker
2025-10-28 10:09:03 +00:00
Britannio Jarrett
074199f2d2 rename cursor to cursor agent (vibe-kanban) (#1072)
* Done! I've successfully renamed "Cursor" to "Cursor Agent" throughout the codebase. The changes include:

- Renamed the Rust struct from `Cursor` to `CursorAgent` in [crates/executors/src/executors/cursor.rs](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/crates/executors/src/executors/cursor.rs)
- Updated the enum variant in [crates/executors/src/executors/mod.rs](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/crates/executors/src/executors/mod.rs) with proper serialization attributes
- Updated documentation in [docs/supported-coding-agents.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/docs/supported-coding-agents.mdx) and [docs/index.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/docs/index.mdx)
- Regenerated TypeScript types
- All type checks pass (frontend and backend)

The serialization still uses "CURSOR" for backwards compatibility, but the struct is now named `CursorAgent` in Rust, making it clear this refers to the Cursor Agent CLI tool.

* Perfect! All checks pass. The renaming is complete. The struct is now `CursorAgent` everywhere, serializing as `CURSOR_AGENT`.

* Perfect! Done. I've reverted all internal code changes and kept only the user-facing documentation updates:

**What remains changed (user-visible):**
- [docs/supported-coding-agents.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/docs/supported-coding-agents.mdx) - Title changed from "Cursor CLI" to "Cursor Agent CLI"
- [docs/index.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/docs/index.mdx) - "Cursor CLI" changed to "Cursor Agent CLI"

**What was reverted (internal, not user-visible):**
- All Rust struct/enum names back to `Cursor`
- All serialization formats back to `CURSOR`
- TypeScript types back to `CURSOR`
- JSON config files back to `CURSOR`

All checks pass 

* Perfect! Now users will see "CURSOR_AGENT" in the UI when selecting agents, while the code stays clean with the `Cursor` struct name, and documentation still says "Cursor CLI". All checks pass 

**What changed (user-visible in UI):**
- Agent selection dropdowns show "CURSOR_AGENT" instead of "CURSOR"
- JSON configs use "CURSOR_AGENT"
- MCP server documentation shows `cursor_agent` / `CURSOR_AGENT`

**What stayed the same:**
- Rust code uses `Cursor` struct name internally (clean code)
- User-facing documentation still says "Cursor CLI" (no doc changes needed)

* Perfect! Now it's backwards compatible. The `#[serde(alias = "CURSOR")]` attribute means:

 **Backwards Compatible:**
- Old configs with `"CURSOR"` will still deserialize correctly
- New configs with `"CURSOR_AGENT"` also work
- All serialization (saving configs) uses the new `"CURSOR_AGENT"` format

**Summary of changes:**
- Users see "CURSOR_AGENT" in the UI dropdown
- New configs are saved with "CURSOR_AGENT"
- Old configs with "CURSOR" continue to work
- Code internally still uses clean `Cursor` struct name
- All checks pass 

* Perfect!  Now it's fully backwards compatible:

**What works:**
-  Old configs with `"CURSOR"` deserialize correctly (via `alias`)
-  New configs with `"CURSOR_AGENT"` deserialize correctly
-  All new saves use `"CURSOR_AGENT"` (via `rename`)
-  The discriminant enum `BaseCodingAgent` also accepts both formats
-  Users see "CURSOR_AGENT" in the UI
-  All type checks pass

The `#[strum_discriminants(serde(rename = "CURSOR_AGENT", alias = "CURSOR"))]` ensures both the full enum AND the discriminant enum accept both old and new formats.

* Perfect!  Now `cursor_agent.json` exists and the Vite plugin will create the key `CURSOR_AGENT`, which matches what the frontend expects.

* cursor agent | fix (vibe-kanban 6594df22)

http://localhost:3044/api/task-attempts

This fails

Payload:
{"task_id":"18fdd148-5049-4772-9385-6d9196087524","executor_profile_id":{"executor":"CURSOR_AGENT","variant":null},"base_branch":"main"}

Response: Failed to deserialize the JSON body into the target type: executor_profile_id.executor: unknown executor 'CURSOR_AGENT' (normalized to 'CURSOR_AGENT') at line 1 column 98

Check the diff of this branch vs main to understand what we've been trying to do (users should see CURSOR_AGENT instead of CURSOR)

Server log:
[0] 2025-10-23T08:38:00.475636Z DEBUG server::routes::tasks: Creating task 'hey' in project f8c8d410-fd1b-48a4-829a-a6bf4b550a62

* rename CodingAgent::Cursor -> CodingAgent::CursorAgent

* update types
2025-10-27 10:24:53 +00:00
Solomon
30cfb07d3c cursor: parse thinking messages in the JSON logs (#1091)
* cursor: parse thinking messages in the JSON logs

* cursor: update log parsing

- update editTool and deleteTool
- add semSearch tool
2025-10-23 18:12:11 +01:00
Louis Knight-Webb
6fc7410b28 Next actions (#1082)
* Scaffold

* Create next action bar (vibe-kanban 1fd0bc9a)

There's a placeholder NextActionCard in frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx

- We should check for the diff summary frontend/src/hooks/useDiffSummary.ts
- If there is a diff, then render a summary box
- The summary box should contain:
  - The diff summary
  - Whether dev server is running for this task attempt
  - Controls to start, stop and view logs (in processes popup) for dev server frontend/src/hooks/useDevServer.ts
  - Button to open task attempt in IDE frontend/src/components/ide/OpenInIdeButton.tsx

* simplify error

* styles

* i18n

* hide dev server controls if no dev server configured

* tooltips

* fmt

* Feedback on next actions (vibe-kanban 7ff2f1b0)

frontend/src/components/NormalizedConversation/NextActionCard.tsx

- File changed and the +/- should be clickable and take you to diffs
- Tooltip for editor should say "See changes in VS Code" (or something that make it clearer that this opens the worktree)

* WIP failed variant for next action

* fail styling

* Create new attempt button (vibe-kanban 4ee265a2)

Please add a "create new attempt" button to frontend/src/components/NormalizedConversation/NextActionCard.tsx

This should be a text button "Try Again" and only show when failed = true

* Git actions dialog (vibe-kanban 328ec790)

frontend/src/components/tasks/Toolbar/GitOperations.tsx

I want these actions to be available in a dialog that's triggerable from:
- Dropdown menu in attempt header frontend/src/pages/project-tasks.tsx
- a new icon in frontend/src/components/NormalizedConversation/NextActionCard.tsx

* Change dev server (vibe-kanban 08df620f)

Instead of hiding if no dev script, show as disabled and change the tooltip to "To start the dev server, add a dev script to this project"

frontend/src/components/NormalizedConversation/NextActionCard.tsx

* i18n (vibe-kanban 0e07797b)

Look for any missing i18n strings in frontend/src/components/NormalizedConversation/NextActionCard.tsx and frontend/src/components/dialogs/tasks/GitActionsDialog.tsx

* Done! I've successfully fixed the i18n issues. The script `scripts/check-i18n.sh` was running correctly, but it was failing because there were missing translation keys in the non-English locales (Spanish, Japanese, and Korean). (#1093)

## What was fixed:

The script checks that all translation keys in the English locale file exist in all other locale files. There were 4 missing keys related to the new Git Actions feature:

1. `actionsMenu.gitActions`
2. `attempt.gitActions`
3. `git.actions.title`
4. `git.actions.prMerged`

I added appropriate translations for these keys to all three locale files:
- **Spanish (es)**: "Acciones de Git" and "PR #{{number}} ya está fusionado"
- **Japanese (ja)**: "Gitアクション" and "PR #{{number}} は既にマージされています"
- **Korean (ko)**: "Git 작업" and "PR #{{number}}은(는) 이미 병합되었습니다"

The i18n check now passes all three validation steps:
-  No new literal strings introduced
-  No duplicate keys found in JSON files
-  Translation keys are consistent across locales

* hide try again if more than 2 execution processes

---------

Co-authored-by: Alex Netsch <alex@bloop.ai>
2025-10-23 17:43:37 +01:00
Solomon
851678c30e fix: align sandbox and approval settings with codex for the "auto" preset (#1076)
Codex auto preset uses: sandbox=workspace-write and ask-for-approval=on-request.

Move AskForApproval docstrings to the enum level to fix the config form-builder selector.
2025-10-22 14:04:44 +01:00
Britannio Jarrett
7bca0b8d0c Done! Updated Amp version to 0.0.1761050239-g36fe88 in [crates/executors/src/executors/amp.rs](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/b0d4-bump-amp-to-0-0/crates/executors/src/executors/amp.rs#L36). (#1070) 2025-10-21 17:34:41 +01:00
Solomon
62834ea581 codex approvals (#993)
* codex approvals

* send deny feedback

* Normalize user-feedback

* use tool call id to match normalized_entry

* store approvals in executor

* add noop approval for api consistency

---------

Co-authored-by: Gabriel Gordon-Hall <ggordonhall@gmail.com>
2025-10-20 18:02:58 +01:00
Solomon
fbfe30c110 Bump OpenCode version to 0.15.8 (#1066) 2025-10-20 13:04:06 +01:00
Solomon
5cfc661219 fix: prevent loss of session and model info in long conversations (#1043)
* fix: prevent loss of session and model info in long conversations

* clippy
2025-10-20 10:53:37 +01:00
Solomon
e4a4c004da fix: handle whole assistant and thinking messages for Codex (#1036)
* fix: handle whole assistant and thinking messages for Codex

* fmt
2025-10-17 15:47:08 +01:00
Solomon
dfa8694d0d fix: auto-approve MCP server for Cursor CLI (#1028)
* fix: auto-approve MCP server for Cursor CLI

Cursor CLI requires interactive approval for enabling MCP server per directory. There is no direct cli flag to auto-approve in non-interactive mode.

* reslove symlinks
2025-10-17 15:46:54 +01:00
Gabriel Gordon-Hall
91d6209c24 bump claude (#1027) 2025-10-15 20:58:28 +01:00
Solomon
e95f6d1db1 Enable streaming message chunks in Claude-Code JSON output (#990)
* Enable streaming message chunks in claude-code JSON output

* pass test

refactor `normalize_entries` to return patches since we emit json-patch replace now.
2025-10-13 10:22:53 +01:00
Solomon
21876fddc1 Bump codex version to 0.46 (#981) 2025-10-09 12:18:39 +01:00
Gabriel Gordon-Hall
a584eda876 bump agent versions (#984) 2025-10-09 12:10:26 +01:00
Solomon
7c10c00d93 Upgrade Codex to the latest version (#947)
* Upgrade Codex to the latest version

Use the new `app-server` protocol to interact with codex cli.

* Fix spawn errors

* simplify session forking

* Append spawn errors to the logs
2025-10-07 14:57:41 +01:00
Alex Netsch
e863e2c8b9 No user deny messages in history (vibe-kanban) (#928)
* Perfect! The implementation is clean and follows the existing patterns. Let me create a summary:

I've successfully implemented the backend solution for displaying user denial messages in the conversation history.

**File: `crates/services/src/services/approvals.rs`**

1. **Added import** (line 8):
   - Imported `EntryIndexProvider` from `executors::logs::utils`

2. **Modified `respond()` method** (lines 153-166):
   - After updating the tool status to `Denied`
   - Check if the `ApprovalStatus::Denied` variant has a `Some(reason)`
   - If yes:
     - Create an `EntryIndexProvider` initialized from the message store to get the next available index
     - Create a `NormalizedEntry` with `UserMessage` type containing the denial reason
     - Add it to the conversation using `ConversationPatch::add_normalized_entry()`

1. **Backend owns the state**: The conversation history lives in `MsgStore` on the backend - this is the proper source of truth
2. **Follows existing patterns**: Uses the same pattern as Claude executor (claude.rs:508-527) for adding user messages
3. **Proper indexing**: `EntryIndexProvider::start_from(&store)` ensures correct sequence numbering
4. **No frontend hackery**: Frontend just renders what backend provides
5. **Type safe**: Uses existing `NormalizedEntryType::UserMessage` - no new types needed
6. **Clean separation**: Backend manages state, frontend displays it

When a user denies an approval with feedback like "Please try a different approach":
1. Backend receives the denial in `approvals.rs:respond()`
2. Updates the tool entry status to `Denied { reason }`
3. Immediately adds a new `UserMessage` entry with the denial text to the conversation stream
4. Frontend receives this as a normal user message patch and displays it
5. The agent sees it as a user message in the conversation history

-  TypeScript compilation passes
-  Rust compilation passes
-  No breaking changes
-  Follows existing architectural patterns

Cleanup script changes for task attempt 8122f303-889b-4333-8024-e79b9ea7dc7e

Great question! Let me explain how a new `UserFeedback` variant would work - it might actually be cleaner. Let me check what that would look like:

A new variant would mean:
1. Add `UserFeedback` to `NormalizedEntryType` enum in `crates/executors/src/logs/mod.rs`
2. Backend uses `NormalizedEntryType::UserFeedback` instead of `UserMessage`
3. Frontend displays it like a user message (same UI component)
4. No filtering issues - it's a distinct type that won't be filtered
5. TypeScript types auto-generated, so frontend gets the type

Let me show you what this would look like:

**Pros:**
- Type-safe, explicit intent
- No filtering workarounds needed
- Clear semantic meaning
- Auto-generates TypeScript types

**Cons:**
- Larger change (need to update Rust enum, regenerate types, update frontend display logic)
- Need to run `npm run generate-types`

Let me present both options clearly so you can choose:

Perfect! Both frontend and backend compile successfully. Let me create a summary of what was implemented:

I've successfully implemented **Option 2: New `UserFeedback` Variant** to display denial messages in the conversation history.

**1. Backend: Added `UserFeedback` entry type** (`crates/executors/src/logs/mod.rs`)
- Added `UserFeedback` variant to `NormalizedEntryType` enum
- Marked with `#[ts(export)]` for TypeScript generation

**2. Backend: Use `UserFeedback` for denial messages** (`crates/services/src/services/approvals.rs`)
- When a denial has a reason, create a `NormalizedEntry` with type `UserFeedback`
- Add it to the conversation stream after the denied tool
- Removed unused metadata structs (cleaner than Option 1)

**3. TypeScript Types: Regenerated** (`shared/types.ts`)
- Ran `npm run generate-types`
- New type `{ "type": "user_feedback" }` added to `NormalizedEntryType`

**4. Frontend: Display `UserFeedback` as user message** (`DisplayConversationEntry.tsx`)
- Check for both `user_message` and `user_feedback` types
- Render both with the same `<UserMessage>` component
- Use same User icon for both types

1. **No filtering issues**: `UserFeedback` is a distinct type, won't be filtered by the user message filter
2. **Type-safe**: Explicit enum variant with auto-generated TypeScript types
3. **Semantic clarity**: Clear distinction between initial prompts and feedback
4. **Natural display**: Appears as a user message in the conversation flow
5. **Extensible**: Can be used for other user feedback scenarios in the future

When a user denies an approval with feedback like "Please try a different approach":
1. Backend creates a `UserFeedback` entry with that text
2. Frontend receives it and displays it as a user message
3. It appears in the conversation history naturally, right after the denied tool
4. The agent sees it in the context as user input

-  Backend (Rust) compiles
-  Frontend (TypeScript) compiles
-  Types regenerated successfully
-  Clean, type-safe implementation

Perfect! So the tool result IS processed. But looking at the log entry you provided, the denial message appears in a `tool_result` with `is_error: true`. Let me check what tool this corresponds to:

Perfect! Both backend and frontend compile successfully. Let me create a summary of the complete solution:

I implemented a **normalization-based approach** that works with both live sessions and old logs by extracting denial reasons from the tool_result that's already in the raw logs.

**1. Added `UserFeedback` Entry Type** (`crates/executors/src/logs/mod.rs:56`)
- New variant in `NormalizedEntryType` enum
- Represents user feedback during execution (like denial reasons)
- Auto-exported to TypeScript types

**2. Added Denial Reason Extraction** (`crates/executors/src/executors/claude.rs:316-339`)
- New function `extract_denial_reason()` that parses hook denial messages
- Pattern: `"operation blocked by hook:\n- {user's reason}"`
- Extracts the text after `"- "`

**3. Create UserFeedback During Normalization** (`crates/executors/src/executors/claude.rs:598-612` and `717-731`)
- When processing tool_result with `is_error: true`
- Call `extract_denial_reason()` to check for denial pattern
- If found, create a `UserFeedback` entry with the extracted reason
- Add it right after the denied tool
- Applies to both command tools and other tools (MCP, etc.)

**4. Display UserFeedback in Frontend** (`frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx`)
- Handle `user_feedback` type same as `user_message`
- Display with `<UserMessage>` component
- Use User icon

**5. Cleaned Up Approvals Service** (`crates/services/src/services/approvals.rs`)
- Removed the live-session-only code that added UserFeedback
- Removed unused `EntryIndexProvider` import
- Let normalization handle everything

1. **Denial reason IS in raw logs**: The hook sends denial as tool_result with `is_error: true` containing the user's feedback
2. **Survives restarts**: Raw logs are persisted to DB, including the tool_result
3. **Works for old logs**: When logs are re-normalized after restart, the extraction logic runs and creates the UserFeedback entry
4. **Type-safe**: New enum variant with proper TypeScript types
5. **No filtering issues**: `UserFeedback` is a distinct type, won't be filtered out

-  Live sessions: Denial feedback appears as user message
-  After restart: Old logs show denial feedback when re-normalized
-  Type-safe: Proper enum variant, auto-generated TypeScript types
-  Both compilations pass

When a user denies a tool with feedback like "Please try a different approach", it now appears as a separate user message in the conversation history, immediately after the denied tool.

Cleanup script changes for task attempt 8122f303-889b-4333-8024-e79b9ea7dc7e

Perfect! Both backend and frontend compile successfully. Let me create a final summary of all the changes:

1.  **Duplicate code block removed** - Consolidated denial detection into one place after both command/non-command branches
2.  **Pattern matching improved** - Changed from `"operation blocked by hook:"` to `"blocked by hook:"` to match both "Edit operation blocked by hook" and "operation blocked by hook"
3.  **Magic strings replaced with constants** - Added `HOOK_DENIAL_PATTERN` and `HOOK_DENIAL_REASON_PREFIX` constants

**1. Added `UserFeedback` Entry Type** (`crates/executors/src/logs/mod.rs:56`)
- New variant in `NormalizedEntryType` enum for user feedback during execution

**2. Added Constants for Hook Patterns** (`crates/executors/src/executors/claude.rs:42-45`)
```rust
const HOOK_DENIAL_PATTERN: &str = "blocked by hook:";
const HOOK_DENIAL_REASON_PREFIX: &str = "- ";
```

**3. Added Denial Extraction Function** (`crates/executors/src/executors/claude.rs:321-345`)
- Detects hook denial messages in tool_result content
- Extracts user's reason from lines starting with `"- "`
- Uses constants for maintainability

**4. Create UserFeedback During Normalization** (`crates/executors/src/executors/claude.rs:703-717`)
- After processing any tool_result with `is_error: true`
- Extract denial reason and create `UserFeedback` entry
- Add it immediately after the denied tool
- **Single consolidated check** for both command and non-command tools

**5. Display UserFeedback in Frontend** (`frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx`)
- Handle `user_feedback` type same as `user_message`
- Display with `<UserMessage>` component
- Use User icon

**6. Regenerated TypeScript Types** (`shared/types.ts:287`)
- Added `{ "type": "user_feedback" }` to `NormalizedEntryType`

**7. Cleaned Up Approvals Service** (`crates/services/src/services/approvals.rs`)
- Removed unused live-session code
- Let normalization handle everything

1. **Works with old logs**: Denial reason is in persisted tool_result, extracted during re-normalization
2. **Works with live sessions**: Denial extracted during initial normalization
3. **No magic strings**: Uses constants for pattern matching
4. **No duplication**: Single denial check after tool processing
5. **Flexible pattern**: Matches "Edit operation blocked by hook" and "operation blocked by hook"
6. **Type-safe**: Proper enum variant with TypeScript types

-  Backend compiles
-  Frontend compiles
-  No duplicate code
-  Pattern improved to match your example

Cleanup script changes for task attempt 8122f303-889b-4333-8024-e79b9ea7dc7e

Perfect! Everything compiles. Let me create a summary of the final solution:

**1. Python Hook - Natural Language Marker** (`crates/executors/src/executors/hooks/confirm.py:14`)
- Prefix denial reason with `"User feedback: {reason}"`
- Natural language format that's both readable to LLM and parseable
- Example output: `"User feedback: Could you add something about a goose?"`

**2. Rust Constant** (`crates/executors/src/executors/claude.rs:44`)
```rust
const USER_FEEDBACK_MARKER: &str = "User feedback: ";
```

**3. Robust Extraction Function** (`crates/executors/src/executors/claude.rs:320-340`)
- Search for `USER_FEEDBACK_MARKER` in tool_result content
- Extract everything after the marker
- No dependency on Claude Code's error message format

**4. Added `UserFeedback` Entry Type** (`crates/executors/src/logs/mod.rs:56`)
- New variant for user feedback during execution

**5. Create UserFeedback During Normalization** (`crates/executors/src/executors/claude.rs:703-717`)
- When tool_result has `is_error: true`, check for user feedback
- Create `UserFeedback` entry with extracted text
- Works for both live sessions and old logs (persisted in raw logs)

**6. Frontend Display** (`frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx`)
- Render `user_feedback` same as `user_message`

1.  **We control the format**: The `"User feedback: "` prefix is added by OUR Python script
2.  **Claude Code independent**: Works regardless of how Claude Code formats hook errors
3.  **Natural language**: Reads naturally - LLM sees "User feedback: {reason}" which is clear
4.  **Survives restarts**: Tool_result is in persisted raw logs, re-extracted on normalization
5.  **Backward compatible**: Old logs without marker simply won't match (no errors)
6.  **Simple**: One constant, one natural prefix

**User denies with**: `"Could you add something about a goose?"`

**Raw log contains**:
```json
{"type":"tool_result","content":"Edit operation blocked by hook:\nUser feedback: Could you add something about a goose?","is_error":true}
```

**Extraction**: Finds `"User feedback: "`, extracts `"Could you add something about a goose?"`

**Display**: Shows as user message in conversation history

**Result**: User's feedback is visible to both user and LLM, survives restarts!

Perfect! The solution is complete. Let me create a final summary:

**Single Source of Truth:** The marker `"User feedback: "` is defined ONLY in Rust and injected into Python at runtime.

**1. Rust Constant** (`crates/executors/src/executors/claude.rs:44`)
```rust
const USER_FEEDBACK_MARKER: &str = "User feedback: ";
```

**2. Python Script Placeholder** (`crates/executors/src/executors/hooks/confirm.py:15-16`)
```python
USER_FEEDBACK_MARKER = "{{USER_FEEDBACK_MARKER}}"
formatted_reason = f"{USER_FEEDBACK_MARKER}{reason}" if reason else None
```

**3. Template Replacement** (`crates/executors/src/executors/claude.rs:241-244`)
```rust
let script_content = CONFIRM_HOOK_SCRIPT.replace(
    "{{USER_FEEDBACK_MARKER}}",
    USER_FEEDBACK_MARKER,
);
file.write_all(script_content.as_bytes()).await?;
```

**4. Extraction Function** (`crates/executors/src/executors/claude.rs:320-340`)
- Searches for `USER_FEEDBACK_MARKER` in tool_result content
- Extracts feedback text after the marker

**5. UserFeedback Entry Creation** (`crates/executors/src/executors/claude.rs:703-717`)
- During normalization, detects denials and creates UserFeedback entries

**6. Frontend Display** (`frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx`)
- Renders UserFeedback as user messages

**7. TypeScript Types** (`shared/types.ts`)
- `user_feedback` variant generated

**At deployment time:**
1. Rust defines `USER_FEEDBACK_MARKER = "User feedback: "`
2. Python script has placeholder `{{USER_FEEDBACK_MARKER}}`
3. When writing hook, Rust replaces `{{USER_FEEDBACK_MARKER}}` → `"User feedback: "`
4. Python script executes with actual value

**When user denies:**
1. Python outputs: `"User feedback: Could you add something about a goose?"`
2. This goes into tool_result in raw logs (persisted)
3. During normalization, Rust finds `"User feedback: "` and extracts the text after it
4. Creates UserFeedback entry
5. Frontend displays it as a user message

 **Single source of truth**: Marker defined only in Rust constant
 **No duplication**: Python gets value via template replacement
 **Format independent**: Works regardless of Claude Code's error format
 **Natural language**: LLM sees readable "User feedback: {text}"
 **Survives restarts**: Tool_result persisted in DB, re-extracted on normalization
 **Maintainable**: Change constant in one place, both Rust and Python updated

-  Backend compiles
-  Frontend compiles
-  Single source of truth maintained

Cleanup script changes for task attempt 8122f303-889b-4333-8024-e79b9ea7dc7e

Perfect! Everything compiles. Let me create a final summary:

**1. Backend: Added Tool Name to UserFeedback** (`crates/executors/src/logs/mod.rs:55-57`)
```rust
UserFeedback {
    denied_tool: String,
}
```

**2. Backend: Capture Display Tool Name** (`crates/executors/src/executors/claude.rs:573-589`)
- Extract tool name before processing branches
- For MCP tools, format as `mcp:server:tool` instead of `mcp__server__tool`
- Store in `display_tool_name` variable

**3. Backend: Include Tool Name in UserFeedback** (`crates/executors/src/executors/claude.rs:734-735`)
```rust
entry_type: NormalizedEntryType::UserFeedback {
    denied_tool: display_tool_name.clone(),
},
```

**4. Backend: Single Source of Truth for Marker** (`crates/executors/src/executors/claude.rs:44`)
```rust
const USER_FEEDBACK_MARKER: &str = "User feedback: ";
```

**5. Python: Placeholder Template** (`crates/executors/src/executors/hooks/confirm.py:15-16`)
```python
USER_FEEDBACK_MARKER = "{{USER_FEEDBACK_MARKER}}"
formatted_reason = f"{USER_FEEDBACK_MARKER}{reason}" if reason else None
```

**6. Backend: Template Replacement** (`crates/executors/src/executors/claude.rs:241-244`)
```rust
let script_content = CONFIRM_HOOK_SCRIPT.replace(
    "{{USER_FEEDBACK_MARKER}}",
    USER_FEEDBACK_MARKER,
);
```

**7. Frontend: Custom Red Accent Display** (`DisplayConversationEntry.tsx:648-666`)
- Red background (`bg-red-50 dark:bg-red-950/20`)
- Red border (`border-red-400/40`)
- Bold header showing: `"{ToolName} denied by user"`
- Red text for the feedback content
- **NO** edit/retry buttons (read-only display)

**8. TypeScript Types Regenerated** (`shared/types.ts`)
```typescript
{ "type": "user_feedback", denied_tool: string }
```

When user denies "Edit" tool with "Could you add something about a goose?":

```
┌─────────────────────────────────────────┐
│ Edit denied by user                     │  ← Bold red text
│ Could you add something about a goose?  │  ← Red feedback text
└─────────────────────────────────────────┘  ← Red border/background
```

 **Single source of truth**: Marker defined only in Rust, injected into Python
 **Tool name included**: Shows which tool was denied
 **Distinct styling**: Red accent makes it clear this is a denial
 **No edit/retry**: Simple read-only display, no complex user message features
 **Works with old logs**: Tool_result persisted, re-extracted on normalization
 **Type-safe**: Tool name field in enum, auto-generated TypeScript types

-  Backend compiles
-  Frontend compiles
-  Types regenerated
-  No duplication

Cleanup script changes for task attempt 8122f303-889b-4333-8024-e79b9ea7dc7e

Perfect! The new styling should be much more subtle and blend better with the existing UI:

- **Background**: Same as user messages (no bright red)
- **Border**: Dashed like user messages, with subtle red tint (30% opacity)
- **Header**: Small text (`text-xs`), muted red, 80% opacity
- **Content**: Same font-light styling as regular user messages

This keeps the denial feedback visible but not overwhelming, similar to how the regular user message integrates into the conversation flow.

Perfect! The new styling is much more subtle:

- **Background**: Same `bg-background` as user messages (no bright red)
- **Border**: Standard dashed border (no red tint)
- **Header**: Uses semantic `--destructive` color with 70% opacity for subtlety
- **Content**: Standard user message styling (no red text)

This approach:
-  Uses semantic CSS variables for proper dark mode support
-  Much less visually intense - just a subtle red label
-  Blends better with the conversation flow
-  The small "denied by user" label provides context without overwhelming

The visual hierarchy is now: subtle header hint → main content, which matches the rest of the UI better.

* Tool denial feedback (vibe-kanban 35abbc86)

The last commit implement log entries for tool denials, it has some problems though:
Update json_error in crates/executors/src/executors/hooks/confirm.py so the marker is only prefixed when an actual user denial reason is passed—fallback errors (network failure, invalid JSON, timeouts) must keep their original text to avoid generating fake user_feedback entries.
Adjust the hook deployment in write_python_hook (crates/executors/src/executors/claude.rs) to refresh existing confirm.py files when the bundled script changes: either always rewrite, compare hashes/timestamps, or at least overwrite when the placeholder is still present. Without that, previously installed hooks never get the marker update.
Refine extract_denial_reason in claude.rs to support the real payloads coming back from Claude: preserve multi-line feedback (don’t stop at the first newline) and handle array/object forms such as [{"type":"text","text":"…"}] so the full user message survives.

lets fix these!

* Clippy

* Perfect! All changes are complete. Here's the summary:

**1. Added i18n Hook** (`DisplayConversationEntry.tsx:603`)
```typescript
const { t } = useTranslation('common');
```

**2. Used Translation Key** (`DisplayConversationEntry.tsx:661`)
```typescript
{t('conversation.deniedByUser', { toolName: feedbackEntry.denied_tool })}
```

**3. Added English Translation** (`frontend/src/i18n/locales/en/common.json:38`)
```json
"deniedByUser": "{{toolName}} denied by user"
```

**4. Added Spanish Translation** (`frontend/src/i18n/locales/es/common.json:26`)
```json
"deniedByUser": "{{toolName}} denegado por el usuario"
```

**5. Added Japanese Translation** (`frontend/src/i18n/locales/ja/common.json:38`)
```json
"deniedByUser": "{{toolName}} がユーザーによって拒否されました"
```

**6. Used Semantic Color** (`DisplayConversationEntry.tsx:658-659`)
```typescript
style={{ color: 'hsl(var(--destructive))' }}
```

The UserFeedback display now:
-  Uses semantic `--destructive` color (adapts to light/dark mode automatically)
-  Supports i18n for English, Spanish, and Japanese
-  Subtle styling that blends with conversation flow
-  Maintains tool name context

The visual is now much more subtle with proper semantic colors and internationalization support!

* Perfect! Everything compiles. Let me create a summary of the final solution:

**1. Python: Added Argument Parser** (`confirm.py:96-102`)
```python
parser.add_argument(
    "-m",
    "--feedback-marker",
    type=str,
    required=True,
    help="Marker prefix for user feedback messages.",
)
```

**2. Python: Updated json_error to Accept Marker** (`confirm.py:11`)
```python
def json_error(reason: Optional[str], feedback_marker: Optional[str] = None) -> None:
    formatted_reason = reason
    if reason and feedback_marker:
        formatted_reason = f"{feedback_marker}{reason}"
```

**3. Python: Pass Marker When Denying** (`confirm.py:162`)
```python
json_error(reason, args.feedback_marker)
```

**4. Rust: Pass Marker as CLI Arg** (`claude.rs:283`)
```rust
format!("... --feedback-marker {}", shlex::try_quote(USER_FEEDBACK_MARKER)...)
```

**5. Rust: Removed String Replacement** (`claude.rs:236-238`)
- No longer need to replace placeholders
- Just write the script as-is

 **Cleaner**: No template placeholder magic, just a regular CLI arg
 **Standard**: Follows same pattern as other args (timeout, port, etc.)
 **Explicit**: Marker is passed explicitly each time hook runs
 **Flexible**: Easy to change or extend with more parameters
 **Single source of truth**: Still only defined in Rust constant

**Rust defines**:
```rust
const USER_FEEDBACK_MARKER: &str = "User feedback: ";
```

**Rust invokes Python with**:
```bash
confirm.py --timeout-seconds 3605 --poll-interval 5 --backend-port 8080 --feedback-marker "User feedback: "
```

**Python receives and uses**:
```python
args.feedback_marker  # "User feedback: "
formatted_reason = f"{args.feedback_marker}{reason}"
```

No template replacement needed - clean and straightforward!

Excellent! Everything compiles. The solution is now complete and much cleaner:

**Single Source of Truth:**
```rust
const USER_FEEDBACK_MARKER: &str = "User feedback: ";
```

**How it flows:**

1. **Rust → Python** (via CLI arg):
   ```bash
   confirm.py ... --feedback-marker 'User feedback: '
   ```

2. **User denies → Python formats**:
   ```python
   formatted_reason = f"User feedback: Could you add something about a goose?"
   ```

3. **Goes into raw logs → Rust extracts**:
   ```rust
   extract_denial_reason() // finds "User feedback: " and extracts what follows
   ```

4. **Creates UserFeedback entry**:
   ```rust
   NormalizedEntryType::UserFeedback {
       denied_tool: "Edit"
   }
   content: "Could you add something about a goose?"
   ```

5. **Frontend displays with red accent**:
   ```
   Edit denied by user          ← Small red text
   Could you add something about a goose?  ← Normal text
   ```

 **No string replacement** - just a CLI argument
 **No sketchy fallbacks** - simple, direct constant usage
 **Single source of truth** - marker only defined in Rust
 **Type-safe** - `denied_tool` field in enum
 **i18n support** - translatable display text
 **Semantic colors** - uses `--destructive` CSS variable
 **Works with old logs** - survives restarts via raw log persistence

The implementation is now straightforward with no unnecessary complexity!

* Simplify marker parsing
2025-10-06 15:38:18 +01:00
Solomon
2e0cabf9c7 Handle stderr output form Cursor cli (#948) 2025-10-06 15:26:46 +01:00
Louis Knight-Webb
613caf91d6 Perfect! The amp version has been successfully updated from 0.0.1758615753-ge2e2fb to 0.0.1759507289-g3e67fa in [crates/executors/src/executors/amp.rs](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/af80-bump-amp-version/crates/executors/src/executors/amp.rs#L36). This was the only file containing the amp version reference. (#929) 2025-10-03 18:52:30 +01:00
Solomon
a43fa76079 Copilot CLI (#915) 2025-10-03 13:12:53 +01:00
Solomon
0f835e9730 fix Gemini on windows (#912) 2025-10-02 18:09:19 +01:00
JonnyDB
eaf24bcb2a fix claude code rotuer version (#911)
2.0.49 is in not valid. 1.0.49 is. this is likely a minor typo
2025-10-02 09:39:17 +01:00
Alex Netsch
0e431705d0 Fix clear text watchkill phrase (#907) 2025-10-01 17:44:52 +01:00
Solomon
7217ab535b claude: Fork session on resume to enable retry (#899) 2025-10-01 15:13:48 +01:00
Britannio Jarrett
b77abac0c3 Use new sonnet models for the cursor agent profiles (#897)
* Updated cursor model from `sonnet-4` to `sonnet-4.5` in [`default_profiles.json`](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/a67d-update-cursor-ag/crates/executors/default_profiles.json#L92-L97), updated available models in [`cursor.json`](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/a67d-update-cursor-ag/shared/schemas/cursor.json#L22) schema, and [`cursor.rs`](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/a67d-update-cursor-ag/crates/executors/src/executors/cursor.rs#L39) documentation.

* Added `SONNET_4_5_THINKING` profile to [`default_profiles.json`](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/a67d-update-cursor-ag/crates/executors/default_profiles.json#L98-L103) for the `sonnet-4.5-thinking` model.
2025-10-01 09:15:16 +01:00
Gabriel Gordon-Hall
ce3c886ac9 bump claude code to 2.0.1 (#896) 2025-09-30 19:18:59 +01:00
Gabriel Gordon-Hall
4177a54d91 feat: default codex permissions (#886)
* add codex option

* update default codex configurations

* fix ci
2025-09-30 09:40:20 +01:00
Solomon
1c23d4fd11 use Gemini-CLI --experimental-acp (#784) 2025-09-25 19:36:08 +01:00
Louis Knight-Webb
fde7ae3efe Parse amp errors (vibe-kanban) (#852)
* ##  Implementation Complete!

I've successfully implemented the amp error parsing functionality. Here's a summary of what was accomplished:

### **Changes Made:**

1. **Extended ClaudeJson::Result** with amp-specific fields:
   - Added `error`, `num_turns`, `session_id` fields with proper serde aliases
   - Used `#[serde(default)]` for backward compatibility

2. **Updated normalize_entries method** to handle amp errors:
   - Only processes Result messages for `HistoryStrategy::AmpResume`
   - Detects errors through multiple criteria: `is_error`, subtype containing "error", error field presence, or result field containing error/message
   - Creates user-friendly ErrorMessage entries with timing and turn information
   - Preserves existing behavior for Claude Code (Default strategy)

3. **Updated extract_session_id** to handle Result messages:
   - Now extracts session_id from Result messages when present

4. **Added comprehensive tests**:
   - `test_amp_result_error_is_surfaced` - Tests the original error case from your example
   - `test_amp_result_error_with_subtype_only` - Tests subtype-only error detection
   - `test_amp_result_error_from_result_field` - Tests error extraction from result field
   - `test_amp_result_success_still_ignored` - Ensures success results remain ignored
   - `test_amp_result_session_id_extraction` - Tests session ID extraction
   - `test_claude_result_still_ignored_for_default_strategy` - Ensures Claude Code behavior unchanged

### **Example Output:**
When amp emits the error JSON you provided:
```json
{"type":"result","subtype":"error_during_execution","duration_ms":456090,"is_error":true,"num_turns":24,"error":"terminated","session_id":"T-efa72d99-3436-467b-a2d2-872546ad6f3c"}
```

It will now appear in the UI as:
> **AMP error (error_during_execution) after 24 turns / 456.1s: terminated**

The execution will correctly show as failed instead of "ended normally", and users will get clear information about what went wrong, how long it took, and how many turns were attempted.

* Cleanup script changes for task attempt daa967fc-b0a1-4c02-966f-ca3435e20a56

* Perfect!

##  Simplified Implementation Complete!

I've successfully simplified the error output as requested. Here's what changed:

### **Key Changes Made:**
1. **Simplified error content** - Now uses `serde_json::to_string(claude_json)` to JSON stringify the entire error object
2. **Removed complex formatting** - No more "AMP error (subtype) after X turns / Y.Ys: message" formatting
3. **Updated tests** - All test assertions now check for the raw JSON fields instead of formatted text
4. **Clean compilation** - Fixed unused variable warnings

### **Example Output:**
When amp emits the error JSON you provided:
```json
{"type":"result","subtype":"error_during_execution","duration_ms":456090,"is_error":true,"num_turns":24,"error":"terminated","session_id":"T-efa72d99-3436-467b-a2d2-872546ad6f3c"}
```

The UI will now show this exact JSON string as the error content, making it simple and giving users direct access to all the error information without interpretation.

### **Benefits:**
-  Simpler, cleaner output
-  No loss of information - all fields are preserved in the JSON
-  Maintains backward compatibility with Claude Code
-  All tests passing
-  Clean compilation with no warnings

The execution will still correctly show as failed instead of "ended normally", and the raw JSON error provides all the context users need to understand what went wrong.

* Cleanup script changes for task attempt daa967fc-b0a1-4c02-966f-ca3435e20a56

* Perfect!

##  Changes Complete!

I've made the requested modifications:

### **Changes Made:**

1. **Changed "AMP error" to "error"** in the fallback case:
   ```rust
   content: serde_json::to_string(claude_json)
       .unwrap_or_else(|_| "error".to_string()),
   ```

2. **Removed all amp result tests** that I added earlier:
   - `test_amp_result_error_is_surfaced`
   - `test_amp_result_error_with_subtype_only`
   - `test_amp_result_error_from_result_field`
   - `test_amp_result_success_still_ignored`
   - `test_amp_result_session_id_extraction`
   - `test_claude_result_still_ignored_for_default_strategy`

### **Final Implementation:**

The core functionality remains: when amp emits error result JSON logs like:
```json
{"type":"result","subtype":"error_during_execution","duration_ms":456090,"is_error":true,"num_turns":24,"error":"terminated","session_id":"T-efa72d99-3436-467b-a2d2-872546ad6f3c"}
```

This exact JSON string will be shown as the error content in the UI, and the execution will correctly be marked as failed instead of "ended normally".

The implementation is now minimal and clean, with only the original `test_result_message_ignored` test remaining to ensure Claude Code compatibility is preserved.

* Excellent!

##  Simplified Error Detection Complete!

I've updated the error detection logic to only trigger when `is_error: true`, making it much simpler and more explicit.

### **Changes Made:**

1. **Simplified error detection** - Now only checks `is_error.unwrap_or(false)`
2. **Removed complex error detection logic** that previously checked:
   - Subtype containing "error"
   - Error field presence/non-empty
   - Result field containing error/message objects
3. **Cleaned up unused variables** - Marked unused fields with `_`

### **Final Behavior:**

The implementation now only creates an ErrorMessage entry when:
- `HistoryStrategy::AmpResume` is used (amp execution)
- `is_error: true` in the JSON result

When your original error case occurs:
```json
{"type":"result","subtype":"error_during_execution","duration_ms":456090,"is_error":true,"num_turns":24,"error":"terminated","session_id":"T-efa72d99-3436-467b-a2d2-872546ad6f3c"}
```

This will be displayed as the raw JSON content since `is_error: true`, and the execution will be marked as failed.

The logic is now clean, explicit, and relies solely on amp's `is_error` flag to determine when to surface errors in the UI.
2025-09-25 17:55:34 +01:00
Louis Knight-Webb
018006c728 Claude code + API_KEY should be a red error message, too easy to miss (vibe-kanban) (#834)
* **Update**
- Escalated the unmanaged Claude key notice to an error so it now renders with the red error styling in the log stream (`crates/executors/src/executors/claude.rs:747`).
- Reworded the message to explicitly call out “Claude Code + ANTHROPIC_API_KEY…” and synced the unit test assertions with the new entry type and copy (`crates/executors/src/executors/claude.rs:1961`).

**Verification**
- `cargo test -p executors`

Next: 1) Give the UI a quick manual check to confirm the error card stands out as intended.

* Red warning copy now states that Anthropic pay-as-you-go billing is used instead of the user’s Claude subscription, while keeping the error styling (`crates/executors/src/executors/claude.rs:747`). Updated the corresponding unit test expectation to match the new text (`crates/executors/src/executors/claude.rs:1961`). Tests: `cargo test -p executors`. Suggested next step: manually confirm the UI wording reads clearly where it renders.
2025-09-24 11:41:16 +01:00
Gabriel Gordon-Hall
e773e418bd fix windows import compile error (#832) 2025-09-24 10:17:17 +01:00
Gabriel Gordon-Hall
794e2304a8 pin agents (#815) 2025-09-23 12:39:04 +01:00
Alex Netsch
40615190cd Check npm run generate-types in CI (vibe-kanban) (#807)
* Perfect! The implementation is now complete and working correctly.

 **Successfully implemented the requested feature**

The CI check for `npm run generate-types` now validates **all** generated files, not just `shared/types.ts`.

1. **Enhanced `crates/server/src/bin/generate_types.rs`**:
   - Added `generate_schema_content<T>()` helper function to generate schema content in-memory
   - Added `check_schemas()` function that validates all 7 JSON schema files
   - Updated the `--check` mode to validate both TypeScript types AND schema files

2. **Comprehensive validation**:
   - Checks `shared/types.ts` (existing functionality)
   - Checks all schema files: `amp.json`, `claude_code.json`, `codex.json`, `cursor.json`, `gemini.json`, `opencode.json`, `qwen_code.json`

3. **Clear error reporting**:
   - Shows exactly which files are outdated
   - Provides actionable error message: "Please run 'npm run generate-types' and commit the changes."

-  Passes when all files are up to date
-  Fails with exit code 1 when any file (types or schemas) is outdated
-  CI integration already in place (`.github/workflows/test.yml:66`)

The CI will now catch any case where developers modify Rust types that affect either TypeScript generation or JSON schema generation without running `npm run generate-types` and committing all resulting changes.

 **Successfully restored the lost cursor schema descriptions!**

1. **Added proper schemars attributes** to `crates/executors/src/executors/cursor.rs`:
   - `force` field: `#[schemars(description = "Force allow commands unless explicitly denied")]`
   - `model` field: `#[schemars(description = "auto, sonnet-4, gpt-5, opus-4.1, grok")]`

2. **Regenerated schema files** using `npm run generate-types`

3. **Verified the fix** - `shared/schemas/cursor.json` now contains the proper descriptions:
   - Line 15: `"description": "Force allow commands unless explicitly denied"`
   - Line 22: `"description": "auto, sonnet-4, gpt-5, opus-4.1, grok"`

- **Source-controlled**: Descriptions are now defined in Rust source code instead of auto-generated files
- **Future-proof**: Future schema regenerations will automatically include these descriptions
- **Proper architecture**: Follows the intended pattern of defining schema metadata in the source code
- **CI compatible**: The enhanced CI check will ensure these descriptions are preserved

The schema descriptions that were accidentally lost in the last commit have been properly restored to the correct location in the source code.

* clippy

* remove macro

* Surface error, remove unneede vec!
2025-09-23 09:15:16 +01:00
Gabriel Gordon-Hall
798bcb80a3 feat: manual approvals (#748)
* manual user approvals

* refactor implementation

* cleanup

* fix lint errors

* i18n

* remove isLastEntry frontend check

* address fe feedback

* always run claude plan with approvals

* add watchkill script back to plan mode

* update timeout

* tooltip hover

* use response type

* put back watchkill append hack
2025-09-22 16:02:42 +01:00
Louis Knight-Webb
510a7cb042 pin codex (#780) 2025-09-18 23:11:33 +01:00
Solomon
9810de7d00 Codex: remove ask-for-approval flag (#771) 2025-09-18 15:17:02 +01:00
Solomon
023e52e555 fix: codex session forking regression (#767)
fix OS issue `Failed to create forked rollout ... File name too long (os error 36)`
2025-09-17 19:15:13 +01:00
Solomon
2b69cbe447 Disable Edit & Retry feature for agents that don't implement session forking (#750) 2025-09-17 11:34:41 +01:00
Solomon
5f37bc258f Update codex to the latest (#724) 2025-09-17 10:03:25 +01:00
Louis Knight-Webb
c6407c64ac Print warning if not using anthropic subscription (#713)
* ##  Implementation Complete!

I've successfully implemented the warning system for Claude Code when `apiKeySource` is not "/login managed key". Here's what was implemented:

### **Changes Made:**

1. **Added `api_key_source` field to `ClaudeJson::System`**
   - Added `#[serde(default, rename = "apiKeySource")] api_key_source: Option<String>` field
   - Backward-compatible with existing JSON parsing

2. **Created warning helper function**
   - `warn_if_unmanaged_key()` function that generates warning entries when API key source is not managed
   - Includes both UI warning and server-side `tracing::warn!()` logging

3. **Modified system message processing**
   - Updated `normalize_entries()` to check API key source and emit warnings immediately
   - Warning appears for any `apiKeySource` value except "/login managed key" and `None`

4. **Added comprehensive test coverage**
   - Test for warning generation with unmanaged keys
   - Test for no warning with managed keys
   - Test for no warning when field is missing
   - All existing tests pass

### **Warning Message:**
```
⚠️  Using apiKeySource "ANTHROPIC_API_KEY" – calls will be billed to that key. Run `claude-code login` (or set `/login managed key`) if you want to route usage through the managed key.
```

### **Key Features:**
- **Immediate visibility**: Warning shows up immediately in the UI as a normalized system message
- **Server-side logging**: Also logs to server with `tracing::warn!()`
- **Backward compatible**: No breaking changes, works with existing implementations
- **Comprehensive**: Handles all cases (managed, unmanaged, missing field)
- **Actionable**: Provides clear guidance on how to fix the issue

The implementation is ready for production use!

* Cleanup script changes for task attempt 4345b766-b8ed-4949-aefb-32e20e891a01

* ##  Review Feedback Addressed!

I've successfully updated the implementation based on your review comments:

### **Changes Made:**

1. **Updated warning logic (Line 621)**
   - Changed from checking "not `/login managed key`" to specifically checking for `"ANTHROPIC_API_KEY"`
   - Now only warns when `apiKeySource` equals exactly `"ANTHROPIC_API_KEY"`
   - All other values (including `/login managed key`, missing field, or other keys) do not trigger warnings

2. **Updated warning message (Line 631)**
   - Changed from the generic billing warning to the specific message:
   - **New message:** `"ANTHROPIC_API_KEY env variable detected, your Anthropic subscription is not being used"`

3. **Updated tests to reflect new behavior**
   - Tests now verify warning only appears for `"ANTHROPIC_API_KEY"`
   - Tests confirm no warning for managed keys, other keys, or missing field
   - Validates exact warning message content

### **Final Behavior:**
-  **Warning shown**: When `apiKeySource` = `"ANTHROPIC_API_KEY"`
-  **No warning**: When `apiKeySource` = `"/login managed key"`
-  **No warning**: When `apiKeySource` = any other value
-  **No warning**: When `apiKeySource` field is missing

The implementation now specifically targets the `ANTHROPIC_API_KEY` environment variable scenario and provides a clear, focused warning message about Anthropic subscription usage.

* Cleanup script changes for task attempt 4345b766-b8ed-4949-aefb-32e20e891a01

* ##  Warning Triangle Added!

I've successfully added the warning triangle (⚠️) to the warning message as requested.

### **Final Warning Message:**
```
⚠️ ANTHROPIC_API_KEY env variable detected, your Anthropic subscription is not being used
```

### **Changes Made:**
- **Line 628**: Added `⚠️` to the warning message content
- **Updated test**: Modified the test assertion to expect the warning triangle in the message

The warning now has a clear visual indicator (⚠️) that makes it more noticeable to users when the `ANTHROPIC_API_KEY` environment variable is being used instead of their Anthropic subscription through Claude Code.

The implementation is complete and ready for production use!
2025-09-15 13:07:32 +01:00
Solomon
d31cca537a Temporarily revert "Update codex to the latest (#700)" (#702)
This reverts commit 248728e756.
2025-09-12 19:10:12 +01:00
Solomon
248728e756 Update codex to the latest (#700) 2025-09-12 18:17:59 +01:00
Louis Knight-Webb
15dddacfe2 Improve performance of conversation (#692)
* Stream endpoint for execution processes (vibe-kanban c5144da6)

I want an endpoint that's similar to task stream in crates/server/src/routes/tasks.rs but contains execution processes.

The structure of the document should be:

```json
{
    "execution_processes": {
        [EXECUTION_PROCESS_ID]: {
            ... execution process fields
        }
    }
}
```

The endpoint should be at `/api/execution_processes/stream?task_attempt_id=...`

crates/server/src/routes/execution_processes.rs

* add virtualizedlist component

* WIP remove execution processes

* rebase syntax fix

* tmp fix lint

* lint

* VirtuosoMessageList

* cache

* event based hook

* historic

* handle failed historic

* running processes

* user message

* loading

* cleanup

* render user message

* style

* fmt

* better indication for setup/cleanup scripts

* fix ref issue

* virtuoso license

* fmt

* update loader

* loading

* fmt

* loading improvements

* copy as markdown styles

* spacing improvement

* flush all historic at once

* padding fix

* markdown copy sticky

* make user message editable

* edit message

* reset

* cleanup

* hook order

* remove dead code
2025-09-12 18:09:14 +01:00
Gabriel Gordon-Hall
a086f82dfa feat: support Codex --full-auto mode (#664)
* make codex --full-auto mode default

* change codex high to auto mode
2025-09-11 16:40:01 +01:00
Solomon
e2b2dd1081 Add model config for claude-code (#685) 2025-09-11 11:26:54 +01:00
Solomon
89beac2dae Collect richer logs from opencode (#655) 2025-09-10 13:14:07 +01:00