crewly 1.1.2 → 1.2.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.
Files changed (216) hide show
  1. package/README.md +6 -6
  2. package/config/roles/ops/prompt.md +140 -0
  3. package/config/roles/ops/role.json +13 -0
  4. package/config/skills/agent/browse-stealth/execute.sh +84 -0
  5. package/config/skills/agent/browse-stealth/instructions.md +108 -0
  6. package/config/skills/agent/browse-stealth/launch-chrome-cdp.sh +141 -0
  7. package/config/skills/agent/browse-stealth/skill.json +20 -0
  8. package/config/skills/agent/browse-stealth/stealth-browse.py +330 -0
  9. package/config/skills/agent/competitor-content-tracker/execute.sh +232 -0
  10. package/config/skills/agent/competitor-content-tracker/instructions.md +210 -0
  11. package/config/skills/agent/competitor-content-tracker/skill.json +22 -0
  12. package/config/skills/agent/content-calendar/execute.sh +294 -0
  13. package/config/skills/agent/content-calendar/instructions.md +122 -0
  14. package/config/skills/agent/content-calendar/skill.json +22 -0
  15. package/config/skills/agent/content-repurposer/execute.sh +194 -0
  16. package/config/skills/agent/content-repurposer/instructions.md +69 -0
  17. package/config/skills/agent/content-repurposer/skill.json +22 -0
  18. package/config/skills/agent/content-writer/execute.sh +311 -0
  19. package/config/skills/agent/content-writer/instructions.md +124 -0
  20. package/config/skills/agent/content-writer/skill.json +22 -0
  21. package/config/skills/agent/core/generate-pdf/execute.sh +88 -0
  22. package/config/skills/agent/core/generate-pdf/instructions.md +46 -0
  23. package/config/skills/agent/core/generate-pdf/skill.json +20 -0
  24. package/config/skills/agent/core/report-status/execute.sh +6 -0
  25. package/config/skills/agent/trend-monitor/execute.sh +211 -0
  26. package/config/skills/agent/trend-monitor/instructions.md +207 -0
  27. package/config/skills/agent/trend-monitor/skill.json +22 -0
  28. package/config/skills/agent/vnc-browser/execute.sh +261 -0
  29. package/config/skills/agent/vnc-browser/instructions.md +102 -0
  30. package/config/skills/agent/vnc-browser/skill.json +20 -0
  31. package/config/skills/orchestrator/delegate-task/execute.sh +63 -4
  32. package/config/skills/orchestrator/delegate-task/instructions.md +60 -0
  33. package/config/skills/orchestrator/delegate-task/skill.json +4 -4
  34. package/config/skills/orchestrator/reply-slack/execute.sh +2 -0
  35. package/config/skills/orchestrator/send-key/execute.sh +19 -6
  36. package/config/skills/orchestrator/send-key/instructions.md +44 -0
  37. package/config/skills/orchestrator/send-key/skill.json +20 -0
  38. package/config/skills/orchestrator/send-message/execute.sh +9 -1
  39. package/config/skills/registry.json +256 -0
  40. package/config/templates/code-review-team/README.md +176 -0
  41. package/config/templates/code-review-team/team-config.json +16 -0
  42. package/config/templates/code-review-team.json +62 -0
  43. package/config/templates/content-generation-team/README.md +128 -0
  44. package/config/templates/content-generation-team/team-config.json +21 -0
  45. package/config/templates/content-generation-team.json +67 -0
  46. package/config/templates/demo-team.json +22 -0
  47. package/config/templates/social-media-ops-team/README.md +145 -0
  48. package/config/templates/social-media-ops-team/team-config.json +21 -0
  49. package/config/templates/social-media-ops-team.json +67 -0
  50. package/dist/backend/backend/src/constants.d.ts +69 -6
  51. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  52. package/dist/backend/backend/src/constants.js +75 -6
  53. package/dist/backend/backend/src/constants.js.map +1 -1
  54. package/dist/backend/backend/src/controllers/index.d.ts.map +1 -1
  55. package/dist/backend/backend/src/controllers/index.js +2 -0
  56. package/dist/backend/backend/src/controllers/index.js.map +1 -1
  57. package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts +8 -0
  58. package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts.map +1 -1
  59. package/dist/backend/backend/src/controllers/messaging/messenger.routes.js +110 -63
  60. package/dist/backend/backend/src/controllers/messaging/messenger.routes.js.map +1 -1
  61. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
  62. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +31 -4
  63. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
  64. package/dist/backend/backend/src/controllers/oauth/oauth.routes.d.ts +8 -0
  65. package/dist/backend/backend/src/controllers/oauth/oauth.routes.d.ts.map +1 -1
  66. package/dist/backend/backend/src/controllers/oauth/oauth.routes.js +127 -111
  67. package/dist/backend/backend/src/controllers/oauth/oauth.routes.js.map +1 -1
  68. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts +34 -0
  69. package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -1
  70. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +219 -2
  71. package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -1
  72. package/dist/backend/backend/src/controllers/user/user.routes.d.ts +7 -0
  73. package/dist/backend/backend/src/controllers/user/user.routes.d.ts.map +1 -1
  74. package/dist/backend/backend/src/controllers/user/user.routes.js +45 -38
  75. package/dist/backend/backend/src/controllers/user/user.routes.js.map +1 -1
  76. package/dist/backend/backend/src/controllers/whatsapp/index.d.ts +17 -0
  77. package/dist/backend/backend/src/controllers/whatsapp/index.d.ts.map +1 -0
  78. package/dist/backend/backend/src/controllers/whatsapp/index.js +18 -0
  79. package/dist/backend/backend/src/controllers/whatsapp/index.js.map +1 -0
  80. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.d.ts +12 -0
  81. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.d.ts.map +1 -0
  82. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.js +185 -0
  83. package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.js.map +1 -0
  84. package/dist/backend/backend/src/index.d.ts +5 -0
  85. package/dist/backend/backend/src/index.d.ts.map +1 -1
  86. package/dist/backend/backend/src/index.js +35 -0
  87. package/dist/backend/backend/src/index.js.map +1 -1
  88. package/dist/backend/backend/src/routes/modules/task-management.routes.d.ts.map +1 -1
  89. package/dist/backend/backend/src/routes/modules/task-management.routes.js +4 -0
  90. package/dist/backend/backend/src/routes/modules/task-management.routes.js.map +1 -1
  91. package/dist/backend/backend/src/services/agent/agent-heartbeat.service.js +1 -1
  92. package/dist/backend/backend/src/services/agent/agent-heartbeat.service.js.map +1 -1
  93. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +14 -3
  94. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  95. package/dist/backend/backend/src/services/agent/agent-registration.service.js +160 -29
  96. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  97. package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts +4 -3
  98. package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts.map +1 -1
  99. package/dist/backend/backend/src/services/agent/claude-runtime.service.js +29 -4
  100. package/dist/backend/backend/src/services/agent/claude-runtime.service.js.map +1 -1
  101. package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
  102. package/dist/backend/backend/src/services/agent/context-window-monitor.service.js +11 -0
  103. package/dist/backend/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
  104. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts +32 -2
  105. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
  106. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +69 -8
  107. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
  108. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  109. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js +14 -2
  110. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  111. package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.d.ts.map +1 -1
  112. package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js +11 -2
  113. package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js.map +1 -1
  114. package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.d.ts +18 -0
  115. package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.d.ts.map +1 -1
  116. package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.js +28 -4
  117. package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.js.map +1 -1
  118. package/dist/backend/backend/src/services/messaging/adapters/slack-messenger.adapter.js +2 -2
  119. package/dist/backend/backend/src/services/messaging/adapters/slack-messenger.adapter.js.map +1 -1
  120. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts +18 -0
  121. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts.map +1 -1
  122. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js +26 -4
  123. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js.map +1 -1
  124. package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts +28 -2
  125. package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts.map +1 -1
  126. package/dist/backend/backend/src/services/messaging/messenger-registry.service.d.ts +33 -2
  127. package/dist/backend/backend/src/services/messaging/messenger-registry.service.d.ts.map +1 -1
  128. package/dist/backend/backend/src/services/messaging/messenger-registry.service.js +33 -0
  129. package/dist/backend/backend/src/services/messaging/messenger-registry.service.js.map +1 -1
  130. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
  131. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +4 -2
  132. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
  133. package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.d.ts.map +1 -1
  134. package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.js +4 -3
  135. package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.js.map +1 -1
  136. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +27 -0
  137. package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +1 -1
  138. package/dist/backend/backend/src/services/project/task-tracking.service.js +54 -0
  139. package/dist/backend/backend/src/services/project/task-tracking.service.js.map +1 -1
  140. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +36 -6
  141. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  142. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +238 -36
  143. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  144. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  145. package/dist/backend/backend/src/services/slack/slack.service.js +6 -4
  146. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  147. package/dist/backend/backend/src/services/user/user-identity.service.d.ts +44 -0
  148. package/dist/backend/backend/src/services/user/user-identity.service.d.ts.map +1 -1
  149. package/dist/backend/backend/src/services/user/user-identity.service.js +75 -8
  150. package/dist/backend/backend/src/services/user/user-identity.service.js.map +1 -1
  151. package/dist/backend/backend/src/services/whatsapp/index.d.ts +11 -0
  152. package/dist/backend/backend/src/services/whatsapp/index.d.ts.map +1 -0
  153. package/dist/backend/backend/src/services/whatsapp/index.js +11 -0
  154. package/dist/backend/backend/src/services/whatsapp/index.js.map +1 -0
  155. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.d.ts +66 -0
  156. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.d.ts.map +1 -0
  157. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.js +96 -0
  158. package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.js.map +1 -0
  159. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts +109 -0
  160. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts.map +1 -0
  161. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js +234 -0
  162. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js.map +1 -0
  163. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.d.ts +127 -0
  164. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.d.ts.map +1 -0
  165. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js +347 -0
  166. package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js.map +1 -0
  167. package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts.map +1 -1
  168. package/dist/backend/backend/src/services/workflow/scheduler.service.js +4 -0
  169. package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
  170. package/dist/backend/backend/src/types/index.d.ts +1 -0
  171. package/dist/backend/backend/src/types/index.d.ts.map +1 -1
  172. package/dist/backend/backend/src/types/index.js.map +1 -1
  173. package/dist/backend/backend/src/types/slack.types.d.ts +24 -0
  174. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  175. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  176. package/dist/backend/backend/src/types/task-tracking.types.d.ts +4 -0
  177. package/dist/backend/backend/src/types/task-tracking.types.d.ts.map +1 -1
  178. package/dist/backend/backend/src/types/task-tracking.types.js.map +1 -1
  179. package/dist/backend/backend/src/types/whatsapp.types.d.ts +84 -0
  180. package/dist/backend/backend/src/types/whatsapp.types.d.ts.map +1 -0
  181. package/dist/backend/backend/src/types/whatsapp.types.js +33 -0
  182. package/dist/backend/backend/src/types/whatsapp.types.js.map +1 -0
  183. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts +11 -0
  184. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
  185. package/dist/backend/backend/src/websocket/terminal.gateway.js +35 -1
  186. package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
  187. package/dist/cli/backend/src/constants.d.ts +69 -6
  188. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  189. package/dist/cli/backend/src/constants.js +75 -6
  190. package/dist/cli/backend/src/constants.js.map +1 -1
  191. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  192. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js +14 -2
  193. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  194. package/dist/cli/backend/src/types/index.d.ts +1 -0
  195. package/dist/cli/backend/src/types/index.d.ts.map +1 -1
  196. package/dist/cli/backend/src/types/index.js.map +1 -1
  197. package/dist/cli/cli/src/commands/publish.d.ts.map +1 -1
  198. package/dist/cli/cli/src/commands/publish.js +17 -15
  199. package/dist/cli/cli/src/commands/publish.js.map +1 -1
  200. package/dist/cli/cli/src/index.js +2 -2
  201. package/dist/cli/cli/src/index.js.map +1 -1
  202. package/dist/cli/cli/src/utils/gh-submit.d.ts +46 -0
  203. package/dist/cli/cli/src/utils/gh-submit.d.ts.map +1 -0
  204. package/dist/cli/cli/src/utils/gh-submit.js +167 -0
  205. package/dist/cli/cli/src/utils/gh-submit.js.map +1 -0
  206. package/dist/cli/cli/src/utils/marketplace.d.ts.map +1 -1
  207. package/dist/cli/cli/src/utils/marketplace.js +13 -5
  208. package/dist/cli/cli/src/utils/marketplace.js.map +1 -1
  209. package/dist/cli/cli/src/utils/templates.d.ts +3 -2
  210. package/dist/cli/cli/src/utils/templates.d.ts.map +1 -1
  211. package/dist/cli/cli/src/utils/templates.js +5 -4
  212. package/dist/cli/cli/src/utils/templates.js.map +1 -1
  213. package/frontend/dist/assets/{index-45eeea99.js → index-a23214ae.js} +241 -241
  214. package/frontend/dist/assets/{index-6972eeee.css → index-c407fe13.css} +1 -1
  215. package/frontend/dist/index.html +2 -2
  216. package/package.json +3 -1
