create-screenfix 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/python/screenfix/annotation_window.py +2 -2
- package/python/screenfix/mcp_server.py +7 -169
- package/templates/commands/screenfix-list-tasks.md +5 -3
- package/templates/commands/screenfix-start.md +1 -1
- package/templates/commands/screenfix-status.md +1 -1
- package/templates/commands/screenfix-tasks-next.md +6 -5
- package/templates/commands/screenfix-tasks-yolo.md +5 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-screenfix",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Screenshot capture tool for Claude Code via MCP",
|
|
5
5
|
"bin": {
|
|
6
6
|
"create-screenfix": "./bin/create-screenfix.js"
|
|
@@ -26,8 +26,9 @@
|
|
|
26
26
|
],
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|
|
29
|
-
"url": "https://github.com/
|
|
29
|
+
"url": "https://github.com/sukhdeepbangar/screenfix.git"
|
|
30
30
|
},
|
|
31
|
+
"homepage": "https://sukhdeepbangar.github.io/screenfix",
|
|
31
32
|
"license": "MIT",
|
|
32
33
|
"dependencies": {
|
|
33
34
|
"commander": "^11.0.0"
|
|
@@ -38,7 +38,7 @@ _current_controller = None
|
|
|
38
38
|
|
|
39
39
|
def save_screenshot(temp_path: str) -> str:
|
|
40
40
|
"""Save screenshot from temp location to final location."""
|
|
41
|
-
save_dir = Path(config.save_directory)
|
|
41
|
+
save_dir = Path(config.save_directory).resolve() # Absolute path
|
|
42
42
|
save_dir.mkdir(parents=True, exist_ok=True)
|
|
43
43
|
|
|
44
44
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
@@ -46,7 +46,7 @@ def save_screenshot(temp_path: str) -> str:
|
|
|
46
46
|
final_path = save_dir / filename
|
|
47
47
|
|
|
48
48
|
shutil.move(temp_path, final_path)
|
|
49
|
-
return str(final_path)
|
|
49
|
+
return str(final_path) # Returns absolute path
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def cleanup_temp_file(temp_path: str):
|
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
"""MCP server for ScreenFix."""
|
|
1
|
+
"""MCP server for ScreenFix - daemon control only."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
import base64
|
|
5
4
|
import json
|
|
6
5
|
import os
|
|
7
6
|
import subprocess
|
|
8
7
|
import sys
|
|
9
8
|
import time
|
|
10
9
|
from pathlib import Path
|
|
11
|
-
from typing import Any
|
|
12
10
|
|
|
13
11
|
from mcp.server import Server
|
|
14
12
|
from mcp.server.stdio import stdio_server
|
|
15
|
-
from mcp.types import Tool, TextContent
|
|
16
|
-
|
|
17
|
-
from .config import config
|
|
18
|
-
from .task_tracker import get_tasks, get_pending_tasks, mark_task_complete
|
|
13
|
+
from mcp.types import Tool, TextContent
|
|
19
14
|
|
|
20
15
|
|
|
21
16
|
STATE_FILE = Path.home() / ".config" / "screenfix" / "state.json"
|
|
@@ -45,30 +40,6 @@ def get_daemon_state() -> dict:
|
|
|
45
40
|
return {"running": False, "listening": False}
|
|
46
41
|
|
|
47
42
|
|
|
48
|
-
def get_screenshots() -> list[dict]:
|
|
49
|
-
"""Get list of screenshots."""
|
|
50
|
-
save_dir = Path(config.save_directory)
|
|
51
|
-
if not save_dir.exists():
|
|
52
|
-
return []
|
|
53
|
-
|
|
54
|
-
screenshots = []
|
|
55
|
-
for f in save_dir.glob("*.png"):
|
|
56
|
-
screenshots.append({
|
|
57
|
-
"path": str(f),
|
|
58
|
-
"filename": f.name,
|
|
59
|
-
"modified": f.stat().st_mtime,
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
screenshots.sort(key=lambda x: x["modified"], reverse=True)
|
|
63
|
-
return screenshots
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def get_last_screenshot() -> dict | None:
|
|
67
|
-
"""Get the most recent screenshot."""
|
|
68
|
-
screenshots = get_screenshots()
|
|
69
|
-
return screenshots[0] if screenshots else None
|
|
70
|
-
|
|
71
|
-
|
|
72
43
|
def start_daemon() -> tuple[bool, str]:
|
|
73
44
|
"""Start the daemon as a background process."""
|
|
74
45
|
state = get_daemon_state()
|
|
@@ -137,72 +108,13 @@ def create_server() -> Server:
|
|
|
137
108
|
),
|
|
138
109
|
Tool(
|
|
139
110
|
name="get_status",
|
|
140
|
-
description="Get ScreenFix status",
|
|
111
|
+
description="Get ScreenFix daemon status",
|
|
141
112
|
inputSchema={"type": "object", "properties": {}, "required": []},
|
|
142
113
|
),
|
|
143
|
-
Tool(
|
|
144
|
-
name="get_last_screenshot",
|
|
145
|
-
description="Get the most recent screenshot with its image and related task",
|
|
146
|
-
inputSchema={
|
|
147
|
-
"type": "object",
|
|
148
|
-
"properties": {
|
|
149
|
-
"include_image": {
|
|
150
|
-
"type": "boolean",
|
|
151
|
-
"description": "Include image data",
|
|
152
|
-
"default": True,
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
"required": [],
|
|
156
|
-
},
|
|
157
|
-
),
|
|
158
|
-
Tool(
|
|
159
|
-
name="list_screenshots",
|
|
160
|
-
description="List all screenshots",
|
|
161
|
-
inputSchema={
|
|
162
|
-
"type": "object",
|
|
163
|
-
"properties": {
|
|
164
|
-
"limit": {"type": "integer", "default": 10}
|
|
165
|
-
},
|
|
166
|
-
"required": [],
|
|
167
|
-
},
|
|
168
|
-
),
|
|
169
|
-
Tool(
|
|
170
|
-
name="get_tasks",
|
|
171
|
-
description="Get tasks from tasks.md",
|
|
172
|
-
inputSchema={
|
|
173
|
-
"type": "object",
|
|
174
|
-
"properties": {
|
|
175
|
-
"pending_only": {"type": "boolean", "default": False}
|
|
176
|
-
},
|
|
177
|
-
"required": [],
|
|
178
|
-
},
|
|
179
|
-
),
|
|
180
|
-
Tool(
|
|
181
|
-
name="complete_task",
|
|
182
|
-
description="Mark a task as complete",
|
|
183
|
-
inputSchema={
|
|
184
|
-
"type": "object",
|
|
185
|
-
"properties": {
|
|
186
|
-
"task_text": {"type": "string", "description": "Task text to mark complete"}
|
|
187
|
-
},
|
|
188
|
-
"required": ["task_text"],
|
|
189
|
-
},
|
|
190
|
-
),
|
|
191
|
-
Tool(
|
|
192
|
-
name="read_screenshot",
|
|
193
|
-
description="Read a specific screenshot by path",
|
|
194
|
-
inputSchema={
|
|
195
|
-
"type": "object",
|
|
196
|
-
"properties": {
|
|
197
|
-
"path": {"type": "string", "description": "Path to screenshot"}
|
|
198
|
-
},
|
|
199
|
-
"required": ["path"],
|
|
200
|
-
},
|
|
201
|
-
),
|
|
202
114
|
]
|
|
203
115
|
|
|
204
116
|
@server.call_tool()
|
|
205
|
-
async def call_tool(name: str, arguments: dict
|
|
117
|
+
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
|
206
118
|
|
|
207
119
|
if name == "start_daemon":
|
|
208
120
|
success, message = start_daemon()
|
|
@@ -214,89 +126,15 @@ def create_server() -> Server:
|
|
|
214
126
|
|
|
215
127
|
elif name == "get_status":
|
|
216
128
|
state = get_daemon_state()
|
|
217
|
-
screenshots = get_screenshots()
|
|
218
|
-
tasks = get_pending_tasks()
|
|
219
|
-
|
|
220
129
|
status = "Running" if state.get("running") else "Not running"
|
|
221
130
|
text = f"""ScreenFix Status:
|
|
222
131
|
- Daemon: {status}
|
|
223
|
-
- Screenshots: {len(screenshots)}
|
|
224
|
-
- Pending tasks: {len(tasks)}
|
|
225
132
|
|
|
226
|
-
Use Cmd+Ctrl+Shift+4 to capture (instant, no delay)
|
|
133
|
+
Use Cmd+Ctrl+Shift+4 to capture (instant, no delay)
|
|
134
|
+
Screenshots saved to: ./screenfix/screenshots/
|
|
135
|
+
Tasks saved to: ./screenfix/tasks/screenfix-tasks.md"""
|
|
227
136
|
return [TextContent(type="text", text=text)]
|
|
228
137
|
|
|
229
|
-
elif name == "get_last_screenshot":
|
|
230
|
-
include_image = arguments.get("include_image", True)
|
|
231
|
-
screenshot = get_last_screenshot()
|
|
232
|
-
|
|
233
|
-
if not screenshot:
|
|
234
|
-
return [TextContent(type="text", text="No screenshots found. Use Cmd+Ctrl+Shift+4 to capture.")]
|
|
235
|
-
|
|
236
|
-
result = [TextContent(type="text", text=f"Screenshot: {screenshot['path']}")]
|
|
237
|
-
|
|
238
|
-
if include_image and os.path.exists(screenshot["path"]):
|
|
239
|
-
with open(screenshot["path"], "rb") as f:
|
|
240
|
-
image_data = base64.standard_b64encode(f.read()).decode("utf-8")
|
|
241
|
-
result.append(ImageContent(type="image", data=image_data, mimeType="image/png"))
|
|
242
|
-
|
|
243
|
-
tasks = get_tasks()
|
|
244
|
-
for task in tasks:
|
|
245
|
-
if task.get("screenshot") == screenshot["path"]:
|
|
246
|
-
result.append(TextContent(
|
|
247
|
-
type="text",
|
|
248
|
-
text=f"\nTask: {task['text']}\nStatus: {'Done' if task['completed'] else 'Pending'}"
|
|
249
|
-
))
|
|
250
|
-
break
|
|
251
|
-
|
|
252
|
-
return result
|
|
253
|
-
|
|
254
|
-
elif name == "list_screenshots":
|
|
255
|
-
limit = arguments.get("limit", 10)
|
|
256
|
-
screenshots = get_screenshots()[:limit]
|
|
257
|
-
|
|
258
|
-
if not screenshots:
|
|
259
|
-
return [TextContent(type="text", text="No screenshots found.")]
|
|
260
|
-
|
|
261
|
-
lines = ["Screenshots:"]
|
|
262
|
-
for i, s in enumerate(screenshots, 1):
|
|
263
|
-
lines.append(f"{i}. {s['filename']}")
|
|
264
|
-
|
|
265
|
-
return [TextContent(type="text", text="\n".join(lines))]
|
|
266
|
-
|
|
267
|
-
elif name == "get_tasks":
|
|
268
|
-
pending_only = arguments.get("pending_only", False)
|
|
269
|
-
tasks = get_pending_tasks() if pending_only else get_tasks()
|
|
270
|
-
|
|
271
|
-
if not tasks:
|
|
272
|
-
return [TextContent(type="text", text="No tasks found.")]
|
|
273
|
-
|
|
274
|
-
lines = ["Tasks:"]
|
|
275
|
-
for i, task in enumerate(tasks, 1):
|
|
276
|
-
status = "[x]" if task["completed"] else "[ ]"
|
|
277
|
-
lines.append(f"{i}. {status} {task['text']}")
|
|
278
|
-
|
|
279
|
-
return [TextContent(type="text", text="\n".join(lines))]
|
|
280
|
-
|
|
281
|
-
elif name == "complete_task":
|
|
282
|
-
task_text = arguments.get("task_text", "")
|
|
283
|
-
if mark_task_complete(task_text):
|
|
284
|
-
return [TextContent(type="text", text=f"Completed: {task_text}")]
|
|
285
|
-
return [TextContent(type="text", text=f"Task not found: {task_text}")]
|
|
286
|
-
|
|
287
|
-
elif name == "read_screenshot":
|
|
288
|
-
path = arguments.get("path", "")
|
|
289
|
-
if not path or not os.path.exists(path):
|
|
290
|
-
return [TextContent(type="text", text=f"Not found: {path}")]
|
|
291
|
-
|
|
292
|
-
with open(path, "rb") as f:
|
|
293
|
-
image_data = base64.standard_b64encode(f.read()).decode("utf-8")
|
|
294
|
-
|
|
295
|
-
return [
|
|
296
|
-
TextContent(type="text", text=f"Screenshot: {path}"),
|
|
297
|
-
ImageContent(type="image", data=image_data, mimeType="image/png"),
|
|
298
|
-
]
|
|
299
|
-
|
|
300
138
|
return [TextContent(type="text", text=f"Unknown tool: {name}")]
|
|
301
139
|
|
|
302
140
|
return server
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
allowed-tools:
|
|
3
|
-
description: View
|
|
2
|
+
allowed-tools: Read, Glob
|
|
3
|
+
description: View ScreenFix tasks and screenshots
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
1. Read the tasks file at `./screenfix/tasks/screenfix-tasks.md`
|
|
7
|
+
2. Use Glob to find screenshots: `./screenfix/screenshots/*.png`
|
|
8
|
+
3. Show pending tasks (lines with `- [ ]`) and their associated screenshots
|
|
@@ -3,6 +3,6 @@ allowed-tools: mcp__screenfix__start_daemon, mcp__screenfix__get_status
|
|
|
3
3
|
description: Start the ScreenFix daemon
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Start the ScreenFix daemon using `mcp__screenfix__start_daemon`. After starting, check the status
|
|
6
|
+
Start the ScreenFix daemon using `mcp__screenfix__start_daemon`. After starting, check the status with `mcp__screenfix__get_status`.
|
|
7
7
|
|
|
8
8
|
Once running, use **Cmd+Ctrl+Shift+4** to capture screenshots instantly (no delay).
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
allowed-tools:
|
|
2
|
+
allowed-tools: Read, Edit, Write, Bash, Glob, Grep
|
|
3
3
|
description: Execute the next pending ScreenFix task
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
1. Read the tasks file at `./screenfix/tasks/screenfix-tasks.md`
|
|
7
|
+
2. Find the FIRST pending task (line with `- [ ]`)
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
1.
|
|
9
|
+
For that task:
|
|
10
|
+
1. The task line contains the screenshot path - read that screenshot using the Read tool
|
|
10
11
|
2. Analyze the screenshot and the task instructions
|
|
11
12
|
3. Implement the fix described in the instructions
|
|
12
|
-
4. Mark the task complete
|
|
13
|
+
4. Mark the task complete by editing the tasks file: change `- [ ]` to `- [x]`
|
|
13
14
|
|
|
14
15
|
Execute one task at a time.
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
allowed-tools:
|
|
2
|
+
allowed-tools: Read, Edit, Write, Bash, Glob, Grep
|
|
3
3
|
description: Execute all pending ScreenFix tasks automatically
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
1. Read the tasks file at `./screenfix/tasks/screenfix-tasks.md`
|
|
7
|
+
2. Find all pending tasks (lines with `- [ ]`)
|
|
7
8
|
|
|
8
9
|
For each pending task:
|
|
9
|
-
1.
|
|
10
|
+
1. The task line contains the screenshot path - read that screenshot using the Read tool
|
|
10
11
|
2. Analyze the screenshot and the task instructions
|
|
11
12
|
3. Implement the fix described in the instructions
|
|
12
|
-
4. Mark the task complete
|
|
13
|
+
4. Mark the task complete by editing the tasks file: change `- [ ]` to `- [x]`
|
|
13
14
|
|
|
14
15
|
Execute all tasks without asking for confirmation. Just do it.
|