@growthub/cli 0.3.56 → 0.3.58
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/assets/worker-kits/growthub-zernio-social-v1/QUICKSTART.md +209 -0
- package/assets/worker-kits/growthub-zernio-social-v1/brands/NEW-CLIENT.md +74 -0
- package/assets/worker-kits/growthub-zernio-social-v1/brands/_template/brand-kit.md +131 -0
- package/assets/worker-kits/growthub-zernio-social-v1/brands/growthub/brand-kit.md +141 -0
- package/assets/worker-kits/growthub-zernio-social-v1/bundles/growthub-zernio-social-v1.json +55 -0
- package/assets/worker-kits/growthub-zernio-social-v1/docs/ai-caption-layer.md +132 -0
- package/assets/worker-kits/growthub-zernio-social-v1/docs/local-adapters.md +123 -0
- package/assets/worker-kits/growthub-zernio-social-v1/docs/platform-coverage.md +112 -0
- package/assets/worker-kits/growthub-zernio-social-v1/docs/postiz-ui-shell-integration.md +166 -0
- package/assets/worker-kits/growthub-zernio-social-v1/docs/posts-and-queues-layer.md +208 -0
- package/assets/worker-kits/growthub-zernio-social-v1/docs/zernio-api-integration.md +265 -0
- package/assets/worker-kits/growthub-zernio-social-v1/examples/analytics-brief-sample.md +97 -0
- package/assets/worker-kits/growthub-zernio-social-v1/examples/client-proposal-sample.md +106 -0
- package/assets/worker-kits/growthub-zernio-social-v1/examples/content-calendar-sample.md +74 -0
- package/assets/worker-kits/growthub-zernio-social-v1/examples/social-campaign-sample.md +105 -0
- package/assets/worker-kits/growthub-zernio-social-v1/growthub-meta/README.md +146 -0
- package/assets/worker-kits/growthub-zernio-social-v1/growthub-meta/kit-standard.md +120 -0
- package/assets/worker-kits/growthub-zernio-social-v1/kit.json +104 -0
- package/assets/worker-kits/growthub-zernio-social-v1/output/README.md +63 -0
- package/assets/worker-kits/growthub-zernio-social-v1/output-standards.md +132 -0
- package/assets/worker-kits/growthub-zernio-social-v1/runtime-assumptions.md +170 -0
- package/assets/worker-kits/growthub-zernio-social-v1/setup/check-deps.mjs +117 -0
- package/assets/worker-kits/growthub-zernio-social-v1/setup/check-deps.sh +86 -0
- package/assets/worker-kits/growthub-zernio-social-v1/setup/install-mcp.mjs +177 -0
- package/assets/worker-kits/growthub-zernio-social-v1/setup/setup.mjs +247 -0
- package/assets/worker-kits/growthub-zernio-social-v1/setup/verify-env.mjs +138 -0
- package/assets/worker-kits/growthub-zernio-social-v1/skills.md +332 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/analytics-brief.md +101 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/caption-copy-deck.md +105 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/client-proposal.md +98 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/content-calendar.md +70 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/platform-publishing-plan.md +86 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/scheduling-manifest.md +92 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/social-campaign-brief.md +102 -0
- package/assets/worker-kits/growthub-zernio-social-v1/validation-checklist.md +85 -0
- package/assets/worker-kits/growthub-zernio-social-v1/workers/zernio-social-operator/CLAUDE.md +307 -0
- package/package.json +1 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Output Standards
|
|
2
|
+
|
|
3
|
+
**All Zernio Social Media Operator outputs must meet these standards before being delivered to a client.**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Output Directory Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
output/
|
|
11
|
+
<client-slug>/
|
|
12
|
+
<project-slug>/
|
|
13
|
+
SocialCampaignBrief_v<N>_<YYYYMMDD>.md
|
|
14
|
+
ContentCalendar_v<N>_<YYYYMMDD>.md
|
|
15
|
+
PlatformPublishingPlan_v<N>_<YYYYMMDD>.md
|
|
16
|
+
CaptionCopyDeck_v<N>_<YYYYMMDD>.md
|
|
17
|
+
SchedulingManifest_v<N>_<YYYYMMDD>.md (if scheduling requested)
|
|
18
|
+
AnalyticsBrief_v<N>_<YYYYMMDD>.md (if analytics data available)
|
|
19
|
+
ClientProposal_v<N>_<YYYYMMDD>.md (if requested)
|
|
20
|
+
scheduling-manifest.json (always when scheduling — powers Zernio POST /api/v1/posts)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## File Naming Convention
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
<ClientSlug>_<OutputType>_v<N>_<YYYYMMDD>.md
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| Part | Rules | Example |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| ClientSlug | TitleCase, no spaces, no special chars | `UrbanCycle` |
|
|
34
|
+
| OutputType | CamelCase from the list below | `ContentCalendar` |
|
|
35
|
+
| Version | `v` + integer, starting at 1 | `v1` |
|
|
36
|
+
| Date | `YYYYMMDD` format | `20260415` |
|
|
37
|
+
|
|
38
|
+
**Output type names:**
|
|
39
|
+
|
|
40
|
+
| Artifact | OutputType string |
|
|
41
|
+
|---|---|
|
|
42
|
+
| Social Campaign Brief | `SocialCampaignBrief` |
|
|
43
|
+
| Content Calendar | `ContentCalendar` |
|
|
44
|
+
| Platform Publishing Plan | `PlatformPublishingPlan` |
|
|
45
|
+
| Caption Copy Deck | `CaptionCopyDeck` |
|
|
46
|
+
| Scheduling Manifest | `SchedulingManifest` |
|
|
47
|
+
| Analytics Brief | `AnalyticsBrief` |
|
|
48
|
+
| Client Proposal | `ClientProposal` |
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Required Sections Per Artifact
|
|
53
|
+
|
|
54
|
+
Each artifact must include all sections from its template. Incomplete sections must be marked `<!-- data-gap: reason -->` — never left blank without explanation.
|
|
55
|
+
|
|
56
|
+
| Artifact | Minimum Required Sections |
|
|
57
|
+
|---|---|
|
|
58
|
+
| SocialCampaignBrief | Project Overview, Campaign Objective, Target Platforms, Audience Profile, KPI Targets, Content Theme Pillars, Brand Voice |
|
|
59
|
+
| ContentCalendar | Calendar Header (client, period, platforms, profile id), Calendar Table (all rows with all columns), Posting Cadence Summary |
|
|
60
|
+
| PlatformPublishingPlan | Per-platform rows (all selected platforms), Format spec, Frequency, Best posting times, Content mix ratio |
|
|
61
|
+
| CaptionCopyDeck | Per-post entries (A/B/C variants each), Hashtag sets, Character counts, Media asset notes |
|
|
62
|
+
| SchedulingManifest | Manifest header (profileId, timezone, dryRun), All post entries (clientPostId, content, scheduledFor, platforms[], media[], status) |
|
|
63
|
+
| AnalyticsBrief | Period summary, Per-platform metrics table, Top 3 posts, Bottom 3 posts, Recommendations |
|
|
64
|
+
| ClientProposal | Campaign Overview, Platform Mix rationale, Content Strategy, Deliverables scope, Pricing (3 tiers), ROI Projection |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Quality Bar
|
|
69
|
+
|
|
70
|
+
### Platform-Accurate
|
|
71
|
+
|
|
72
|
+
- All platform IDs must match the official list in `docs/platform-coverage.md`
|
|
73
|
+
- Character limits must be respected for every caption variant
|
|
74
|
+
- Post types must be valid for the target platform (e.g., no carousels on TikTok or X)
|
|
75
|
+
|
|
76
|
+
### Caption Quality
|
|
77
|
+
|
|
78
|
+
- Every caption must have an explicit CTA — "Learn more" is acceptable; blank is not
|
|
79
|
+
- All 3 variants (A/B/C) must be meaningfully different — not minor word swaps
|
|
80
|
+
- Hashtags must be relevant to the content — no generic filler unless platform context demands it
|
|
81
|
+
|
|
82
|
+
### Scheduling Manifest
|
|
83
|
+
|
|
84
|
+
- `scheduledFor` timestamps must be ISO 8601 format with timezone offset
|
|
85
|
+
- `clientPostId` must follow the naming convention: `<client-slug>-<YYYYMMDD>-<sequence>`
|
|
86
|
+
- All posts in the manifest must have a corresponding entry in the ContentCalendar
|
|
87
|
+
- `profileId` must be present (non-empty) — never hardcode to a placeholder string without also setting `dryRun: true`
|
|
88
|
+
- Every `platforms[].platform` value must exist in `docs/platform-coverage.md`
|
|
89
|
+
- Every `platforms[].accountId` must either be a real Zernio account id (live mode) or a documented placeholder tagged with the handle (agent-only mode)
|
|
90
|
+
|
|
91
|
+
### No Filler
|
|
92
|
+
|
|
93
|
+
- Every sentence must either present data, explain a constraint, or specify an action
|
|
94
|
+
- Remove phrases like "Great content is key" — replace with the actual content specification
|
|
95
|
+
- Recommendations must be specific: name the exact platform, posting time, content format, and expected impact
|
|
96
|
+
|
|
97
|
+
### Actionable
|
|
98
|
+
|
|
99
|
+
- Every post entry in the ContentCalendar must have a ready-to-use caption variant
|
|
100
|
+
- Every platform in the PlatformPublishingPlan must have a posting time recommendation
|
|
101
|
+
- Every finding in the AnalyticsBrief must have a corresponding action item
|
|
102
|
+
|
|
103
|
+
### Consistent
|
|
104
|
+
|
|
105
|
+
- Platform names in all artifacts must use the same slug format from `docs/platform-coverage.md`
|
|
106
|
+
- Dates must be consistent across all artifacts
|
|
107
|
+
- Client name must match the brand kit exactly
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Versioning Rules
|
|
112
|
+
|
|
113
|
+
| Scenario | Action |
|
|
114
|
+
|---|---|
|
|
115
|
+
| First campaign for a client | All files at v1 |
|
|
116
|
+
| Campaign revised post-approval | Increment all files to v2 |
|
|
117
|
+
| Partial update (one artifact revised) | Increment only the revised artifact's version |
|
|
118
|
+
| New campaign, same client | Start new project-slug, all files at v1 |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## scheduling-manifest.json
|
|
123
|
+
|
|
124
|
+
This file must always be written to the output directory when scheduling is requested. It is the machine-readable record required for:
|
|
125
|
+
|
|
126
|
+
- Zernio API scheduled post creation (one `POST /api/v1/posts` per entry or a batched sequence)
|
|
127
|
+
- Manual review before submitting to Zernio
|
|
128
|
+
- Campaign audit trail
|
|
129
|
+
|
|
130
|
+
See `templates/scheduling-manifest.md` and `docs/posts-and-queues-layer.md` for the complete format with all required fields.
|
|
131
|
+
|
|
132
|
+
Every write request to Zernio must include an `Idempotency-Key` header — the operator must instruct the downstream executor to use the `clientPostId` as that key so re-submissions are safe.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Runtime Assumptions
|
|
2
|
+
|
|
3
|
+
**Frozen at kit creation: 2026-04-15. Update this file when Zernio API behavior changes.**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Execution Mode Overview
|
|
8
|
+
|
|
9
|
+
| Mode | Requirements | Zernio API? | Live scheduling? | Caption AI? |
|
|
10
|
+
|---|---|---|---|---|
|
|
11
|
+
| `api-live` | Valid `ZERNIO_API_KEY` with `read-write` scope | Yes | Yes | Built-in (optional Anthropic enhancement) |
|
|
12
|
+
| `agent-only` | Nothing (Claude Code only) | No | Dry-run JSON only | Yes |
|
|
13
|
+
| `hybrid` | `ANTHROPIC_API_KEY` + valid `ZERNIO_API_KEY` | Yes | Yes | Enhanced via Anthropic |
|
|
14
|
+
|
|
15
|
+
### Choosing a Mode
|
|
16
|
+
|
|
17
|
+
- **Use `api-live`** when you want real Zernio scheduling, queue management, and analytics pull-back.
|
|
18
|
+
- **Use `agent-only`** when you only need campaign planning, content calendars, and caption drafts, or when no Zernio key is available.
|
|
19
|
+
- **Use `hybrid`** for the highest-quality caption drafting plus live Zernio scheduling.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Zernio API Assumptions (frozen at kit creation)
|
|
24
|
+
|
|
25
|
+
These are the assumptions frozen at kit creation time about the Zernio API at `https://zernio.com/api/v1`.
|
|
26
|
+
|
|
27
|
+
### Base URL + versioning
|
|
28
|
+
|
|
29
|
+
| Field | Value |
|
|
30
|
+
|---|---|
|
|
31
|
+
| Base URL | `https://zernio.com/api/v1` |
|
|
32
|
+
| Version prefix | `v1` in the path |
|
|
33
|
+
| Content-Type | `application/json` for all JSON endpoints |
|
|
34
|
+
| Media upload | `multipart/form-data` on `/api/v1/media` |
|
|
35
|
+
|
|
36
|
+
### Authentication
|
|
37
|
+
|
|
38
|
+
- Header: `Authorization: Bearer ${ZERNIO_API_KEY}`
|
|
39
|
+
- Key format: `sk_` + 64 hex characters (67 total)
|
|
40
|
+
- Scopes: `read` or `read-write`
|
|
41
|
+
- Scope per key: `full` or `profiles-specific`
|
|
42
|
+
- Rotate keys via `POST /api/v1/api-keys` / `DELETE /api/v1/api-keys/<id>`
|
|
43
|
+
|
|
44
|
+
### Core resources
|
|
45
|
+
|
|
46
|
+
| Resource | Endpoint | Purpose |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| Profiles | `/api/v1/profiles` | Containers that group social accounts together |
|
|
49
|
+
| Accounts | `/api/v1/accounts` | Connected social accounts on a profile |
|
|
50
|
+
| Posts | `/api/v1/posts` | Schedulable content, fan-out to multiple accounts |
|
|
51
|
+
| Queues | `/api/v1/queues` | Recurring time-slot schedules |
|
|
52
|
+
| Media | `/api/v1/media` | Upload images, videos, carousels |
|
|
53
|
+
| Inbox | `/api/v1/inbox` | Unified DMs, comments, reviews |
|
|
54
|
+
| Analytics | `/api/v1/analytics` | Per-post and per-account metrics |
|
|
55
|
+
| API Keys | `/api/v1/api-keys` | Key lifecycle management |
|
|
56
|
+
| Connect | `/api/v1/connect/<platform>` | OAuth / credential flow entrypoint |
|
|
57
|
+
|
|
58
|
+
### 14 platforms (at time of freeze)
|
|
59
|
+
|
|
60
|
+
| Platform | Zernio platform id | Auth method (Zernio-managed) |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| X/Twitter | `twitter` | Twitter OAuth 2.0 |
|
|
63
|
+
| Instagram | `instagram` | Meta OAuth |
|
|
64
|
+
| Facebook | `facebook` | Meta OAuth |
|
|
65
|
+
| LinkedIn | `linkedin` | LinkedIn OAuth |
|
|
66
|
+
| TikTok | `tiktok` | TikTok OAuth |
|
|
67
|
+
| YouTube | `youtube` | Google OAuth |
|
|
68
|
+
| Pinterest | `pinterest` | Pinterest OAuth |
|
|
69
|
+
| Reddit | `reddit` | Reddit OAuth |
|
|
70
|
+
| Bluesky | `bluesky` | AT Protocol |
|
|
71
|
+
| Threads | `threads` | Meta OAuth |
|
|
72
|
+
| Google Business | `googlebusiness` | Google OAuth |
|
|
73
|
+
| Telegram | `telegram` | Bot API token |
|
|
74
|
+
| Snapchat | `snapchat` | Snapchat Marketing API |
|
|
75
|
+
| WhatsApp | `whatsapp` | WhatsApp Business API |
|
|
76
|
+
|
|
77
|
+
*Additional platforms may be added in newer Zernio releases. Always confirm against `GET /api/v1/platforms` for the live list.*
|
|
78
|
+
|
|
79
|
+
### Rate limits (assumed)
|
|
80
|
+
|
|
81
|
+
| Limit | Value |
|
|
82
|
+
|---|---|
|
|
83
|
+
| Default plan | 60 requests/minute per API key |
|
|
84
|
+
| Posts burst | ≤30 scheduled posts per single `POST /api/v1/posts` call |
|
|
85
|
+
| Media uploads | ≤10 media objects per minute per profile |
|
|
86
|
+
| Analytics pull | ≤10 calls/minute per profile |
|
|
87
|
+
|
|
88
|
+
If a 429 is returned, back off using the `Retry-After` header. Treat rate-limit retries as idempotent only when a client-provided `Idempotency-Key` header is attached.
|
|
89
|
+
|
|
90
|
+
### Idempotency
|
|
91
|
+
|
|
92
|
+
- Include `Idempotency-Key: <uuid>` on every write (`POST /posts`, `POST /queues`, `POST /media`)
|
|
93
|
+
- Use `clientPostId` values from the manifest as the idempotency key when creating scheduled posts — this makes manifest re-submission safe
|
|
94
|
+
|
|
95
|
+
### Optional AI caption enhancement
|
|
96
|
+
|
|
97
|
+
Zernio ships its own caption-enhancement endpoint, but this kit uses the operator's Anthropic key directly for caption drafting. Zernio's built-in caption service is treated as secondary.
|
|
98
|
+
|
|
99
|
+
- Kit caption source: Anthropic (via the agent calling Claude)
|
|
100
|
+
- Zernio caption service: documented but not used as the primary source
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Execution Surface Flows
|
|
105
|
+
|
|
106
|
+
### Api-Live Mode
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
User request → Environment gate (Step 0)
|
|
110
|
+
↓
|
|
111
|
+
Read skills.md + brand kit (Step 1)
|
|
112
|
+
↓
|
|
113
|
+
Read runtime docs (Step 2)
|
|
114
|
+
↓
|
|
115
|
+
Inspect Zernio account: profiles, accounts, queues, scheduled posts (Step 3)
|
|
116
|
+
↓
|
|
117
|
+
4-question gate (Step 4)
|
|
118
|
+
↓
|
|
119
|
+
Select /zernio command (Step 5)
|
|
120
|
+
↓
|
|
121
|
+
Phase 1: Campaign strategy + platform selection (Step 6)
|
|
122
|
+
↓
|
|
123
|
+
Phase 2: Content calendar + caption copy deck (Step 7)
|
|
124
|
+
↓
|
|
125
|
+
Phase 3: Scheduling manifest → POST /api/v1/posts (Step 8)
|
|
126
|
+
↓
|
|
127
|
+
Optional queue definition → POST /api/v1/queues (Step 8b)
|
|
128
|
+
↓
|
|
129
|
+
Artifact package: 5–7 Markdown files + scheduling-manifest.json (Step 9)
|
|
130
|
+
↓
|
|
131
|
+
Log deliverable → brand kit DELIVERABLES LOG (Step 10)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Agent-Only Mode
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
User request → Environment gate (Step 0 — confirm agent-only)
|
|
138
|
+
↓
|
|
139
|
+
Read skills.md + brand kit (Step 1)
|
|
140
|
+
↓
|
|
141
|
+
Read runtime docs (Step 2)
|
|
142
|
+
↓
|
|
143
|
+
Skip live account inspection (Step 3 — N/A)
|
|
144
|
+
↓
|
|
145
|
+
4-question gate (Step 4)
|
|
146
|
+
↓
|
|
147
|
+
Select /zernio command (Step 5)
|
|
148
|
+
↓
|
|
149
|
+
Phase 1: Campaign strategy + platform selection (Step 6)
|
|
150
|
+
↓
|
|
151
|
+
Phase 2: Content calendar + caption copy deck (Step 7)
|
|
152
|
+
↓
|
|
153
|
+
Phase 3: Dry-run scheduling manifest (JSON, dryRun: true) (Step 8)
|
|
154
|
+
↓
|
|
155
|
+
Artifact package: 5–7 Markdown files + scheduling-manifest.json (Step 9)
|
|
156
|
+
↓
|
|
157
|
+
Log deliverable → brand kit DELIVERABLES LOG (Step 10)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Output Assumption
|
|
163
|
+
|
|
164
|
+
All outputs are Markdown files written to:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
output/<client-slug>/<project-slug>/
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The scheduling manifest is a JSON file (`scheduling-manifest.json`) written alongside the Markdown artifacts. It is the machine-readable record for Zernio API submission and stays aligned to the `POST /api/v1/posts` body shape documented in `docs/posts-and-queues-layer.md`.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// check-deps.mjs — cross-platform dependency check for the Zernio Social Media Studio
|
|
3
|
+
//
|
|
4
|
+
// Works identically on macOS, Linux, and Windows (PowerShell, cmd, WSL, git-bash).
|
|
5
|
+
// Functional parity with setup/check-deps.sh (bash, unix-only) so Windows users
|
|
6
|
+
// get a first-class experience without bash.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// node setup/check-deps.mjs
|
|
10
|
+
|
|
11
|
+
import { spawn } from "node:child_process";
|
|
12
|
+
import { platform, release } from "node:os";
|
|
13
|
+
|
|
14
|
+
const RED = "\x1b[31m";
|
|
15
|
+
const GREEN = "\x1b[32m";
|
|
16
|
+
const YELLOW = "\x1b[33m";
|
|
17
|
+
const BOLD = "\x1b[1m";
|
|
18
|
+
const RESET = "\x1b[0m";
|
|
19
|
+
|
|
20
|
+
let pass = 0;
|
|
21
|
+
let warn = 0;
|
|
22
|
+
let fail = 0;
|
|
23
|
+
|
|
24
|
+
function ok(msg) { console.log(` ${GREEN}\u2713${RESET} ${msg}`); pass += 1; }
|
|
25
|
+
function warning(msg) { console.log(` ${YELLOW}!${RESET} ${msg}`); warn += 1; }
|
|
26
|
+
function failure(msg) { console.log(` ${RED}\u2717${RESET} ${msg}`); fail += 1; }
|
|
27
|
+
|
|
28
|
+
function which(binary) {
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
const isWin = platform() === "win32";
|
|
31
|
+
const lookup = isWin ? "where" : "which";
|
|
32
|
+
const child = spawn(lookup, [binary], { shell: false });
|
|
33
|
+
let out = "";
|
|
34
|
+
child.stdout?.on("data", (d) => (out += String(d)));
|
|
35
|
+
child.on("close", (code) => resolve(code === 0 ? out.trim().split(/\r?\n/)[0] : null));
|
|
36
|
+
child.on("error", () => resolve(null));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function version(binary, args = ["--version"]) {
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
const child = spawn(binary, args, { shell: false });
|
|
43
|
+
let out = "";
|
|
44
|
+
child.stdout?.on("data", (d) => (out += String(d)));
|
|
45
|
+
child.stderr?.on("data", (d) => (out += String(d)));
|
|
46
|
+
child.on("close", (code) => resolve(code === 0 ? out.trim() : null));
|
|
47
|
+
child.on("error", () => resolve(null));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log("");
|
|
52
|
+
console.log(`${BOLD}Growthub Zernio Social Media Studio — Dependency Check${RESET}`);
|
|
53
|
+
console.log(`host: ${platform()} ${release()} · node: ${process.version}`);
|
|
54
|
+
console.log("");
|
|
55
|
+
|
|
56
|
+
// --- Node.js (required, built-in check) ---
|
|
57
|
+
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0], 10);
|
|
58
|
+
if (Number.isFinite(nodeMajor) && nodeMajor >= 18) {
|
|
59
|
+
ok(`node ${process.version} (>= 18 required)`);
|
|
60
|
+
} else {
|
|
61
|
+
failure(`node ${process.version} — version 18+ required. Install from https://nodejs.org`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- Built-in fetch (Node 18+ has it) ---
|
|
65
|
+
if (typeof fetch === "function") {
|
|
66
|
+
ok("Node built-in fetch() is available — no curl dependency required");
|
|
67
|
+
} else {
|
|
68
|
+
failure("Node built-in fetch() is not available — upgrade to Node 18+");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// --- npm (optional but expected) ---
|
|
72
|
+
{
|
|
73
|
+
const path = await which("npm");
|
|
74
|
+
if (path) {
|
|
75
|
+
const v = await version("npm");
|
|
76
|
+
ok(`npm ${v ?? ""} at ${path}`);
|
|
77
|
+
} else {
|
|
78
|
+
warning("npm not found — usually ships with Node.js; only needed if you install additional CLIs");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// --- curl (optional — useful for manual API smoke tests) ---
|
|
83
|
+
{
|
|
84
|
+
const path = await which("curl");
|
|
85
|
+
if (path) {
|
|
86
|
+
ok(`curl at ${path} — optional, useful for ad-hoc API tests`);
|
|
87
|
+
} else {
|
|
88
|
+
warning("curl not found — optional. Node's fetch() handles everything the kit needs.");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --- git (optional) ---
|
|
93
|
+
{
|
|
94
|
+
const path = await which("git");
|
|
95
|
+
if (path) {
|
|
96
|
+
ok(`git at ${path}`);
|
|
97
|
+
} else {
|
|
98
|
+
warning("git not found — optional for this kit. Install from https://git-scm.com/downloads if you want repo versioning.");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// --- Summary ---
|
|
103
|
+
console.log("");
|
|
104
|
+
console.log(`${BOLD}Summary${RESET}`);
|
|
105
|
+
console.log(` Passed: ${pass}`);
|
|
106
|
+
if (warn > 0) console.log(` ${YELLOW}Warnings: ${warn}${RESET}`);
|
|
107
|
+
if (fail > 0) console.log(` ${RED}Failed: ${fail}${RESET}`);
|
|
108
|
+
console.log("");
|
|
109
|
+
|
|
110
|
+
if (fail > 0) {
|
|
111
|
+
console.log(`${RED}${BOLD}Install the missing required dependencies and re-run.${RESET}`);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
} else if (warn > 0) {
|
|
114
|
+
console.log(`${YELLOW}Dependencies OK with warnings. All warnings are optional.${RESET}`);
|
|
115
|
+
} else {
|
|
116
|
+
console.log(`${GREEN}All dependencies satisfied.${RESET}`);
|
|
117
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# check-deps.sh — Verify system dependencies for the Zernio Social Media Studio
|
|
3
|
+
# Usage: bash setup/check-deps.sh
|
|
4
|
+
set -e
|
|
5
|
+
|
|
6
|
+
GREEN="\033[0;32m"
|
|
7
|
+
RED="\033[0;31m"
|
|
8
|
+
YELLOW="\033[0;33m"
|
|
9
|
+
RESET="\033[0m"
|
|
10
|
+
|
|
11
|
+
PASS=0
|
|
12
|
+
FAIL=0
|
|
13
|
+
WARN=0
|
|
14
|
+
|
|
15
|
+
ok() {
|
|
16
|
+
echo -e " ${GREEN}✓${RESET} $1"
|
|
17
|
+
PASS=$((PASS + 1))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fail() {
|
|
21
|
+
echo -e " ${RED}✗${RESET} $1"
|
|
22
|
+
FAIL=$((FAIL + 1))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
warn() {
|
|
26
|
+
echo -e " ${YELLOW}⚠${RESET} $1"
|
|
27
|
+
WARN=$((WARN + 1))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
echo "=== Growthub Zernio Social Media Studio — Dependency Check ==="
|
|
31
|
+
echo ""
|
|
32
|
+
|
|
33
|
+
# --- Node.js ---
|
|
34
|
+
if command -v node &>/dev/null; then
|
|
35
|
+
NODE_VER=$(node --version | sed 's/v//')
|
|
36
|
+
NODE_MAJOR=$(echo "$NODE_VER" | cut -d. -f1)
|
|
37
|
+
if [ "$NODE_MAJOR" -ge 18 ]; then
|
|
38
|
+
ok "node v${NODE_VER} (18+ required)"
|
|
39
|
+
else
|
|
40
|
+
fail "node v${NODE_VER} — version 18+ required. Install from https://nodejs.org"
|
|
41
|
+
fi
|
|
42
|
+
else
|
|
43
|
+
fail "node — not found. Install from https://nodejs.org"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# --- npm ---
|
|
47
|
+
if command -v npm &>/dev/null; then
|
|
48
|
+
ok "npm $(npm --version)"
|
|
49
|
+
else
|
|
50
|
+
warn "npm — not found. Usually installed with Node.js."
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# --- curl ---
|
|
54
|
+
if command -v curl &>/dev/null; then
|
|
55
|
+
ok "curl $(curl --version | head -1 | awk '{print $2}')"
|
|
56
|
+
else
|
|
57
|
+
fail "curl — not found. Required for Zernio healthchecks. Install from https://curl.se/download.html"
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# --- Git ---
|
|
61
|
+
if command -v git &>/dev/null; then
|
|
62
|
+
ok "git $(git --version | awk '{print $3}')"
|
|
63
|
+
else
|
|
64
|
+
warn "git — not found. Not strictly required for this kit but strongly recommended."
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# --- Summary ---
|
|
68
|
+
echo ""
|
|
69
|
+
echo "=== Summary ==="
|
|
70
|
+
echo " Passed: $PASS"
|
|
71
|
+
if [ "$WARN" -gt 0 ]; then
|
|
72
|
+
echo -e " ${YELLOW}Warnings: $WARN${RESET}"
|
|
73
|
+
fi
|
|
74
|
+
if [ "$FAIL" -gt 0 ]; then
|
|
75
|
+
echo -e " ${RED}Failed: $FAIL${RESET}"
|
|
76
|
+
echo ""
|
|
77
|
+
echo "Install missing dependencies and re-run this script."
|
|
78
|
+
exit 1
|
|
79
|
+
else
|
|
80
|
+
echo ""
|
|
81
|
+
if [ "$WARN" -gt 0 ]; then
|
|
82
|
+
echo -e "${YELLOW}Dependencies OK with warnings.${RESET}"
|
|
83
|
+
else
|
|
84
|
+
echo -e "${GREEN}All dependencies satisfied.${RESET}"
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// install-mcp.mjs — print the per-IDE Zernio MCP server config JSON
|
|
3
|
+
//
|
|
4
|
+
// This is a print-only helper. It does NOT run `pip install zernio-sdk[mcp]`
|
|
5
|
+
// for you, and it does NOT mutate any config file. It prints the exact
|
|
6
|
+
// copy-paste JSON blocks you need to wire Zernio's official MCP server into
|
|
7
|
+
// each MCP-compatible IDE.
|
|
8
|
+
//
|
|
9
|
+
// Cross-platform (macOS, Linux, Windows). Pure Node stdlib — no deps.
|
|
10
|
+
//
|
|
11
|
+
// Usage:
|
|
12
|
+
// node setup/install-mcp.mjs # print all IDE configs
|
|
13
|
+
// node setup/install-mcp.mjs claude-desktop # one IDE only
|
|
14
|
+
// node setup/install-mcp.mjs cursor
|
|
15
|
+
// node setup/install-mcp.mjs claude-code
|
|
16
|
+
// node setup/install-mcp.mjs generic
|
|
17
|
+
|
|
18
|
+
import { platform } from "node:os";
|
|
19
|
+
import { join } from "node:path";
|
|
20
|
+
import { homedir } from "node:os";
|
|
21
|
+
|
|
22
|
+
const BOLD = "\x1b[1m";
|
|
23
|
+
const DIM = "\x1b[2m";
|
|
24
|
+
const GREEN = "\x1b[32m";
|
|
25
|
+
const YELLOW = "\x1b[33m";
|
|
26
|
+
const BLUE = "\x1b[34m";
|
|
27
|
+
const RESET = "\x1b[0m";
|
|
28
|
+
|
|
29
|
+
const arg = (process.argv[2] ?? "all").toLowerCase();
|
|
30
|
+
const osPlatform = platform();
|
|
31
|
+
|
|
32
|
+
// ---- Config path hints (cross-platform) ----
|
|
33
|
+
function claudeDesktopConfigPath() {
|
|
34
|
+
const home = homedir();
|
|
35
|
+
if (osPlatform === "darwin") return join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
36
|
+
if (osPlatform === "win32") return join(process.env.APPDATA ?? join(home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
|
|
37
|
+
return join(home, ".config", "Claude", "claude_desktop_config.json");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function claudeCodeConfigPath() {
|
|
41
|
+
return join(homedir(), ".claude", "mcp.json");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function cursorConfigPath() {
|
|
45
|
+
return join(homedir(), ".cursor", "mcp.json");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ---- MCP server definition ----
|
|
49
|
+
// Zernio's official MCP server ships inside the zernio-python SDK:
|
|
50
|
+
// pip install zernio-sdk[mcp]
|
|
51
|
+
// The server entrypoint is the Python module. Auth is via ZERNIO_API_KEY env var.
|
|
52
|
+
const ZERNIO_MCP_BLOCK = {
|
|
53
|
+
command: "python",
|
|
54
|
+
args: ["-m", "zernio.mcp"],
|
|
55
|
+
env: {
|
|
56
|
+
ZERNIO_API_KEY: "${ZERNIO_API_KEY}",
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function header(label) {
|
|
61
|
+
console.log("");
|
|
62
|
+
console.log(`${BOLD}${BLUE}${label}${RESET}`);
|
|
63
|
+
console.log("-".repeat(Math.max(24, label.length)));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function note(msg) {
|
|
67
|
+
console.log(`${DIM}${msg}${RESET}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function codeBlock(obj) {
|
|
71
|
+
console.log("```json");
|
|
72
|
+
console.log(JSON.stringify(obj, null, 2));
|
|
73
|
+
console.log("```");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function printPreamble() {
|
|
77
|
+
console.log("");
|
|
78
|
+
console.log(`${BOLD}Zernio MCP Server — per-IDE config${RESET}`);
|
|
79
|
+
note(`host: ${osPlatform} · pre-req: pip install zernio-sdk[mcp] · env: ZERNIO_API_KEY`);
|
|
80
|
+
console.log("");
|
|
81
|
+
console.log(`${GREEN}1.${RESET} Install Zernio's MCP server (one-time):`);
|
|
82
|
+
console.log(` ${BOLD}pip install zernio-sdk[mcp]${RESET}`);
|
|
83
|
+
console.log("");
|
|
84
|
+
console.log(`${GREEN}2.${RESET} Ensure ZERNIO_API_KEY is set in your shell profile (or pass it via the IDE):`);
|
|
85
|
+
if (osPlatform === "win32") {
|
|
86
|
+
console.log(` ${DIM}setx ZERNIO_API_KEY "sk_..."${RESET} ${DIM}# PowerShell, persistent${RESET}`);
|
|
87
|
+
} else {
|
|
88
|
+
console.log(` ${DIM}echo 'export ZERNIO_API_KEY="sk_..."' >> ~/.zshrc${RESET} ${DIM}# or ~/.bashrc${RESET}`);
|
|
89
|
+
}
|
|
90
|
+
console.log("");
|
|
91
|
+
console.log(`${GREEN}3.${RESET} Paste one of the JSON blocks below into the matching IDE's MCP config.`);
|
|
92
|
+
console.log("");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function printClaudeDesktop() {
|
|
96
|
+
header("Claude Desktop");
|
|
97
|
+
note(`Config file: ${claudeDesktopConfigPath()}`);
|
|
98
|
+
console.log(`Add the ${BOLD}zernio${RESET} server under the top-level ${BOLD}mcpServers${RESET} object:`);
|
|
99
|
+
console.log("");
|
|
100
|
+
codeBlock({
|
|
101
|
+
mcpServers: {
|
|
102
|
+
zernio: ZERNIO_MCP_BLOCK,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
console.log(`${YELLOW}Restart Claude Desktop${RESET} after editing the config.`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function printClaudeCode() {
|
|
109
|
+
header("Claude Code");
|
|
110
|
+
note(`Config file: ${claudeCodeConfigPath()}`);
|
|
111
|
+
console.log(`Add to ${BOLD}.claude/mcp.json${RESET} (or use ${BOLD}claude mcp add${RESET}):`);
|
|
112
|
+
console.log("");
|
|
113
|
+
codeBlock({
|
|
114
|
+
mcpServers: {
|
|
115
|
+
zernio: ZERNIO_MCP_BLOCK,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
console.log(`Alternative one-liner:`);
|
|
119
|
+
console.log(` ${BOLD}claude mcp add zernio -- python -m zernio.mcp${RESET}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function printCursor() {
|
|
123
|
+
header("Cursor");
|
|
124
|
+
note(`Config file: ${cursorConfigPath()}`);
|
|
125
|
+
console.log(`Add the ${BOLD}zernio${RESET} entry under the top-level ${BOLD}mcpServers${RESET} object:`);
|
|
126
|
+
console.log("");
|
|
127
|
+
codeBlock({
|
|
128
|
+
mcpServers: {
|
|
129
|
+
zernio: ZERNIO_MCP_BLOCK,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
console.log(`${YELLOW}Restart Cursor${RESET} after editing the config.`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function printGeneric() {
|
|
136
|
+
header("Generic MCP-compatible IDE");
|
|
137
|
+
note("Use this shape for any IDE that speaks MCP (Codex-mcp, n8n MCP nodes, custom clients).");
|
|
138
|
+
console.log("");
|
|
139
|
+
codeBlock({
|
|
140
|
+
mcpServers: {
|
|
141
|
+
zernio: ZERNIO_MCP_BLOCK,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
console.log("Adjust the top-level key if your IDE uses a different name (e.g. `servers` vs `mcpServers`).");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function printFooter() {
|
|
148
|
+
console.log("");
|
|
149
|
+
header("What this enables");
|
|
150
|
+
console.log("- The agent can call Zernio endpoints as typed MCP tools instead of raw HTTP.");
|
|
151
|
+
console.log("- Works alongside this kit's Working Directory pattern — strictly additive.");
|
|
152
|
+
console.log("- All writes still use Idempotency-Key = clientPostId for safe re-submission.");
|
|
153
|
+
console.log("- See docs/local-adapters.md for the full matrix of supported IDEs.");
|
|
154
|
+
console.log("");
|
|
155
|
+
console.log(`${DIM}Zernio's MCP server lives in the zernio-python SDK:${RESET}`);
|
|
156
|
+
console.log(` ${DIM}https://github.com/zernio-dev/zernio-python${RESET}`);
|
|
157
|
+
console.log("");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ---- Dispatch ----
|
|
161
|
+
printPreamble();
|
|
162
|
+
|
|
163
|
+
switch (arg) {
|
|
164
|
+
case "claude-desktop": printClaudeDesktop(); break;
|
|
165
|
+
case "claude-code": printClaudeCode(); break;
|
|
166
|
+
case "cursor": printCursor(); break;
|
|
167
|
+
case "generic": printGeneric(); break;
|
|
168
|
+
case "all":
|
|
169
|
+
default:
|
|
170
|
+
printClaudeDesktop();
|
|
171
|
+
printClaudeCode();
|
|
172
|
+
printCursor();
|
|
173
|
+
printGeneric();
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
printFooter();
|