@@ -1,11 +1,13 @@
1
1
  #!/bin/bash
2
- # Delegate a task to an agent with a structured task template
2
+ # Delegate a task to an agent with a structured task template.
3
+ # Optionally sets up auto-monitoring (idle event subscription + fallback schedule)
4
+ # that will be cleaned up automatically when the task completes.
3
5
  set -euo pipefail
4
6
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
7
  source "${SCRIPT_DIR}/../_common/lib.sh"
6
8
 
7
9
  INPUT="${1:-}"
8
- [ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"to\":\"agent-session\",\"task\":\"implement feature X\",\"priority\":\"high\",\"projectPath\":\"/path/to/project\"}'"
10
+ [ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"to\":\"agent-session\",\"task\":\"implement feature X\",\"priority\":\"high\",\"projectPath\":\"/path/to/project\",\"monitor\":{\"idleEvent\":true,\"fallbackCheckMinutes\":5}}'"
9
11
 
10
12
  TO=$(echo "$INPUT" | jq -r '.to // empty')
11
13
  TASK=$(echo "$INPUT" | jq -r '.task // empty')
@@ -15,6 +17,10 @@ PROJECT_PATH=$(echo "$INPUT" | jq -r '.projectPath // empty')
15
17
  require_param "to" "$TO"
16
18
  require_param "task" "$TASK"
17
19
 
20
+ # Monitor parameters (optional)
21
+ MONITOR_IDLE=$(echo "$INPUT" | jq -r '.monitor.idleEvent // false')
22
+ MONITOR_FALLBACK_MINUTES=$(echo "$INPUT" | jq -r '.monitor.fallbackCheckMinutes // 0')
23
+
18
24
  # Resolve Crewly root from this script path:
19
25
  # config/skills/orchestrator/delegate-task/execute.sh -> project root
20
26
  CREWLY_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
@@ -40,10 +46,14 @@ TASK_MESSAGE="[TASK] Priority: ${PRIORITY}\n\n${TASK}"
40
46
  [ -n "$CONTEXT" ] && TASK_MESSAGE="${TASK_MESSAGE}\n\nContext: ${CONTEXT}"
41
47
  TASK_MESSAGE="${TASK_MESSAGE}\n\nWhen done, report back using: bash ${CREWLY_ROOT}/config/skills/agent/core/report-status/execute.sh '{\"sessionName\":\"${TO}\",\"status\":\"done\",\"summary\":\"<brief summary>\"}'"
42
48
 
43
- BODY=$(jq -n --arg message "$TASK_MESSAGE" '{message: $message}')
49
+ # waitTimeout matches EVENT_DELIVERY_CONSTANTS.AGENT_READY_TIMEOUT (120000ms)
50
+ BODY=$(jq -n --arg message "$TASK_MESSAGE" '{message: $message, waitForReady: true, waitTimeout: 120000}')
44
51
 
45
52
  api_call POST "/terminal/${TO}/deliver" "$BODY"
46
53
 
54
+ # Track the task file path from create response for monitoring linkage
55
+ TASK_FILE_PATH=""
56
+
47
57
  # Create task file in project's .crewly/tasks/ directory
48
58
  if [ -n "$PROJECT_PATH" ]; then
49
59
  CREATE_BODY=$(jq -n \
@@ -53,5 +63,54 @@ if [ -n "$PROJECT_PATH" ]; then
53
63
  --arg sessionName "$TO" \
54
64
  --arg milestone "delegated" \
55
65
  '{projectPath: $projectPath, task: $task, priority: $priority, sessionName: $sessionName, milestone: $milestone}')
56
- api_call POST "/task-management/create" "$CREATE_BODY" || true
66
+ CREATE_RESULT=$(api_call POST "/task-management/create" "$CREATE_BODY" 2>/dev/null || true)
67
+ TASK_FILE_PATH=$(echo "$CREATE_RESULT" | jq -r '.taskPath // empty' 2>/dev/null || true)
68
+ fi
69
+
70
+ # --- Auto-monitoring setup ---
71
+ # Collect IDs for monitoring cleanup linkage
72
+ COLLECTED_SCHEDULE_IDS="[]"
73
+ COLLECTED_SUBSCRIPTION_IDS="[]"
74
+
75
+ # Set up idle event subscription if requested
76
+ if [ "$MONITOR_IDLE" = "true" ]; then
77
+ SUBSCRIBER_SESSION="${CREWLY_SESSION_NAME:-crewly-orc}"
78
+ SUB_BODY=$(jq -n \
79
+ --arg eventType "agent:idle" \
80
+ --arg sessionName "$TO" \
81
+ --arg subscriber "$SUBSCRIBER_SESSION" \
82
+ '{eventType: $eventType, filter: {sessionName: $sessionName}, subscriberSession: $subscriber, oneShot: true, ttlMinutes: 120}')
83
+ SUB_RESULT=$(api_call POST "/events/subscribe" "$SUB_BODY" 2>/dev/null || true)
84
+ SUB_ID=$(echo "$SUB_RESULT" | jq -r '.data.id // empty' 2>/dev/null || true)
85
+ if [ -n "$SUB_ID" ]; then
86
+ COLLECTED_SUBSCRIPTION_IDS=$(echo "$COLLECTED_SUBSCRIPTION_IDS" | jq --arg id "$SUB_ID" '. + [$id]')
87
+ fi
88
+ fi
89
+
90
+ # Set up fallback recurring schedule if requested
91
+ if [ "$MONITOR_FALLBACK_MINUTES" != "0" ] && [ -n "$MONITOR_FALLBACK_MINUTES" ]; then
92
+ SCHEDULE_TARGET="${CREWLY_SESSION_NAME:-crewly-orc}"
93
+ SCHED_BODY=$(jq -n \
94
+ --arg target "$SCHEDULE_TARGET" \
95
+ --arg minutes "$MONITOR_FALLBACK_MINUTES" \
96
+ --arg message "[CHECK] Review progress of ${TO} — task: ${TASK:0:100}" \
97
+ '{targetSession: $target, minutes: ($minutes | tonumber), intervalMinutes: ($minutes | tonumber), message: $message, isRecurring: true}')
98
+ SCHED_RESULT=$(api_call POST "/schedule" "$SCHED_BODY" 2>/dev/null || true)
99
+ SCHED_ID=$(echo "$SCHED_RESULT" | jq -r '.checkId // .data.checkId // empty' 2>/dev/null || true)
100
+ if [ -n "$SCHED_ID" ]; then
101
+ COLLECTED_SCHEDULE_IDS=$(echo "$COLLECTED_SCHEDULE_IDS" | jq --arg id "$SCHED_ID" '. + [$id]')
102
+ fi
103
+ fi
104
+
105
+ # Store monitoring IDs for auto-cleanup if we have any
106
+ HAS_SCHEDULE_IDS=$(echo "$COLLECTED_SCHEDULE_IDS" | jq 'length > 0')
107
+ HAS_SUBSCRIPTION_IDS=$(echo "$COLLECTED_SUBSCRIPTION_IDS" | jq 'length > 0')
108
+
109
+ if [ "$HAS_SCHEDULE_IDS" = "true" ] || [ "$HAS_SUBSCRIPTION_IDS" = "true" ]; then
110
+ MONITOR_BODY=$(jq -n \
111
+ --arg sessionName "$TO" \
112
+ --argjson scheduleIds "$COLLECTED_SCHEDULE_IDS" \
113
+ --argjson subscriptionIds "$COLLECTED_SUBSCRIPTION_IDS" \
114
+ '{sessionName: $sessionName, scheduleIds: $scheduleIds, subscriptionIds: $subscriptionIds}')
115
+ api_call POST "/task-management/add-monitoring" "$MONITOR_BODY" 2>/dev/null || true
57
116
  fi
@@ -3,12 +3,20 @@
3
3
  Sends a structured task assignment to an agent. When a `projectPath` is provided, also creates a task MD file in the project's `.crewly/tasks/delegated/in_progress/` directory for tracking.
4
4
  The script auto-resolves `config/skills/...` references to absolute paths so delegated tasks remain runnable from any working directory.
5
5
 
6
+ When the optional `monitor` block is provided, the skill automatically sets up idle event subscriptions and/or fallback schedule checks. These are linked to the task and will be **automatically cleaned up** when the task is completed via `report-status` or `complete-task`.
7
+
6
8
  ## Usage
7
9
 
8
10
  ```bash
9
11
  bash config/skills/orchestrator/delegate-task/execute.sh '{"to":"agent-joe","task":"Implement the login form","priority":"high","context":"Use React hooks","projectPath":"/path/to/project"}'
10
12
  ```
11
13
 
14
+ ### With auto-monitoring
15
+
16
+ ```bash
17
+ bash config/skills/orchestrator/delegate-task/execute.sh '{"to":"agent-joe","task":"Implement the login form","priority":"high","projectPath":"/path/to/project","monitor":{"idleEvent":true,"fallbackCheckMinutes":5}}'
18
+ ```
19
+
12
20
  ## Parameters
13
21
 
14
22
  | Parameter | Required | Description |
@@ -18,7 +26,59 @@ bash config/skills/orchestrator/delegate-task/execute.sh '{"to":"agent-joe","tas
18
26
  | `priority` | No | Task priority: `low`, `normal`, `high` (default: `normal`) |
19
27
  | `context` | No | Additional context for the task |
20
28
  | `projectPath` | No | Project path; when provided, creates a task MD file in `.crewly/tasks/` |
29
+ | `monitor` | No | Auto-monitoring configuration (see below) |
30
+ | `monitor.idleEvent` | No | If `true`, subscribes to `agent:idle` event for the target agent (default: `false`) |
31
+ | `monitor.fallbackCheckMinutes` | No | If > 0, sets up a recurring fallback check every N minutes (default: `0` = disabled) |
32
+
33
+ ## Examples
34
+
35
+ ### Example 1: Basic delegation (no monitoring)
36
+ ```bash
37
+ bash config/skills/orchestrator/delegate-task/execute.sh '{"to":"agent-joe","task":"Fix the login bug","priority":"high"}'
38
+ ```
39
+
40
+ ### Example 2: Delegation with full monitoring
41
+ ```bash
42
+ bash config/skills/orchestrator/delegate-task/execute.sh '{"to":"agent-joe","task":"Implement user auth","priority":"high","projectPath":"/path/to/project","monitor":{"idleEvent":true,"fallbackCheckMinutes":5}}'
43
+ ```
44
+ This will:
45
+ 1. Send the task to agent-joe's terminal
46
+ 2. Create a task file in the project
47
+ 3. Subscribe to `agent:idle` for agent-joe (auto-notifies when agent goes idle)
48
+ 4. Schedule a recurring check every 5 minutes (auto-reminds orchestrator to check progress)
49
+ 5. Link all monitoring IDs to the task for auto-cleanup on completion
50
+
51
+ ### Example 3: Delegation with idle monitoring only
52
+ ```bash
53
+ bash config/skills/orchestrator/delegate-task/execute.sh '{"to":"agent-sam","task":"Write unit tests","priority":"normal","monitor":{"idleEvent":true}}'
54
+ ```
21
55
 
22
56
  ## Output
23
57
 
24
58
  JSON confirmation of task delivery. When `projectPath` is provided, also returns the created task file path.
59
+
60
+ ## Auto-Cleanup
61
+
62
+ When the agent completes the task (via `report-status` with `status: done` or `complete-task`), all linked monitoring is automatically cleaned up:
63
+ - Scheduled checks are cancelled
64
+ - Event subscriptions are unsubscribed
65
+
66
+ No manual cleanup needed.
67
+
68
+ ## Error Handling
69
+
70
+ | Error | Cause | Solution |
71
+ |-------|-------|----------|
72
+ | `Missing required parameter: to` | `to` not provided | Include target session name |
73
+ | `Missing required parameter: task` | `task` not provided | Include task description |
74
+ | `curl failed with exit code N` | Backend not running | Start the Crewly backend |
75
+
76
+ Monitoring setup failures are non-fatal — if subscribe-event or schedule-check fails, the task is still delegated successfully.
77
+
78
+ ## Related Skills
79
+
80
+ - `assign-task` — for formal task tracking in the management system (file-based kanban)
81
+ - `send-message` — for simple messages without task structure
82
+ - `subscribe-event` — manual event subscription (auto-handled when using `monitor`)
83
+ - `schedule-check` — manual schedule creation (auto-handled when using `monitor`)
84
+ - `report-status` — agent reports completion, triggers auto-cleanup
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "orc-delegate-task",
3
3
  "name": "Delegate Task",
4
- "description": "Send a structured task assignment to an agent with priority and context.",
4
+ "description": "Send a structured task assignment to an agent with priority, context, and optional auto-monitoring. When monitor is provided, automatically subscribes to idle events and schedules fallback checks that are cleaned up on task completion. For formal task tracking, use assign-task instead. For simple messages, use send-message.",
5
5
  "category": "management",
6
6
  "skillType": "claude-skill",
7
7
  "promptFile": "instructions.md",
@@ -14,7 +14,7 @@
14
14
  }
15
15
  },
