daemora 1.0.1 ā 1.0.3
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/README.md +106 -76
- package/SOUL.md +100 -28
- package/config/mcp.json +9 -9
- package/package.json +15 -8
- package/skills/apple-notes.md +0 -52
- package/skills/apple-reminders.md +1 -87
- package/skills/camsnap.md +20 -144
- package/skills/coding.md +7 -7
- package/skills/documents.md +6 -6
- package/skills/email.md +6 -6
- package/skills/gif-search.md +28 -171
- package/skills/healthcheck.md +21 -203
- package/skills/image-gen.md +24 -123
- package/skills/model-usage.md +18 -165
- package/skills/obsidian.md +28 -174
- package/skills/pdf.md +30 -181
- package/skills/research.md +6 -6
- package/skills/skill-creator.md +35 -111
- package/skills/spotify.md +2 -17
- package/skills/summarize.md +36 -193
- package/skills/things.md +23 -175
- package/skills/tmux.md +1 -91
- package/skills/trello.md +32 -157
- package/skills/video-frames.md +26 -166
- package/skills/weather.md +6 -6
- package/src/a2a/A2AClient.js +2 -2
- package/src/a2a/A2AServer.js +6 -6
- package/src/a2a/AgentCard.js +2 -2
- package/src/agents/SubAgentManager.js +61 -19
- package/src/agents/Supervisor.js +4 -4
- package/src/channels/BaseChannel.js +6 -6
- package/src/channels/BlueBubblesChannel.js +112 -0
- package/src/channels/DiscordChannel.js +8 -8
- package/src/channels/EmailChannel.js +54 -26
- package/src/channels/FeishuChannel.js +140 -0
- package/src/channels/GoogleChatChannel.js +8 -8
- package/src/channels/HttpChannel.js +2 -2
- package/src/channels/IRCChannel.js +144 -0
- package/src/channels/LineChannel.js +13 -13
- package/src/channels/MatrixChannel.js +97 -0
- package/src/channels/MattermostChannel.js +119 -0
- package/src/channels/NextcloudChannel.js +133 -0
- package/src/channels/NostrChannel.js +175 -0
- package/src/channels/SignalChannel.js +9 -9
- package/src/channels/SlackChannel.js +10 -10
- package/src/channels/TeamsChannel.js +10 -10
- package/src/channels/TelegramChannel.js +8 -8
- package/src/channels/TwitchChannel.js +128 -0
- package/src/channels/WhatsAppChannel.js +10 -10
- package/src/channels/ZaloChannel.js +119 -0
- package/src/channels/iMessageChannel.js +150 -0
- package/src/channels/index.js +241 -11
- package/src/cli.js +835 -38
- package/src/config/agentProfiles.js +19 -19
- package/src/config/channels.js +1 -1
- package/src/config/default.js +12 -7
- package/src/config/models.js +3 -3
- package/src/config/permissions.js +2 -2
- package/src/core/AgentLoop.js +13 -13
- package/src/core/Compaction.js +3 -3
- package/src/core/CostTracker.js +2 -2
- package/src/core/EventBus.js +15 -15
- package/src/core/TaskQueue.js +24 -7
- package/src/core/TaskRunner.js +19 -6
- package/src/daemon/DaemonManager.js +4 -4
- package/src/hooks/HookRunner.js +4 -4
- package/src/index.js +6 -2
- package/src/mcp/MCPAgentRunner.js +3 -3
- package/src/mcp/MCPClient.js +9 -9
- package/src/mcp/MCPManager.js +14 -14
- package/src/models/ModelRouter.js +2 -2
- package/src/safety/AuditLog.js +3 -3
- package/src/safety/CircuitBreaker.js +2 -2
- package/src/safety/CommandGuard.js +132 -0
- package/src/safety/FilesystemGuard.js +23 -3
- package/src/safety/GitRollback.js +5 -5
- package/src/safety/HumanApproval.js +9 -9
- package/src/safety/InputSanitizer.js +81 -8
- package/src/safety/PermissionGuard.js +2 -2
- package/src/safety/Sandbox.js +1 -1
- package/src/safety/SecretScanner.js +90 -28
- package/src/safety/SecretVault.js +2 -2
- package/src/scheduler/Heartbeat.js +3 -3
- package/src/scheduler/Scheduler.js +6 -6
- package/src/setup/theme.js +171 -66
- package/src/setup/wizard.js +432 -57
- package/src/skills/SkillLoader.js +145 -8
- package/src/storage/TaskStore.js +39 -15
- package/src/systemPrompt.js +45 -43
- package/src/tenants/TenantManager.js +79 -22
- package/src/tools/ToolRegistry.js +3 -3
- package/src/tools/applyPatch.js +2 -2
- package/src/tools/browserAutomation.js +4 -4
- package/src/tools/calendar.js +155 -0
- package/src/tools/clipboard.js +71 -0
- package/src/tools/contacts.js +138 -0
- package/src/tools/createDocument.js +2 -2
- package/src/tools/cronTool.js +14 -14
- package/src/tools/database.js +165 -0
- package/src/tools/editFile.js +10 -10
- package/src/tools/executeCommand.js +11 -3
- package/src/tools/generateImage.js +79 -0
- package/src/tools/gitTool.js +141 -0
- package/src/tools/glob.js +1 -1
- package/src/tools/googlePlaces.js +136 -0
- package/src/tools/grep.js +2 -2
- package/src/tools/iMessageTool.js +86 -0
- package/src/tools/imageAnalysis.js +3 -3
- package/src/tools/index.js +56 -2
- package/src/tools/makeVoiceCall.js +283 -0
- package/src/tools/manageAgents.js +2 -2
- package/src/tools/manageMCP.js +38 -20
- package/src/tools/memory.js +25 -32
- package/src/tools/messageChannel.js +1 -1
- package/src/tools/notification.js +90 -0
- package/src/tools/philipsHue.js +147 -0
- package/src/tools/projectTracker.js +8 -8
- package/src/tools/readFile.js +1 -1
- package/src/tools/readPDF.js +73 -0
- package/src/tools/screenCapture.js +6 -6
- package/src/tools/searchContent.js +2 -2
- package/src/tools/searchFiles.js +1 -1
- package/src/tools/sendEmail.js +79 -24
- package/src/tools/sendFile.js +4 -4
- package/src/tools/sonos.js +137 -0
- package/src/tools/sshTool.js +130 -0
- package/src/tools/textToSpeech.js +5 -5
- package/src/tools/transcribeAudio.js +4 -4
- package/src/tools/useMCP.js +4 -4
- package/src/tools/webFetch.js +2 -2
- package/src/tools/webSearch.js +1 -1
- package/src/utils/Embeddings.js +79 -0
- package/src/voice/VoiceSessionManager.js +170 -0
- package/src/voice/VoiceWebhook.js +188 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "daemora",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "A powerful open-source AI agent that runs on your machine. Connects to any AI model, any MCP server, any channel. Fully autonomous
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "A powerful open-source AI agent that runs on your machine. Connects to any AI model, any MCP server, any channel. Fully autonomous - plans, codes, tests, browses, emails, and manages your tools without asking permission.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"daemora": "src/cli.js"
|
|
@@ -12,7 +12,12 @@
|
|
|
12
12
|
"daemon:install": "node src/cli.js daemon install",
|
|
13
13
|
"daemon:start": "node src/cli.js daemon start",
|
|
14
14
|
"daemon:stop": "node src/cli.js daemon stop",
|
|
15
|
-
"daemon:status": "node src/cli.js daemon status"
|
|
15
|
+
"daemon:status": "node src/cli.js daemon status",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:watch": "vitest",
|
|
18
|
+
"test:coverage": "vitest run --coverage",
|
|
19
|
+
"test:unit": "vitest run tests/unit",
|
|
20
|
+
"test:integration": "vitest run tests/integration"
|
|
16
21
|
},
|
|
17
22
|
"keywords": [
|
|
18
23
|
"ai-agent",
|
|
@@ -39,11 +44,11 @@
|
|
|
39
44
|
},
|
|
40
45
|
"repository": {
|
|
41
46
|
"type": "git",
|
|
42
|
-
"url": "https://github.com/
|
|
47
|
+
"url": "https://github.com/CodeAndCanvasLabs/Daemora.git"
|
|
43
48
|
},
|
|
44
49
|
"homepage": "https://daemora.com",
|
|
45
50
|
"bugs": {
|
|
46
|
-
"url": "https://github.com/
|
|
51
|
+
"url": "https://github.com/CodeAndCanvasLabs/Daemora/issues"
|
|
47
52
|
},
|
|
48
53
|
"files": [
|
|
49
54
|
"src/",
|
|
@@ -61,11 +66,13 @@
|
|
|
61
66
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
62
67
|
"@slack/bolt": "^4.4.0",
|
|
63
68
|
"ai": "^6.0.105",
|
|
69
|
+
"botbuilder": "^4.23.1",
|
|
64
70
|
"chalk": "^5.6.2",
|
|
65
71
|
"discord.js": "^14.18.0",
|
|
66
72
|
"dotenv": "^17.3.1",
|
|
67
73
|
"express": "^5.2.1",
|
|
68
74
|
"glob": "^13.0.6",
|
|
75
|
+
"google-auth-library": "^9.15.0",
|
|
69
76
|
"grammy": "^1.40.1",
|
|
70
77
|
"html-to-text": "^9.0.5",
|
|
71
78
|
"imap": "^0.8.19",
|
|
@@ -73,14 +80,14 @@
|
|
|
73
80
|
"nodemailer": "^8.0.1",
|
|
74
81
|
"ollama-ai-provider": "^1.2.0",
|
|
75
82
|
"openai": "^6.25.0",
|
|
76
|
-
"botbuilder": "^4.23.1",
|
|
77
|
-
"google-auth-library": "^9.15.0",
|
|
78
83
|
"twilio": "^5.12.2",
|
|
79
84
|
"uuid": "^13.0.0",
|
|
80
85
|
"zod": "^3.25.76"
|
|
81
86
|
},
|
|
82
87
|
"devDependencies": {
|
|
83
88
|
"@playwright/test": "^1.58.2",
|
|
84
|
-
"@types/node": "^25.3.2"
|
|
89
|
+
"@types/node": "^25.3.2",
|
|
90
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
91
|
+
"vitest": "^4.0.18"
|
|
85
92
|
}
|
|
86
93
|
}
|
package/skills/apple-notes.md
CHANGED
|
@@ -131,58 +131,6 @@ EOF
|
|
|
131
131
|
osascript -e 'tell application "Notes" to get name of folders'
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
## Python Wrapper for Convenience
|
|
135
|
-
|
|
136
|
-
```python
|
|
137
|
-
#!/usr/bin/env python3
|
|
138
|
-
import subprocess
|
|
139
|
-
|
|
140
|
-
def run_applescript(script: str) -> str:
|
|
141
|
-
result = subprocess.run(
|
|
142
|
-
["osascript", "-e", script],
|
|
143
|
-
capture_output=True, text=True
|
|
144
|
-
)
|
|
145
|
-
if result.returncode != 0:
|
|
146
|
-
raise RuntimeError(f"AppleScript error: {result.stderr.strip()}")
|
|
147
|
-
return result.stdout.strip()
|
|
148
|
-
|
|
149
|
-
def create_note(title: str, body: str, folder: str = "Notes", account: str = "iCloud") -> None:
|
|
150
|
-
# Escape single quotes in content
|
|
151
|
-
title = title.replace('"', '\\"')
|
|
152
|
-
body = body.replace('"', '\\"')
|
|
153
|
-
script = f'''
|
|
154
|
-
tell application "Notes"
|
|
155
|
-
tell account "{account}"
|
|
156
|
-
tell folder "{folder}"
|
|
157
|
-
make new note with properties {{name:"{title}", body:"{body}"}}
|
|
158
|
-
end tell
|
|
159
|
-
end tell
|
|
160
|
-
end tell
|
|
161
|
-
'''
|
|
162
|
-
run_applescript(script)
|
|
163
|
-
print(f"ā
Note created: {title}")
|
|
164
|
-
|
|
165
|
-
def find_notes(keyword: str) -> list[str]:
|
|
166
|
-
script = f'''
|
|
167
|
-
tell application "Notes"
|
|
168
|
-
set results to {{}}
|
|
169
|
-
repeat with n in notes
|
|
170
|
-
if name of n contains "{keyword}" or body of n contains "{keyword}" then
|
|
171
|
-
set end of results to name of n
|
|
172
|
-
end if
|
|
173
|
-
end repeat
|
|
174
|
-
return results
|
|
175
|
-
end tell
|
|
176
|
-
'''
|
|
177
|
-
output = run_applescript(script)
|
|
178
|
-
return [n.strip() for n in output.split(",") if n.strip()] if output else []
|
|
179
|
-
|
|
180
|
-
# Usage
|
|
181
|
-
create_note("Research: AI Trends 2026", "## Summary\n\nKey findings...", folder="Research")
|
|
182
|
-
matches = find_notes("meeting")
|
|
183
|
-
print(f"Found {len(matches)} notes: {matches}")
|
|
184
|
-
```
|
|
185
|
-
|
|
186
134
|
## Error Handling
|
|
187
135
|
|
|
188
136
|
| Error | Fix |
|
|
@@ -8,7 +8,7 @@ triggers: reminder, reminders, add reminder, set reminder, due date, alert, remi
|
|
|
8
8
|
|
|
9
9
|
ā
Create reminders with due dates/times, list pending reminders, mark complete, create reminder lists, set location-based reminders
|
|
10
10
|
|
|
11
|
-
ā Complex task management (use Things or Trello skill)
|
|
11
|
+
ā Complex task management (use Things or Trello skill) - use Reminders for simple "remind me at X time" tasks
|
|
12
12
|
|
|
13
13
|
## Create a Reminder
|
|
14
14
|
|
|
@@ -43,52 +43,6 @@ end tell
|
|
|
43
43
|
EOF
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
## Create Reminder with Dynamic Date
|
|
47
|
-
|
|
48
|
-
```python
|
|
49
|
-
#!/usr/bin/env python3
|
|
50
|
-
import subprocess
|
|
51
|
-
from datetime import datetime, timedelta
|
|
52
|
-
|
|
53
|
-
def create_reminder(title: str, notes: str = "", due: datetime = None, list_name: str = "Reminders"):
|
|
54
|
-
"""Create a reminder. due=None means no due date."""
|
|
55
|
-
if due:
|
|
56
|
-
# AppleScript date format
|
|
57
|
-
due_str = due.strftime("%B %d, %Y %I:%M:%S %p")
|
|
58
|
-
date_block = f'''
|
|
59
|
-
set dueDate to date "{due_str}"
|
|
60
|
-
set due date of newReminder to dueDate
|
|
61
|
-
set remind me date of newReminder to dueDate
|
|
62
|
-
'''
|
|
63
|
-
else:
|
|
64
|
-
date_block = ""
|
|
65
|
-
|
|
66
|
-
# Escape quotes
|
|
67
|
-
title = title.replace('"', '\\"')
|
|
68
|
-
notes = notes.replace('"', '\\"')
|
|
69
|
-
|
|
70
|
-
script = f'''
|
|
71
|
-
tell application "Reminders"
|
|
72
|
-
tell list "{list_name}"
|
|
73
|
-
set newReminder to make new reminder with properties {{name:"{title}"}}
|
|
74
|
-
{f'set body of newReminder to "{notes}"' if notes else ""}
|
|
75
|
-
{date_block}
|
|
76
|
-
end tell
|
|
77
|
-
end tell
|
|
78
|
-
'''
|
|
79
|
-
result = subprocess.run(["osascript", "-e", script], capture_output=True, text=True)
|
|
80
|
-
if result.returncode == 0:
|
|
81
|
-
due_display = due.strftime("%a %b %d at %I:%M %p") if due else "no due date"
|
|
82
|
-
print(f"ā
Reminder: '{title}' ({due_display})")
|
|
83
|
-
else:
|
|
84
|
-
print(f"ā Failed: {result.stderr}")
|
|
85
|
-
|
|
86
|
-
# Examples
|
|
87
|
-
create_reminder("Weekly team sync", due=datetime.now() + timedelta(days=1, hours=2))
|
|
88
|
-
create_reminder("Pay rent", due=datetime(2026, 4, 1, 9, 0), list_name="Bills")
|
|
89
|
-
create_reminder("Buy coffee beans") # no due date
|
|
90
|
-
```
|
|
91
|
-
|
|
92
46
|
## List Pending Reminders
|
|
93
47
|
|
|
94
48
|
```bash
|
|
@@ -109,46 +63,6 @@ end tell
|
|
|
109
63
|
EOF
|
|
110
64
|
```
|
|
111
65
|
|
|
112
|
-
## List Reminders Due Today
|
|
113
|
-
|
|
114
|
-
```python
|
|
115
|
-
#!/usr/bin/env python3
|
|
116
|
-
import subprocess
|
|
117
|
-
from datetime import datetime, date
|
|
118
|
-
|
|
119
|
-
script = '''
|
|
120
|
-
tell application "Reminders"
|
|
121
|
-
set output to ""
|
|
122
|
-
repeat with r in reminders
|
|
123
|
-
if completed of r is false and due date of r is not missing value then
|
|
124
|
-
set output to output & name of r & "|" & (due date of r as string) & "\n"
|
|
125
|
-
end if
|
|
126
|
-
end repeat
|
|
127
|
-
return output
|
|
128
|
-
end tell
|
|
129
|
-
'''
|
|
130
|
-
result = subprocess.run(["osascript", "-e", script], capture_output=True, text=True)
|
|
131
|
-
lines = [l.strip() for l in result.stdout.strip().split("\n") if l.strip()]
|
|
132
|
-
|
|
133
|
-
today = date.today()
|
|
134
|
-
today_items = []
|
|
135
|
-
for line in lines:
|
|
136
|
-
if "|" in line:
|
|
137
|
-
name, due_str = line.rsplit("|", 1)
|
|
138
|
-
# Parse AppleScript date string
|
|
139
|
-
try:
|
|
140
|
-
due = datetime.strptime(due_str.strip()[:10], "%A, %B")
|
|
141
|
-
except:
|
|
142
|
-
pass
|
|
143
|
-
today_items.append(f"⢠{name.strip()}")
|
|
144
|
-
|
|
145
|
-
if today_items:
|
|
146
|
-
print("š
Reminders due today:")
|
|
147
|
-
print("\n".join(today_items))
|
|
148
|
-
else:
|
|
149
|
-
print("ā
No reminders due today")
|
|
150
|
-
```
|
|
151
|
-
|
|
152
66
|
## Mark Reminder Complete
|
|
153
67
|
|
|
154
68
|
```bash
|
package/skills/camsnap.md
CHANGED
|
@@ -1,162 +1,38 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: camsnap
|
|
3
|
-
description: Capture photos or screenshots from the Mac camera or screen. Use when the user asks to take a photo, capture a webcam shot, take a selfie, capture the screen, or grab a camera frame. macOS only.
|
|
3
|
+
description: Capture photos or screenshots from the Mac camera or screen. Use when the user asks to take a photo, capture a webcam shot, take a selfie, capture the screen, or grab a camera frame. macOS only.
|
|
4
4
|
triggers: take photo, camera, webcam, selfie, snap photo, capture camera, camsnap, take picture, camera shot, photo capture
|
|
5
|
+
metadata: {"daemora": {"emoji": "šø", "requires": {"bins": ["imagesnap"]}, "install": ["brew install imagesnap"], "os": ["darwin"]}}
|
|
5
6
|
---
|
|
6
7
|
|
|
7
|
-
##
|
|
8
|
+
## Screen capture
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
Use the built-in `screenCapture` tool - no install needed.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
## Webcam
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```python
|
|
16
|
-
# Use the built-in screenCapture tool
|
|
17
|
-
# screenCapture(path: string) ā saves screenshot to path and returns it for vision analysis
|
|
18
|
-
|
|
19
|
-
# Capture full screen
|
|
20
|
-
screenCapture("/tmp/screen.png")
|
|
21
|
-
|
|
22
|
-
# Then analyze with imageAnalysis
|
|
23
|
-
imageAnalysis("/tmp/screen.png", "What is shown on the screen?")
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Webcam / Camera Capture
|
|
14
|
+
Install: `brew install imagesnap`
|
|
27
15
|
|
|
28
16
|
```bash
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
#
|
|
33
|
-
imagesnap /tmp/photo.jpg
|
|
34
|
-
|
|
35
|
-
# Take photo with delay (gives time to position)
|
|
36
|
-
imagesnap -w 3 /tmp/photo.jpg # 3 second warmup
|
|
37
|
-
|
|
38
|
-
# List available cameras
|
|
39
|
-
imagesnap -l
|
|
40
|
-
# ā Video Devices:
|
|
41
|
-
# FaceTime HD Camera
|
|
42
|
-
# iPhone Camera (Continuity Camera)
|
|
43
|
-
|
|
44
|
-
# Use specific camera
|
|
45
|
-
imagesnap -d "iPhone Camera" /tmp/photo.jpg
|
|
46
|
-
|
|
47
|
-
# Take multiple frames (burst)
|
|
48
|
-
imagesnap -t 1 /tmp/burst # 1 second between shots; creates burst-001.jpg, burst-002.jpg, etc.
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Python Wrapper
|
|
52
|
-
|
|
53
|
-
```python
|
|
54
|
-
#!/usr/bin/env python3
|
|
55
|
-
import subprocess, os
|
|
56
|
-
from pathlib import Path
|
|
57
|
-
from datetime import datetime
|
|
58
|
-
|
|
59
|
-
def capture_webcam(
|
|
60
|
-
output: str = None,
|
|
61
|
-
camera: str = None,
|
|
62
|
-
warmup: float = 1.5,
|
|
63
|
-
quality: str = "high"
|
|
64
|
-
) -> str:
|
|
65
|
-
"""
|
|
66
|
-
Capture a photo from the webcam.
|
|
67
|
-
Returns path to saved image.
|
|
68
|
-
"""
|
|
69
|
-
if output is None:
|
|
70
|
-
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
71
|
-
output = f"/tmp/webcam_{ts}.jpg"
|
|
72
|
-
|
|
73
|
-
cmd = ["imagesnap", "-w", str(warmup)]
|
|
74
|
-
if camera:
|
|
75
|
-
cmd += ["-d", camera]
|
|
76
|
-
cmd.append(output)
|
|
77
|
-
|
|
78
|
-
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
79
|
-
if result.returncode != 0:
|
|
80
|
-
raise RuntimeError(f"Camera capture failed: {result.stderr}")
|
|
81
|
-
|
|
82
|
-
size = os.path.getsize(output)
|
|
83
|
-
print(f"šø Photo saved: {output} ({size//1024}KB)")
|
|
84
|
-
return output
|
|
85
|
-
|
|
86
|
-
def list_cameras() -> list[str]:
|
|
87
|
-
"""List available cameras."""
|
|
88
|
-
result = subprocess.run(["imagesnap", "-l"], capture_output=True, text=True)
|
|
89
|
-
cameras = []
|
|
90
|
-
for line in result.stdout.split('\n'):
|
|
91
|
-
if line.strip() and not line.startswith('Video'):
|
|
92
|
-
cameras.append(line.strip())
|
|
93
|
-
return cameras
|
|
94
|
-
|
|
95
|
-
# Capture and analyze
|
|
96
|
-
cameras = list_cameras()
|
|
97
|
-
print(f"Available cameras: {cameras}")
|
|
98
|
-
|
|
99
|
-
photo_path = capture_webcam(warmup=2.0)
|
|
100
|
-
|
|
101
|
-
# Analyze the photo with vision
|
|
102
|
-
# imageAnalysis(photo_path, "Describe what you see in this photo")
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Time-Lapse Capture
|
|
106
|
-
|
|
107
|
-
```python
|
|
108
|
-
#!/usr/bin/env python3
|
|
109
|
-
"""Capture multiple photos over time."""
|
|
110
|
-
import subprocess, time
|
|
111
|
-
from pathlib import Path
|
|
112
|
-
from datetime import datetime
|
|
113
|
-
|
|
114
|
-
out_dir = Path("/tmp/timelapse")
|
|
115
|
-
out_dir.mkdir(exist_ok=True)
|
|
116
|
-
|
|
117
|
-
interval_seconds = 30 # photo every 30 seconds
|
|
118
|
-
count = 20 # take 20 photos
|
|
119
|
-
|
|
120
|
-
print(f"Starting time-lapse: {count} photos, every {interval_seconds}s")
|
|
121
|
-
for i in range(count):
|
|
122
|
-
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
123
|
-
path = out_dir / f"frame_{i+1:03d}_{ts}.jpg"
|
|
124
|
-
subprocess.run(["imagesnap", "-w", "0.5", str(path)], capture_output=True)
|
|
125
|
-
print(f"šø {i+1}/{count}: {path.name}")
|
|
126
|
-
if i < count - 1:
|
|
127
|
-
time.sleep(interval_seconds)
|
|
128
|
-
|
|
129
|
-
print(f"\nā
{count} photos saved to {out_dir}")
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Combine Screen + Camera (Picture-in-Picture)
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
# Take both and combine with ffmpeg
|
|
136
|
-
imagesnap -w 1 /tmp/webcam.jpg
|
|
137
|
-
screencapture /tmp/screen.png
|
|
138
|
-
|
|
139
|
-
# Overlay webcam in bottom-right corner of screen
|
|
140
|
-
ffmpeg -i /tmp/screen.png -i /tmp/webcam.jpg \
|
|
141
|
-
-filter_complex "[1:v]scale=320:-1[cam]; [0:v][cam]overlay=W-w-20:H-h-20" \
|
|
142
|
-
/tmp/combined.jpg -y -loglevel quiet
|
|
143
|
-
echo "Combined: /tmp/combined.jpg"
|
|
144
|
-
open /tmp/combined.jpg
|
|
17
|
+
imagesnap -w 2 /tmp/photo.jpg # take photo (2s warmup)
|
|
18
|
+
imagesnap -l # list available cameras
|
|
19
|
+
imagesnap -d "iPhone Camera" /tmp/photo.jpg # specific camera
|
|
20
|
+
imagesnap -t 1 /tmp/burst # burst: one shot per second
|
|
145
21
|
```
|
|
146
22
|
|
|
147
|
-
##
|
|
23
|
+
## Workflow
|
|
148
24
|
|
|
149
|
-
1.
|
|
150
|
-
2.
|
|
151
|
-
3.
|
|
152
|
-
4.
|
|
25
|
+
1. Screen ā `screenCapture("/tmp/screen.png")`
|
|
26
|
+
2. Webcam ā check `imagesnap` installed, then run with `-w 2` warmup
|
|
27
|
+
3. Report the saved path
|
|
28
|
+
4. If user asked to "look at" or "check" something ā auto-run `imageAnalysis(path, "What do you see?")`
|
|
29
|
+
5. To send ā `sendFile(path, channel, sessionId)`
|
|
153
30
|
|
|
154
|
-
##
|
|
31
|
+
## Errors
|
|
155
32
|
|
|
156
33
|
| Error | Fix |
|
|
157
34
|
|-------|-----|
|
|
158
35
|
| `imagesnap: command not found` | `brew install imagesnap` |
|
|
159
|
-
|
|
|
160
|
-
|
|
|
161
|
-
|
|
|
162
|
-
| Permission denied | System Settings ā Privacy & Security ā Camera ā enable Terminal |
|
|
36
|
+
| Black/dark photo | Increase warmup: `-w 3` (camera needs time to adjust) |
|
|
37
|
+
| Camera busy | Close FaceTime/Zoom/Photo Booth |
|
|
38
|
+
| Permission denied | System Settings ā Privacy ā Camera ā enable Terminal |
|
package/skills/coding.md
CHANGED
|
@@ -5,10 +5,10 @@ triggers: code, function, bug, error, refactor, implement, class, module, typesc
|
|
|
5
5
|
---
|
|
6
6
|
You are an expert programmer. When working on code tasks:
|
|
7
7
|
|
|
8
|
-
1. **Read before writing**
|
|
9
|
-
2. **Edit, don't rewrite**
|
|
10
|
-
3. **Test after changes**
|
|
11
|
-
4. **Follow existing patterns**
|
|
12
|
-
5. **Explain your reasoning**
|
|
13
|
-
6. **Handle errors**
|
|
14
|
-
7. **Security first**
|
|
8
|
+
1. **Read before writing** - Always read existing files before making changes. Understand the codebase patterns first.
|
|
9
|
+
2. **Edit, don't rewrite** - Use editFile for surgical changes. Never rewrite entire files unless asked.
|
|
10
|
+
3. **Test after changes** - Run tests or verify your changes work after making them.
|
|
11
|
+
4. **Follow existing patterns** - Match the existing code style, naming conventions, and architecture.
|
|
12
|
+
5. **Explain your reasoning** - Briefly explain why you made each change.
|
|
13
|
+
6. **Handle errors** - Add appropriate error handling but don't over-engineer.
|
|
14
|
+
7. **Security first** - Never introduce SQL injection, XSS, command injection, or other vulnerabilities.
|
package/skills/documents.md
CHANGED
|
@@ -5,9 +5,9 @@ triggers: document, report, pdf, write up, summary, proposal, template, markdown
|
|
|
5
5
|
---
|
|
6
6
|
You are an expert technical writer. When creating documents:
|
|
7
7
|
|
|
8
|
-
1. **Structure first**
|
|
9
|
-
2. **Use headings**
|
|
10
|
-
3. **Bullet points**
|
|
11
|
-
4. **Be concise**
|
|
12
|
-
5. **Format for audience**
|
|
13
|
-
6. **Save properly**
|
|
8
|
+
1. **Structure first** - Start with an outline (headings, sections) before writing content.
|
|
9
|
+
2. **Use headings** - Organize with clear hierarchy: # Title, ## Section, ### Subsection.
|
|
10
|
+
3. **Bullet points** - Use bullets for lists, steps, and multiple items.
|
|
11
|
+
4. **Be concise** - Every sentence should add value. Remove filler words.
|
|
12
|
+
5. **Format for audience** - Technical docs for developers, simple language for non-technical users.
|
|
13
|
+
6. **Save properly** - Use createDocument with the right format (markdown or pdf).
|
package/skills/email.md
CHANGED
|
@@ -5,9 +5,9 @@ triggers: email, mail, send, draft, reply, compose, message, inbox
|
|
|
5
5
|
---
|
|
6
6
|
You are an expert email writer. When handling email tasks:
|
|
7
7
|
|
|
8
|
-
1. **Professional tone**
|
|
9
|
-
2. **Clear subject lines**
|
|
10
|
-
3. **Brief and scannable**
|
|
11
|
-
4. **Call to action**
|
|
12
|
-
5. **Proofread**
|
|
13
|
-
6. **Confirm before sending**
|
|
8
|
+
1. **Professional tone** - Default to professional but friendly. Match the tone of the conversation.
|
|
9
|
+
2. **Clear subject lines** - Write specific, actionable subject lines.
|
|
10
|
+
3. **Brief and scannable** - Keep emails concise. Use bullet points for multiple items.
|
|
11
|
+
4. **Call to action** - End with a clear next step or ask.
|
|
12
|
+
5. **Proofread** - Check for typos and clarity before sending.
|
|
13
|
+
6. **Confirm before sending** - Always confirm with the user before actually sending an email.
|