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
@@ -0,0 +1,124 @@
1
+ # Content Writer
2
+
3
+ Generate platform-specific content drafts with brand voice, tone, and format guidelines. Manages the full lifecycle from writing brief to saved draft.
4
+
5
+ ## Workflow
6
+
7
+ ```
8
+ 1. Generate writing brief → execute.sh '{"action":"draft",...}'
9
+ 2. Write content using brief → Agent uses LLM to write
10
+ 3. Save completed draft → execute.sh '{"action":"save",...}'
11
+ 4. Add to content calendar → content-calendar skill
12
+ 5. Steve reviews + publishes → Manual
13
+ ```
14
+
15
+ ## Actions
16
+
17
+ ### `draft` — Generate a writing brief
18
+
19
+ Returns structured guidelines for writing a specific piece of content. The agent then uses these to generate the actual text.
20
+
21
+ | Parameter | Required | Description |
22
+ |-----------|----------|-------------|
23
+ | `action` | Yes | `"draft"` |
24
+ | `topic` | Yes | What to write about |
25
+ | `platform` | Yes | `x-thread`, `x-single`, `linkedin`, `xiaohongshu`, `substack`, `youtube-desc`, `blog` |
26
+ | `line` | No | `crewly` (brand) or `personal` (Steve). Default: `crewly` |
27
+ | `tone` | No | `professional`, `casual`, `technical`, `inspiring`, `provocative`, `educational`. Default: `professional` |
28
+ | `length` | No | `short`, `medium`, `long`. Default: `medium` |
29
+ | `audience` | No | Custom audience description (overrides default) |
30
+ | `context` | No | Additional context: reference data, trend info, competitor analysis |
31
+ | `references` | No | URLs or docs to reference |
32
+ | `cta` | No | Specific call-to-action to include |
33
+
34
+ ### `save` — Save a completed draft
35
+
36
+ | Parameter | Required | Description |
37
+ |-----------|----------|-------------|
38
+ | `action` | Yes | `"save"` |
39
+ | `title` | Yes | Content title |
40
+ | `platform` | Yes | Platform name |
41
+ | `content` | Yes | The full content text (markdown) |
42
+ | `line` | No | Content line (default: crewly) |
43
+ | `draftId` | No | Draft ID from the brief (for traceability) |
44
+ | `calendarId` | No | Content calendar entry ID to link |
45
+
46
+ ### `get` — Read a saved draft
47
+
48
+ | Parameter | Required | Description |
49
+ |-----------|----------|-------------|
50
+ | `action` | Yes | `"get"` |
51
+ | `filePath` | Yes* | Path to the draft file |
52
+ | `draftId` | Yes* | Or search by draft ID |
53
+
54
+ *One of filePath or draftId required.
55
+
56
+ ### `list` — List saved drafts
57
+
58
+ | Parameter | Required | Description |
59
+ |-----------|----------|-------------|
60
+ | `action` | Yes | `"list"` |
61
+ | `platform` | No | Filter by platform |
62
+ | `limit` | No | Max results (default: 20) |
63
+
64
+ ## Examples
65
+
66
+ ### Generate a writing brief for an X thread
67
+ ```bash
68
+ bash execute.sh '{"action":"draft","topic":"AI agent security - what we learned from n8n 8 CVEs","platform":"x-thread","line":"crewly","tone":"provocative","context":"n8n disclosed 8 critical CVEs on 2/25/2026 including RCE via sandbox escape. Crewly uses PTY isolation."}'
69
+ ```
70
+
71
+ ### Generate a brief for a Xiaohongshu post
72
+ ```bash
73
+ bash execute.sh '{"action":"draft","topic":"My AI team shipped while I slept - week 1 report","platform":"xiaohongshu","line":"personal","tone":"casual"}'
74
+ ```
75
+
76
+ ### Save a completed draft
77
+ ```bash
78
+ bash execute.sh '{"action":"save","title":"AI agent security thread","platform":"x-thread","line":"crewly","content":"[1/5] n8n just disclosed 8 critical CVEs...\n\n[2/5] The scariest one?...","projectPath":"/path/to/project"}'
79
+ ```
80
+
81
+ ### List all LinkedIn drafts
82
+ ```bash
83
+ bash execute.sh '{"action":"list","platform":"linkedin","projectPath":"/path/to/project"}'
84
+ ```
85
+
86
+ ## Platform Writing Tips
87
+
88
+ ### X Thread Best Practices
89
+ - Hook tweet is everything — if they don't stop scrolling, nothing else matters
90
+ - Each tweet = one idea, one screenshot, or one data point
91
+ - Use numbers: "3 things I learned" > "Things I learned"
92
+ - End with a thread-pull: "If this was useful, follow me for more"
93
+ - Steve's top performers on Xiaohongshu all had strong visual hooks — apply same principle
94
+
95
+ ### LinkedIn Best Practices
96
+ - First line shows in feed preview — make it impossible to not click "see more"
97
+ - "I" stories outperform "You should" advice
98
+ - Specific > general: "We saved 47 hours/week" > "We saved a lot of time"
99
+ - Post between 8-10am EST Tuesday-Thursday for max reach
100
+
101
+ ### Xiaohongshu Best Practices (from Steve's data)
102
+ - Video outperforms image-text (20 videos vs 12 image-text in Steve's archive)
103
+ - Top tags to use: 创业MVP, 职场smalltalk, 用好ai拿捏职场, vibecoding
104
+ - Steve's top post (201 likes): "Claude Code牛马工厂" — visual + relatable + specific tool
105
+ - Social/community posts (Google coffee chat: 164 likes) also perform well
106
+ - Include 8+ hashtags for discovery
107
+
108
+ ### Substack Best Practices
109
+ - Subject line = open rate. Test: numbers, questions, or contrarian takes
110
+ - Personal stories in the opening paragraph build connection
111
+ - Include 1 actionable takeaway readers can use this week
112
+ - Cross-promote: mention X thread, YouTube video in each issue
113
+
114
+ ## Brand Voice Quick Reference
115
+
116
+ ### Crewly Brand
117
+ - **Do:** Use specific metrics, show product screenshots, reference real use cases
118
+ - **Don't:** Claim "revolutionary" or "game-changing", oversell features not yet built
119
+ - **Signature phrases:** "AI Team", "Ready in Days", "Quality Gates", "Live Terminal"
120
+
121
+ ### Steve Personal
122
+ - **Do:** Share real numbers, mention Google/side projects, be vulnerable about failures
123
+ - **Don't:** Lecture, be preachy, use generic "hustle" motivation
124
+ - **Signature phrases:** "一人公司", "下班2小时", "留在牌桌上", "Build in Public"
@@ -0,0 +1,22 @@
1
+ {
2
+ "id": "content-writer",
3
+ "name": "Content Writer",
4
+ "description": "Generate platform-specific writing briefs and manage content drafts. Supports X threads, LinkedIn posts, Xiaohongshu notes, Substack newsletters, YouTube descriptions, and blog posts. Includes brand voice presets for Crewly and Steve's personal content.",
5
+ "category": "content",
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": ["content-strategist", "product-manager", "generalist", "designer"],
17
+ "triggers": ["write content", "create post", "draft content", "write thread", "write article", "content draft"],
18
+ "tags": ["content", "writing", "draft", "social-media", "marketing", "x-thread", "linkedin", "xiaohongshu", "substack", "youtube", "blog"],
19
+ "version": "1.0.0",
20
+ "author": "Luna (Content Strategist)",
21
+ "license": "MIT"
22
+ }
@@ -0,0 +1,88 @@
1
+ #!/bin/bash
2
+ # Generate PDF from Markdown with CJK font support
3
+ # Uses pandoc (md→html) + weasyprint (html→pdf)
4
+ set -euo pipefail
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ source "${SCRIPT_DIR}/../../_common/lib.sh"
7
+
8
+ INPUT="${1:-}"
9
+ [ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"input\":\"/tmp/report.md\",\"output\":\"/tmp/report.pdf\",\"title\":\"My Report\"}'"
10
+
11
+ MD_PATH=$(echo "$INPUT" | jq -r '.input // empty')
12
+ PDF_PATH=$(echo "$INPUT" | jq -r '.output // empty')
13
+ TITLE=$(echo "$INPUT" | jq -r '.title // empty')
14
+
15
+ require_param "input" "$MD_PATH"
16
+
17
+ # Default output: same path with .pdf extension
18
+ if [ -z "$PDF_PATH" ]; then
19
+ PDF_PATH="${MD_PATH%.md}.pdf"
20
+ fi
21
+
22
+ # Intermediate HTML path
23
+ HTML_PATH="${PDF_PATH%.pdf}.html"
24
+
25
+ # Default title from filename
26
+ if [ -z "$TITLE" ]; then
27
+ TITLE=$(basename "$MD_PATH" .md | tr '-' ' ' | tr '_' ' ')
28
+ fi
29
+
30
+ # Ensure the CJK CSS header exists
31
+ CJK_HEADER="/tmp/cjk-header.html"
32
+ if [ ! -f "$CJK_HEADER" ]; then
33
+ cat > "$CJK_HEADER" << 'CSSEOF'
34
+ <style>
35
+ body {
36
+ font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
37
+ max-width: 900px;
38
+ margin: 0 auto;
39
+ padding: 2rem;
40
+ line-height: 1.8;
41
+ color: #1a1a1a;
42
+ font-size: 14px;
43
+ }
44
+ h1, h2, h3, h4 {
45
+ font-family: -apple-system, "PingFang SC", "Hiragino Sans GB", sans-serif;
46
+ margin-top: 1.5em;
47
+ color: #111;
48
+ }
49
+ h1 { font-size: 1.8em; border-bottom: 2px solid #333; padding-bottom: 0.3em; }
50
+ h2 { font-size: 1.4em; border-bottom: 1px solid #ccc; padding-bottom: 0.2em; }
51
+ h3 { font-size: 1.15em; }
52
+ table { border-collapse: collapse; width: 100%; margin: 1em 0; font-size: 13px; }
53
+ th, td { border: 1px solid #ddd; padding: 8px 12px; text-align: left; }
54
+ th { background: #f5f5f5; font-weight: 600; }
55
+ tr:nth-child(even) { background: #fafafa; }
56
+ blockquote { border-left: 4px solid #4a90d9; margin: 1em 0; padding: 0.5em 1em; background: #f0f6ff; color: #333; }
57
+ code { background: #f4f4f4; padding: 2px 5px; border-radius: 3px; font-size: 0.9em; }
58
+ hr { border: none; border-top: 1px solid #ddd; margin: 2em 0; }
59
+ strong { color: #111; }
60
+ </style>
61
+ CSSEOF
62
+ fi
63
+
64
+ # Check dependencies
65
+ if ! command -v pandoc &>/dev/null; then
66
+ error_exit "pandoc is not installed. Run: brew install pandoc"
67
+ fi
68
+ if ! command -v weasyprint &>/dev/null; then
69
+ error_exit "weasyprint is not installed. Run: brew install weasyprint"
70
+ fi
71
+
72
+ # Step 1: Markdown → HTML (with CJK CSS header)
73
+ pandoc "$MD_PATH" -o "$HTML_PATH" \
74
+ --standalone \
75
+ --metadata title="$TITLE" \
76
+ --include-in-header="$CJK_HEADER" 2>/dev/null
77
+
78
+ # Step 2: HTML → PDF (weasyprint handles CJK fonts correctly)
79
+ weasyprint "$HTML_PATH" "$PDF_PATH" 2>/dev/null
80
+
81
+ # Get file size
82
+ PDF_SIZE=$(wc -c < "$PDF_PATH" | tr -d ' ')
83
+
84
+ # Clean up intermediate HTML
85
+ rm -f "$HTML_PATH"
86
+
87
+ # Output result
88
+ echo "{\"success\":true,\"pdf\":\"${PDF_PATH}\",\"size\":${PDF_SIZE}}"
@@ -0,0 +1,46 @@
1
+ # Generate PDF
2
+
3
+ Convert a Markdown file to a professionally styled PDF with full CJK (Chinese/Japanese/Korean) font support.
4
+
5
+ ## Pipeline
6
+
7
+ 1. **Markdown → HTML**: Uses `pandoc` with `--standalone` and an inline CJK-compatible CSS header
8
+ 2. **HTML → PDF**: Uses `weasyprint` (NOT Chrome headless, which cannot render CJK characters)
9
+
10
+ ## Parameters
11
+
12
+ | Parameter | Required | Description |
13
+ |-----------|----------|-------------|
14
+ | `input` | Yes | Path to the input Markdown file |
15
+ | `output` | No | Path for the output PDF file (defaults to input path with `.pdf` extension) |
16
+ | `title` | No | Document title for the HTML metadata |
17
+
18
+ ## Example
19
+
20
+ ```bash
21
+ bash config/skills/agent/core/generate-pdf/execute.sh '{"input":"/tmp/report.md","output":"/tmp/report.pdf","title":"My Report"}'
22
+ ```
23
+
24
+ ### Minimal usage (auto-generates output path)
25
+
26
+ ```bash
27
+ bash config/skills/agent/core/generate-pdf/execute.sh '{"input":"/tmp/report.md"}'
28
+ ```
29
+
30
+ This produces `/tmp/report.pdf`.
31
+
32
+ ## Important Notes
33
+
34
+ - **Always use this skill** instead of manually running pandoc + Chrome headless
35
+ - **Chrome headless cannot render Chinese/CJK characters** — they appear blank in the PDF
36
+ - **weasyprint** properly embeds CJK fonts (PingFang SC, Hiragino Sans GB, STHeiti) on macOS
37
+ - The skill auto-generates a CSS header with CJK font declarations if one doesn't exist
38
+ - Output is a clean, styled PDF suitable for sharing via Slack or email
39
+
40
+ ## Output
41
+
42
+ JSON with the path to the generated PDF file:
43
+
44
+ ```json
45
+ {"success": true, "pdf": "/tmp/report.pdf", "size": 364024}
46
+ ```
@@ -0,0 +1,20 @@
1
+ {
2
+ "id": "agent-generate-pdf",
3
+ "name": "Generate PDF",
4
+ "description": "Convert a Markdown file to a styled PDF with full CJK (Chinese/Japanese/Korean) font support. Uses pandoc for Markdown→HTML and weasyprint for HTML→PDF rendering.",
5
+ "category": "document",
6
+ "skillType": "claude-skill",
7
+ "promptFile": "instructions.md",
8
+ "execution": {
9
+ "type": "script",
10
+ "script": {
11
+ "file": "execute.sh",
12
+ "interpreter": "bash",
13
+ "timeoutMs": 60000
14
+ }
15
+ },
16
+ "assignableRoles": ["developer", "qa", "tpm", "designer", "frontend-developer", "backend-developer", "fullstack-dev", "qa-engineer", "product-manager", "architect", "generalist", "sales", "support", "content-strategist"],
17
+ "triggers": ["generate pdf", "convert to pdf", "create pdf", "markdown to pdf", "make pdf"],
18
+ "tags": ["pdf", "document", "markdown", "pandoc", "weasyprint", "cjk"],
19
+ "version": "1.0.0"
20
+ }
@@ -33,3 +33,9 @@ if [ "$STATUS" = "done" ] && [ -n "$TASK_PATH" ]; then
33
33
  '{taskPath: $taskPath, sessionName: $sessionName}')
34
34
  api_call POST "/task-management/complete" "$COMPLETE_BODY" || true
35
35
  fi
36
+
37
+ # Auto-complete tracked tasks when status is done
38
+ if [ "$STATUS" = "done" ]; then
39
+ SESSION_BODY=$(jq -n --arg sessionName "$SESSION_NAME" '{sessionName: $sessionName}')
40
+ api_call POST "/task-management/complete-by-session" "$SESSION_BODY" || true
41
+ fi
@@ -0,0 +1,211 @@
1
+ #!/bin/bash
2
+ # Trend Monitor — save, read, and manage trend data from browser scans
3
+ set -euo pipefail
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ source "${SCRIPT_DIR}/../_common/lib.sh"
6
+
7
+ INPUT="${1:-}"
8
+ [ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"action\":\"save|list|latest|suggest\",\"projectPath\":\"/path/to/project\",...}'"
9
+
10
+ ACTION=$(echo "$INPUT" | jq -r '.action // empty')
11
+ PROJECT_PATH=$(echo "$INPUT" | jq -r '.projectPath // empty')
12
+
13
+ require_param "action" "$ACTION"
14
+
15
+ # Resolve trends directory
16
+ if [ -n "$PROJECT_PATH" ]; then
17
+ TRENDS_DIR="${PROJECT_PATH}/.crewly/content/trends"
18
+ else
19
+ TRENDS_DIR="${HOME}/.crewly/content/trends"
20
+ fi
21
+ mkdir -p "$TRENDS_DIR"
22
+
23
+ case "$ACTION" in
24
+
25
+ # ─────────────────────────────────────────────
26
+ # SAVE: Store a batch of trends from a browser scan
27
+ # ─────────────────────────────────────────────
28
+ save)
29
+ SOURCE=$(echo "$INPUT" | jq -r '.source // empty')
30
+ TRENDS=$(echo "$INPUT" | jq -r '.trends // empty')
31
+
32
+ require_param "source" "$SOURCE"
33
+ require_param "trends" "$TRENDS"
34
+
35
+ # Validate source
36
+ case "$SOURCE" in
37
+ x-trending|google-trends|hackernews|producthunt|reddit|github-trending|custom) ;;
38
+ *) error_exit "Invalid source: $SOURCE. Valid: x-trending, google-trends, hackernews, producthunt, reddit, github-trending, custom" ;;
39
+ esac
40
+
41
+ # Validate trends is a JSON array
42
+ if ! echo "$TRENDS" | jq 'type == "array"' 2>/dev/null | grep -q true; then
43
+ error_exit "trends must be a JSON array of objects"
44
+ fi
45
+
46
+ NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
47
+ TODAY=$(date -u +%Y-%m-%d)
48
+ SCAN_ID="scan-$(date +%s)-$((RANDOM % 1000))"
49
+
50
+ # Add metadata to each trend
51
+ ENRICHED=$(echo "$TRENDS" | jq --arg source "$SOURCE" --arg scanId "$SCAN_ID" --arg ts "$NOW" \
52
+ '[.[] | . + {"source": $source, "scanId": $scanId, "scannedAt": $ts}]')
53
+
54
+ # Count items
55
+ COUNT=$(echo "$ENRICHED" | jq 'length')
56
+
57
+ # Save to date-based file
58
+ SCAN_FILE="${TRENDS_DIR}/${TODAY}-${SOURCE}.json"
59
+
60
+ if [ -f "$SCAN_FILE" ]; then
61
+ # Append to existing file
62
+ EXISTING=$(cat "$SCAN_FILE")
63
+ MERGED=$(jq -n --argjson existing "$EXISTING" --argjson new "$ENRICHED" \
64
+ '{"scans": ($existing.scans + [{"scanId": $new[0].scanId, "scannedAt": $new[0].scannedAt, "count": ($new | length), "items": $new}])}')
65
+ echo "$MERGED" > "$SCAN_FILE"
66
+ else
67
+ # Create new file
68
+ jq -n --argjson items "$ENRICHED" --arg source "$SOURCE" --arg date "$TODAY" \
69
+ '{"source": $source, "date": $date, "scans": [{"scanId": $items[0].scanId, "scannedAt": $items[0].scannedAt, "count": ($items | length), "items": $items}]}' > "$SCAN_FILE"
70
+ fi
71
+
72
+ jq -n \
73
+ --arg scanId "$SCAN_ID" \
74
+ --arg source "$SOURCE" \
75
+ --argjson count "$COUNT" \
76
+ --arg file "$SCAN_FILE" \
77
+ --arg scannedAt "$NOW" \
78
+ '{"success":true,"action":"save","scanId":$scanId,"source":$source,"count":$count,"file":$file,"scannedAt":$scannedAt}'
79
+ ;;
80
+
81
+ # ─────────────────────────────────────────────
82
+ # LIST: List available trend scans
83
+ # ─────────────────────────────────────────────
84
+ list)
85
+ FILTER_SOURCE=$(echo "$INPUT" | jq -r '.source // empty')
86
+ FILTER_DATE=$(echo "$INPUT" | jq -r '.date // empty')
87
+ LIMIT=$(echo "$INPUT" | jq -r '.limit // "10"')
88
+
89
+ FILES="[]"
90
+ for f in "$TRENDS_DIR"/*.json; do
91
+ [ -f "$f" ] || continue
92
+ BASENAME=$(basename "$f" .json)
93
+ FILE_DATE=$(echo "$BASENAME" | cut -d'-' -f1-3)
94
+ FILE_SOURCE=$(echo "$BASENAME" | cut -d'-' -f4-)
95
+
96
+ # Apply filters
97
+ if [ -n "$FILTER_SOURCE" ] && [ "$FILE_SOURCE" != "$FILTER_SOURCE" ]; then
98
+ continue
99
+ fi
100
+ if [ -n "$FILTER_DATE" ] && [ "$FILE_DATE" != "$FILTER_DATE" ]; then
101
+ continue
102
+ fi
103
+
104
+ SCAN_COUNT=$(jq '.scans | length' "$f" 2>/dev/null || echo "0")
105
+ TOTAL_ITEMS=$(jq '[.scans[].count] | add // 0' "$f" 2>/dev/null || echo "0")
106
+ LAST_SCAN=$(jq -r '.scans[-1].scannedAt // "unknown"' "$f" 2>/dev/null || echo "unknown")
107
+
108
+ FILES=$(echo "$FILES" | jq \
109
+ --arg file "$f" \
110
+ --arg date "$FILE_DATE" \
111
+ --arg source "$FILE_SOURCE" \
112
+ --argjson scanCount "$SCAN_COUNT" \
113
+ --argjson totalItems "$TOTAL_ITEMS" \
114
+ --arg lastScan "$LAST_SCAN" \
115
+ '. + [{"file":$file,"date":$date,"source":$source,"scanCount":$scanCount,"totalItems":$totalItems,"lastScan":$lastScan}]')
116
+ done
117
+
118
+ # Sort by date descending and limit
119
+ FILES=$(echo "$FILES" | jq --argjson limit "$LIMIT" 'sort_by(.date) | reverse | .[:$limit]')
120
+ COUNT=$(echo "$FILES" | jq 'length')
121
+
122
+ jq -n --argjson files "$FILES" --argjson count "$COUNT" \
123
+ '{"success":true,"action":"list","count":$count,"files":$files}'
124
+ ;;
125
+
126
+ # ─────────────────────────────────────────────
127
+ # LATEST: Get the latest trends from a specific source
128
+ # ─────────────────────────────────────────────
129
+ latest)
130
+ FILTER_SOURCE=$(echo "$INPUT" | jq -r '.source // empty')
131
+ LIMIT=$(echo "$INPUT" | jq -r '.limit // "20"')
132
+
133
+ # Find most recent file(s)
134
+ ALL_ITEMS="[]"
135
+
136
+ for f in $(ls -t "$TRENDS_DIR"/*.json 2>/dev/null | head -5); do
137
+ [ -f "$f" ] || continue
138
+ FILE_SOURCE=$(basename "$f" .json | cut -d'-' -f4-)
139
+
140
+ if [ -n "$FILTER_SOURCE" ] && [ "$FILE_SOURCE" != "$FILTER_SOURCE" ]; then
141
+ continue
142
+ fi
143
+
144
+ # Get items from the latest scan in each file
145
+ ITEMS=$(jq '.scans[-1].items // []' "$f" 2>/dev/null || echo "[]")
146
+ ALL_ITEMS=$(jq -n --argjson a "$ALL_ITEMS" --argjson b "$ITEMS" '$a + $b')
147
+ done
148
+
149
+ # Sort by relevance score if available, limit
150
+ ALL_ITEMS=$(echo "$ALL_ITEMS" | jq --argjson limit "$LIMIT" \
151
+ 'sort_by(.relevanceScore // 0) | reverse | .[:$limit]')
152
+ COUNT=$(echo "$ALL_ITEMS" | jq 'length')
153
+
154
+ jq -n --argjson items "$ALL_ITEMS" --argjson count "$COUNT" \
155
+ '{"success":true,"action":"latest","count":$count,"items":$items}'
156
+ ;;
157
+
158
+ # ─────────────────────────────────────────────
159
+ # SUGGEST: Generate topic suggestions from recent trends
160
+ # ─────────────────────────────────────────────
161
+ suggest)
162
+ CONTENT_LINE=$(echo "$INPUT" | jq -r '.line // "crewly"')
163
+ LIMIT=$(echo "$INPUT" | jq -r '.limit // "5"')
164
+
165
+ # Gather all recent trend items (last 3 days)
166
+ ALL_ITEMS="[]"
167
+ for f in $(ls -t "$TRENDS_DIR"/*.json 2>/dev/null | head -10); do
168
+ [ -f "$f" ] || continue
169
+ ITEMS=$(jq '.scans[-1].items // []' "$f" 2>/dev/null || echo "[]")
170
+ ALL_ITEMS=$(jq -n --argjson a "$ALL_ITEMS" --argjson b "$ITEMS" '$a + $b')
171
+ done
172
+
173
+ COUNT=$(echo "$ALL_ITEMS" | jq 'length')
174
+
175
+ if [ "$COUNT" -eq 0 ]; then
176
+ jq -n '{"success":true,"action":"suggest","suggestions":[],"message":"No trend data available. Run a browser scan first using the instructions in instructions.md."}'
177
+ exit 0
178
+ fi
179
+
180
+ # Filter for AI-related trends
181
+ AI_ITEMS=$(echo "$ALL_ITEMS" | jq '[.[] | select(
182
+ (.title // "" | test("(?i)ai|agent|llm|gpt|claude|gemini|automation|saas|startup")) or
183
+ (.relevanceScore // 0) >= 7
184
+ )]')
185
+
186
+ AI_COUNT=$(echo "$AI_ITEMS" | jq 'length')
187
+
188
+ # Build suggestion context
189
+ TOPICS=$(echo "$AI_ITEMS" | jq --argjson limit "$LIMIT" \
190
+ '[.[:$limit] | .[] | {title: .title, source: .source, url: (.url // ""), relevanceScore: (.relevanceScore // 0)}]')
191
+
192
+ jq -n \
193
+ --argjson allTrends "$COUNT" \
194
+ --argjson aiRelevant "$AI_COUNT" \
195
+ --argjson topics "$TOPICS" \
196
+ --arg line "$CONTENT_LINE" \
197
+ '{
198
+ "success": true,
199
+ "action": "suggest",
200
+ "totalTrendsScanned": $allTrends,
201
+ "aiRelevantTrends": $aiRelevant,
202
+ "contentLine": $line,
203
+ "suggestedTopics": $topics,
204
+ "instruction": "Use these trending topics as input for content-writer skill. Match with your content calendar and brand voice."
205
+ }'
206
+ ;;
207
+
208
+ *)
209
+ error_exit "Unknown action: $ACTION. Valid: save, list, latest, suggest"
210
+ ;;
211
+ esac