16
16
  "assignableRoles": ["orchestrator"],
17
- "triggers": ["delegate task", "assign work", "task agent"],
18
- "tags": ["task", "delegation", "management"],
19
- "version": "1.0.0"
17
+ "triggers": ["delegate task", "assign work", "task agent", "delegate with monitoring", "send task to agent"],
18
+ "tags": ["task", "delegation", "management", "monitoring"],
19
+ "version": "2.0.0"
20
20
  }
@@ -120,6 +120,8 @@ if [ -n "$INPUT_JSON" ]; then
120
120
  TEXT=${TEXT:-$(echo "$INPUT_JSON" | jq -r '.text // empty')}
121
121
  THREAD_TS=${THREAD_TS:-$(echo "$INPUT_JSON" | jq -r '.threadTs // empty')}
122
122
  CONVERSATION_ID=${CONVERSATION_ID:-$(echo "$INPUT_JSON" | jq -r '.conversationId // empty')}
123
+ FILE_PATH=${FILE_PATH:-$(echo "$INPUT_JSON" | jq -r '.file // .filePath // empty')}
124
+ IMAGE_PATH=${IMAGE_PATH:-$(echo "$INPUT_JSON" | jq -r '.image // .imagePath // empty')}
123
125
  fi
124
126
 
125
127
  require_param "channelId" "$CHANNEL_ID"
