Skip to content

Commit e0dfd4c

Browse files
committed
docs: document affectedFiles and diff support in code review skill
- Add affectedFiles payload guide with status types and unified diff format - Show how to generate diffs with git diff before submitting for review - Add test-code-review.sh covering all file statuses and diff rendering
1 parent 7524a9d commit e0dfd4c

2 files changed

Lines changed: 145 additions & 2 deletions

File tree

skills/clawui-code/SKILL.md

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ description: Use this skill when you want to run a shell command that could be d
55

66
# ClawUI Code Review
77

8-
Before running risky shell commands, get user approval via this skill.
8+
Before running risky shell commands, get user approval via this skill. You can also show the user exactly which files will change and what the diff looks like.
99

1010
## Step 1: Submit the command for review
1111

12+
### Basic (file list only)
13+
1214
```bash
1315
RESPONSE=$(curl -s -X POST http://host.docker.internal:3001/api/review \
1416
-H "Content-Type: application/json" \
@@ -25,7 +27,67 @@ RESPONSE=$(curl -s -X POST http://host.docker.internal:3001/api/review \
2527
echo "$RESPONSE"
2628
```
2729

28-
`files` is optional — list the files this command will affect, shown as a file tree in the UI.
30+
`files` is the legacy form — a plain list of affected paths shown as a file tree. Use `affectedFiles` (below) when you can provide diffs.
31+
32+
### With diffs (recommended)
33+
34+
Use `affectedFiles` instead of `files` to show the user exactly what will change. Each entry includes the file path, change type, and an optional unified diff.
35+
36+
```bash
37+
RESPONSE=$(curl -s -X POST http://host.docker.internal:3001/api/review \
38+
-H "Content-Type: application/json" \
39+
-d '{
40+
"type": "code_review",
41+
"payload": {
42+
"command": "git apply feature.patch",
43+
"cwd": "/project",
44+
"explanation": "Applies the feature patch: adds a retry helper and updates the API client to use it.",
45+
"risk": "medium",
46+
"affectedFiles": [
47+
{
48+
"path": "src/utils/retry.ts",
49+
"status": "added",
50+
"diff": "@@ -0,0 +1,12 @@\n+export async function retry<T>(fn: () => Promise<T>, times = 3): Promise<T> {\n+ let last: unknown\n+ for (let i = 0; i < times; i++) {\n+ try { return await fn() } catch (e) { last = e }\n+ }\n+ throw last\n+}"
51+
},
52+
{
53+
"path": "src/api/client.ts",
54+
"status": "modified",
55+
"diff": "@@ -1,8 +1,9 @@\n import axios from 'axios'\n+import { retry } from '../utils/retry'\n \n export async function fetchUser(id: string) {\n- return axios.get(`/users/${id}`)\n+ return retry(() => axios.get(`/users/${id}`))\n }"
56+
},
57+
{
58+
"path": "src/api/legacyClient.ts",
59+
"status": "deleted",
60+
"diff": "@@ -1,5 +0,0 @@\n-// deprecated — use client.ts\n-import axios from 'axios'\n-export const get = (url: string) => axios.get(url)"
61+
}
62+
]
63+
}
64+
}')
65+
echo "$RESPONSE"
66+
```
67+
68+
#### `affectedFiles` entry fields
69+
70+
| Field | Required | Description |
71+
|-------|----------|-------------|
72+
| `path` | yes | File path relative to `cwd` |
73+
| `status` | yes | `"added"` \| `"modified"` \| `"deleted"` \| `"renamed"` |
74+
| `diff` | no | Unified diff string (shown as GitHub-style diff in the UI) |
75+
| `oldPath` | no | Previous path, only for `"renamed"` files |
76+
77+
#### How to generate the diff string
78+
79+
```bash
80+
# For a patch you're about to apply:
81+
git diff --unified=3 HEAD -- src/api/client.ts
82+
83+
# For staged changes:
84+
git diff --cached --unified=3
85+
86+
# For a specific commit:
87+
git show abc123 --unified=3 -- src/utils/retry.ts
88+
```
89+
90+
Escape the output as a JSON string (replace newlines with `\n`) before embedding in the payload.
2991

3092
Save the `sessionId` from the response.
3193

