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.
- package/README.md +6 -6
- package/config/roles/ops/prompt.md +140 -0
- package/config/roles/ops/role.json +13 -0
- package/config/skills/agent/browse-stealth/execute.sh +84 -0
- package/config/skills/agent/browse-stealth/instructions.md +108 -0
- package/config/skills/agent/browse-stealth/launch-chrome-cdp.sh +141 -0
- package/config/skills/agent/browse-stealth/skill.json +20 -0
- package/config/skills/agent/browse-stealth/stealth-browse.py +330 -0
- package/config/skills/agent/competitor-content-tracker/execute.sh +232 -0
- package/config/skills/agent/competitor-content-tracker/instructions.md +210 -0
- package/config/skills/agent/competitor-content-tracker/skill.json +22 -0
- package/config/skills/agent/content-calendar/execute.sh +294 -0
- package/config/skills/agent/content-calendar/instructions.md +122 -0
- package/config/skills/agent/content-calendar/skill.json +22 -0
- package/config/skills/agent/content-repurposer/execute.sh +194 -0
- package/config/skills/agent/content-repurposer/instructions.md +69 -0
- package/config/skills/agent/content-repurposer/skill.json +22 -0
- package/config/skills/agent/content-writer/execute.sh +311 -0
- package/config/skills/agent/content-writer/instructions.md +124 -0
- package/config/skills/agent/content-writer/skill.json +22 -0
- package/config/skills/agent/core/generate-pdf/execute.sh +88 -0
- package/config/skills/agent/core/generate-pdf/instructions.md +46 -0
- package/config/skills/agent/core/generate-pdf/skill.json +20 -0
- package/config/skills/agent/core/report-status/execute.sh +6 -0
- package/config/skills/agent/trend-monitor/execute.sh +211 -0
- package/config/skills/agent/trend-monitor/instructions.md +207 -0
- package/config/skills/agent/trend-monitor/skill.json +22 -0
- package/config/skills/agent/vnc-browser/execute.sh +261 -0
- package/config/skills/agent/vnc-browser/instructions.md +102 -0
- package/config/skills/agent/vnc-browser/skill.json +20 -0
- package/config/skills/orchestrator/delegate-task/execute.sh +63 -4
- package/config/skills/orchestrator/delegate-task/instructions.md +60 -0
- package/config/skills/orchestrator/delegate-task/skill.json +4 -4
- package/config/skills/orchestrator/reply-slack/execute.sh +2 -0
- package/config/skills/orchestrator/send-key/execute.sh +19 -6
- package/config/skills/orchestrator/send-key/instructions.md +44 -0
- package/config/skills/orchestrator/send-key/skill.json +20 -0
- package/config/skills/orchestrator/send-message/execute.sh +9 -1
- package/config/skills/registry.json +256 -0
- package/config/templates/code-review-team/README.md +176 -0
- package/config/templates/code-review-team/team-config.json +16 -0
- package/config/templates/code-review-team.json +62 -0
- package/config/templates/content-generation-team/README.md +128 -0
- package/config/templates/content-generation-team/team-config.json +21 -0
- package/config/templates/content-generation-team.json +67 -0
- package/config/templates/demo-team.json +22 -0
- package/config/templates/social-media-ops-team/README.md +145 -0
- package/config/templates/social-media-ops-team/team-config.json +21 -0
- package/config/templates/social-media-ops-team.json +67 -0
- package/dist/backend/backend/src/constants.d.ts +69 -6
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +75 -6
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/index.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/index.js +2 -0
- package/dist/backend/backend/src/controllers/index.js.map +1 -1
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts +8 -0
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.js +110 -63
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +31 -4
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.d.ts +8 -0
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.js +127 -111
- package/dist/backend/backend/src/controllers/oauth/oauth.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts +34 -0
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +219 -2
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/user/user.routes.d.ts +7 -0
- package/dist/backend/backend/src/controllers/user/user.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/user/user.routes.js +45 -38
- package/dist/backend/backend/src/controllers/user/user.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/whatsapp/index.d.ts +17 -0
- package/dist/backend/backend/src/controllers/whatsapp/index.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/whatsapp/index.js +18 -0
- package/dist/backend/backend/src/controllers/whatsapp/index.js.map +1 -0
- package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.d.ts +12 -0
- package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.js +185 -0
- package/dist/backend/backend/src/controllers/whatsapp/whatsapp.controller.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts +5 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +35 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.js +4 -0
- package/dist/backend/backend/src/routes/modules/task-management.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-heartbeat.service.js +1 -1
- package/dist/backend/backend/src/services/agent/agent-heartbeat.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +14 -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 +160 -29
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts +4 -3
- package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/claude-runtime.service.js +29 -4
- package/dist/backend/backend/src/services/agent/claude-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js +11 -0
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts +32 -2
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +69 -8
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js +14 -2
- package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js +11 -2
- package/dist/backend/backend/src/services/marketplace/marketplace-installer.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.d.ts +18 -0
- package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.js +28 -4
- package/dist/backend/backend/src/services/messaging/adapters/discord-messenger.adapter.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/slack-messenger.adapter.js +2 -2
- package/dist/backend/backend/src/services/messaging/adapters/slack-messenger.adapter.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts +18 -0
- package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js +26 -4
- package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts +28 -2
- package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/messenger-registry.service.d.ts +33 -2
- package/dist/backend/backend/src/services/messaging/messenger-registry.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/messenger-registry.service.js +33 -0
- package/dist/backend/backend/src/services/messaging/messenger-registry.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 +4 -2
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.js +4 -3
- package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.js.map +1 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +27 -0
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.js +54 -0
- package/dist/backend/backend/src/services/project/task-tracking.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +36 -6
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +238 -36
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +6 -4
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/backend/src/services/user/user-identity.service.d.ts +44 -0
- package/dist/backend/backend/src/services/user/user-identity.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/user/user-identity.service.js +75 -8
- package/dist/backend/backend/src/services/user/user-identity.service.js.map +1 -1
- package/dist/backend/backend/src/services/whatsapp/index.d.ts +11 -0
- package/dist/backend/backend/src/services/whatsapp/index.d.ts.map +1 -0
- package/dist/backend/backend/src/services/whatsapp/index.js +11 -0
- package/dist/backend/backend/src/services/whatsapp/index.js.map +1 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.d.ts +66 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.d.ts.map +1 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.js +96 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp-initializer.js.map +1 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts +109 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts.map +1 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js +234 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js.map +1 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp.service.d.ts +127 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js +347 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js.map +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 +4 -0
- package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +1 -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/slack.types.d.ts +24 -0
- package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/slack.types.js.map +1 -1
- package/dist/backend/backend/src/types/task-tracking.types.d.ts +4 -0
- package/dist/backend/backend/src/types/task-tracking.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/task-tracking.types.js.map +1 -1
- package/dist/backend/backend/src/types/whatsapp.types.d.ts +84 -0
- package/dist/backend/backend/src/types/whatsapp.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/whatsapp.types.js +33 -0
- package/dist/backend/backend/src/types/whatsapp.types.js.map +1 -0
- package/dist/backend/backend/src/websocket/terminal.gateway.d.ts +11 -0
- package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
- package/dist/backend/backend/src/websocket/terminal.gateway.js +35 -1
- package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +69 -6
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +75 -6
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js +14 -2
- package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
- package/dist/cli/backend/src/types/index.d.ts +1 -0
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/dist/cli/cli/src/commands/publish.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/publish.js +17 -15
- package/dist/cli/cli/src/commands/publish.js.map +1 -1
- package/dist/cli/cli/src/index.js +2 -2
- package/dist/cli/cli/src/index.js.map +1 -1
- package/dist/cli/cli/src/utils/gh-submit.d.ts +46 -0
- package/dist/cli/cli/src/utils/gh-submit.d.ts.map +1 -0
- package/dist/cli/cli/src/utils/gh-submit.js +167 -0
- package/dist/cli/cli/src/utils/gh-submit.js.map +1 -0
- package/dist/cli/cli/src/utils/marketplace.d.ts.map +1 -1
- package/dist/cli/cli/src/utils/marketplace.js +13 -5
- package/dist/cli/cli/src/utils/marketplace.js.map +1 -1
- package/dist/cli/cli/src/utils/templates.d.ts +3 -2
- package/dist/cli/cli/src/utils/templates.d.ts.map +1 -1
- package/dist/cli/cli/src/utils/templates.js +5 -4
- package/dist/cli/cli/src/utils/templates.js.map +1 -1
- package/frontend/dist/assets/{index-45eeea99.js → index-a23214ae.js} +241 -241
- package/frontend/dist/assets/{index-6972eeee.css → index-c407fe13.css} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +3 -1
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Competitor Content Tracker
|
|
2
|
+
|
|
3
|
+
Track and compare competitor content activity using browser automation and web search. Store structured data for trend analysis and content strategy.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
1. **Browser scanning** (agent-driven) — Visit competitor pages, extract content data
|
|
8
|
+
2. **Data management** (execute.sh) — Save, query, and compare stored data
|
|
9
|
+
|
|
10
|
+
## Data Actions (execute.sh)
|
|
11
|
+
|
|
12
|
+
### `save` — Store content items from a competitor scan
|
|
13
|
+
|
|
14
|
+
| Parameter | Required | Description |
|
|
15
|
+
|-----------|----------|-------------|
|
|
16
|
+
| `action` | Yes | `"save"` |
|
|
17
|
+
| `competitor` | Yes | `crewai`, `n8n`, `relevance-ai`, `autogen`, `langchain`, `langraph`, `openai`, `other` |
|
|
18
|
+
| `sourceType` | Yes | `blog`, `twitter`, `linkedin`, `github-release`, `changelog`, `youtube`, `community`, `press`, `other` |
|
|
19
|
+
| `items` | Yes | JSON array of content items (see schema below) |
|
|
20
|
+
|
|
21
|
+
**Content item schema:**
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"title": "Blog post or content title",
|
|
25
|
+
"url": "https://...",
|
|
26
|
+
"publishedDate": "2026-02-27",
|
|
27
|
+
"description": "Brief summary",
|
|
28
|
+
"engagement": "45 likes, 12 comments",
|
|
29
|
+
"contentType": "blog post / tweet / video",
|
|
30
|
+
"tags": ["mcp", "agents", "enterprise"]
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `list` — List tracked content files
|
|
35
|
+
|
|
36
|
+
| Parameter | Required | Description |
|
|
37
|
+
|-----------|----------|-------------|
|
|
38
|
+
| `action` | Yes | `"list"` |
|
|
39
|
+
| `competitor` | No | Filter by competitor |
|
|
40
|
+
| `limit` | No | Max results (default: 20) |
|
|
41
|
+
|
|
42
|
+
### `latest` — Get latest content from a competitor
|
|
43
|
+
|
|
44
|
+
| Parameter | Required | Description |
|
|
45
|
+
|-----------|----------|-------------|
|
|
46
|
+
| `action` | Yes | `"latest"` |
|
|
47
|
+
| `competitor` | Yes | Which competitor |
|
|
48
|
+
| `sourceType` | No | Filter by source type |
|
|
49
|
+
| `limit` | No | Max items (default: 15) |
|
|
50
|
+
|
|
51
|
+
### `compare` — Compare content activity across competitors
|
|
52
|
+
|
|
53
|
+
| Parameter | Required | Description |
|
|
54
|
+
|-----------|----------|-------------|
|
|
55
|
+
| `action` | Yes | `"compare"` |
|
|
56
|
+
| `competitors` | No | Comma-separated list (default: `crewai,n8n,relevance-ai`) |
|
|
57
|
+
| `days` | No | Lookback period in days (default: 7) |
|
|
58
|
+
|
|
59
|
+
## Browser Scanning Guide
|
|
60
|
+
|
|
61
|
+
### Competitor: CrewAI
|
|
62
|
+
|
|
63
|
+
**Blog:**
|
|
64
|
+
- URL: `https://www.crewai.com/blog`
|
|
65
|
+
- Extract: title, date, summary, URL for each post
|
|
66
|
+
- Focus on: product announcements, enterprise features, case studies
|
|
67
|
+
|
|
68
|
+
**GitHub:**
|
|
69
|
+
- URL: `https://github.com/crewAIInc/crewAI/releases`
|
|
70
|
+
- Extract: version, release date, key changes
|
|
71
|
+
- Also check: `https://docs.crewai.com/en/changelog`
|
|
72
|
+
|
|
73
|
+
**Twitter/X:**
|
|
74
|
+
- URL: `https://x.com/craborai` (CrewAI official)
|
|
75
|
+
- Extract: recent tweets, engagement (likes, retweets, replies)
|
|
76
|
+
- Focus on: product announcements, partnership news
|
|
77
|
+
|
|
78
|
+
**PyPI (version tracking):**
|
|
79
|
+
- URL: `https://pypi.org/project/crewai/#history`
|
|
80
|
+
- Extract: version numbers, release dates
|
|
81
|
+
|
|
82
|
+
**Example save:**
|
|
83
|
+
```bash
|
|
84
|
+
bash execute.sh '{"action":"save","competitor":"crewai","sourceType":"blog","projectPath":"/path","items":[
|
|
85
|
+
{"title":"The State of Agentic AI in 2026","url":"https://www.crewai.com/blog/state-of-agentic-ai","publishedDate":"2026-02-25","description":"Survey of 500 enterprises on AI agent adoption","engagement":"high - featured on front page","tags":["enterprise","survey","market-data"]},
|
|
86
|
+
{"title":"CrewAI v1.10.0 Release","url":"https://github.com/crewAIInc/crewAI/releases/tag/v1.10.0","publishedDate":"2026-02-27","description":"MCP enhancements, HITL improvements","engagement":"64 open issues","tags":["release","mcp","hitl"]}
|
|
87
|
+
]}'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
### Competitor: n8n
|
|
93
|
+
|
|
94
|
+
**Blog / Community:**
|
|
95
|
+
- URL: `https://community.n8n.io/c/announcements/`
|
|
96
|
+
- URL: `https://blog.n8n.io/`
|
|
97
|
+
- Extract: announcements, feature updates, security bulletins
|
|
98
|
+
|
|
99
|
+
**GitHub:**
|
|
100
|
+
- URL: `https://github.com/n8n-io/n8n/releases`
|
|
101
|
+
- Extract: version, date, key changes
|
|
102
|
+
- Also: `https://docs.n8n.io/release-notes/`
|
|
103
|
+
|
|
104
|
+
**Twitter/X:**
|
|
105
|
+
- URL: `https://x.com/n8n_io`
|
|
106
|
+
- Extract: recent tweets, engagement
|
|
107
|
+
|
|
108
|
+
**Security (critical to track):**
|
|
109
|
+
- URL: `https://community.n8n.io/tag/security`
|
|
110
|
+
- Extract: CVE disclosures, patch versions
|
|
111
|
+
|
|
112
|
+
**Example save:**
|
|
113
|
+
```bash
|
|
114
|
+
bash execute.sh '{"action":"save","competitor":"n8n","sourceType":"community","projectPath":"/path","items":[
|
|
115
|
+
{"title":"Security Bulletin February 25, 2026","url":"https://community.n8n.io/t/security-bulletin-february-25-2026/270324","publishedDate":"2026-02-25","description":"8 critical/high CVEs disclosed","engagement":"community discussion active","tags":["security","cve","critical"]}
|
|
116
|
+
]}'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### Competitor: Relevance AI
|
|
122
|
+
|
|
123
|
+
**Changelog:**
|
|
124
|
+
- URL: `https://relevanceai.com/changelog`
|
|
125
|
+
- Extract: feature name, date, description
|
|
126
|
+
|
|
127
|
+
**Blog:**
|
|
128
|
+
- URL: `https://relevanceai.com/blog`
|
|
129
|
+
- Extract: posts, topics, publication dates
|
|
130
|
+
|
|
131
|
+
**Twitter/X:**
|
|
132
|
+
- URL: `https://x.com/RelevanceAI_`
|
|
133
|
+
- Extract: tweets, engagement
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### Competitor: AutoGen (Microsoft)
|
|
138
|
+
|
|
139
|
+
**GitHub:**
|
|
140
|
+
- URL: `https://github.com/microsoft/autogen/releases`
|
|
141
|
+
- Extract: version, changes, community engagement
|
|
142
|
+
|
|
143
|
+
**Blog:**
|
|
144
|
+
- URL: `https://microsoft.github.io/autogen/blog/`
|
|
145
|
+
- Extract: posts, research papers
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Competitor: LangChain / LangGraph
|
|
150
|
+
|
|
151
|
+
**Blog:**
|
|
152
|
+
- URL: `https://blog.langchain.dev/`
|
|
153
|
+
- Extract: posts, product announcements
|
|
154
|
+
|
|
155
|
+
**GitHub:**
|
|
156
|
+
- URL: `https://github.com/langchain-ai/langgraph/releases`
|
|
157
|
+
- Extract: releases, features
|
|
158
|
+
|
|
159
|
+
**Twitter/X:**
|
|
160
|
+
- URL: `https://x.com/LangChainAI`
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Recommended Scan Schedule
|
|
165
|
+
|
|
166
|
+
| Frequency | What to Scan |
|
|
167
|
+
|-----------|-------------|
|
|
168
|
+
| **Daily** | CrewAI Twitter, n8n Twitter — quick check for announcements |
|
|
169
|
+
| **Twice/week** | CrewAI blog, n8n community, Relevance AI changelog |
|
|
170
|
+
| **Weekly** | GitHub releases (all competitors), full comparison report |
|
|
171
|
+
| **Ad-hoc** | When WebSearch reveals breaking news (acquisitions, security events, major launches) |
|
|
172
|
+
|
|
173
|
+
## Workflow Integration
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
1. Agent scans competitor pages via browser/WebSearch
|
|
177
|
+
2. Agent saves structured data via execute.sh save
|
|
178
|
+
3. Agent runs compare to see cross-competitor activity
|
|
179
|
+
4. Agent identifies content opportunities (reactive or counter-narrative)
|
|
180
|
+
5. Agent feeds opportunities to trend-monitor suggest or content-writer draft
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Content Strategy Angles by Competitor
|
|
184
|
+
|
|
185
|
+
### vs CrewAI
|
|
186
|
+
- **Their strength:** Enterprise narrative, large community, Python ecosystem
|
|
187
|
+
- **Our angle:** TypeScript/runtime-agnostic, live terminal, simpler setup for SMBs
|
|
188
|
+
- **Content trigger:** When they release enterprise features, we publish "here's how SMBs get the same power without the complexity"
|
|
189
|
+
|
|
190
|
+
### vs n8n
|
|
191
|
+
- **Their strength:** Massive community (177K stars), mature integrations, visual workflow builder
|
|
192
|
+
- **Our angle:** Security (PTY isolation vs their CVE history), AI-native (they added AI), full autonomy vs workflow steps
|
|
193
|
+
- **Content trigger:** Security events, workflow builder limitations for AI tasks
|
|
194
|
+
|
|
195
|
+
### vs Relevance AI
|
|
196
|
+
- **Their strength:** No-code agents, marketplace scale (215+ agents)
|
|
197
|
+
- **Our angle:** Developer control, open source, custom skills, not locked into their platform
|
|
198
|
+
- **Content trigger:** When they push no-code, we publish "why developers need code-level control for AI agents"
|
|
199
|
+
|
|
200
|
+
## Compare Report Example
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Weekly comparison across top 3 competitors
|
|
204
|
+
bash execute.sh '{"action":"compare","competitors":"crewai,n8n,relevance-ai","days":"7","projectPath":"/path"}'
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
This outputs total items tracked, breakdown by source type, and recent titles for each competitor. Use this to identify:
|
|
208
|
+
- Who is publishing most actively?
|
|
209
|
+
- What topics are they focusing on?
|
|
210
|
+
- Where are there gaps we can fill?
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "competitor-content-tracker",
|
|
3
|
+
"name": "Competitor Content Tracker",
|
|
4
|
+
"description": "Track and compare competitor content activity across blogs, social media, GitHub releases, and community channels. Supports CrewAI, n8n, Relevance AI, AutoGen, LangChain, and others.",
|
|
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"],
|
|
17
|
+
"triggers": ["competitor content", "track competitor", "competitor analysis", "what are competitors posting", "competitive content"],
|
|
18
|
+
"tags": ["competitors", "content", "tracking", "analysis", "crewai", "n8n", "relevance-ai", "marketing", "competitive-intelligence"],
|
|
19
|
+
"version": "1.0.0",
|
|
20
|
+
"author": "Luna (Content Strategist)",
|
|
21
|
+
"license": "MIT"
|
|
22
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Content Calendar Manager — CRUD operations for content scheduling
|
|
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\":\"add|list|update|next|stats\",\"calendarPath\":\"/path/to/calendar.json\",...}'"
|
|
9
|
+
|
|
10
|
+
# Parse common parameters
|
|
11
|
+
ACTION=$(echo "$INPUT" | jq -r '.action // empty')
|
|
12
|
+
CALENDAR_PATH=$(echo "$INPUT" | jq -r '.calendarPath // empty')
|
|
13
|
+
|
|
14
|
+
require_param "action" "$ACTION"
|
|
15
|
+
|
|
16
|
+
# Default calendar path
|
|
17
|
+
if [ -z "$CALENDAR_PATH" ]; then
|
|
18
|
+
# Try to find project .crewly directory
|
|
19
|
+
PROJECT_PATH=$(echo "$INPUT" | jq -r '.projectPath // empty')
|
|
20
|
+
if [ -n "$PROJECT_PATH" ]; then
|
|
21
|
+
CALENDAR_PATH="${PROJECT_PATH}/.crewly/content/calendar.json"
|
|
22
|
+
else
|
|
23
|
+
CALENDAR_PATH="${HOME}/.crewly/content/calendar.json"
|
|
24
|
+
fi
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Ensure calendar directory and file exist
|
|
28
|
+
CALENDAR_DIR=$(dirname "$CALENDAR_PATH")
|
|
29
|
+
mkdir -p "$CALENDAR_DIR"
|
|
30
|
+
if [ ! -f "$CALENDAR_PATH" ]; then
|
|
31
|
+
echo '{"entries":[],"metadata":{"createdAt":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'","version":"1.0"}}' > "$CALENDAR_PATH"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Validate calendar JSON
|
|
35
|
+
if ! jq empty "$CALENDAR_PATH" 2>/dev/null; then
|
|
36
|
+
error_exit "Calendar file is not valid JSON: $CALENDAR_PATH"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
case "$ACTION" in
|
|
40
|
+
|
|
41
|
+
# ─────────────────────────────────────────────
|
|
42
|
+
# ADD: Add a new content entry
|
|
43
|
+
# ─────────────────────────────────────────────
|
|
44
|
+
add)
|
|
45
|
+
TITLE=$(echo "$INPUT" | jq -r '.title // empty')
|
|
46
|
+
PLATFORM=$(echo "$INPUT" | jq -r '.platform // empty')
|
|
47
|
+
CONTENT_TYPE=$(echo "$INPUT" | jq -r '.type // "post"')
|
|
48
|
+
SCHEDULED_DATE=$(echo "$INPUT" | jq -r '.scheduledDate // empty')
|
|
49
|
+
STATUS=$(echo "$INPUT" | jq -r '.status // "draft"')
|
|
50
|
+
CONTENT_PATH=$(echo "$INPUT" | jq -r '.contentPath // empty')
|
|
51
|
+
LINE=$(echo "$INPUT" | jq -r '.line // "crewly"')
|
|
52
|
+
TOPIC=$(echo "$INPUT" | jq -r '.topic // empty')
|
|
53
|
+
NOTES=$(echo "$INPUT" | jq -r '.notes // empty')
|
|
54
|
+
TAGS=$(echo "$INPUT" | jq -r '.tags // "[]"')
|
|
55
|
+
|
|
56
|
+
require_param "title" "$TITLE"
|
|
57
|
+
require_param "platform" "$PLATFORM"
|
|
58
|
+
require_param "scheduledDate" "$SCHEDULED_DATE"
|
|
59
|
+
|
|
60
|
+
# Validate platform
|
|
61
|
+
VALID_PLATFORMS="x|linkedin|xiaohongshu|substack|youtube|github|reddit"
|
|
62
|
+
if ! echo "$PLATFORM" | grep -qE "^(${VALID_PLATFORMS})$"; then
|
|
63
|
+
error_exit "Invalid platform: $PLATFORM. Valid: x, linkedin, xiaohongshu, substack, youtube, github, reddit"
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Validate status
|
|
67
|
+
VALID_STATUSES="idea|draft|ready|in-review|approved|published|archived"
|
|
68
|
+
if ! echo "$STATUS" | grep -qE "^(${VALID_STATUSES})$"; then
|
|
69
|
+
error_exit "Invalid status: $STATUS. Valid: idea, draft, ready, in-review, approved, published, archived"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Validate content type
|
|
73
|
+
VALID_TYPES="post|thread|article|video|image-text|newsletter|showcase|tutorial"
|
|
74
|
+
if ! echo "$CONTENT_TYPE" | grep -qE "^(${VALID_TYPES})$"; then
|
|
75
|
+
error_exit "Invalid type: $CONTENT_TYPE. Valid: post, thread, article, video, image-text, newsletter, showcase, tutorial"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Generate entry ID (timestamp-based)
|
|
79
|
+
ENTRY_ID="cc-$(date +%s)-$((RANDOM % 1000))"
|
|
80
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
81
|
+
|
|
82
|
+
# Ensure tags is valid JSON array
|
|
83
|
+
if ! echo "$TAGS" | jq empty 2>/dev/null; then
|
|
84
|
+
TAGS="[]"
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Build new entry
|
|
88
|
+
NEW_ENTRY=$(jq -n \
|
|
89
|
+
--arg id "$ENTRY_ID" \
|
|
90
|
+
--arg title "$TITLE" \
|
|
91
|
+
--arg platform "$PLATFORM" \
|
|
92
|
+
--arg type "$CONTENT_TYPE" \
|
|
93
|
+
--arg scheduledDate "$SCHEDULED_DATE" \
|
|
94
|
+
--arg status "$STATUS" \
|
|
95
|
+
--arg contentPath "$CONTENT_PATH" \
|
|
96
|
+
--arg line "$LINE" \
|
|
97
|
+
--arg topic "$TOPIC" \
|
|
98
|
+
--arg notes "$NOTES" \
|
|
99
|
+
--argjson tags "$TAGS" \
|
|
100
|
+
--arg createdAt "$NOW" \
|
|
101
|
+
--arg updatedAt "$NOW" \
|
|
102
|
+
'{
|
|
103
|
+
id: $id,
|
|
104
|
+
title: $title,
|
|
105
|
+
platform: $platform,
|
|
106
|
+
type: $type,
|
|
107
|
+
scheduledDate: $scheduledDate,
|
|
108
|
+
status: $status,
|
|
109
|
+
contentPath: $contentPath,
|
|
110
|
+
line: $line,
|
|
111
|
+
topic: $topic,
|
|
112
|
+
notes: $notes,
|
|
113
|
+
tags: $tags,
|
|
114
|
+
createdAt: $createdAt,
|
|
115
|
+
updatedAt: $updatedAt
|
|
116
|
+
}')
|
|
117
|
+
|
|
118
|
+
# Append to calendar
|
|
119
|
+
jq --argjson entry "$NEW_ENTRY" '.entries += [$entry]' "$CALENDAR_PATH" > "${CALENDAR_PATH}.tmp" \
|
|
120
|
+
&& mv "${CALENDAR_PATH}.tmp" "$CALENDAR_PATH"
|
|
121
|
+
|
|
122
|
+
jq -n --argjson entry "$NEW_ENTRY" '{"success":true,"action":"add","entry":$entry}'
|
|
123
|
+
;;
|
|
124
|
+
|
|
125
|
+
# ─────────────────────────────────────────────
|
|
126
|
+
# LIST: List calendar entries with filters
|
|
127
|
+
# ─────────────────────────────────────────────
|
|
128
|
+
list)
|
|
129
|
+
FILTER_PLATFORM=$(echo "$INPUT" | jq -r '.platform // empty')
|
|
130
|
+
FILTER_STATUS=$(echo "$INPUT" | jq -r '.status // empty')
|
|
131
|
+
FILTER_DATE=$(echo "$INPUT" | jq -r '.date // empty')
|
|
132
|
+
FILTER_DATE_FROM=$(echo "$INPUT" | jq -r '.dateFrom // empty')
|
|
133
|
+
FILTER_DATE_TO=$(echo "$INPUT" | jq -r '.dateTo // empty')
|
|
134
|
+
FILTER_LINE=$(echo "$INPUT" | jq -r '.line // empty')
|
|
135
|
+
LIMIT=$(echo "$INPUT" | jq -r '.limit // "50"')
|
|
136
|
+
|
|
137
|
+
# Build jq filter
|
|
138
|
+
JQ_FILTER=".entries"
|
|
139
|
+
|
|
140
|
+
if [ -n "$FILTER_PLATFORM" ]; then
|
|
141
|
+
JQ_FILTER="${JQ_FILTER} | map(select(.platform == \"${FILTER_PLATFORM}\"))"
|
|
142
|
+
fi
|
|
143
|
+
if [ -n "$FILTER_STATUS" ]; then
|
|
144
|
+
JQ_FILTER="${JQ_FILTER} | map(select(.status == \"${FILTER_STATUS}\"))"
|
|
145
|
+
fi
|
|
146
|
+
if [ -n "$FILTER_DATE" ]; then
|
|
147
|
+
JQ_FILTER="${JQ_FILTER} | map(select(.scheduledDate == \"${FILTER_DATE}\"))"
|
|
148
|
+
fi
|
|
149
|
+
if [ -n "$FILTER_DATE_FROM" ]; then
|
|
150
|
+
JQ_FILTER="${JQ_FILTER} | map(select(.scheduledDate >= \"${FILTER_DATE_FROM}\"))"
|
|
151
|
+
fi
|
|
152
|
+
if [ -n "$FILTER_DATE_TO" ]; then
|
|
153
|
+
JQ_FILTER="${JQ_FILTER} | map(select(.scheduledDate <= \"${FILTER_DATE_TO}\"))"
|
|
154
|
+
fi
|
|
155
|
+
if [ -n "$FILTER_LINE" ]; then
|
|
156
|
+
JQ_FILTER="${JQ_FILTER} | map(select(.line == \"${FILTER_LINE}\"))"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# Sort by scheduled date and limit
|
|
160
|
+
JQ_FILTER="${JQ_FILTER} | sort_by(.scheduledDate) | .[:${LIMIT}]"
|
|
161
|
+
|
|
162
|
+
ENTRIES=$(jq "$JQ_FILTER" "$CALENDAR_PATH")
|
|
163
|
+
COUNT=$(echo "$ENTRIES" | jq 'length')
|
|
164
|
+
|
|
165
|
+
jq -n \
|
|
166
|
+
--argjson entries "$ENTRIES" \
|
|
167
|
+
--argjson count "$COUNT" \
|
|
168
|
+
--arg calendarPath "$CALENDAR_PATH" \
|
|
169
|
+
'{"success":true,"action":"list","count":$count,"entries":$entries,"calendarPath":$calendarPath}'
|
|
170
|
+
;;
|
|
171
|
+
|
|
172
|
+
# ─────────────────────────────────────────────
|
|
173
|
+
# UPDATE: Update an existing entry
|
|
174
|
+
# ─────────────────────────────────────────────
|
|
175
|
+
update)
|
|
176
|
+
ENTRY_ID=$(echo "$INPUT" | jq -r '.id // empty')
|
|
177
|
+
require_param "id" "$ENTRY_ID"
|
|
178
|
+
|
|
179
|
+
# Check if entry exists
|
|
180
|
+
EXISTS=$(jq --arg id "$ENTRY_ID" '[.entries[] | select(.id == $id)] | length' "$CALENDAR_PATH")
|
|
181
|
+
if [ "$EXISTS" -eq 0 ]; then
|
|
182
|
+
error_exit "Entry not found: $ENTRY_ID"
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
186
|
+
|
|
187
|
+
# Build update fields dynamically
|
|
188
|
+
UPDATE_FIELDS=".updatedAt = \"${NOW}\""
|
|
189
|
+
|
|
190
|
+
NEW_STATUS=$(echo "$INPUT" | jq -r '.status // empty')
|
|
191
|
+
NEW_TITLE=$(echo "$INPUT" | jq -r '.title // empty')
|
|
192
|
+
NEW_DATE=$(echo "$INPUT" | jq -r '.scheduledDate // empty')
|
|
193
|
+
NEW_CONTENT_PATH=$(echo "$INPUT" | jq -r '.contentPath // empty')
|
|
194
|
+
NEW_NOTES=$(echo "$INPUT" | jq -r '.notes // empty')
|
|
195
|
+
NEW_TOPIC=$(echo "$INPUT" | jq -r '.topic // empty')
|
|
196
|
+
|
|
197
|
+
[ -n "$NEW_STATUS" ] && UPDATE_FIELDS="${UPDATE_FIELDS} | .status = \"${NEW_STATUS}\""
|
|
198
|
+
[ -n "$NEW_TITLE" ] && UPDATE_FIELDS="${UPDATE_FIELDS} | .title = \"${NEW_TITLE}\""
|
|
199
|
+
[ -n "$NEW_DATE" ] && UPDATE_FIELDS="${UPDATE_FIELDS} | .scheduledDate = \"${NEW_DATE}\""
|
|
200
|
+
[ -n "$NEW_CONTENT_PATH" ] && UPDATE_FIELDS="${UPDATE_FIELDS} | .contentPath = \"${NEW_CONTENT_PATH}\""
|
|
201
|
+
[ -n "$NEW_NOTES" ] && UPDATE_FIELDS="${UPDATE_FIELDS} | .notes = \"${NEW_NOTES}\""
|
|
202
|
+
[ -n "$NEW_TOPIC" ] && UPDATE_FIELDS="${UPDATE_FIELDS} | .topic = \"${NEW_TOPIC}\""
|
|
203
|
+
|
|
204
|
+
# If marking as published, record publishedAt
|
|
205
|
+
if [ "$NEW_STATUS" = "published" ]; then
|
|
206
|
+
UPDATE_FIELDS="${UPDATE_FIELDS} | .publishedAt = \"${NOW}\""
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
# Apply update
|
|
210
|
+
jq --arg id "$ENTRY_ID" \
|
|
211
|
+
"(.entries[] | select(.id == \$id)) |= (${UPDATE_FIELDS})" \
|
|
212
|
+
"$CALENDAR_PATH" > "${CALENDAR_PATH}.tmp" \
|
|
213
|
+
&& mv "${CALENDAR_PATH}.tmp" "$CALENDAR_PATH"
|
|
214
|
+
|
|
215
|
+
# Return updated entry
|
|
216
|
+
UPDATED=$(jq --arg id "$ENTRY_ID" '.entries[] | select(.id == $id)' "$CALENDAR_PATH")
|
|
217
|
+
jq -n --argjson entry "$UPDATED" '{"success":true,"action":"update","entry":$entry}'
|
|
218
|
+
;;
|
|
219
|
+
|
|
220
|
+
# ─────────────────────────────────────────────
|
|
221
|
+
# NEXT: Get the next content to publish
|
|
222
|
+
# ─────────────────────────────────────────────
|
|
223
|
+
next)
|
|
224
|
+
FILTER_PLATFORM=$(echo "$INPUT" | jq -r '.platform // empty')
|
|
225
|
+
TODAY=$(date -u +%Y-%m-%d)
|
|
226
|
+
|
|
227
|
+
# Find entries that are ready/approved and scheduled for today or earlier
|
|
228
|
+
JQ_FILTER='.entries | map(select(.status == "ready" or .status == "approved"))'
|
|
229
|
+
JQ_FILTER="${JQ_FILTER} | map(select(.scheduledDate <= \"${TODAY}\"))"
|
|
230
|
+
|
|
231
|
+
if [ -n "$FILTER_PLATFORM" ]; then
|
|
232
|
+
JQ_FILTER="${JQ_FILTER} | map(select(.platform == \"${FILTER_PLATFORM}\"))"
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
JQ_FILTER="${JQ_FILTER} | sort_by(.scheduledDate) | .[0] // null"
|
|
236
|
+
|
|
237
|
+
NEXT_ENTRY=$(jq "$JQ_FILTER" "$CALENDAR_PATH")
|
|
238
|
+
|
|
239
|
+
if [ "$NEXT_ENTRY" = "null" ]; then
|
|
240
|
+
# Also show upcoming entries
|
|
241
|
+
UPCOMING=$(jq --arg today "$TODAY" \
|
|
242
|
+
'[.entries[] | select(.status == "draft" or .status == "ready" or .status == "approved") | select(.scheduledDate > $today)] | sort_by(.scheduledDate) | .[:3]' \
|
|
243
|
+
"$CALENDAR_PATH")
|
|
244
|
+
jq -n --argjson upcoming "$UPCOMING" \
|
|
245
|
+
'{"success":true,"action":"next","next":null,"message":"No content ready to publish right now.","upcoming":$upcoming}'
|
|
246
|
+
else
|
|
247
|
+
jq -n --argjson entry "$NEXT_ENTRY" \
|
|
248
|
+
'{"success":true,"action":"next","next":$entry}'
|
|
249
|
+
fi
|
|
250
|
+
;;
|
|
251
|
+
|
|
252
|
+
# ─────────────────────────────────────────────
|
|
253
|
+
# STATS: Calendar statistics
|
|
254
|
+
# ─────────────────────────────────────────────
|
|
255
|
+
stats)
|
|
256
|
+
TOTAL=$(jq '.entries | length' "$CALENDAR_PATH")
|
|
257
|
+
BY_STATUS=$(jq '[.entries[] | .status] | group_by(.) | map({(.[0]): length}) | add // {}' "$CALENDAR_PATH")
|
|
258
|
+
BY_PLATFORM=$(jq '[.entries[] | .platform] | group_by(.) | map({(.[0]): length}) | add // {}' "$CALENDAR_PATH")
|
|
259
|
+
BY_LINE=$(jq '[.entries[] | .line] | group_by(.) | map({(.[0]): length}) | add // {}' "$CALENDAR_PATH")
|
|
260
|
+
|
|
261
|
+
TODAY=$(date -u +%Y-%m-%d)
|
|
262
|
+
OVERDUE=$(jq --arg today "$TODAY" \
|
|
263
|
+
'[.entries[] | select(.scheduledDate < $today and (.status == "draft" or .status == "ready" or .status == "approved"))] | length' \
|
|
264
|
+
"$CALENDAR_PATH")
|
|
265
|
+
THIS_WEEK_END=$(date -u -v+7d +%Y-%m-%d 2>/dev/null || date -u -d "+7 days" +%Y-%m-%d 2>/dev/null || echo "$TODAY")
|
|
266
|
+
THIS_WEEK=$(jq --arg from "$TODAY" --arg to "$THIS_WEEK_END" \
|
|
267
|
+
'[.entries[] | select(.scheduledDate >= $from and .scheduledDate <= $to)] | length' \
|
|
268
|
+
"$CALENDAR_PATH")
|
|
269
|
+
|
|
270
|
+
jq -n \
|
|
271
|
+
--argjson total "$TOTAL" \
|
|
272
|
+
--argjson byStatus "$BY_STATUS" \
|
|
273
|
+
--argjson byPlatform "$BY_PLATFORM" \
|
|
274
|
+
--argjson byLine "$BY_LINE" \
|
|
275
|
+
--argjson overdue "$OVERDUE" \
|
|
276
|
+
--argjson thisWeek "$THIS_WEEK" \
|
|
277
|
+
--arg calendarPath "$CALENDAR_PATH" \
|
|
278
|
+
'{
|
|
279
|
+
"success": true,
|
|
280
|
+
"action": "stats",
|
|
281
|
+
"total": $total,
|
|
282
|
+
"byStatus": $byStatus,
|
|
283
|
+
"byPlatform": $byPlatform,
|
|
284
|
+
"byLine": $byLine,
|
|
285
|
+
"overdue": $overdue,
|
|
286
|
+
"thisWeek": $thisWeek,
|
|
287
|
+
"calendarPath": $calendarPath
|
|
288
|
+
}'
|
|
289
|
+
;;
|
|
290
|
+
|
|
291
|
+
*)
|
|
292
|
+
error_exit "Unknown action: $ACTION. Valid actions: add, list, update, next, stats"
|
|
293
|
+
;;
|
|
294
|
+
esac
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Content Calendar Manager
|
|
2
|
+
|
|
3
|
+
Manage a content calendar with CRUD operations. Track planned content across platforms, schedule dates, and publication status.
|
|
4
|
+
|
|
5
|
+
## Storage
|
|
6
|
+
|
|
7
|
+
Calendar data is stored as a JSON file. Default location: `{projectPath}/.crewly/content/calendar.json`
|
|
8
|
+
|
|
9
|
+
## Actions
|
|
10
|
+
|
|
11
|
+
### `add` — Add a new content entry
|
|
12
|
+
|
|
13
|
+
| Parameter | Required | Description |
|
|
14
|
+
|-----------|----------|-------------|
|
|
15
|
+
| `action` | Yes | `"add"` |
|
|
16
|
+
| `title` | Yes | Content title or headline |
|
|
17
|
+
| `platform` | Yes | `x`, `linkedin`, `xiaohongshu`, `substack`, `youtube`, `github`, `reddit` |
|
|
18
|
+
| `type` | No | `post`, `thread`, `article`, `video`, `image-text`, `newsletter`, `showcase`, `tutorial` (default: `post`) |
|
|
19
|
+
| `scheduledDate` | Yes | Target publish date in `YYYY-MM-DD` format |
|
|
20
|
+
| `status` | No | `idea`, `draft`, `ready`, `in-review`, `approved`, `published`, `archived` (default: `draft`) |
|
|
21
|
+
| `contentPath` | No | Path to the content file (markdown) |
|
|
22
|
+
| `line` | No | Content line: `crewly` (brand) or `personal` (Steve). Default: `crewly` |
|
|
23
|
+
| `topic` | No | Topic or brief description |
|
|
24
|
+
| `notes` | No | Internal notes |
|
|
25
|
+
| `tags` | No | JSON array of tags, e.g. `["ai-agent","security"]` |
|
|
26
|
+
| `projectPath` | No | Project path to determine calendar location |
|
|
27
|
+
| `calendarPath` | No | Custom calendar file path (overrides default) |
|
|
28
|
+
|
|
29
|
+
### `list` — List entries with filters
|
|
30
|
+
|
|
31
|
+
| Parameter | Required | Description |
|
|
32
|
+
|-----------|----------|-------------|
|
|
33
|
+
| `action` | Yes | `"list"` |
|
|
34
|
+
| `platform` | No | Filter by platform |
|
|
35
|
+
| `status` | No | Filter by status |
|
|
36
|
+
| `date` | No | Filter by exact date (`YYYY-MM-DD`) |
|
|
37
|
+
| `dateFrom` | No | Filter entries from this date |
|
|
38
|
+
| `dateTo` | No | Filter entries up to this date |
|
|
39
|
+
| `line` | No | Filter by content line (`crewly` or `personal`) |
|
|
40
|
+
| `limit` | No | Max entries to return (default: 50) |
|
|
41
|
+
|
|
42
|
+
### `update` — Update an entry
|
|
43
|
+
|
|
44
|
+
| Parameter | Required | Description |
|
|
45
|
+
|-----------|----------|-------------|
|
|
46
|
+
| `action` | Yes | `"update"` |
|
|
47
|
+
| `id` | Yes | Entry ID to update |
|
|
48
|
+
| `status` | No | New status |
|
|
49
|
+
| `title` | No | New title |
|
|
50
|
+
| `scheduledDate` | No | New date |
|
|
51
|
+
| `contentPath` | No | New content file path |
|
|
52
|
+
| `notes` | No | New notes |
|
|
53
|
+
| `topic` | No | New topic |
|
|
54
|
+
|
|
55
|
+
### `next` — Get next content to publish
|
|
56
|
+
|
|
57
|
+
Returns the next entry with status `ready` or `approved` that is scheduled for today or earlier.
|
|
58
|
+
|
|
59
|
+
| Parameter | Required | Description |
|
|
60
|
+
|-----------|----------|-------------|
|
|
61
|
+
| `action` | Yes | `"next"` |
|
|
62
|
+
| `platform` | No | Filter by platform |
|
|
63
|
+
|
|
64
|
+
### `stats` — Calendar statistics
|
|
65
|
+
|
|
66
|
+
Returns counts by status, platform, and content line. Also shows overdue and this-week counts.
|
|
67
|
+
|
|
68
|
+
| Parameter | Required | Description |
|
|
69
|
+
|-----------|----------|-------------|
|
|
70
|
+
| `action` | Yes | `"stats"` |
|
|
71
|
+
|
|
72
|
+
## Examples
|
|
73
|
+
|
|
74
|
+
### Add a new X thread for Monday
|
|
75
|
+
```bash
|
|
76
|
+
bash execute.sh '{"action":"add","title":"AI Agent security - lessons from n8n CVEs","platform":"x","type":"thread","scheduledDate":"2026-03-03","status":"draft","line":"crewly","topic":"AI agent security","tags":["ai-agent","security","n8n"],"projectPath":"/path/to/project"}'
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### List all content for next week
|
|
80
|
+
```bash
|
|
81
|
+
bash execute.sh '{"action":"list","dateFrom":"2026-03-03","dateTo":"2026-03-07","projectPath":"/path/to/project"}'
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### List only draft X content
|
|
85
|
+
```bash
|
|
86
|
+
bash execute.sh '{"action":"list","platform":"x","status":"draft","projectPath":"/path/to/project"}'
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Mark content as published
|
|
90
|
+
```bash
|
|
91
|
+
bash execute.sh '{"action":"update","id":"cc-1709012345-42","status":"published","projectPath":"/path/to/project"}'
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Get next content to publish
|
|
95
|
+
```bash
|
|
96
|
+
bash execute.sh '{"action":"next","projectPath":"/path/to/project"}'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Get calendar stats
|
|
100
|
+
```bash
|
|
101
|
+
bash execute.sh '{"action":"stats","projectPath":"/path/to/project"}'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Status Workflow
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
idea → draft → ready → in-review → approved → published
|
|
108
|
+
↓
|
|
109
|
+
archived
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- **idea**: Just a topic/concept, no content written
|
|
113
|
+
- **draft**: Content being written
|
|
114
|
+
- **ready**: Content complete, pending review
|
|
115
|
+
- **in-review**: Sent to Steve for review
|
|
116
|
+
- **approved**: Steve approved, ready to publish
|
|
117
|
+
- **published**: Live on the platform
|
|
118
|
+
- **archived**: Removed from active calendar
|
|
119
|
+
|
|
120
|
+
## Output
|
|
121
|
+
|
|
122
|
+
All actions return JSON with `success: true` and the relevant data. Errors return JSON to stderr with `error` field.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "content-calendar",
|
|
3
|
+
"name": "Content Calendar Manager",
|
|
4
|
+
"description": "CRUD operations for content scheduling. Add, list, update, and query content calendar entries. Supports filtering by platform, status, date range, and content line (brand vs personal).",
|
|
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": 10000
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"assignableRoles": ["content-strategist", "product-manager", "generalist"],
|
|
17
|
+
"triggers": ["content calendar", "schedule content", "content plan", "what to publish", "next post", "content schedule"],
|
|
18
|
+
"tags": ["content", "calendar", "scheduling", "planning", "marketing", "editorial"],
|
|
19
|
+
"version": "1.0.0",
|
|
20
|
+
"author": "Luna (Content Strategist)",
|
|
21
|
+
"license": "MIT"
|
|
22
|
+
}
|