@@ -1,17 +1,30 @@
1
1
  #!/bin/bash
2
- # Send a key to an agent's terminal session
2
+ # Send a key or key sequence to an agent's terminal session
3
3
  set -euo pipefail
4
4
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
5
  source "${SCRIPT_DIR}/../_common/lib.sh"
6
6
 
7
7
  INPUT="${1:-""}"
8
- [ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"sessionName\":\"agent-session\",\"key\":\"Enter\"}'"
8
+ [ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"sessionName\":\"agent-session\",\"key\":\"Enter\"}' or '{\"sessionName\":\"...\",\"keys\":[\"Down\",\"Down\",\"Enter\"]}'"
9
9
 
10
10
  SESSION_NAME=$(echo "$INPUT" | jq -r '.sessionName // empty')
11
11
  KEY=$(echo "$INPUT" | jq -r '.key // empty')
12
+ KEYS=$(echo "$INPUT" | jq -r '.keys // empty')
12
13
  require_param "sessionName" "$SESSION_NAME"
13
- require_param "key" "$KEY"
14
14
 
15
- BODY=$(jq -n --arg key "$KEY" '{key: $key}')
16
-
17
- api_call POST "/terminal/${SESSION_NAME}/key" "$BODY"
15
+ # Support both single key and key sequence
16
+ if [ -n "$KEY" ]; then
17
+ BODY=$(jq -n --arg key "$KEY" '{key: $key}')
18
+ api_call POST "/terminal/${SESSION_NAME}/key" "$BODY"
19
+ elif [ "$KEYS" != "" ] && [ "$KEYS" != "null" ]; then
20
+ KEY_COUNT=$(echo "$INPUT" | jq '.keys | length')
21
+ for (( i=0; i<KEY_COUNT; i++ )); do
22
+ CURRENT_KEY=$(echo "$INPUT" | jq -r ".keys[$i]")
23
+ BODY=$(jq -n --arg key "$CURRENT_KEY" '{key: $key}')
24
+ api_call POST "/terminal/${SESSION_NAME}/key" "$BODY"
25
+ # Small delay between keys to allow processing
26
+ [ "$i" -lt "$((KEY_COUNT - 1))" ] && sleep 0.3
27
+ done
28
+ else
29
+ error_exit "Either 'key' (single) or 'keys' (array) parameter is required"
30
+ fi
@@ -0,0 +1,44 @@
1
+ # Send Key
2
+
3
+ Sends a keyboard key or key sequence to an agent's terminal session. Useful for navigating interactive prompts, accepting plan mode, dismissing dialogs, or sending control sequences.
4
+
5
+ ## Usage
6
+
7
+ ### Single key
8
+ ```bash
9
+ bash config/skills/orchestrator/send-key/execute.sh '{"sessionName":"agent-joe","key":"Enter"}'
10
+ ```
11
+
12
+ ### Key sequence
13
+ ```bash
14
+ bash config/skills/orchestrator/send-key/execute.sh '{"sessionName":"agent-joe","keys":["Down","Down","Enter"]}'
15
+ ```
16
+
17
+ ## Parameters
18
+
19
+ | Parameter | Required | Description |
20
+ |-----------|----------|-------------|
21
+ | `sessionName` | Yes | The target agent's PTY session name |
22
+ | `key` | One of `key`/`keys` | A single key to send |
23
+ | `keys` | One of `key`/`keys` | An array of keys to send in sequence (300ms delay between each) |
24
+
25
+ ## Supported Keys
26
+
27
+ | Key | Description |
28
+ |-----|-------------|
29
+ | `Enter` / `Return` | Submit / confirm |
30
+ | `Escape` | Cancel / dismiss |
31
+ | `Tab` | Tab key |
32
+ | `Backspace` | Delete character before cursor |
33
+ | `Delete` | Delete character after cursor |
34
+ | `Up` / `Down` / `Left` / `Right` | Arrow keys |
35
+ | `Home` / `End` | Jump to start/end of line |
36
+ | `PageUp` / `PageDown` | Scroll page |
37
+ | `C-c` | Ctrl+C (interrupt) |
38
+ | `C-d` | Ctrl+D (EOF) |
39
+ | `C-z` | Ctrl+Z (suspend) |
40
+ | `C-l` | Ctrl+L (clear screen) |
41
+
42
+ ## Output
43
+
44
+ JSON confirmation of delivery for each key sent.
@@ -0,0 +1,20 @@
1
+ {
2
+ "id": "orc-send-key",
3
+ "name": "Send Key",
4
+ "description": "Send a keyboard key or key sequence to an agent's terminal session.",
5
+ "category": "system",
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
+ "assignableRoles": ["orchestrator"],
17
+ "triggers": ["send key", "press key", "key press", "send enter"],
18
+ "tags": ["system", "terminal", "key", "input"],
19
+ "version": "1.0.0"
20
+ }
@@ -9,9 +9,17 @@ INPUT="${1:-}"
9
9
 
10
10
  SESSION_NAME=$(echo "$INPUT" | jq -r '.sessionName // empty')
11
11
  MESSAGE=$(echo "$INPUT" | jq -r '.message // empty')
12
+ FORCE=$(echo "$INPUT" | jq -r '.force // empty')
12
13
  require_param "sessionName" "$SESSION_NAME"
13
14
  require_param "message" "$MESSAGE"
14
15
 
15
- BODY=$(jq -n --arg message "$MESSAGE" '{message: $message}')
16
+ # force=true: write directly to PTY without waiting for agent prompt.
17
+ # Use when the agent is busy and you need immediate delivery.
18
+ if [ "$FORCE" = "true" ]; then
19
+ BODY=$(jq -n --arg message "$MESSAGE" '{message: $message, force: true}')
20
+ else
21
+ # waitTimeout matches EVENT_DELIVERY_CONSTANTS.AGENT_READY_TIMEOUT (120000ms)
22
+ BODY=$(jq -n --arg message "$MESSAGE" '{message: $message, waitForReady: true, waitTimeout: 120000}')
23
+ fi
16
24
 
17
25
  api_call POST "/terminal/${SESSION_NAME}/deliver" "$BODY"
@@ -4,6 +4,49 @@
4
4
  "cdnBaseUrl": "https://raw.githubusercontent.com/stevehuang0115/crewly/main",
5
5
  "source": "github",
6
6
  "items": [
7
+ {
8
+ "id": "ai-studio",
9
+ "type": "skill",
10
+ "name": "AI Studio App Builder",
11
+ "description": "Use Chrome to build React apps on Google AI Studio (aistudio.google.com). Navigate to the Build page, input prompts, and generate interactive prototypes.",
12
+ "author": "Crewly Team",
13
+ "version": "1.0.0",
14
+ "category": "automation",
15
+ "tags": [
16
+ "ai-studio",
17
+ "google",
18
+ "gemini",
19
+ "react",
20
+ "prototype",
21
+ "chrome"
22
+ ],
23
+ "license": "MIT",
24
+ "downloads": 0,
25
+ "rating": 0,
26
+ "createdAt": "2026-02-27T00:00:00.000Z",
27
+ "updatedAt": "2026-02-27T00:00:00.000Z",
28
+ "source": "config/skills/agent/marketplace/ai-studio",
29
+ "assets": {
30
+ "archive": "config/skills/agent/marketplace/ai-studio",
31
+ "checksum": "",
32
+ "sizeBytes": 3000
33
+ },
34
+ "metadata": {
35
+ "skillType": "claude-skill",
36
+ "assignableRoles": [],
37
+ "triggers": [
38
+ "ai studio",
39
+ "google ai studio",
40
+ "build app",
41
+ "react prototype",
42
+ "gemini app"
43
+ ],
44
+ "files": [
45
+ "skill.json",
46
+ "instructions.md"
47
+ ]
48
+ }
49
+ },
7
50
  {
8
51
  "id": "bug-triage",
9
52
  "type": "skill",
@@ -87,6 +130,10 @@
87
130
  "click",
88
131
  "fill form",
89
132
  "navigate"
133
+ ],
134
+ "files": [
135
+ "skill.json",
136
+ "instructions.md"
90
137
  ]
91
138
  }
92
139
  },
@@ -529,6 +576,57 @@
529
576
  "nano banana",
530
577
  "gemini image",
531
578
  "ai image"
579
+ ],
580
+ "files": [
581
+ "skill.json",
582
+ "generate.sh",
583
+ "instructions.md"
584
+ ]
585
+ }
586
+ },
587
+ {
588
+ "id": "notebooklm",
589
+ "type": "skill",
590
+ "name": "NotebookLM",
591
+ "description": "Interact with Google NotebookLM to create notebooks, add sources, and generate audio overviews. Requires NotebookLM MCP server to be configured.",
592
+ "author": "Crewly Team",
593
+ "version": "0.1.0",
594
+ "category": "research",
595
+ "tags": [
596
+ "notebooklm",
597
+ "research",
598
+ "audio",
599
+ "notebook",
600
+ "google",
601
+ "mcp"
602
+ ],
603
+ "license": "MIT",
604
+ "downloads": 0,
605
+ "rating": 0,
606
+ "createdAt": "2026-02-28T00:00:00.000Z",
607
+ "updatedAt": "2026-02-28T00:00:00.000Z",
608
+ "source": "config/skills/agent/marketplace/notebooklm",
609
+ "assets": {
610
+ "archive": "config/skills/agent/marketplace/notebooklm",
611
+ "checksum": "",
612
+ "sizeBytes": 5000
613
+ },
614
+ "metadata": {
615
+ "skillType": "mcp-skill",
616
+ "assignableRoles": [
617
+ "researcher",
618
+ "developer",
619
+ "generalist",
620
+ "fullstack-dev",
621
+ "qa",
622
+ "qa-engineer"
623
+ ],
624
+ "triggers": [
625
+ "notebooklm",
626
+ "notebook lm",
627
+ "create notebook",
628
+ "audio overview",
629
+ "research notebook"
532
630
  ]
533
631
  }
534
632
  },
