create-screenfix 0.1.0
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/bin/create-screenfix.js +40 -0
- package/lib/doctor.js +120 -0
- package/lib/init.js +165 -0
- package/lib/uninstall.js +67 -0
- package/lib/update.js +62 -0
- package/package.json +35 -0
- package/python/build/lib/screenfix/__init__.py +3 -0
- package/python/build/lib/screenfix/annotation_window.py +222 -0
- package/python/build/lib/screenfix/clipboard_watcher.py +164 -0
- package/python/build/lib/screenfix/config.py +66 -0
- package/python/build/lib/screenfix/daemon.py +204 -0
- package/python/build/lib/screenfix/mcp_server.py +318 -0
- package/python/build/lib/screenfix/task_tracker.py +129 -0
- package/python/pyproject.toml +24 -0
- package/python/requirements.txt +5 -0
- package/python/screenfix/__init__.py +3 -0
- package/python/screenfix/annotation_window.py +222 -0
- package/python/screenfix/clipboard_watcher.py +164 -0
- package/python/screenfix/config.py +66 -0
- package/python/screenfix/daemon.py +204 -0
- package/python/screenfix/mcp_server.py +318 -0
- package/python/screenfix/task_tracker.py +129 -0
- package/python/screenfix.egg-info/PKG-INFO +11 -0
- package/python/screenfix.egg-info/SOURCES.txt +14 -0
- package/python/screenfix.egg-info/dependency_links.txt +1 -0
- package/python/screenfix.egg-info/entry_points.txt +3 -0
- package/python/screenfix.egg-info/requires.txt +5 -0
- package/python/screenfix.egg-info/top_level.txt +1 -0
- package/templates/commands/screenfix-list-tasks.md +6 -0
- package/templates/commands/screenfix-start.md +8 -0
- package/templates/commands/screenfix-status.md +6 -0
- package/templates/commands/screenfix-stop.md +6 -0
- package/templates/commands/screenfix-tasks-next.md +14 -0
- package/templates/commands/screenfix-tasks-yolo.md +14 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"""MCP server for ScreenFix."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import base64
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
import time
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from mcp.server import Server
|
|
14
|
+
from mcp.server.stdio import stdio_server
|
|
15
|
+
from mcp.types import Tool, TextContent, ImageContent
|
|
16
|
+
|
|
17
|
+
from .config import config
|
|
18
|
+
from .task_tracker import get_tasks, get_pending_tasks, mark_task_complete
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
STATE_FILE = Path.home() / ".config" / "screenfix" / "state.json"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_daemon_state() -> dict:
|
|
25
|
+
"""Read the daemon state file."""
|
|
26
|
+
if not STATE_FILE.exists():
|
|
27
|
+
return {"running": False, "listening": False}
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
with open(STATE_FILE, "r") as f:
|
|
31
|
+
state = json.load(f)
|
|
32
|
+
|
|
33
|
+
pid = state.get("pid")
|
|
34
|
+
if pid:
|
|
35
|
+
try:
|
|
36
|
+
os.kill(pid, 0)
|
|
37
|
+
state["running"] = True
|
|
38
|
+
except OSError:
|
|
39
|
+
state["running"] = False
|
|
40
|
+
else:
|
|
41
|
+
state["running"] = False
|
|
42
|
+
|
|
43
|
+
return state
|
|
44
|
+
except (json.JSONDecodeError, IOError):
|
|
45
|
+
return {"running": False, "listening": False}
|
|
46
|
+
|
|
47
|
+
|
|
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
|
+
def start_daemon() -> tuple[bool, str]:
|
|
73
|
+
"""Start the daemon as a background process."""
|
|
74
|
+
state = get_daemon_state()
|
|
75
|
+
if state.get("running"):
|
|
76
|
+
return True, "Daemon is already running"
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
log_dir = Path.home() / ".config" / "screenfix"
|
|
80
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
81
|
+
log_file = log_dir / "daemon.log"
|
|
82
|
+
|
|
83
|
+
with open(log_file, "a") as log:
|
|
84
|
+
subprocess.Popen(
|
|
85
|
+
[sys.executable, "-m", "screenfix.daemon"],
|
|
86
|
+
cwd=os.getcwd(),
|
|
87
|
+
stdout=log,
|
|
88
|
+
stderr=log,
|
|
89
|
+
start_new_session=True,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
time.sleep(0.5)
|
|
93
|
+
|
|
94
|
+
new_state = get_daemon_state()
|
|
95
|
+
if new_state.get("running"):
|
|
96
|
+
return True, f"Daemon started (PID: {new_state.get('pid')}). Use Cmd+Ctrl+Shift+4 to capture."
|
|
97
|
+
else:
|
|
98
|
+
return True, f"Daemon starting... Check logs at {log_file}"
|
|
99
|
+
|
|
100
|
+
except Exception as e:
|
|
101
|
+
return False, f"Failed to start daemon: {e}"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def stop_daemon() -> tuple[bool, str]:
|
|
105
|
+
"""Stop the daemon."""
|
|
106
|
+
state = get_daemon_state()
|
|
107
|
+
if not state.get("running"):
|
|
108
|
+
return True, "Daemon is not running"
|
|
109
|
+
|
|
110
|
+
pid = state.get("pid")
|
|
111
|
+
if pid:
|
|
112
|
+
try:
|
|
113
|
+
os.kill(pid, 15)
|
|
114
|
+
return True, "Daemon stopped"
|
|
115
|
+
except OSError as e:
|
|
116
|
+
return False, f"Failed to stop daemon: {e}"
|
|
117
|
+
|
|
118
|
+
return False, "Could not find daemon PID"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def create_server() -> Server:
|
|
122
|
+
"""Create the MCP server."""
|
|
123
|
+
server = Server("screenfix")
|
|
124
|
+
|
|
125
|
+
@server.list_tools()
|
|
126
|
+
async def list_tools() -> list[Tool]:
|
|
127
|
+
return [
|
|
128
|
+
Tool(
|
|
129
|
+
name="start_daemon",
|
|
130
|
+
description="Start ScreenFix daemon. Use Cmd+Ctrl+Shift+4 to capture screenshots instantly.",
|
|
131
|
+
inputSchema={"type": "object", "properties": {}, "required": []},
|
|
132
|
+
),
|
|
133
|
+
Tool(
|
|
134
|
+
name="stop_daemon",
|
|
135
|
+
description="Stop the ScreenFix daemon",
|
|
136
|
+
inputSchema={"type": "object", "properties": {}, "required": []},
|
|
137
|
+
),
|
|
138
|
+
Tool(
|
|
139
|
+
name="get_status",
|
|
140
|
+
description="Get ScreenFix status",
|
|
141
|
+
inputSchema={"type": "object", "properties": {}, "required": []},
|
|
142
|
+
),
|
|
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
|
+
]
|
|
203
|
+
|
|
204
|
+
@server.call_tool()
|
|
205
|
+
async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent | ImageContent]:
|
|
206
|
+
|
|
207
|
+
if name == "start_daemon":
|
|
208
|
+
success, message = start_daemon()
|
|
209
|
+
return [TextContent(type="text", text=message)]
|
|
210
|
+
|
|
211
|
+
elif name == "stop_daemon":
|
|
212
|
+
success, message = stop_daemon()
|
|
213
|
+
return [TextContent(type="text", text=message)]
|
|
214
|
+
|
|
215
|
+
elif name == "get_status":
|
|
216
|
+
state = get_daemon_state()
|
|
217
|
+
screenshots = get_screenshots()
|
|
218
|
+
tasks = get_pending_tasks()
|
|
219
|
+
|
|
220
|
+
status = "Running" if state.get("running") else "Not running"
|
|
221
|
+
text = f"""ScreenFix Status:
|
|
222
|
+
- Daemon: {status}
|
|
223
|
+
- Screenshots: {len(screenshots)}
|
|
224
|
+
- Pending tasks: {len(tasks)}
|
|
225
|
+
|
|
226
|
+
Use Cmd+Ctrl+Shift+4 to capture (instant, no delay)"""
|
|
227
|
+
return [TextContent(type="text", text=text)]
|
|
228
|
+
|
|
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
|
+
return [TextContent(type="text", text=f"Unknown tool: {name}")]
|
|
301
|
+
|
|
302
|
+
return server
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
async def run_server():
|
|
306
|
+
"""Run the MCP server."""
|
|
307
|
+
server = create_server()
|
|
308
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
309
|
+
await server.run(read_stream, write_stream, server.create_initialization_options())
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def main():
|
|
313
|
+
"""Main entry point."""
|
|
314
|
+
asyncio.run(run_server())
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
if __name__ == "__main__":
|
|
318
|
+
main()
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Task tracker for managing tasks.md file."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional
|
|
7
|
+
from .config import config
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def add_task(instruction: str, screenshot_path: Optional[str] = None) -> str:
|
|
11
|
+
"""
|
|
12
|
+
Add a task to the tasks.md file.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
instruction: Task instruction text
|
|
16
|
+
screenshot_path: Optional path to related screenshot
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
The formatted task entry that was added
|
|
20
|
+
"""
|
|
21
|
+
tasks_path = Path(config.tasks_file)
|
|
22
|
+
|
|
23
|
+
# Create parent directory if needed
|
|
24
|
+
tasks_path.parent.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
|
|
26
|
+
# Create file with header if it doesn't exist
|
|
27
|
+
if not tasks_path.exists():
|
|
28
|
+
with open(tasks_path, "w") as f:
|
|
29
|
+
f.write("# Tasks for Claude Code\n\n")
|
|
30
|
+
|
|
31
|
+
# Format the task entry
|
|
32
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
|
|
33
|
+
|
|
34
|
+
# Build task lines
|
|
35
|
+
task_lines = [f"- [ ] {instruction.strip()}"]
|
|
36
|
+
|
|
37
|
+
# Add screenshot reference if provided
|
|
38
|
+
if screenshot_path:
|
|
39
|
+
task_lines.append(f" - Screenshot: `{screenshot_path}`")
|
|
40
|
+
|
|
41
|
+
task_lines.append(f" - Added: {timestamp}")
|
|
42
|
+
task_lines.append("") # Blank line after entry
|
|
43
|
+
|
|
44
|
+
task_entry = "\n".join(task_lines) + "\n"
|
|
45
|
+
|
|
46
|
+
# Append to file
|
|
47
|
+
with open(tasks_path, "a") as f:
|
|
48
|
+
f.write(task_entry)
|
|
49
|
+
|
|
50
|
+
return task_entry
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_tasks() -> list[dict]:
|
|
54
|
+
"""
|
|
55
|
+
Read all tasks from tasks.md.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
List of task dictionaries with keys: text, completed, screenshot, added
|
|
59
|
+
"""
|
|
60
|
+
tasks_path = Path(config.tasks_file)
|
|
61
|
+
|
|
62
|
+
if not tasks_path.exists():
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
tasks = []
|
|
66
|
+
current_task = None
|
|
67
|
+
|
|
68
|
+
with open(tasks_path, "r") as f:
|
|
69
|
+
for line in f:
|
|
70
|
+
# Check for task line
|
|
71
|
+
if line.startswith("- [ ] ") or line.startswith("- [x] "):
|
|
72
|
+
if current_task:
|
|
73
|
+
tasks.append(current_task)
|
|
74
|
+
completed = line.startswith("- [x] ")
|
|
75
|
+
current_task = {
|
|
76
|
+
"text": line[6:].strip(),
|
|
77
|
+
"completed": completed,
|
|
78
|
+
"screenshot": None,
|
|
79
|
+
"added": None,
|
|
80
|
+
}
|
|
81
|
+
elif current_task and line.strip().startswith("- Screenshot:"):
|
|
82
|
+
# Extract screenshot path
|
|
83
|
+
path = line.strip()[14:].strip().strip("`")
|
|
84
|
+
current_task["screenshot"] = path
|
|
85
|
+
elif current_task and line.strip().startswith("- Added:"):
|
|
86
|
+
# Extract timestamp
|
|
87
|
+
current_task["added"] = line.strip()[9:].strip()
|
|
88
|
+
|
|
89
|
+
# Don't forget the last task
|
|
90
|
+
if current_task:
|
|
91
|
+
tasks.append(current_task)
|
|
92
|
+
|
|
93
|
+
return tasks
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_pending_tasks() -> list[dict]:
|
|
97
|
+
"""Get only incomplete tasks."""
|
|
98
|
+
return [t for t in get_tasks() if not t["completed"]]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def mark_task_complete(task_text: str) -> bool:
|
|
102
|
+
"""
|
|
103
|
+
Mark a task as complete by its text.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
task_text: The task text to find and mark complete
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
True if task was found and marked, False otherwise
|
|
110
|
+
"""
|
|
111
|
+
tasks_path = Path(config.tasks_file)
|
|
112
|
+
|
|
113
|
+
if not tasks_path.exists():
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
with open(tasks_path, "r") as f:
|
|
117
|
+
content = f.read()
|
|
118
|
+
|
|
119
|
+
# Find and replace the checkbox
|
|
120
|
+
search = f"- [ ] {task_text}"
|
|
121
|
+
replace = f"- [x] {task_text}"
|
|
122
|
+
|
|
123
|
+
if search in content:
|
|
124
|
+
content = content.replace(search, replace, 1)
|
|
125
|
+
with open(tasks_path, "w") as f:
|
|
126
|
+
f.write(content)
|
|
127
|
+
return True
|
|
128
|
+
|
|
129
|
+
return False
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: screenfix
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Screenshot capture tool for Claude Code via MCP
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: mcp>=1.0.0
|
|
8
|
+
Requires-Dist: pyobjc-core>=10.0
|
|
9
|
+
Requires-Dist: pyobjc-framework-Cocoa>=10.0
|
|
10
|
+
Requires-Dist: pyobjc-framework-Quartz>=10.0
|
|
11
|
+
Requires-Dist: Pillow>=10.0.0
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
pyproject.toml
|
|
2
|
+
screenfix/__init__.py
|
|
3
|
+
screenfix/annotation_window.py
|
|
4
|
+
screenfix/clipboard_watcher.py
|
|
5
|
+
screenfix/config.py
|
|
6
|
+
screenfix/daemon.py
|
|
7
|
+
screenfix/mcp_server.py
|
|
8
|
+
screenfix/task_tracker.py
|
|
9
|
+
screenfix.egg-info/PKG-INFO
|
|
10
|
+
screenfix.egg-info/SOURCES.txt
|
|
11
|
+
screenfix.egg-info/dependency_links.txt
|
|
12
|
+
screenfix.egg-info/entry_points.txt
|
|
13
|
+
screenfix.egg-info/requires.txt
|
|
14
|
+
screenfix.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
screenfix
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
allowed-tools: mcp__screenfix__start_daemon, mcp__screenfix__get_status
|
|
3
|
+
description: Start the ScreenFix daemon
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Start the ScreenFix daemon using `mcp__screenfix__start_daemon`. After starting, check the status.
|
|
7
|
+
|
|
8
|
+
Once running, use **Cmd+Ctrl+Shift+4** to capture screenshots instantly (no delay).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
allowed-tools: mcp__screenfix__get_tasks, mcp__screenfix__get_last_screenshot, mcp__screenfix__read_screenshot, mcp__screenfix__complete_task, Read, Edit, Write, Bash, Glob, Grep
|
|
3
|
+
description: Execute the next pending ScreenFix task
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Get all pending tasks using `mcp__screenfix__get_tasks` with `pending_only: true`.
|
|
7
|
+
|
|
8
|
+
Take only the FIRST pending task:
|
|
9
|
+
1. Read the associated screenshot using `mcp__screenfix__read_screenshot`
|
|
10
|
+
2. Analyze the screenshot and the task instructions
|
|
11
|
+
3. Implement the fix described in the instructions
|
|
12
|
+
4. Mark the task complete using `mcp__screenfix__complete_task`
|
|
13
|
+
|
|
14
|
+
Execute one task at a time.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
allowed-tools: mcp__screenfix__get_tasks, mcp__screenfix__get_last_screenshot, mcp__screenfix__read_screenshot, mcp__screenfix__complete_task, Read, Edit, Write, Bash, Glob, Grep
|
|
3
|
+
description: Execute all pending ScreenFix tasks automatically
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Get all pending tasks using `mcp__screenfix__get_tasks` with `pending_only: true`.
|
|
7
|
+
|
|
8
|
+
For each pending task:
|
|
9
|
+
1. Read the associated screenshot using `mcp__screenfix__read_screenshot`
|
|
10
|
+
2. Analyze the screenshot and the task instructions
|
|
11
|
+
3. Implement the fix described in the instructions
|
|
12
|
+
4. Mark the task complete using `mcp__screenfix__complete_task`
|
|
13
|
+
|
|
14
|
+
Execute all tasks without asking for confirmation. Just do it.
|