crewly 1.0.0 → 1.0.1
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/config/constants.ts +40 -2
- package/config/skills/_common/lib.sh +2 -1
- package/config/skills/agent/computer-use/execute.sh +151 -0
- package/config/skills/agent/computer-use/instructions.md +60 -0
- package/config/skills/agent/computer-use/skill.json +22 -0
- package/config/skills/agent/heartbeat/execute.sh +22 -0
- package/config/skills/agent/heartbeat/instructions.md +23 -0
- package/config/skills/agent/heartbeat/skill.json +20 -0
- package/config/skills/orchestrator/schedule-check/execute.sh +1 -1
- package/config/skills/orchestrator/send-pdf-to-slack/execute.sh +28 -5
- package/config/skills/orchestrator/send-pdf-to-slack/instructions.md +49 -10
- package/config/skills/orchestrator/send-pdf-to-slack/skill.json +1 -1
- package/config/skills/orchestrator/subscribe-event/execute.sh +2 -2
- package/dist/backend/backend/src/constants.d.ts +24 -2
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +13 -3
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/session/session.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/session/session.controller.js +16 -7
- package/dist/backend/backend/src/controllers/session/session.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +27 -0
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +7 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +131 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/middleware/agent-heartbeat.middleware.d.ts +3 -2
- package/dist/backend/backend/src/middleware/agent-heartbeat.middleware.d.ts.map +1 -1
- package/dist/backend/backend/src/middleware/agent-heartbeat.middleware.js +8 -2
- package/dist/backend/backend/src/middleware/agent-heartbeat.middleware.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.d.ts +185 -0
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.js +508 -0
- package/dist/backend/backend/src/services/agent/agent-heartbeat-monitor.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/agent-heartbeat.service.d.ts +5 -5
- package/dist/backend/backend/src/services/agent/agent-heartbeat.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-heartbeat.service.js +3 -3
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +36 -13
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/disk-cleanup.service.d.ts +24 -3
- package/dist/backend/backend/src/services/agent/disk-cleanup.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/disk-cleanup.service.js +15 -3
- package/dist/backend/backend/src/services/agent/disk-cleanup.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/idle-detection.service.js +18 -0
- package/dist/backend/backend/src/services/agent/idle-detection.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.d.ts +7 -2
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.js +11 -3
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts +42 -0
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +190 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/tmux.service.js +2 -2
- package/dist/backend/backend/src/services/agent/tmux.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +13 -19
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts +129 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js +253 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js.map +1 -0
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +5 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-state-persistence.d.ts +4 -1
- package/dist/backend/backend/src/services/session/session-state-persistence.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-state-persistence.js +3 -1
- package/dist/backend/backend/src/services/session/session-state-persistence.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts +1 -0
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.js +1 -0
- package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +2 -0
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/types/scheduler.types.d.ts +17 -0
- package/dist/backend/backend/src/types/scheduler.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/scheduler.types.js.map +1 -1
- package/dist/backend/config/constants.d.ts +36 -2
- package/dist/backend/config/constants.d.ts.map +1 -1
- package/dist/backend/config/constants.js +37 -2
- package/dist/backend/config/constants.js.map +1 -1
- package/dist/backend/config/index.d.ts +1 -1
- package/dist/cli/cli/src/constants.d.ts +1 -1
- package/dist/cli/cli/src/index.js +1 -1
- package/dist/cli/cli/src/index.js.map +1 -1
- package/dist/cli/config/constants.d.ts +36 -2
- package/dist/cli/config/constants.d.ts.map +1 -1
- package/dist/cli/config/constants.js +37 -2
- package/dist/cli/config/constants.js.map +1 -1
- package/dist/cli/config/index.d.ts +1 -1
- package/frontend/dist/assets/{index-77b6a2a0.js → index-4c56763b.js} +31 -31
- package/frontend/dist/assets/{index-5ddf71c8.css → index-c1dd0b10.css} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +8 -4
- package/config/constants.test.ts +0 -469
- package/config/quality-gates/default-gates.test.ts +0 -246
- package/config/skills/agent/nano-banana-image/.env +0 -2
- package/config/skills/agent/nano-banana-image/.env.example +0 -6
- package/config/skills/nano-banana-image/.env +0 -2
- package/config/skills/nano-banana-image/.env.example +0 -6
package/config/constants.ts
CHANGED
|
@@ -346,8 +346,8 @@ export const MESSAGE_CONSTANTS = {
|
|
|
346
346
|
* Environment variable names used across domains
|
|
347
347
|
*/
|
|
348
348
|
export const ENV_CONSTANTS = {
|
|
349
|
-
/**
|
|
350
|
-
|
|
349
|
+
/** PTY session name used for agent identity and heartbeat tracking */
|
|
350
|
+
CREWLY_SESSION_NAME: 'CREWLY_SESSION_NAME',
|
|
351
351
|
/** Crewly role identifier */
|
|
352
352
|
CREWLY_ROLE: 'CREWLY_ROLE',
|
|
353
353
|
/** API server port */
|
|
@@ -768,6 +768,44 @@ export const ORCHESTRATOR_RESTART_CONSTANTS = {
|
|
|
768
768
|
RESTART_DELAY_MS: 5000,
|
|
769
769
|
} as const;
|
|
770
770
|
|
|
771
|
+
// ========================= ORCHESTRATOR HEARTBEAT MONITOR =========================
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Orchestrator heartbeat monitoring configuration.
|
|
775
|
+
* Used by OrchestratorHeartbeatMonitorService to detect unresponsive orchestrators,
|
|
776
|
+
* send proactive heartbeat requests, and trigger auto-restart with resume.
|
|
777
|
+
*/
|
|
778
|
+
export const ORCHESTRATOR_HEARTBEAT_CONSTANTS = {
|
|
779
|
+
/** Interval between heartbeat checks in milliseconds (30 seconds) */
|
|
780
|
+
CHECK_INTERVAL_MS: 30_000,
|
|
781
|
+
/** Time without API activity before sending a heartbeat request to orchestrator (5 minutes) */
|
|
782
|
+
HEARTBEAT_REQUEST_THRESHOLD_MS: 300_000,
|
|
783
|
+
/** Time after heartbeat request before triggering auto-restart (1 minute) */
|
|
784
|
+
RESTART_THRESHOLD_MS: 60_000,
|
|
785
|
+
/** Message sent to orchestrator PTY to request a heartbeat */
|
|
786
|
+
HEARTBEAT_REQUEST_MESSAGE: 'Please run your heartbeat skill now: bash config/skills/orchestrator/heartbeat/execute.sh',
|
|
787
|
+
/** Grace period after server start before monitoring begins (30 seconds) */
|
|
788
|
+
STARTUP_GRACE_PERIOD_MS: 30_000,
|
|
789
|
+
} as const;
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Agent heartbeat monitor configuration.
|
|
793
|
+
* Used by AgentHeartbeatMonitorService to detect crashed/unresponsive agents
|
|
794
|
+
* and auto-restart them with task re-delivery.
|
|
795
|
+
*/
|
|
796
|
+
export const AGENT_HEARTBEAT_MONITOR_CONSTANTS = {
|
|
797
|
+
/** Interval between heartbeat checks in milliseconds (30 seconds) */
|
|
798
|
+
CHECK_INTERVAL_MS: 30_000,
|
|
799
|
+
/** Time without activity (both PTY and API) before checking process liveness (5 minutes) */
|
|
800
|
+
HEARTBEAT_REQUEST_THRESHOLD_MS: 300_000,
|
|
801
|
+
/** Grace period after server start before monitoring begins (1 minute) */
|
|
802
|
+
STARTUP_GRACE_PERIOD_MS: 60_000,
|
|
803
|
+
/** Maximum restarts per cooldown window per agent */
|
|
804
|
+
MAX_RESTARTS_PER_WINDOW: 3,
|
|
805
|
+
/** Cooldown window for restart tracking (1 hour) */
|
|
806
|
+
COOLDOWN_WINDOW_MS: 3_600_000,
|
|
807
|
+
} as const;
|
|
808
|
+
|
|
771
809
|
// ========================= AGENT SUSPEND SYSTEM =========================
|
|
772
810
|
|
|
773
811
|
/**
|
|
@@ -19,7 +19,8 @@ api_call() {
|
|
|
19
19
|
local url="${CREWLY_API_URL}/api${endpoint}"
|
|
20
20
|
local args=(-s -w '\n%{http_code}' -X "$method" -H "Content-Type: application/json")
|
|
21
21
|
# Include agent session identity header for heartbeat tracking
|
|
22
|
-
|
|
22
|
+
# Use ${VAR:-} pattern to avoid 'unbound variable' error under set -u (nounset)
|
|
23
|
+
[ -n "${CREWLY_SESSION_NAME:-}" ] && args+=(-H "X-Agent-Session: $CREWLY_SESSION_NAME")
|
|
23
24
|
[ -n "$body" ] && args+=(-d "$body")
|
|
24
25
|
|
|
25
26
|
local response
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Desktop Automation (Computer Use) Skill
|
|
4
|
+
# Controls macOS desktop: screenshots, mouse, keyboard
|
|
5
|
+
# Uses native macOS APIs — no external dependencies required
|
|
6
|
+
# =============================================================================
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
+
source "${SCRIPT_DIR}/../_common/lib.sh"
|
|
11
|
+
|
|
12
|
+
INPUT="${1:-}"
|
|
13
|
+
[ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"action\":\"screenshot|move|click|type\", ...}'"
|
|
14
|
+
|
|
15
|
+
ACTION=$(echo "$INPUT" | jq -r '.action // empty')
|
|
16
|
+
require_param "action" "$ACTION"
|
|
17
|
+
|
|
18
|
+
# -----------------------------------------------------------------------------
|
|
19
|
+
# screenshot — capture the screen to a file
|
|
20
|
+
# -----------------------------------------------------------------------------
|
|
21
|
+
do_screenshot() {
|
|
22
|
+
local output
|
|
23
|
+
output=$(echo "$INPUT" | jq -r '.output // "/tmp/screenshot.png"')
|
|
24
|
+
|
|
25
|
+
# Ensure output directory exists
|
|
26
|
+
mkdir -p "$(dirname "$output")"
|
|
27
|
+
|
|
28
|
+
screencapture -x "$output" 2>/dev/null
|
|
29
|
+
|
|
30
|
+
if [ -f "$output" ]; then
|
|
31
|
+
local size
|
|
32
|
+
size=$(stat -f%z "$output" 2>/dev/null || stat -c%s "$output" 2>/dev/null || echo "unknown")
|
|
33
|
+
echo "{\"success\":true,\"action\":\"screenshot\",\"file\":\"$output\",\"size\":$size}"
|
|
34
|
+
else
|
|
35
|
+
error_exit "Screenshot failed — file not created"
|
|
36
|
+
fi
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# -----------------------------------------------------------------------------
|
|
40
|
+
# move — move mouse cursor to (x, y)
|
|
41
|
+
# -----------------------------------------------------------------------------
|
|
42
|
+
do_move() {
|
|
43
|
+
local x y
|
|
44
|
+
x=$(echo "$INPUT" | jq -r '.x // empty')
|
|
45
|
+
y=$(echo "$INPUT" | jq -r '.y // empty')
|
|
46
|
+
require_param "x" "$x"
|
|
47
|
+
require_param "y" "$y"
|
|
48
|
+
|
|
49
|
+
osascript -l JavaScript -e "
|
|
50
|
+
ObjC.import('CoreGraphics');
|
|
51
|
+
var point = $.CGPointMake($x, $y);
|
|
52
|
+
var event = $.CGEventCreateMouseEvent(null, $.kCGEventMouseMoved, point, 0);
|
|
53
|
+
$.CGEventPost($.kCGHIDEventTap, event);
|
|
54
|
+
'moved';
|
|
55
|
+
" >/dev/null 2>&1
|
|
56
|
+
|
|
57
|
+
echo "{\"success\":true,\"action\":\"move\",\"x\":$x,\"y\":$y}"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# -----------------------------------------------------------------------------
|
|
61
|
+
# click — click at (x, y) with optional button type
|
|
62
|
+
# -----------------------------------------------------------------------------
|
|
63
|
+
do_click() {
|
|
64
|
+
local x y button
|
|
65
|
+
x=$(echo "$INPUT" | jq -r '.x // empty')
|
|
66
|
+
y=$(echo "$INPUT" | jq -r '.y // empty')
|
|
67
|
+
button=$(echo "$INPUT" | jq -r '.button // "left"')
|
|
68
|
+
require_param "x" "$x"
|
|
69
|
+
require_param "y" "$y"
|
|
70
|
+
|
|
71
|
+
case "$button" in
|
|
72
|
+
left)
|
|
73
|
+
osascript -l JavaScript -e "
|
|
74
|
+
ObjC.import('CoreGraphics');
|
|
75
|
+
var point = $.CGPointMake($x, $y);
|
|
76
|
+
var move = $.CGEventCreateMouseEvent(null, $.kCGEventMouseMoved, point, 0);
|
|
77
|
+
$.CGEventPost($.kCGHIDEventTap, move);
|
|
78
|
+
var down = $.CGEventCreateMouseEvent(null, $.kCGEventLeftMouseDown, point, 0);
|
|
79
|
+
$.CGEventPost($.kCGHIDEventTap, down);
|
|
80
|
+
var up = $.CGEventCreateMouseEvent(null, $.kCGEventLeftMouseUp, point, 0);
|
|
81
|
+
$.CGEventPost($.kCGHIDEventTap, up);
|
|
82
|
+
'clicked';
|
|
83
|
+
" >/dev/null 2>&1
|
|
84
|
+
;;
|
|
85
|
+
right)
|
|
86
|
+
osascript -l JavaScript -e "
|
|
87
|
+
ObjC.import('CoreGraphics');
|
|
88
|
+
var point = $.CGPointMake($x, $y);
|
|
89
|
+
var move = $.CGEventCreateMouseEvent(null, $.kCGEventMouseMoved, point, 0);
|
|
90
|
+
$.CGEventPost($.kCGHIDEventTap, move);
|
|
91
|
+
var down = $.CGEventCreateMouseEvent(null, $.kCGEventRightMouseDown, point, $.kCGMouseButtonRight);
|
|
92
|
+
$.CGEventPost($.kCGHIDEventTap, down);
|
|
93
|
+
var up = $.CGEventCreateMouseEvent(null, $.kCGEventRightMouseUp, point, $.kCGMouseButtonRight);
|
|
94
|
+
$.CGEventPost($.kCGHIDEventTap, up);
|
|
95
|
+
'clicked';
|
|
96
|
+
" >/dev/null 2>&1
|
|
97
|
+
;;
|
|
98
|
+
double)
|
|
99
|
+
osascript -l JavaScript -e "
|
|
100
|
+
ObjC.import('CoreGraphics');
|
|
101
|
+
var point = $.CGPointMake($x, $y);
|
|
102
|
+
var move = $.CGEventCreateMouseEvent(null, $.kCGEventMouseMoved, point, 0);
|
|
103
|
+
$.CGEventPost($.kCGHIDEventTap, move);
|
|
104
|
+
var down1 = $.CGEventCreateMouseEvent(null, $.kCGEventLeftMouseDown, point, 0);
|
|
105
|
+
$.CGEventSetIntegerValueField(down1, $.kCGMouseEventClickState, 1);
|
|
106
|
+
$.CGEventPost($.kCGHIDEventTap, down1);
|
|
107
|
+
var up1 = $.CGEventCreateMouseEvent(null, $.kCGEventLeftMouseUp, point, 0);
|
|
108
|
+
$.CGEventSetIntegerValueField(up1, $.kCGMouseEventClickState, 1);
|
|
109
|
+
$.CGEventPost($.kCGHIDEventTap, up1);
|
|
110
|
+
delay(0.05);
|
|
111
|
+
var down2 = $.CGEventCreateMouseEvent(null, $.kCGEventLeftMouseDown, point, 0);
|
|
112
|
+
$.CGEventSetIntegerValueField(down2, $.kCGMouseEventClickState, 2);
|
|
113
|
+
$.CGEventPost($.kCGHIDEventTap, down2);
|
|
114
|
+
var up2 = $.CGEventCreateMouseEvent(null, $.kCGEventLeftMouseUp, point, 0);
|
|
115
|
+
$.CGEventSetIntegerValueField(up2, $.kCGMouseEventClickState, 2);
|
|
116
|
+
$.CGEventPost($.kCGHIDEventTap, up2);
|
|
117
|
+
'double-clicked';
|
|
118
|
+
" >/dev/null 2>&1
|
|
119
|
+
;;
|
|
120
|
+
*)
|
|
121
|
+
error_exit "Unknown button type: $button (use left, right, or double)"
|
|
122
|
+
;;
|
|
123
|
+
esac
|
|
124
|
+
|
|
125
|
+
echo "{\"success\":true,\"action\":\"click\",\"x\":$x,\"y\":$y,\"button\":\"$button\"}"
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# -----------------------------------------------------------------------------
|
|
129
|
+
# type — simulate keyboard input
|
|
130
|
+
# -----------------------------------------------------------------------------
|
|
131
|
+
do_type() {
|
|
132
|
+
local text
|
|
133
|
+
text=$(echo "$INPUT" | jq -r '.text // empty')
|
|
134
|
+
require_param "text" "$text"
|
|
135
|
+
|
|
136
|
+
osascript -e "tell application \"System Events\" to keystroke \"$text\"" 2>/dev/null
|
|
137
|
+
|
|
138
|
+
local char_count=${#text}
|
|
139
|
+
echo "{\"success\":true,\"action\":\"type\",\"characters\":$char_count}"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# -----------------------------------------------------------------------------
|
|
143
|
+
# Dispatch
|
|
144
|
+
# -----------------------------------------------------------------------------
|
|
145
|
+
case "$ACTION" in
|
|
146
|
+
screenshot) do_screenshot ;;
|
|
147
|
+
move) do_move ;;
|
|
148
|
+
click) do_click ;;
|
|
149
|
+
type) do_type ;;
|
|
150
|
+
*) error_exit "Unknown action: $ACTION (use screenshot, move, click, or type)" ;;
|
|
151
|
+
esac
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Desktop Automation (Computer Use)
|
|
2
|
+
|
|
3
|
+
Control the macOS desktop by taking screenshots, moving/clicking the mouse, and typing text.
|
|
4
|
+
|
|
5
|
+
## Actions
|
|
6
|
+
|
|
7
|
+
### Screenshot
|
|
8
|
+
Capture the screen (or a region) to an image file.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bash execute.sh '{"action":"screenshot"}'
|
|
12
|
+
bash execute.sh '{"action":"screenshot","output":"/tmp/my-screenshot.png"}'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Move Mouse
|
|
16
|
+
Move the mouse cursor to a specific coordinate.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bash execute.sh '{"action":"move","x":500,"y":300}'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Click
|
|
23
|
+
Click at a specific coordinate. Supports left click, right click, and double click.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bash execute.sh '{"action":"click","x":500,"y":300}'
|
|
27
|
+
bash execute.sh '{"action":"click","x":500,"y":300,"button":"right"}'
|
|
28
|
+
bash execute.sh '{"action":"click","x":500,"y":300,"button":"double"}'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Type Text
|
|
32
|
+
Type a string of text using simulated keystrokes.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bash execute.sh '{"action":"type","text":"Hello, world!"}'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Parameters
|
|
39
|
+
|
|
40
|
+
| Parameter | Required | Default | Description |
|
|
41
|
+
|-----------|----------|---------|-------------|
|
|
42
|
+
| `action` | Yes | - | One of: `screenshot`, `move`, `click`, `type` |
|
|
43
|
+
| `x` | For move/click | - | X coordinate (pixels from left) |
|
|
44
|
+
| `y` | For move/click | - | Y coordinate (pixels from top) |
|
|
45
|
+
| `button` | No | `left` | Click button: `left`, `right`, or `double` |
|
|
46
|
+
| `text` | For type | - | Text string to type |
|
|
47
|
+
| `output` | No | `/tmp/screenshot.png` | Screenshot output file path |
|
|
48
|
+
|
|
49
|
+
## Requirements
|
|
50
|
+
|
|
51
|
+
- macOS (uses native `screencapture` and CoreGraphics)
|
|
52
|
+
- Accessibility permissions must be granted to the terminal app (System Settings > Privacy & Security > Accessibility)
|
|
53
|
+
|
|
54
|
+
## Typical Workflow
|
|
55
|
+
|
|
56
|
+
1. Take a screenshot to see the current screen state
|
|
57
|
+
2. Identify the coordinates of the target element
|
|
58
|
+
3. Move the mouse and/or click on the target
|
|
59
|
+
4. Optionally type text into a focused field
|
|
60
|
+
5. Take another screenshot to verify the result
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "computer-use",
|
|
3
|
+
"name": "Desktop Automation (Computer Use)",
|
|
4
|
+
"description": "Control the macOS desktop: take screenshots, move/click the mouse, and type text. Uses native macOS APIs (screencapture, CoreGraphics via JXA, System Events) with zero external dependencies.",
|
|
5
|
+
"category": "automation",
|
|
6
|
+
"skillType": "claude-skill",
|
|
7
|
+
"promptFile": "instructions.md",
|
|
8
|
+
"execution": {
|
|
9
|
+
"type": "script",
|
|
10
|
+
"script": {
|
|
11
|
+
"file": "execute.sh",
|
|
12
|
+
"interpreter": "bash",
|
|
13
|
+
"timeoutMs": 30000
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"triggers": ["screenshot", "click", "mouse", "type text", "desktop automation", "computer use"],
|
|
17
|
+
"tags": ["automation", "desktop", "screenshot", "mouse", "keyboard", "macos"],
|
|
18
|
+
"assignableRoles": ["generalist", "designer", "qa"],
|
|
19
|
+
"version": "1.0.0",
|
|
20
|
+
"createdAt": "2026-02-20T00:00:00.000Z",
|
|
21
|
+
"updatedAt": "2026-02-20T00:00:00.000Z"
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Agent Heartbeat Skill - Lightweight health check and heartbeat update
|
|
4
|
+
#
|
|
5
|
+
# Calls the /health endpoint to update the agent heartbeat via the
|
|
6
|
+
# X-Agent-Session middleware header (set automatically by lib.sh).
|
|
7
|
+
# =============================================================================
|
|
8
|
+
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
+
source "$SCRIPT_DIR/../../_common/lib.sh"
|
|
11
|
+
|
|
12
|
+
# Single API call updates heartbeat via the X-Agent-Session middleware
|
|
13
|
+
health_response=$(api_call GET "/health" 2>/dev/null) || health_response='{"error":"unavailable"}'
|
|
14
|
+
|
|
15
|
+
cat <<EOF
|
|
16
|
+
{
|
|
17
|
+
"status": "ok",
|
|
18
|
+
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
19
|
+
"session": "${CREWLY_SESSION_NAME:-unknown}",
|
|
20
|
+
"health": $health_response
|
|
21
|
+
}
|
|
22
|
+
EOF
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Agent Heartbeat Skill
|
|
2
|
+
|
|
3
|
+
Perform a lightweight health check to confirm that you are responsive.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
Run this skill when the system asks you to perform a heartbeat check. This updates your heartbeat timestamp so the monitoring system knows you are alive and responsive.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bash config/skills/agent/heartbeat/execute.sh
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
No parameters required.
|
|
16
|
+
|
|
17
|
+
## Output
|
|
18
|
+
|
|
19
|
+
Returns a JSON object with:
|
|
20
|
+
- `status`: "ok" if the health endpoint responded
|
|
21
|
+
- `timestamp`: UTC timestamp of the check
|
|
22
|
+
- `session`: your session name
|
|
23
|
+
- `health`: response from the health endpoint
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "agent-heartbeat",
|
|
3
|
+
"name": "Heartbeat",
|
|
4
|
+
"description": "Perform a lightweight health check to confirm the agent is responsive. Updates the heartbeat timestamp via the API middleware.",
|
|
5
|
+
"category": "monitoring",
|
|
6
|
+
"skillType": "claude-skill",
|
|
7
|
+
"promptFile": "instructions.md",
|
|
8
|
+
"execution": {
|
|
9
|
+
"type": "script",
|
|
10
|
+
"script": {
|
|
11
|
+
"file": "execute.sh",
|
|
12
|
+
"interpreter": "bash",
|
|
13
|
+
"timeoutMs": 15000
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"assignableRoles": ["developer", "qa", "devops", "pm", "tpm"],
|
|
17
|
+
"triggers": ["heartbeat", "health check"],
|
|
18
|
+
"tags": ["monitoring", "heartbeat", "health"],
|
|
19
|
+
"version": "1.0.0"
|
|
20
|
+
}
|
|
@@ -16,7 +16,7 @@ require_param "minutes" "$MINUTES"
|
|
|
16
16
|
require_param "message" "$MESSAGE"
|
|
17
17
|
|
|
18
18
|
# Default target to the caller's own session (orchestrator sends reminders to itself)
|
|
19
|
-
TARGET_SESSION="${TARGET:-${
|
|
19
|
+
TARGET_SESSION="${TARGET:-${CREWLY_SESSION_NAME:-crewly-orc}}"
|
|
20
20
|
|
|
21
21
|
# API expects: targetSession, minutes, message
|
|
22
22
|
# When recurring, also send isRecurring, intervalMinutes, and optional maxOccurrences
|
|
@@ -105,7 +105,7 @@ trap cleanup EXIT
|
|
|
105
105
|
|
|
106
106
|
# Convert markdown to PDF using weasyprint
|
|
107
107
|
if ! "$PYTHON" -c "
|
|
108
|
-
import sys, markdown, weasyprint
|
|
108
|
+
import sys, os, re, markdown, weasyprint
|
|
109
109
|
|
|
110
110
|
md_file = sys.argv[1]
|
|
111
111
|
pdf_file = sys.argv[2]
|
|
@@ -113,28 +113,51 @@ pdf_file = sys.argv[2]
|
|
|
113
113
|
with open(md_file, 'r', encoding='utf-8') as f:
|
|
114
114
|
md_content = f.read()
|
|
115
115
|
|
|
116
|
+
# Resolve the base directory for relative image paths
|
|
117
|
+
base_dir = os.path.dirname(os.path.abspath(md_file))
|
|
118
|
+
|
|
119
|
+
# Convert local absolute image paths to file:// URLs so weasyprint can load them
|
|
120
|
+
def fix_image_paths(content):
|
|
121
|
+
# Match markdown image syntax: 
|
|
122
|
+
def replace_path(match):
|
|
123
|
+
alt = match.group(1)
|
|
124
|
+
path = match.group(2)
|
|
125
|
+
if os.path.isabs(path) and os.path.exists(path):
|
|
126
|
+
return ''
|
|
127
|
+
elif not path.startswith(('http://', 'https://', 'file://')) and os.path.exists(os.path.join(base_dir, path)):
|
|
128
|
+
full = os.path.join(base_dir, path)
|
|
129
|
+
return ''
|
|
130
|
+
return match.group(0)
|
|
131
|
+
return re.sub(r'!\[([^\]]*)\]\(([^)]+)\)', replace_path, content)
|
|
132
|
+
|
|
133
|
+
md_content = fix_image_paths(md_content)
|
|
134
|
+
|
|
116
135
|
html = markdown.markdown(md_content, extensions=['tables', 'fenced_code', 'codehilite', 'toc', 'meta'])
|
|
117
136
|
|
|
118
137
|
styled_html = '''<!DOCTYPE html>
|
|
119
138
|
<html><head><meta charset=\"utf-8\">
|
|
120
139
|
<style>
|
|
140
|
+
@page { size: A4; margin: 20mm 15mm; }
|
|
121
141
|
body { font-family: -apple-system, \"Noto Sans SC\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif;
|
|
122
|
-
max-width: 800px; margin:
|
|
142
|
+
max-width: 800px; margin: 0 auto; padding: 0; line-height: 1.8;
|
|
123
143
|
font-size: 14px; color: #333; }
|
|
124
144
|
h1 { font-size: 24px; border-bottom: 2px solid #333; padding-bottom: 8px; }
|
|
125
145
|
h2 { font-size: 20px; border-bottom: 1px solid #ddd; padding-bottom: 6px; margin-top: 28px; }
|
|
126
146
|
h3 { font-size: 16px; margin-top: 20px; }
|
|
127
|
-
|
|
128
|
-
|
|
147
|
+
img { max-width: 100%; height: auto; display: block; margin: 16px auto;
|
|
148
|
+
border: 1px solid #e0e0e0; border-radius: 4px; }
|
|
149
|
+
table { border-collapse: collapse; width: 100%; margin: 16px 0; font-size: 12px; }
|
|
150
|
+
th, td { border: 1px solid #ddd; padding: 6px 10px; text-align: left; }
|
|
129
151
|
th { background-color: #f5f5f5; font-weight: 600; }
|
|
130
152
|
code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; font-size: 13px; }
|
|
131
153
|
pre { background: #f4f4f4; padding: 16px; border-radius: 6px; overflow-x: auto; }
|
|
132
154
|
blockquote { border-left: 4px solid #ddd; margin: 16px 0; padding: 8px 16px; color: #666; }
|
|
133
155
|
ul, ol { padding-left: 24px; }
|
|
134
156
|
li { margin: 4px 0; }
|
|
157
|
+
hr { border: none; border-top: 1px solid #ddd; margin: 24px 0; }
|
|
135
158
|
</style></head><body>''' + html + '</body></html>'
|
|
136
159
|
|
|
137
|
-
weasyprint.HTML(string=styled_html).write_pdf(pdf_file)
|
|
160
|
+
weasyprint.HTML(string=styled_html, base_url='file://' + base_dir + '/').write_pdf(pdf_file)
|
|
138
161
|
" "$MD_FILE" "$PDF_FILE" 2>/tmp/weasyprint-err-$$.log; then
|
|
139
162
|
WP_ERR="$(cat /tmp/weasyprint-err-$$.log 2>/dev/null || echo 'unknown error')"
|
|
140
163
|
error_exit "weasyprint conversion failed: ${WP_ERR}"
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# Send PDF to Slack
|
|
2
2
|
|
|
3
|
-
Converts a markdown file to
|
|
3
|
+
Converts a markdown file to a styled PDF and uploads it to a Slack channel via the `/api/slack/upload-file` endpoint. Supports embedding local images referenced in the markdown.
|
|
4
|
+
|
|
5
|
+
## Image Support
|
|
6
|
+
|
|
7
|
+
The skill automatically handles local images referenced in markdown:
|
|
8
|
+
|
|
9
|
+
- **Absolute paths**: `` — converted to `file://` URLs
|
|
10
|
+
- **Relative paths**: `` — resolved relative to the markdown file's directory
|
|
11
|
+
- **Remote URLs**: `` — passed through as-is
|
|
12
|
+
|
|
13
|
+
Images are rendered at full width (max 100% of page) with auto height scaling, centered with a subtle border.
|
|
4
14
|
|
|
5
15
|
## Prerequisites
|
|
6
16
|
|
|
@@ -10,7 +20,12 @@ Converts a markdown file to PDF using `weasyprint` (Python) and uploads it to a
|
|
|
10
20
|
## Usage
|
|
11
21
|
|
|
12
22
|
```bash
|
|
13
|
-
bash config/skills/orchestrator/send-pdf-to-slack/execute.sh
|
|
23
|
+
bash config/skills/orchestrator/send-pdf-to-slack/execute.sh \
|
|
24
|
+
--channel C0123ABC \
|
|
25
|
+
--file /path/to/document.md \
|
|
26
|
+
--title "Weekly Report" \
|
|
27
|
+
--text "Here is the report" \
|
|
28
|
+
--thread 1707123456.789000
|
|
14
29
|
```
|
|
15
30
|
|
|
16
31
|
## Parameters
|
|
@@ -23,19 +38,43 @@ bash config/skills/orchestrator/send-pdf-to-slack/execute.sh --channel C0123ABC
|
|
|
23
38
|
| `--text`, `-t` | No | Initial comment to include with the upload |
|
|
24
39
|
| `--thread`, `-r` | No | Slack thread timestamp for threaded upload |
|
|
25
40
|
|
|
26
|
-
##
|
|
41
|
+
## Example: Daily Report with Infographics
|
|
27
42
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
43
|
+
Create a markdown file with embedded images:
|
|
44
|
+
|
|
45
|
+
```markdown
|
|
46
|
+
# AI Daily Report - 2026-02-21
|
|
47
|
+
|
|
48
|
+
## 1. Paper Title
|
|
49
|
+
Summary of the paper.
|
|
31
50
|
|
|
32
|
-
|
|
33
|
-
bash execute.sh --channel C0123ABC --file report.md --title "Q4 Report" --text "Here is the quarterly report"
|
|
51
|
+

|
|
34
52
|
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
## 2. Another Paper
|
|
54
|
+
Summary here.
|
|
55
|
+
|
|
56
|
+

|
|
37
57
|
```
|
|
38
58
|
|
|
59
|
+
Then send it:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
bash config/skills/orchestrator/send-pdf-to-slack/execute.sh \
|
|
63
|
+
--channel D0AC7NF5N7L \
|
|
64
|
+
--file /path/to/daily-report.md \
|
|
65
|
+
--title "AI Daily Report 2026-02-21" \
|
|
66
|
+
--text "Today's AI report with infographics" \
|
|
67
|
+
--thread 1771651155.079579
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## PDF Styling
|
|
71
|
+
|
|
72
|
+
- A4 page size with 20mm/15mm margins
|
|
73
|
+
- System fonts with CJK support (PingFang SC, Noto Sans SC)
|
|
74
|
+
- Images: max-width 100%, centered, with subtle border
|
|
75
|
+
- Tables: full width, bordered cells
|
|
76
|
+
- Code blocks: gray background with monospace font
|
|
77
|
+
|
|
39
78
|
## Output
|
|
40
79
|
|
|
41
80
|
JSON response from the upload API with `fileId` on success. Also emits a `[NOTIFY]` block for chat service integration.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "orc-send-pdf-to-slack",
|
|
3
3
|
"name": "Send PDF to Slack",
|
|
4
|
-
"description": "Convert a markdown file to PDF and upload it to a Slack channel.",
|
|
4
|
+
"description": "Convert a markdown file to a styled PDF (with embedded local images) and upload it to a Slack channel. Supports markdown image syntax  — local absolute and relative image paths are automatically resolved and embedded in the PDF.",
|
|
5
5
|
"category": "communication",
|
|
6
6
|
"skillType": "claude-skill",
|
|
7
7
|
"promptFile": "instructions.md",
|
|
@@ -10,9 +10,9 @@ INPUT="${1:-}"
|
|
|
10
10
|
EVENT_TYPE=$(echo "$INPUT" | jq -r '.eventType // empty')
|
|
11
11
|
require_param "eventType" "$EVENT_TYPE"
|
|
12
12
|
|
|
13
|
-
# Inject subscriberSession from env (set by Crewly on each
|
|
13
|
+
# Inject subscriberSession from env (set by Crewly on each PTY session)
|
|
14
14
|
# The API requires subscriberSession and filter but the agent doesn't need to provide them
|
|
15
|
-
SUBSCRIBER_SESSION="${
|
|
15
|
+
SUBSCRIBER_SESSION="${CREWLY_SESSION_NAME:-crewly-orc}"
|
|
16
16
|
BODY=$(echo "$INPUT" | jq --arg ss "$SUBSCRIBER_SESSION" \
|
|
17
17
|
'. + {subscriberSession: $ss} | if .filter == null then .filter = {} else . end')
|
|
18
18
|
|
|
@@ -160,6 +160,20 @@ export declare const VERSION_CHECK_CONSTANTS: {
|
|
|
160
160
|
readonly CACHE_TTL_MS: number;
|
|
161
161
|
readonly REQUEST_TIMEOUT_MS: 5000;
|
|
162
162
|
};
|
|
163
|
+
export declare const AGENT_HEARTBEAT_MONITOR_CONSTANTS: {
|
|
164
|
+
readonly CHECK_INTERVAL_MS: 30000;
|
|
165
|
+
readonly HEARTBEAT_REQUEST_THRESHOLD_MS: 300000;
|
|
166
|
+
readonly STARTUP_GRACE_PERIOD_MS: 60000;
|
|
167
|
+
readonly MAX_RESTARTS_PER_WINDOW: 3;
|
|
168
|
+
readonly COOLDOWN_WINDOW_MS: 3600000;
|
|
169
|
+
};
|
|
170
|
+
export declare const ORCHESTRATOR_HEARTBEAT_CONSTANTS: {
|
|
171
|
+
readonly CHECK_INTERVAL_MS: 30000;
|
|
172
|
+
readonly HEARTBEAT_REQUEST_THRESHOLD_MS: 300000;
|
|
173
|
+
readonly RESTART_THRESHOLD_MS: 60000;
|
|
174
|
+
readonly HEARTBEAT_REQUEST_MESSAGE: "Please run your heartbeat skill now: bash config/skills/orchestrator/heartbeat/execute.sh";
|
|
175
|
+
readonly STARTUP_GRACE_PERIOD_MS: 30000;
|
|
176
|
+
};
|
|
163
177
|
export declare const ORCHESTRATOR_SESSION_NAME = "crewly-orc";
|
|
164
178
|
export declare const ORCHESTRATOR_ROLE = "orchestrator";
|
|
165
179
|
export declare const ORCHESTRATOR_WINDOW_NAME = "Crewly Orchestrator";
|
|
@@ -229,8 +243,8 @@ export declare const CREWLY_CONSTANTS: {
|
|
|
229
243
|
};
|
|
230
244
|
};
|
|
231
245
|
export declare const ENV_CONSTANTS: {
|
|
232
|
-
/**
|
|
233
|
-
readonly
|
|
246
|
+
/** PTY session name used for agent identity and heartbeat tracking */
|
|
247
|
+
readonly CREWLY_SESSION_NAME: "CREWLY_SESSION_NAME";
|
|
234
248
|
readonly CREWLY_ROLE: "CREWLY_ROLE";
|
|
235
249
|
/** Base URL for the Crewly backend API (used by orchestrator bash skills) */
|
|
236
250
|
readonly CREWLY_API_URL: "CREWLY_API_URL";
|
|
@@ -553,6 +567,14 @@ export declare const RUNTIME_EXIT_CONSTANTS: {
|
|
|
553
567
|
* normal runtime initialization output.
|
|
554
568
|
*/
|
|
555
569
|
readonly STARTUP_GRACE_PERIOD_MS: 0;
|
|
570
|
+
/**
|
|
571
|
+
* Grace period for API activity before confirming a runtime exit (ms).
|
|
572
|
+
* If the agent made an API call within this window, the exit detection
|
|
573
|
+
* is treated as a false positive and skipped. This prevents false
|
|
574
|
+
* restarts when agents are actively calling skills/APIs but happen to
|
|
575
|
+
* produce PTY output that matches exit patterns.
|
|
576
|
+
*/
|
|
577
|
+
readonly API_ACTIVITY_GRACE_PERIOD_MS: 120000;
|
|
556
578
|
};
|
|
557
579
|
/**
|
|
558
580
|
* Constants for sub-agent message queue.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../backend/src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../backend/src/constants.ts"],"names":[],"mappings":"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"}
|