Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"name": "warp",
"description": "Native Warp notifications when Claude completes tasks or needs input",
"source": "./plugins/warp",
"version": "2.2.0",
"version": "2.3.0",
"category": "productivity",
"tags": ["notifications", "terminal", "warp"]
},
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Official [Warp](https://warp.dev) terminal integration for [Claude Code](https:/

Get native Warp notifications when Claude Code:
- **Completes a task** — with a summary showing your prompt and Claude's response
- **Needs your input** — when Claude has been idle and is waiting for you
- **Needs your input** — when Claude is waiting for you, including background agents
- **Requests permission** — when Claude wants to run a tool and needs your approval

Notifications appear in Warp's notification center and as system notifications, so you can context-switch while Claude works and get alerted when attention is needed.
Expand Down Expand Up @@ -47,10 +47,10 @@ The plugin communicates with Warp via OSC 777 escape sequences. Each hook script

Payloads include a protocol version negotiated between the plugin and Warp (`min(plugin_version, warp_version)`), the session ID, working directory, and event-specific fields.

The plugin registers six hooks:
The plugin registers lifecycle hooks including:
- **SessionStart** — emits the plugin version and a welcome system message
- **Stop** — reads the transcript to extract your prompt and Claude's response, then sends a task-complete notification
- **Notification** (`idle_prompt`) — fires when Claude has been idle and needs your input
- **Notification** (`idle_prompt`, `agent_needs_input`) — fires when Claude is waiting for user input
- **PermissionRequest** — fires when Claude wants to run a tool, includes the tool name and a preview of its input
- **UserPromptSubmit** — fires when you submit a prompt, signaling the session is active again
- **PostToolUse** — fires when a tool call completes, signaling the session is no longer blocked
Expand Down
2 changes: 1 addition & 1 deletion plugins/warp/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "warp",
"description": "Warp terminal integration for Claude Code - native notifications, and more to come",
"version": "2.2.0",
"version": "2.3.0",
"author": {
"name": "Warp",
"url": "https://warp.dev"
Expand Down
2 changes: 1 addition & 1 deletion plugins/warp/hooks/hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
],
"Notification": [
{
"matcher": "idle_prompt",
"matcher": "idle_prompt|agent_needs_input",
"hooks": [
{
"type": "command",
Expand Down
7 changes: 5 additions & 2 deletions plugins/warp/scripts/on-notification.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash
# Hook script for Claude Code Notification event (idle_prompt only)
# Sends a structured Warp notification when Claude has been idle
# Hook script for Claude Code Notification event (idle_prompt and agent_needs_input)
# Sends a structured Warp notification when Claude has been idle or needs input

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/should-use-structured.sh"
Expand All @@ -20,6 +20,9 @@ INPUT=$(cat)
NOTIF_TYPE=$(echo "$INPUT" | jq -r '.notification_type // "unknown"' 2>/dev/null)
MSG=$(echo "$INPUT" | jq -r '.message // "Input needed"' 2>/dev/null)
[ -z "$MSG" ] && MSG="Input needed"
if [ ${#MSG} -gt 120 ]; then
MSG="${MSG:0:117}..."
fi

BODY=$(build_payload "$INPUT" "$NOTIF_TYPE" \
--arg summary "$MSG")
Expand Down
22 changes: 22 additions & 0 deletions plugins/warp/tests/test-hooks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../scripts" && pwd)"
source "$SCRIPT_DIR/build-payload.sh"
PLUGIN_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
REPO_DIR="$(cd "$PLUGIN_DIR/../.." && pwd)"

PASSED=0
FAILED=0
Expand Down Expand Up @@ -47,6 +49,20 @@ assert_json_field() {

# --- Tests ---

echo "=== plugin configuration ==="

PLUGIN_VERSION=$(jq -r '.version' "$PLUGIN_DIR/.claude-plugin/plugin.json")
MARKETPLACE_VERSION=$(jq -r '.plugins[] | select(.name == "warp") | .version' \
"$REPO_DIR/.claude-plugin/marketplace.json")
NOTIFICATION_MATCHER=$(jq -r '.hooks.Notification[0].matcher' "$PLUGIN_DIR/hooks/hooks.json")

assert_eq "plugin version bumped" "2.3.0" "$PLUGIN_VERSION"
assert_eq "marketplace version matches plugin" "$PLUGIN_VERSION" "$MARKETPLACE_VERSION"
assert_eq "notification matcher includes input-required events" \
"idle_prompt|agent_needs_input" \
"$NOTIFICATION_MATCHER"

echo ""
echo "=== build-payload.sh ==="

echo ""
Expand Down Expand Up @@ -103,6 +119,12 @@ PAYLOAD=$(build_payload '{"session_id":"s1","cwd":"/tmp/proj","notification_type
--arg summary "Claude is waiting for your input")
assert_json_field "event is idle_prompt" "$PAYLOAD" ".event" "idle_prompt"
assert_json_field "summary present" "$PAYLOAD" ".summary" "Claude is waiting for your input"
echo ""
echo "--- Agent needs input event ---"
PAYLOAD=$(build_payload '{"session_id":"s1","cwd":"/tmp/proj","notification_type":"agent_needs_input"}' "agent_needs_input" \
--arg summary "Agent requires user input")
assert_json_field "event is agent_needs_input" "$PAYLOAD" ".event" "agent_needs_input"
assert_json_field "generic summary present" "$PAYLOAD" ".summary" "Agent requires user input"

echo ""
echo "--- JSON special characters in values ---"
Expand Down
Loading