diff --git a/Makefile b/Makefile index 0e18ae511f..53dd7636f3 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ fmt: ## Format code with Prettier fmt-check: ## Check code formatting @echo "Checking TypeScript/JSON/Markdown formatting..." - @bun x prettier --check $(PRETTIER_PATTERNS) 2>&1 | grep -v 'No files matching' + @bun x prettier --check $(PRETTIER_PATTERNS) fmt-shell: ## Format shell scripts with shfmt @./scripts/fmt.sh --shell diff --git a/docs/context-management.md b/docs/context-management.md index 38e1fbf657..f8d09f0938 100644 --- a/docs/context-management.md +++ b/docs/context-management.md @@ -4,12 +4,23 @@ Commands for managing conversation history length and token usage. ## Comparison -| Feature | `/clear` | `/truncate` | `/compact` | -| ------------------------ | -------- | ----------- | ---------------- | -| **Speed** | Instant | Instant | Slower (uses AI) | -| **Context Preservation** | None | Temporal | Intelligent | -| **Cost** | Free | Free | Uses API tokens | -| **Reversible** | No | No | No | +| Approach | `/clear` | `/truncate` | `/compact` | Plan Compaction | +| ------------------------ | -------- | ----------- | ---------------- | --------------- | +| **Speed** | Instant | Instant | Slower (uses AI) | Instant | +| **Context Preservation** | None | Temporal | Intelligent | Intelligent | +| **Cost** | Free | Free | Uses API tokens | Free | +| **Reversible** | No | No | No | Yes | + +## Plan Compaction + +If you've produced a plan, you can opportunistically click "Compact Here" on the plan to use it +as the entire conversation history. This operation is instant as all of the LLM's work was already +done when it created the plan. + +![Plan Compaction](./img/plan-compact.webp) + +This is a form of "opportunistic compaction" and is special in that you can review the post-compact +context before the old context is permanently removed. ## `/clear` - Clear All History diff --git a/docs/img/plan-compact.webp b/docs/img/plan-compact.webp new file mode 100644 index 0000000000..e848b7f601 Binary files /dev/null and b/docs/img/plan-compact.webp differ diff --git a/docs/vim-mode.md b/docs/vim-mode.md index 82eb89a3b8..6161f66d93 100644 --- a/docs/vim-mode.md +++ b/docs/vim-mode.md @@ -48,7 +48,7 @@ Vim mode is always enabled. Press **ESC** to enter normal mode from insert mode. ### Line Movement - **0** - Move to beginning of line -- **_** - Move to first non-whitespace character of line +- **\_** - Move to first non-whitespace character of line - **$** - Move to end of line - **Home** - Same as **0** - **End** - Same as **$** @@ -102,7 +102,7 @@ Vim's power comes from combining operators with motions. All operators work with - **e** - To end of word - **$** - To end of line - **0** - To beginning of line -- **_** - To first non-whitespace character +- **\_** - To first non-whitespace character ### Examples diff --git a/scripts/quick-cp-screenshot.sh b/scripts/quick-cp-screenshot.sh new file mode 100755 index 0000000000..fee2151474 --- /dev/null +++ b/scripts/quick-cp-screenshot.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Check if filename argument is provided +if [ -z "$1" ]; then + echo "Usage: $0 " + echo "Example: $0 command-palette" + echo "" + echo "This will find the latest screenshot, convert it to WebP, and save as docs/img/.webp" + exit 1 +fi + +FILENAME="$1" + +# Remove .webp or .png extension if provided +FILENAME="${FILENAME%.webp}" +FILENAME="${FILENAME%.png}" + +# Find the latest screenshot - check custom location first, then Desktop +LATEST_SCREENSHOT=$(ls -t ~/Documents/Screenshots/Screen*.png ~/Desktop/Screen*.png 2>/dev/null | head -1) + +if [ -z "$LATEST_SCREENSHOT" ]; then + echo "❌ Error: No screenshots found in ~/Documents/Screenshots/ or ~/Desktop/" + exit 1 +fi + +echo "Found screenshot: $LATEST_SCREENSHOT" + +# Ensure docs/img directory exists +mkdir -p "$PROJECT_ROOT/docs/img" + +OUTPUT_FILE="$PROJECT_ROOT/docs/img/$FILENAME.webp" + +# Convert PNG to WebP using cwebp (as suggested by lint) +echo "Converting to WebP..." +if ! command -v cwebp &> /dev/null; then + echo "❌ Error: cwebp not found. Install with: brew install webp" + exit 1 +fi + +cwebp "$LATEST_SCREENSHOT" -o "$OUTPUT_FILE" -q 85 + +# Remove the original screenshot +rm "$LATEST_SCREENSHOT" + +echo "✅ Screenshot saved as: docs/img/$FILENAME.webp" +echo " Original screenshot removed" diff --git a/src/components/tools/ProposePlanToolCall.tsx b/src/components/tools/ProposePlanToolCall.tsx index 9f0b5f6de8..3629dfbba9 100644 --- a/src/components/tools/ProposePlanToolCall.tsx +++ b/src/components/tools/ProposePlanToolCall.tsx @@ -273,7 +273,7 @@ export const ProposePlanToolCall: React.FC = ({ // Create a compacted message with the plan content // Format: Title as H1 + plan content const compactedContent = `# ${args.title}\n\n${args.plan}`; - + const summaryMessage = createCmuxMessage( `compact-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`, "assistant", @@ -285,7 +285,7 @@ export const ProposePlanToolCall: React.FC = ({ ); const result = await window.api.workspace.replaceChatHistory(workspaceId, summaryMessage); - + if (!result.success) { console.error("Failed to compact:", result.error); } diff --git a/src/utils/vim.test.ts b/src/utils/vim.test.ts index 50cc497420..305f99de3e 100644 --- a/src/utils/vim.test.ts +++ b/src/utils/vim.test.ts @@ -515,4 +515,3 @@ describe("Vim Command Integration Tests", () => { }); }); }); - diff --git a/src/utils/vim.ts b/src/utils/vim.ts index 1aba43a54f..7378ac59b8 100644 --- a/src/utils/vim.ts +++ b/src/utils/vim.ts @@ -103,7 +103,6 @@ export function moveToFirstNonWhitespace(text: string, cursor: number): number { return i >= lineEnd ? lineStart : i; } - /** * Move cursor vertically by delta lines, maintaining desiredColumn if provided. */ @@ -743,7 +742,10 @@ function tryHandleNavigation(state: VimState, key: string): VimKeyResult | null } case "_": - return handleKey(state, { cursor: moveToFirstNonWhitespace(text, cursor), desiredColumn: null }); + return handleKey(state, { + cursor: moveToFirstNonWhitespace(text, cursor), + desiredColumn: null, + }); case "$": case "End": {