test-code-review.sh

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/bin/bash
2+
# Test AgentClick code review — mind-map file tree + diff viewer
3+
4+
AGENTCLICK_URL="http://localhost:3001"
5+
6+
echo "Creating code review session..."
7+
8+
SESSION_PAYLOAD='{
9+
"type": "code_review",
10+
"sessionKey": "main-session",
11+
"payload": {
12+
"command": "git apply feature/retry-client.patch",
13+
"cwd": "/project/src",
14+
"explanation": "Introduces a generic retry helper and updates the API client to use it. Removes the deprecated legacy client module.",
15+
"risk": "medium",
16+
"affectedFiles": [
17+
{
18+
"path": "src/utils/retry.ts",
19+
"status": "added",
20+
"diff": "@@ -0,0 +1,14 @@\n+/**\n+ * Retries an async function up to `times` attempts.\n+ */\n+export async function retry<T>(\n+ fn: () => Promise<T>,\n+ times = 3,\n+ delayMs = 200,\n+): Promise<T> {\n+ let last: unknown\n+ for (let i = 0; i < times; i++) {\n+ try { return await fn() } catch (e) { last = e }\n+ if (i < times - 1) await new Promise(r => setTimeout(r, delayMs))\n+ }\n+ throw last\n+}"
21+
},
22+
{
23+
"path": "src/api/client.ts",
24+
"status": "modified",
25+
"diff": "@@ -1,10 +1,11 @@\n import axios from 'axios'\n+import { retry } from '../utils/retry'\n \n-export async function fetchUser(id: string) {\n- return axios.get(`/users/${id}`)\n+export async function fetchUser(id: string) {\n+ return retry(() => axios.get(`/users/${id}`))\n }\n \n-export async function updateUser(id: string, data: object) {\n- return axios.put(`/users/${id}`, data)\n+export async function updateUser(id: string, data: object) {\n+ return retry(() => axios.put(`/users/${id}`, data))\n }"
26+
},
27+
{
28+
"path": "src/api/legacyClient.ts",
29+
"status": "deleted",
30+
"diff": "@@ -1,7 +0,0 @@\n-// Deprecated — use client.ts\n-import axios from 'axios'\n-\n-export const get = (url: string) => axios.get(url)\n-export const post = (url: string, body: object) => axios.post(url, body)\n-export const del = (url: string) => axios.delete(url)"
31+
},
32+
{
33+
"path": "src/api/index.ts",
34+
"status": "renamed",
35+
"oldPath": "src/api/exports.ts",
36+
"diff": "@@ -1,3 +1,3 @@\n-export * from '\''./legacyClient'\''\n+export * from '\''./client'\''\n export * from '\''./types'\''"
37+
},
38+
{
39+
"path": "src/config/constants.ts",
40+
"status": "modified"
41+
},
42+
{
43+
"path": "tests/api/client.test.ts",
44+
"status": "added"
45+
}
46+
]
47+
}
48+
}'
49+
50+
RESPONSE=$(curl -s -X POST "$AGENTCLICK_URL/api/review" \
51+
-H "Content-Type: application/json" \
52+
-d "$SESSION_PAYLOAD")
53+
54+
SESSION_ID=$(echo "$RESPONSE" | grep -o '"sessionId":"[^"]*"' | cut -d'"' -f4)
55+
URL=$(echo "$RESPONSE" | grep -o '"url":"[^"]*"' | cut -d'"' -f4)
56+
57+
if [ -z "$SESSION_ID" ]; then
58+
echo "❌ Failed to create session. Is AgentClick running?"
59+
echo " Start it with: npm run dev"
60+
echo " Response: $RESPONSE"
61+
exit 1
62+
fi
63+
64+
echo ""
65+
echo "✅ Code review session created!"
66+
echo " Session ID: $SESSION_ID"
67+
echo " Review URL: $URL"
68+
echo ""
69+
echo "What to check in the UI:"
70+
echo " • Mind-map file tree — pills connected by spine + arms"
71+
echo " • src/ directory auto-expanded (all files are on-path)"
72+
echo " • Diffs shown below the tree for 4 files"
73+
echo " • Added file (retry.ts) → green pill"
74+
echo " • Modified files → blue pill"
75+
echo " • Deleted file → red pill"
76+
echo " • Renamed file → amber pill with '← exports.ts'"
77+
echo " • Two entries without diffs (constants.ts, client.test.ts) show in tree only"
78+
echo ""
79+
80+
# Open browser (macOS)
81+
open "$URL" 2>/dev/null || echo "Open in browser: $URL"

0 commit comments

Comments
 (0)