@wahlu/cli 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wahlu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,484 @@
1
+ # Wahlu CLI
2
+
3
+ Manage your social media from the terminal. Works for humans, AI agents, and CI/CD pipelines.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g @wahlu/cli
9
+ ```
10
+
11
+ ## Authentication
12
+
13
+ Generate an API key at [wahlu.com](https://wahlu.com) under Settings > API Keys.
14
+
15
+ ```bash
16
+ # Option 1: Save to config
17
+ wahlu auth login wahlu_live_abc123...
18
+
19
+ # Option 2: Environment variable
20
+ export WAHLU_API_KEY=wahlu_live_abc123...
21
+ ```
22
+
23
+ Authentication priority:
24
+ 1. `WAHLU_API_KEY` environment variable (highest)
25
+ 2. Saved key in `~/.config/wahlu/config.json`
26
+
27
+ ## Quick start
28
+
29
+ ```bash
30
+ # List your brands
31
+ wahlu brand list
32
+
33
+ # Set a default brand so you don't need --brand every time
34
+ wahlu brand switch <brand-id>
35
+
36
+ # List posts
37
+ wahlu post list
38
+
39
+ # Create a post
40
+ wahlu post create --name "Monday motivation" \
41
+ --instagram '{"description":"Rise and grind","post_type":"grid_post"}'
42
+
43
+ # Schedule it
44
+ wahlu schedule create <post-id> \
45
+ --at 2026-03-15T14:00:00Z \
46
+ --integrations <integration-id>
47
+
48
+ # Upload media
49
+ wahlu media upload ./photo.jpg
50
+
51
+ # List what's been published
52
+ wahlu publication list
53
+ ```
54
+
55
+ ## Commands
56
+
57
+ ### Auth
58
+
59
+ | Command | Description |
60
+ |---------|-------------|
61
+ | `wahlu auth login <key>` | Save API key to `~/.config/wahlu/config.json` |
62
+ | `wahlu auth logout` | Remove saved API key |
63
+ | `wahlu auth status` | Show current auth method, masked key, and config |
64
+
65
+ ### Brands
66
+
67
+ Brands represent social media profiles. All posts, media, schedules, and queues belong to a brand.
68
+
69
+ | Command | Description |
70
+ |---------|-------------|
71
+ | `wahlu brand list` | List all brands |
72
+ | `wahlu brand get <id>` | Get full brand details |
73
+ | `wahlu brand switch <id>` | Set default brand for all commands |
74
+
75
+ **Response fields:**
76
+
77
+ | Field | Type | Description |
78
+ |-------|------|-------------|
79
+ | `id` | string | Brand ID |
80
+ | `name` | string | Brand name |
81
+ | `description` | string\|null | Brand description |
82
+ | `logo_url` | string\|null | Logo URL |
83
+ | `timezone` | string\|null | IANA timezone (e.g. `Australia/Sydney`) |
84
+ | `website` | string\|null | Brand website URL |
85
+ | `business_category` | string\|null | Business category |
86
+ | `brand_kit` | object\|null | Brand kit (fonts, colours, voice) |
87
+ | `content_preferences` | object\|null | CTA, logo frequency settings |
88
+ | `image_posting` | object\|null | Image posting preferences |
89
+ | `video_posting` | object\|null | Video posting preferences |
90
+ | `created_at` | string | ISO 8601 timestamp |
91
+ | `updated_at` | string | ISO 8601 timestamp |
92
+
93
+ ### Posts
94
+
95
+ Posts are the core content unit. Each post can have platform-specific settings for Instagram, TikTok, Facebook, YouTube, and LinkedIn.
96
+
97
+ | Command | Description |
98
+ |---------|-------------|
99
+ | `wahlu post list` | List posts (paginated) |
100
+ | `wahlu post get <id>` | Get full post details |
101
+ | `wahlu post create [options]` | Create a new post |
102
+ | `wahlu post update <id> [options]` | Update a post (partial update) |
103
+ | `wahlu post delete <id>` | Permanently delete a post |
104
+
105
+ **Create/update options:**
106
+
107
+ | Option | Description |
108
+ |--------|-------------|
109
+ | `--name <name>` | Post name (max 500 chars) |
110
+ | `--instagram <json>` | Instagram settings as JSON string |
111
+ | `--tiktok <json>` | TikTok settings as JSON string |
112
+ | `--facebook <json>` | Facebook settings as JSON string |
113
+ | `--youtube <json>` | YouTube settings as JSON string |
114
+ | `--linkedin <json>` | LinkedIn settings as JSON string |
115
+ | `--labels <ids...>` | Label IDs to attach (max 50) |
116
+
117
+ **Response fields:**
118
+
119
+ | Field | Type | Description |
120
+ |-------|------|-------------|
121
+ | `id` | string | Post ID |
122
+ | `name` | string\|null | Post name |
123
+ | `brand_id` | string | Brand ID |
124
+ | `label_ids` | string[] | Attached label IDs |
125
+ | `created_by` | string\|null | Creator user ID |
126
+ | `thumbnail_timestamp` | number | Thumbnail timestamp (seconds) |
127
+ | `instagram_settings` | object\|null | Instagram configuration |
128
+ | `tiktok_settings` | object\|null | TikTok configuration |
129
+ | `facebook_settings` | object\|null | Facebook configuration |
130
+ | `youtube_settings` | object\|null | YouTube configuration |
131
+ | `linkedin_settings` | object\|null | LinkedIn configuration |
132
+ | `created_at` | string | ISO 8601 timestamp |
133
+ | `updated_at` | string | ISO 8601 timestamp |
134
+
135
+ #### Platform settings reference
136
+
137
+ **Instagram** (`--instagram`):
138
+
139
+ | Field | Type | Values |
140
+ |-------|------|--------|
141
+ | `description` | string | Caption text |
142
+ | `post_type` | string | `grid_post` \| `reel` \| `story` |
143
+ | `media_ids` | string[] | Media IDs to attach |
144
+ | `trial_reel` | boolean | Post as trial reel (non-followers first) |
145
+ | `graduation_strategy` | string | `MANUAL` \| `SS_PERFORMANCE` |
146
+
147
+ **TikTok** (`--tiktok`):
148
+
149
+ | Field | Type | Values |
150
+ |-------|------|--------|
151
+ | `description` | string | Caption text |
152
+ | `post_type` | string | `video` \| `image` \| `carousel` |
153
+ | `media_ids` | string[] | Media IDs to attach |
154
+ | `privacy_level` | string | `PUBLIC_TO_EVERYONE` \| `MUTUAL_FOLLOW_FRIENDS` \| `FOLLOWER_OF_CREATOR` \| `SELF_ONLY` |
155
+ | `allow_comment` | boolean | Allow comments (default: true) |
156
+ | `allow_duet` | boolean | Allow duets (default: true, video only) |
157
+ | `allow_stitch` | boolean | Allow stitches (default: true, video only) |
158
+ | `auto_add_music` | boolean | Auto-add music (photo/carousel only) |
159
+ | `is_aigc` | boolean | Disclose as AI-generated content |
160
+ | `is_commercial_content` | boolean | Mark as commercial/branded content |
161
+
162
+ **Facebook** (`--facebook`):
163
+
164
+ | Field | Type | Values |
165
+ |-------|------|--------|
166
+ | `description` | string | Caption text |
167
+ | `post_type` | string | `fb_post` \| `fb_story` \| `fb_reel` \| `fb_text` |
168
+ | `media_ids` | string[] | Media IDs to attach |
169
+
170
+ **YouTube** (`--youtube`):
171
+
172
+ | Field | Type | Values |
173
+ |-------|------|--------|
174
+ | `title` | string | Video title |
175
+ | `description` | string | Video description |
176
+ | `post_type` | string | `yt_short` \| `yt_video` |
177
+ | `media_ids` | string[] | Media IDs to attach |
178
+ | `privacy_level` | string | `public` \| `unlisted` \| `private` |
179
+ | `notify_subscribers` | boolean | Notify subscribers on publish |
180
+
181
+ **LinkedIn** (`--linkedin`):
182
+
183
+ | Field | Type | Values |
184
+ |-------|------|--------|
185
+ | `description` | string | Post text |
186
+ | `post_type` | string | `li_text` \| `li_image` \| `li_video` \| `li_article` |
187
+ | `media_ids` | string[] | Media IDs to attach |
188
+ | `visibility` | string | `PUBLIC` \| `CONNECTIONS` |
189
+ | `title` | string | Article title (`li_article` only) |
190
+ | `original_url` | string | Article URL (`li_article` only) |
191
+
192
+ **Examples:**
193
+
194
+ ```bash
195
+ # Instagram grid post
196
+ wahlu post create --name "Photo post" \
197
+ --instagram '{"description":"Hello!","post_type":"grid_post","media_ids":["mid-123"]}'
198
+
199
+ # Cross-platform video
200
+ wahlu post create --name "Video" \
201
+ --tiktok '{"description":"Check this out","post_type":"video","media_ids":["mid-123"]}' \
202
+ --instagram '{"description":"Check this out","post_type":"reel","media_ids":["mid-123"]}'
203
+
204
+ # LinkedIn article
205
+ wahlu post create --name "Article share" \
206
+ --linkedin '{"description":"Read our latest","post_type":"li_article","original_url":"https://example.com","title":"Our Post"}'
207
+ ```
208
+
209
+ ### Scheduled posts
210
+
211
+ Schedule posts for future publishing to specific integrations.
212
+
213
+ | Command | Description |
214
+ |---------|-------------|
215
+ | `wahlu schedule list` | List scheduled posts (paginated) |
216
+ | `wahlu schedule create <post-id>` | Schedule a post |
217
+ | `wahlu schedule delete <id>` | Remove from schedule (does not delete the post) |
218
+
219
+ **Create options:**
220
+
221
+ | Option | Required | Description |
222
+ |--------|----------|-------------|
223
+ | `--at <datetime>` | Yes | ISO 8601 datetime (e.g. `2026-03-15T14:00:00Z`) |
224
+ | `--integrations <ids...>` | Yes | Integration IDs to publish to (max 20) |
225
+
226
+ **Response fields:**
227
+
228
+ | Field | Type | Description |
229
+ |-------|------|-------------|
230
+ | `id` | string | Scheduled post ID |
231
+ | `post_id` | string | Referenced post ID |
232
+ | `scheduled_at` | string | ISO 8601 datetime |
233
+ | `integration_ids` | string[] | Integration IDs |
234
+ | `status` | string | e.g. `ready_for_publishing`, `published`, `failed` |
235
+ | `approval_status` | string\|null | Approval status |
236
+ | `source` | string\|null | `api` for API-created entries |
237
+ | `failure_reason` | string\|null | Failure reason |
238
+ | `created_at` | string | ISO 8601 timestamp |
239
+ | `updated_at` | string | ISO 8601 timestamp |
240
+
241
+ **Example:**
242
+
243
+ ```bash
244
+ wahlu schedule create post-abc \
245
+ --at 2026-03-15T14:00:00Z \
246
+ --integrations int-123 int-456
247
+ ```
248
+
249
+ ### Queues
250
+
251
+ Queues define recurring time slots for automatic post publishing.
252
+
253
+ | Command | Description |
254
+ |---------|-------------|
255
+ | `wahlu queue list` | List all queues |
256
+ | `wahlu queue add <queue-id> <post-id>` | Add a post to a queue |
257
+
258
+ **Response fields:**
259
+
260
+ | Field | Type | Description |
261
+ |-------|------|-------------|
262
+ | `id` | string | Queue ID |
263
+ | `name` | string | Queue name |
264
+ | `active` | boolean | Whether the queue is active |
265
+ | `mode` | string | Queue mode |
266
+ | `times_of_day` | string[] | Scheduled times (e.g. `["09:00","17:00"]`) |
267
+ | `timezone` | string\|null | IANA timezone |
268
+ | `next_run_at` | string\|null | Next scheduled publishing time |
269
+ | `loop` | boolean | Whether to loop through posts |
270
+ | `post_ids` | string[] | Ordered post IDs in the queue |
271
+ | `integration_ids` | string[] | Integration IDs |
272
+ | `created_at` | string | ISO 8601 timestamp |
273
+ | `updated_at` | string | ISO 8601 timestamp |
274
+
275
+ ### Media
276
+
277
+ Upload images and videos to your media library.
278
+
279
+ | Command | Description |
280
+ |---------|-------------|
281
+ | `wahlu media list` | List media files (paginated) |
282
+ | `wahlu media upload <file>` | Upload a local file |
283
+ | `wahlu media delete <id>` | Permanently delete a media file |
284
+
285
+ **Supported formats:** `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.mp4`, `.mov`, `.webm`
286
+
287
+ **Response fields:**
288
+
289
+ | Field | Type | Description |
290
+ |-------|------|-------------|
291
+ | `id` | string | Media ID (use in `media_ids` arrays) |
292
+ | `file_name` | string | Original filename |
293
+ | `content_type` | string | MIME type (e.g. `image/jpeg`) |
294
+ | `size` | number | File size in bytes |
295
+ | `duration` | number\|null | Duration in seconds (video only) |
296
+ | `status` | string | `available` \| `processing` \| `completed` \| `failed` |
297
+ | `download_url` | string\|null | Signed download URL |
298
+ | `thumbnail_large_url` | string\|null | Large thumbnail |
299
+ | `thumbnail_small_url` | string\|null | Small thumbnail |
300
+ | `source` | string\|null | `upload` \| `generated` \| `stock` \| `scan` |
301
+ | `description` | string\|null | Media description |
302
+ | `created_at` | string | ISO 8601 timestamp |
303
+ | `updated_at` | string | ISO 8601 timestamp |
304
+
305
+ **Upload workflow:**
306
+
307
+ ```bash
308
+ # Upload returns a media ID
309
+ wahlu media upload ./photo.jpg
310
+ # Uploaded photo.jpg — media ID: mid-abc123
311
+
312
+ # Use the media ID in a post
313
+ wahlu post create --name "Photo post" \
314
+ --instagram '{"description":"Nice!","post_type":"grid_post","media_ids":["mid-abc123"]}'
315
+ ```
316
+
317
+ ### Ideas
318
+
319
+ Save content ideas for later development into full posts.
320
+
321
+ | Command | Description |
322
+ |---------|-------------|
323
+ | `wahlu idea list` | List ideas (paginated) |
324
+ | `wahlu idea create <name>` | Save a new idea |
325
+ | `wahlu idea delete <id>` | Delete an idea |
326
+
327
+ **Create options:**
328
+
329
+ | Option | Description |
330
+ |--------|-------------|
331
+ | `--description <text>` | Detailed description (max 10000 chars) |
332
+ | `--type <type>` | Idea type (max 50 chars) |
333
+
334
+ **Response fields:**
335
+
336
+ | Field | Type | Description |
337
+ |-------|------|-------------|
338
+ | `id` | string | Idea ID |
339
+ | `name` | string\|null | Idea name/title |
340
+ | `description` | string\|null | Detailed description |
341
+ | `type` | string\|null | Idea type |
342
+ | `status` | string | Status |
343
+ | `labels` | string[] | Text labels |
344
+ | `created_at` | string | ISO 8601 timestamp |
345
+ | `updated_at` | string | ISO 8601 timestamp |
346
+
347
+ ### Labels
348
+
349
+ Labels categorise and organise posts and media.
350
+
351
+ | Command | Description |
352
+ |---------|-------------|
353
+ | `wahlu label list` | List all labels |
354
+ | `wahlu label create <name>` | Create a label |
355
+ | `wahlu label delete <id>` | Delete a label |
356
+
357
+ **Create options:**
358
+
359
+ | Option | Description |
360
+ |--------|-------------|
361
+ | `--color <hex>` | Colour hex code (e.g. `#ff5500`) |
362
+
363
+ **Response fields:**
364
+
365
+ | Field | Type | Description |
366
+ |-------|------|-------------|
367
+ | `id` | string | Label ID |
368
+ | `name` | string | Label name |
369
+ | `color` | string\|null | Colour hex code |
370
+ | `created_at` | string | ISO 8601 timestamp |
371
+ | `updated_at` | string | ISO 8601 timestamp |
372
+
373
+ ### Integrations (read-only)
374
+
375
+ Connected social media accounts. You need integration IDs when scheduling posts.
376
+
377
+ | Command | Description |
378
+ |---------|-------------|
379
+ | `wahlu integration list` | List connected integrations |
380
+
381
+ **Response fields:**
382
+
383
+ | Field | Type | Description |
384
+ |-------|------|-------------|
385
+ | `id` | string | Integration ID (use in `--integrations` when scheduling) |
386
+ | `platform` | string | `instagram` \| `tiktok` \| `facebook` \| `youtube` \| `linkedin` |
387
+ | `status` | string | Connection status |
388
+ | `display_name` | string\|null | Display name on the platform |
389
+ | `username` | string\|null | Platform username/handle |
390
+ | `avatar_url` | string\|null | Profile avatar URL |
391
+ | `permissions` | object\|null | Granted permissions |
392
+ | `created_at` | string | ISO 8601 timestamp |
393
+ | `updated_at` | string | ISO 8601 timestamp |
394
+
395
+ ### Publications (read-only)
396
+
397
+ Records of posts published to social media platforms.
398
+
399
+ | Command | Description |
400
+ |---------|-------------|
401
+ | `wahlu publication list` | List published posts (paginated) |
402
+
403
+ **Response fields:**
404
+
405
+ | Field | Type | Description |
406
+ |-------|------|-------------|
407
+ | `id` | string | Publication ID |
408
+ | `platform` | string | `instagram` \| `tiktok` \| `facebook` \| `youtube` \| `linkedin` |
409
+ | `post_id` | string | Source post ID |
410
+ | `post_name` | string\|null | Post name |
411
+ | `post_type` | string\|null | Post type |
412
+ | `status` | string | `processing` \| `published` \| `failed` |
413
+ | `source` | string\|null | `calendar` (from schedule) or `queue` (from queue) |
414
+ | `failure_reason` | string\|null | Failure reason |
415
+ | `integration_id` | string | Integration used |
416
+ | `publish_id` | string\|null | Platform content ID |
417
+ | `published_at` | string | When published (ISO 8601) |
418
+ | `created_at` | string | ISO 8601 timestamp |
419
+ | `updated_at` | string | ISO 8601 timestamp |
420
+
421
+ ## Global options
422
+
423
+ | Flag | Description |
424
+ |------|-------------|
425
+ | `--brand <id>` | Use a specific brand (overrides default) |
426
+ | `--json` | Output as JSON (available on all list/get/create/update commands) |
427
+ | `--help` | Show help for any command |
428
+ | `--version` | Show CLI version |
429
+
430
+ ## Pagination
431
+
432
+ All `list` commands support pagination:
433
+
434
+ | Flag | Default | Max | Description |
435
+ |------|---------|-----|-------------|
436
+ | `--page <n>` | 1 | - | Page number |
437
+ | `--limit <n>` | 50 | 100 | Items per page |
438
+
439
+ ## Configuration
440
+
441
+ Config is stored at `~/.config/wahlu/config.json`:
442
+
443
+ ```json
444
+ {
445
+ "api_key": "wahlu_live_...",
446
+ "api_url": "https://api.wahlu.com",
447
+ "default_brand_id": "abc123"
448
+ }
449
+ ```
450
+
451
+ Environment variables take priority over config file:
452
+
453
+ | Variable | Description |
454
+ |----------|-------------|
455
+ | `WAHLU_API_KEY` | API key |
456
+ | `WAHLU_API_URL` | API base URL (default: `https://api.wahlu.com`) |
457
+ | `WAHLU_BRAND_ID` | Default brand ID |
458
+
459
+ ## For AI agents
460
+
461
+ Every command supports `--json` for structured output:
462
+
463
+ ```bash
464
+ # Get post IDs
465
+ wahlu post list --json | jq '.[].id'
466
+
467
+ # Get integration IDs for scheduling
468
+ wahlu integration list --json | jq '.[] | {id, platform, username}'
469
+
470
+ # Find failed publications
471
+ wahlu publication list --json | jq '.[] | select(.status == "failed")'
472
+
473
+ # Create and capture the ID
474
+ POST_ID=$(wahlu post create --name "Auto post" --json | jq -r '.id')
475
+ wahlu schedule create $POST_ID --at 2026-03-15T14:00:00Z --integrations int-123
476
+ ```
477
+
478
+ ## Documentation
479
+
480
+ Full documentation: [wahlu.com/docs](https://wahlu.com/docs)
481
+
482
+ ## License
483
+
484
+ MIT
@@ -0,0 +1,2 @@
1
+
2
+ export { }