@@ -572,6 +670,10 @@
572
670
  "fill form",
573
671
  "navigate",
574
672
  "headless"
673
+ ],
674
+ "files": [
675
+ "skill.json",
676
+ "instructions.md"
575
677
  ]
576
678
  }
577
679
  },
@@ -799,6 +901,160 @@
799
901
  ]
800
902
  }
801
903
  },
904
+ {
905
+ "id": "browse-stealth",
906
+ "type": "skill",
907
+ "name": "Stealth Browser (Patchright + CDP)",
908
+ "description": "Anti-detection browser automation using Patchright (Playwright fork) connected to a real Chrome instance via CDP. Bypasses navigator.webdriver checks, fingerprint anomalies, and headless detection used by platforms like 小红书, X/Twitter, and LinkedIn.",
909
+ "author": "Crewly Team",
910
+ "version": "1.0.0",
911
+ "category": "automation",
912
+ "tags": [
913
+ "browser",
914
+ "stealth",
915
+ "patchright",
916
+ "cdp",
917
+ "anti-detection",
918
+ "automation"
919
+ ],
920
+ "license": "MIT",
921
+ "downloads": 0,
922
+ "rating": 0,
923
+ "createdAt": "2026-02-28T00:00:00.000Z",
924
+ "updatedAt": "2026-02-28T00:00:00.000Z",
925
+ "source": "config/skills/agent/browse-stealth",
926
+ "assets": {
927
+ "archive": "config/skills/agent/browse-stealth",
928
+ "checksum": "",
929
+ "sizeBytes": 20000
930
+ },
931
+ "metadata": {
932
+ "skillType": "claude-skill",
933
+ "assignableRoles": [
934
+ "developer",
935
+ "qa",
936
+ "qa-engineer",
937
+ "fullstack-dev",
938
+ "backend-developer",
939
+ "frontend-developer",
940
+ "generalist",
941
+ "ops",
942
+ "content-strategist"
943
+ ],
944
+ "triggers": [
945
+ "stealth browse",
946
+ "browse stealth",
947
+ "anti-detection",
948
+ "xiaohongshu",
949
+ "rednote browse",
950
+ "patchright",
951
+ "cdp browse",
952
+ "stealth scrape"
953
+ ],
954
+ "files": [
955
+ "skill.json",
956
+ "execute.sh",
957
+ "instructions.md",
958
+ "launch-chrome-cdp.sh",
959
+ "stealth-browse.py"
960
+ ]
961
+ }
962
+ },
963
+ {
964
+ "id": "remotion-video",
965
+ "type": "skill",
966
+ "name": "Remotion Video Generator",
967
+ "description": "Generate motion graphic videos programmatically using Remotion and React. Supports template-based video creation with customizable text, colors, images, and transitions. Renders to MP4 locally.",
968
+ "author": "Crewly Team",
969
+ "version": "1.0.0",
970
+ "category": "content",
971
+ "tags": [
972
+ "video",
973
+ "remotion",
974
+ "react",
975
+ "motion-graphics",
976
+ "animation",
977
+ "mp4",
978
+ "content"
979
+ ],
980
+ "license": "MIT",
981
+ "downloads": 0,
982
+ "rating": 0,
983
+ "createdAt": "2026-02-28T00:00:00.000Z",
984
+ "updatedAt": "2026-02-28T00:00:00.000Z",
985
+ "source": "config/skills/agent/marketplace/remotion-video",
986
+ "assets": {
987
+ "archive": "config/skills/agent/marketplace/remotion-video",
988
+ "checksum": "",
989
+ "sizeBytes": 25000
990
+ },
991
+ "metadata": {
992
+ "skillType": "claude-skill",
993
+ "assignableRoles": [
994
+ "developer",
995
+ "designer",
996
+ "content",
997
+ "generalist",
998
+ "product-manager"
999
+ ],
1000
+ "triggers": [
1001
+ "create video",
1002
+ "generate video",
1003
+ "motion graphics",
1004
+ "remotion",
1005
+ "launch video",
1006
+ "promo video",
1007
+ "video animation"
1008
+ ]
1009
+ }
1010
+ },
1011
+ {
1012
+ "id": "gemini-video",
1013
+ "type": "skill",
1014
+ "name": "Gemini Video Understanding",
1015
+ "description": "Analyze videos using Google's Gemini API. Supports YouTube URLs (direct analysis) and local video files (upload via Files API). Produces summaries, key points, transcript highlights, and Q&A.",
1016
+ "author": "Crewly Team",
1017
+ "version": "1.0.0",
1018
+ "category": "content",
1019
+ "tags": [
1020
+ "video",
1021
+ "analysis",
1022
+ "youtube",
1023
+ "gemini",
1024
+ "ai",
1025
+ "content",
1026
+ "summary"
1027
+ ],
1028
+ "license": "MIT",
1029
+ "downloads": 0,
1030
+ "rating": 0,
1031
+ "createdAt": "2026-02-28T00:00:00.000Z",
1032
+ "updatedAt": "2026-02-28T00:00:00.000Z",
1033
+ "source": "config/skills/agent/marketplace/gemini-video",
1034
+ "assets": {
1035
+ "archive": "config/skills/agent/marketplace/gemini-video",
1036
+ "checksum": "",
1037
+ "sizeBytes": 8500
1038
+ },
1039
+ "metadata": {
1040
+ "skillType": "claude-skill",
1041
+ "assignableRoles": [
1042
+ "developer",
1043
+ "researcher",
1044
+ "content",
1045
+ "product-manager",
1046
+ "generalist"
1047
+ ],
1048
+ "triggers": [
1049
+ "analyze video",
1050
+ "video summary",
1051
+ "youtube analysis",
1052
+ "video understanding",
1053
+ "gemini video",
1054
+ "watch video"
1055
+ ]
1056
+ }
1057
+ },
802
1058
  {
803
1059
  "id": "test-runner",
804
1060
  "type": "skill",