superx-cli 0.4.0 → 0.5.1
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/CHANGELOG.md +10 -0
- package/PLAYBOOKS.md +22 -3
- package/README.md +2 -2
- package/SKILL.md +29 -6
- package/dist/index.js +112 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.1 (2026-09-14)
|
|
4
|
+
|
|
5
|
+
- Lead search recency: `signals:search --max-age-days <n>` only counts posts from the last N days (1-90, default 30), so every lead comes from something written recently rather than a lifetime match. Older matches are skipped and counted in `freshness.stale_skipped`, each lead's `provenance.posted_at` / `provenance.post_age_days` says when the matched post was written, and leads come back freshest first within each score. Use `--max-age-days 7` to catch a pain point while it is fresh; an empty result with `stale_skipped` above 0 means people do post about this, just not lately. `SKILL.md` and `PLAYBOOKS.md` (lead hunt recipe) carry the flag
|
|
6
|
+
|
|
7
|
+
## 0.5.0 (2026-09-13)
|
|
8
|
+
|
|
9
|
+
- Workers: `workers:list` shows the account's Workers (the agents inside SuperX that write posts for one account on a schedule) with their schedules and next run times, and `workers:suggestions` lists what they wrote, newest first (`--status to_review|drafted|scheduled|dismissed|all`, default `to_review`; `--worker <id>`, `--limit` up to 100, `--page`). `workers:draft <id>` saves one suggestion to Drafts as written, `workers:schedule <id> --at <UTC ISO-8601>` queues it as written (no Default Post Settings inherited: add auto retweet, plug, delete or DM afterwards with `scheduled:update`), and `workers:dismiss <id>` clears it out of To review. Workers are created, edited and run in the app; there is no create or run command. A suggestion can only be saved once (second save = 400, another account's Worker = 404). Costs no AI credits. `PLAYBOOKS.md` gains recipe 29, Worker output review
|
|
10
|
+
- Drafts: `scheduled:list --status draft` now lists drafts newest first (the API previously returned the oldest drafts) and accepts `--page`
|
|
11
|
+
- Docs and help text only: `posts:draft --voice mine` writes in the voice of the account you pass in `--account` (your main account when omitted, using that account's own posts and style guide), and `posts:draft` returns 403 `writes_main_account_only` on an account shared with you, unlike the other writing helpers
|
|
12
|
+
|
|
3
13
|
## 0.4.0 (2026-09-11)
|
|
4
14
|
|
|
5
15
|
- Playbooks: a new `PLAYBOOKS.md` ships with the package, holding 28 goal-shaped recipes, one per SuperX skill (weekly recap, week of posts, queue reshuffle, reply sprint, lead hunt, audience export, warm outreach and the rest). Each entry gives the CLI chain in order, the equivalent MCP tool chain, and where the chain STOPS: the four that stop short of a send say so in the entry, because no reply is posted and no DM is delivered from here. `SKILL.md` gains a `## Playbooks` index so an agent can pick a recipe by goal before opening the file
|
package/PLAYBOOKS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SuperX Playbooks
|
|
2
2
|
|
|
3
|
-
Twenty-
|
|
3
|
+
Twenty-nine goal-shaped recipes, one per SuperX skill. Each is the same job the
|
|
4
4
|
in-app skill of that name does, run from the CLI or from the hosted MCP server.
|
|
5
5
|
Pick by goal, run the chain in order, hand the result to the person.
|
|
6
6
|
|
|
@@ -219,6 +219,25 @@ MCP: `find_inspiration`
|
|
|
219
219
|
|
|
220
220
|
Stops at: the posts and the suggested angles in chat. Reads only, no AI credits.
|
|
221
221
|
|
|
222
|
+
### Worker Output Review
|
|
223
|
+
|
|
224
|
+
The posts a Worker wrote while the person was away, triaged: save the good ones, queue one, clear the rest.
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
superx workers:list
|
|
228
|
+
superx workers:suggestions --status to_review --limit 20
|
|
229
|
+
superx workers:draft <suggestion-id>
|
|
230
|
+
superx workers:schedule <suggestion-id> --at "<UTC ISO-8601 with Z>"
|
|
231
|
+
superx workers:dismiss <suggestion-id>
|
|
232
|
+
superx scheduled:list --status draft --limit 10
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Workers are created, edited and RUN in the SuperX app: this chain only reads what they produced and acts on it. The text is saved exactly as the Worker wrote it, so show each suggestion to the person and let them pick before you save or queue anything. To change the wording, run it through `posts:remix` and save your version with `scheduled:create`, then dismiss the original. A suggestion can only be saved once, so a second draft or schedule call on the same id is a 400.
|
|
236
|
+
|
|
237
|
+
MCP: `list_workers` -> `list_worker_suggestions` -> `draft_worker_suggestion` / `schedule_worker_suggestion` / `dismiss_worker_suggestion` -> `get_scheduled_posts`
|
|
238
|
+
|
|
239
|
+
Stops at: the saved drafts and the queued post, for the person to edit. Reads and the three actions cost no AI credits.
|
|
240
|
+
|
|
222
241
|
---
|
|
223
242
|
|
|
224
243
|
## Queue
|
|
@@ -332,10 +351,10 @@ A live search of X right now for people matching the audience described, scored,
|
|
|
332
351
|
|
|
333
352
|
```bash
|
|
334
353
|
superx signals:suggest-keywords --icp "<who you want to reach>"
|
|
335
|
-
superx signals:search --keywords "<phrase>,<phrase>" --icp "<who you want to reach>" --max 30
|
|
354
|
+
superx signals:search --keywords "<phrase>,<phrase>" --icp "<who you want to reach>" --max 30 --max-age-days 7
|
|
336
355
|
```
|
|
337
356
|
|
|
338
|
-
The search creates no agent and stores no leads, so keep what the person needs from that one response.
|
|
357
|
+
The search creates no agent and stores no leads, so keep what the person needs from that one response. `--max-age-days` is the recency window (1-90, default 30): 7 for a pain point worth catching while it is fresh.
|
|
339
358
|
|
|
340
359
|
MCP: `suggest_keywords` -> `search_leads`
|
|
341
360
|
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npx skills add superx-so/superx-agent
|
|
|
11
11
|
Two things ship in this repo:
|
|
12
12
|
|
|
13
13
|
- `superx-cli`, an npm package installing the `superx` binary (a thin client for `api.superx.so/v1`)
|
|
14
|
-
- An agent skill (`SKILL.md`) plus a growth strategy guide (`PLAYBOOK.md`) and
|
|
14
|
+
- An agent skill (`SKILL.md`) plus a growth strategy guide (`PLAYBOOK.md`) and 29 goal-shaped recipes (`PLAYBOOKS.md`) so agents do not just schedule posts, they follow a strategy that works
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -344,7 +344,7 @@ superx docs # Prints the API quickstart as markdown; works without auth
|
|
|
344
344
|
|
|
345
345
|
- **Skill included**: `npx skills add superx-so/superx-agent` installs [SKILL.md](./SKILL.md), a complete agent reference with hard rules, workflows, and gotchas.
|
|
346
346
|
- **Strategy included**: [PLAYBOOK.md](./PLAYBOOK.md) distills the SuperX growth methodology (action hierarchy, out-of-network discovery, the 3-3-3 engagement loop, weekly operating system) into directives an agent can execute with this CLI. The skill instructs agents to read it before creating content.
|
|
347
|
-
- **Playbooks included**: [PLAYBOOKS.md](./PLAYBOOKS.md) holds
|
|
347
|
+
- **Playbooks included**: [PLAYBOOKS.md](./PLAYBOOKS.md) holds 29 goal-shaped recipes, one per SuperX skill, each with its CLI chain, the matching MCP tool chain, and the point where the agent hands the result back to a person.
|
|
348
348
|
- **Clean JSON stdout**: no decoration to strip; every data command is `jq`-safe.
|
|
349
349
|
- **Idempotent writes**: agents can retry `scheduled:create` safely with `--idempotency-key`.
|
|
350
350
|
- **Self-describing**: `superx docs` fetches the current API quickstart at runtime.
|
package/SKILL.md
CHANGED
|
@@ -30,9 +30,9 @@ official website: https://superx.so
|
|
|
30
30
|
|
|
31
31
|
**Rule 1: Run `superx status` before anything else.** Every other command fails without valid credentials. If the `superx` binary is missing, install it with `npm install -g superx-cli`. If not authenticated, either run `superx login` (interactive) or set `export SUPERX_API_KEY=sxk_...` (CI and non-interactive sessions). Keys are created at https://app.superx.so/account?tab=api.
|
|
32
32
|
|
|
33
|
-
**Rule 2: Read PLAYBOOK.md before creating any content.** This repo ships a growth strategy guide (`PLAYBOOK.md`, also inside the installed npm package). It tells you WHAT to post, WHEN, and WHY: the action hierarchy, out-of-network discovery, the engagement loop, and the failure modes that kill reach. The CLI gives you data and actions; the playbook gives you judgment. Do not schedule content without it. For a goal-shaped task ("give me my weekly recap", "DM the people who replied to this post"), read `PLAYBOOKS.md` too: it holds the
|
|
33
|
+
**Rule 2: Read PLAYBOOK.md before creating any content.** This repo ships a growth strategy guide (`PLAYBOOK.md`, also inside the installed npm package). It tells you WHAT to post, WHEN, and WHY: the action hierarchy, out-of-network discovery, the engagement loop, and the failure modes that kill reach. The CLI gives you data and actions; the playbook gives you judgment. Do not schedule content without it. For a goal-shaped task ("give me my weekly recap", "DM the people who replied to this post"), read `PLAYBOOKS.md` too: it holds the 29 named recipes with their exact command chains, MCP tool names and stopping points.
|
|
34
34
|
|
|
35
|
-
**Rule 3: Know the write constraints.** `scheduled:create` without `--at` creates a DRAFT (nothing publishes). With `--at` it schedules for that time. `scheduled:update` changes only the flags you pass, and a new `--at` alone never schedules a draft; add `--status scheduled` to promote. Writes work on your main account or any linked account (pass the same `--account` you used to read it); accounts shared with you by other people are read-only, and tags are workspace-wide. Images attach via `media:upload` then `--media` (JPG/PNG/WEBP up to 5MB, GIF up to 15MB; max 4 images or 1 GIF per post); video is not supported. Timestamps MUST be UTC ISO-8601 with an explicit `Z` or offset; naive timestamps are rejected with 400. `posts:publish` and `articles:publish` post to X IMMEDIATELY and irreversibly; treat them like hitting Publish in public and get human confirmation of the exact text unless the user already gave it. `posts:publish` also requires `--idempotency-key`, which you reuse verbatim on any retry. `posts:draft` writes post text in the user's voice and saves NOTHING: show the drafts, let the user pick and edit one, then pass the final text to `scheduled:create` yourself; it costs AI credits per draft, so ask for the count the user actually wants.
|
|
35
|
+
**Rule 3: Know the write constraints.** `scheduled:create` without `--at` creates a DRAFT (nothing publishes). With `--at` it schedules for that time. `scheduled:update` changes only the flags you pass, and a new `--at` alone never schedules a draft; add `--status scheduled` to promote. Writes work on your main account or any linked account (pass the same `--account` you used to read it); accounts shared with you by other people are read-only, and tags are workspace-wide. Images attach via `media:upload` then `--media` (JPG/PNG/WEBP up to 5MB, GIF up to 15MB; max 4 images or 1 GIF per post); video is not supported. Timestamps MUST be UTC ISO-8601 with an explicit `Z` or offset; naive timestamps are rejected with 400. `posts:publish` and `articles:publish` post to X IMMEDIATELY and irreversibly; treat them like hitting Publish in public and get human confirmation of the exact text unless the user already gave it. `posts:publish` also requires `--idempotency-key`, which you reuse verbatim on any retry. `posts:draft` writes post text in the user's voice and saves NOTHING: show the drafts, let the user pick and edit one, then pass the final text to `scheduled:create` yourself; it costs AI credits per draft, so ask for the count the user actually wants. `--voice mine` is the voice of the `--account` you pass (its own posts and style guide); shared accounts are refused.
|
|
36
36
|
|
|
37
37
|
---
|
|
38
38
|
|
|
@@ -371,7 +371,7 @@ superx signals:feedback 4821 --clear
|
|
|
371
371
|
superx signals:search \
|
|
372
372
|
--keywords "losing customers to churn, cancellations killing my MRR" \
|
|
373
373
|
--icp "B2B SaaS founders worried about retention" \
|
|
374
|
-
--precision discovery --max 10
|
|
374
|
+
--precision discovery --max 10 --max-age-days 7
|
|
375
375
|
|
|
376
376
|
# Turn people into outreach briefs saved as a dataset (exactly one source)
|
|
377
377
|
superx datasets:research --handles levelsio,naval --focus "audience-growth tooling" --wait
|
|
@@ -387,7 +387,7 @@ superx datasets:rows <dataset-id> --limit 50 # read every drafted message
|
|
|
387
387
|
|
|
388
388
|
- **Nothing in this chain sends a DM.** `datasets:outreach-drafts` writes message TEXT onto the dataset's `message` column and stops there. A person reviews and sends them from the SuperX app. Never tell the user their messages have gone out, and never imply the CLI can send them.
|
|
389
389
|
- `signals:suggest-keywords --icp "..."` and `signals:expand-icp (--text | --url)` stage what a new agent needs before you create one: keyword ideas, and the rubric the scorer reads the ICP as. Both are FREE and create nothing. Pass a suggestion to `signals:create-agent --keyword`; the rubric has nowhere to be saved (agents are created with `--icp`), so use it to sharpen that text. `--url` reads a website and also returns an `icp_description` to pass straight to `--icp`; it costs one of the account's 20 page reads a day, shared with the app, and takes up to a minute.
|
|
390
|
-
- `signals:search` needs a key with the **write** scope (every non-GET API route does), even though it CREATES NOTHING. The leads exist only in that response, so save what you need. For an audience that keeps filling up on its own, use `signals:create-agent` instead. It takes up to a minute, and each lead comes from ONE matched post: `posts_count` is lifetime volume, not proof of current activity.
|
|
390
|
+
- `signals:search` needs a key with the **write** scope (every non-GET API route does), even though it CREATES NOTHING. The leads exist only in that response, so save what you need. For an audience that keeps filling up on its own, use `signals:create-agent` instead. It takes up to a minute, and each lead comes from ONE matched post: `posts_count` is lifetime volume, not proof of current activity. That post is always recent: `--max-age-days` sets the window (1-90, default 30), older matches are skipped and counted in `freshness.stale_skipped`, and each lead's `provenance.posted_at` / `provenance.post_age_days` says when it was written. Use `--max-age-days 7` for a pain point worth catching while it is fresh; leads come back freshest first within each score, so keep that order. An empty result with a `stale_skipped` above 0 means people DO post about this, just not lately: broaden the keywords, or raise the window only if the user wants people active over a longer stretch.
|
|
391
391
|
- `datasets:research` needs exactly one of `--handles` (max 25), `--list`, `--agent` or `--dataset`, and `--max` is 1-25 (default 10). Every hook in a brief QUOTES one of the person's real posts; proposed quotes that failed the verbatim check are dropped server-side, so a brief with no hooks is honest, not broken. More than 5 profiles run in the background (`202 collecting`) - pass `--wait` or poll `datasets:get`.
|
|
392
392
|
- `datasets:outreach-drafts` needs a `--format` from the USER: their template or an example message. Never invent one. `[name]`, `[first]` and `[handle]` are kept intact for per-recipient fill-in at send time. A brief with no usable hook gets an honest generic message counted in `generic`, and a draft that names a DIFFERENT recipient is discarded and counted in `contaminated` (run it again to retry those rows). Re-running overwrites every draft.
|
|
393
393
|
- Costs: `signals:search` is measured, at least 1 credit for a search that reaches X; `datasets:research` is a flat **1 credit per profile actually researched** (the rest are returned); `datasets:outreach-drafts` is measured and usually 1-3 credits. Research settles when the run finishes, so after a `--wait` read `superx status` for the pool rather than the response.
|
|
@@ -424,6 +424,29 @@ superx tools:predict --a "$(cat v1.txt)" --b "$(cat v2.txt)"
|
|
|
424
424
|
- `tools:factcheck` reports `result` (true, false or unknown), a one-sentence `comment` and the `sources` it read. It is a model's reading of a couple of search results, NOT a guarantee: show the sources and never present the verdict as settled. `tools:predict` scores are an opinion for comparing two drafts against each other, not a prediction of reach.
|
|
425
425
|
- Costs are measured AI credits: typically 1 each, and 2 for a remix or a reply draft. None of them spends a live X request except `engage:reply-draft --post`.
|
|
426
426
|
|
|
427
|
+
### Workers (posts written for you on a schedule)
|
|
428
|
+
|
|
429
|
+
```bash
|
|
430
|
+
superx workers:list # your Workers, schedules, next run times
|
|
431
|
+
superx workers:suggestions --limit 10 # newest posts waiting for review
|
|
432
|
+
superx workers:suggestions --worker 3 --status all # everything one Worker has written
|
|
433
|
+
superx workers:suggestions --status scheduled # the ones already queued
|
|
434
|
+
|
|
435
|
+
# Act on one (suggestion id from workers:suggestions; write scope)
|
|
436
|
+
superx workers:draft 4821 # save it to Drafts
|
|
437
|
+
superx workers:schedule 4821 --at "2026-09-15T14:00:00Z"
|
|
438
|
+
superx workers:dismiss 4821 # clear it out of To review
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
- A Worker is an agent inside SuperX that writes posts for one account on a schedule. Workers are CREATED, EDITED AND RUN IN THE APP: there is no create or run command here, and no API endpoint for either. This chain reads what they wrote and acts on it.
|
|
442
|
+
- `workers:suggestions` defaults to `--status to_review`, the ones waiting on a person. The other values are `drafted`, `scheduled`, `dismissed` and `all`. `--worker <id>` narrows to one Worker, `--limit` (max 100, default 20) and `--page` walk the list, newest first.
|
|
443
|
+
- Each suggestion carries `id`, `worker_id`, `text`, `status`, `generated_at`, the `drafted_at`/`scheduled_at`/`dismissed_at` stamps, `post_id` once it has been saved, and `reference` (the kind of source the Worker wrote from). The Worker's own collection ids stay private.
|
|
444
|
+
- AI OUTPUT NEEDS A HUMAN: show the user the text and let them edit it before it is saved or queued. `workers:draft` saves it as written, `workers:schedule` queues it as written, and neither asks for confirmation. To change the wording first, rewrite it with `posts:remix` or `tools:rephrase` and save your version with `scheduled:create` instead, then `workers:dismiss` the original so the list stays clean.
|
|
445
|
+
- `workers:schedule` requires `--at` in UTC ISO-8601. The post does NOT inherit the account's Default Post Settings: it carries only what the call passes, which from the CLI is nothing beyond the time, so no auto retweet, auto plug, auto delete or auto DM. Add those afterwards with `scheduled:update`, which is also how you retime it; `scheduled:delete` cancels it.
|
|
446
|
+
- One suggestion can only be saved once. A second `workers:draft` or `workers:schedule` on the same id is a 400, as is acting on a dismissed one. An id belonging to another account's Worker is a 404.
|
|
447
|
+
- `workers:draft` and `workers:schedule` land the post in the same Drafts and Queue the rest of the CLI reads: `scheduled:list --status draft` shows a drafted suggestion, newest first, and the response gives you its `post_id` directly.
|
|
448
|
+
- Endpoints behind these commands: `GET /v1/workers`, `GET /v1/workers/suggestions`, `POST /v1/workers/suggestions/{id}/draft`, `POST /v1/workers/suggestions/{id}/schedule`, `POST /v1/workers/suggestions/{id}/dismiss`. The three POSTs need a key with the **write** scope. Every command here takes `--account` for an account you own (main or linked); an account someone shared with you is read-only, so a write against it returns 403 `writes_main_account_only`.
|
|
449
|
+
|
|
427
450
|
### Scheduling
|
|
428
451
|
|
|
429
452
|
```bash
|
|
@@ -809,7 +832,7 @@ Full recipes with flags and MCP tool chains: [PLAYBOOKS.md](./PLAYBOOKS.md). Pic
|
|
|
809
832
|
1. **Naive timestamps are rejected (400)**. Always include `Z` or an offset: `2026-08-01T15:00:00Z`, not `2026-08-01T15:00:00`.
|
|
810
833
|
2. **Schedule window**: `--at` must be at least 60 seconds in the future and within 18 months.
|
|
811
834
|
3. **Read-only keys cannot write**: `scheduled:create`/`scheduled:delete` with a read-only key returns 403 `insufficient_scope`. Check `superx me` for the key's scopes.
|
|
812
|
-
4. **Shared accounts are read-only for writes**: writes work on your main account or any linked account (pass the same `--account` you used to read it). Accounts shared with you by other people return 403 `writes_main_account_only` for post, article, signal and contact-list member writes
|
|
835
|
+
4. **Shared accounts are read-only for writes**: writes work on your main account or any linked account (pass the same `--account` you used to read it). Accounts shared with you by other people return 403 `writes_main_account_only` for post, article, signal and contact-list member writes, and for `posts:draft`. `context:*` and `queue:set` are per-account settings that do accept a shared account.
|
|
813
836
|
5. **Images need an upload first**: `--media` takes `object_key`s from `media:upload`, never file paths or URLs. Unknown keys return 400 `invalid_media`; a presign whose bytes were never PUT returns 400 `media_not_uploaded`. Video is not supported.
|
|
814
837
|
6. **Size caps**: max 25 thread parts, 25,000 characters total.
|
|
815
838
|
7. **Rate limited (429)**: `rate_limited` on stderr with a retry delay. Back off; do not hammer.
|
|
@@ -858,7 +881,7 @@ Full recipes with flags and MCP tool chains: [PLAYBOOKS.md](./PLAYBOOKS.md). Pic
|
|
|
858
881
|
49. **Nothing in the outreach chain sends a DM.** `datasets:outreach-drafts` writes message TEXT onto a research dataset and stops there; a person reviews and sends them from the SuperX app. Never say messages were sent and never offer to send them. If the user explicitly asks, you may QUEUE them with `dm:campaign` (one recipient entry per person, each with its own `message`), which is still an enqueue: the app sends. Ask the user for the `--format`; never invent one. Re-running overwrites every draft, `generic` counts messages written with no personal claims (that brief had no usable hook), and `contaminated` counts drafts discarded for naming a different recipient - run it again to retry those rows.
|
|
859
882
|
50. **`signals:search` saves nothing and `datasets:research` charges per profile.** A search creates no agent and no stored leads, so keep what the user needs from that response; use `signals:create-agent` when they want leads to keep arriving. Research is a flat 1 credit per profile ACTUALLY researched (handles that cannot be resolved, and people with no recent posts, come back in `skipped` and are refunded), and over 5 profiles it runs in the background: never state a brief count from a `collecting` result. `datasets:refine` also creates a dataset, so it spends one of the same 10 collections a day.
|
|
860
883
|
51. **`ai_action_limited` has two scopes.** Read `error.scope` before telling the user anything: `"account"` is their plan's own daily cap for that action, `"platform"` is a fair-use ceiling on live-data actions shared by every SuperX account. On `"platform"` their own allowance is untouched, so wait for `reset_at` and retry rather than reporting them as out of quota.
|
|
861
|
-
52. **The writing helpers draft, they never publish.** `engage:reply-draft`, `posts:remix`, `tools:inline-edit`, `tools:rephrase`, `tools:factcheck` and `tools:predict` all return TEXT and stop there - nothing is posted, scheduled or sent. Show the output, let the user edit it, and use `posts:draft`, `scheduled:create` or `posts:publish` when they say so. A `tools:factcheck` verdict is a model reading two search results: report it with its sources, never as settled fact.
|
|
884
|
+
52. **The writing helpers draft, they never publish.** `engage:reply-draft`, `posts:remix`, `tools:inline-edit`, `tools:rephrase`, `tools:factcheck` and `tools:predict` all return TEXT and stop there - nothing is posted, scheduled or sent. Unlike `posts:draft`, they also accept an account shared with you. Show the output, let the user edit it, and use `posts:draft`, `scheduled:create` or `posts:publish` when they say so. A `tools:factcheck` verdict is a model reading two search results: report it with its sources, never as settled fact.
|
|
862
885
|
53. **The free helpers cost nothing but are not unlimited.** `context:regenerate-style-guide` is once an hour per account and does not override a manual style-guide setting; `context:scrape-product` and `signals:expand-icp --url` share 20 page reads a day with the SuperX app, and `--url` also inherits the app's limit of 10 prefills per 10 minutes (that one comes back as `rate_limited` and clears in about a minute, so retry rather than reporting a daily budget); `signals:suggest-keywords` and `signals:expand-icp --text` have no ceiling of their own, so do not loop them - each one is a model call. All five send `X-Credits-Remaining` but no `X-Credits-Charged`, because nothing was charged. All four commands still need a key with the write scope: they are POSTs, and every non-GET API route needs it.
|
|
863
886
|
54. **A DM campaign is an ENQUEUE, not a send.** `dm:campaign` returns counts of what was QUEUED; the SuperX app's scheduler sends them later, within the account's daily and monthly DM limits, so never report messages as delivered from that response - `dm:campaign-status` and `dm:queue` show what actually went out. Confirm the recipient list and the exact text with the user first: they are responsible for these messages under X's automation rules. Cancel the unsent ones with `dm:cancel`; anything already sent cannot be recalled.
|
|
864
887
|
|
package/dist/index.js
CHANGED
|
@@ -317,6 +317,26 @@ var SuperXAPI = class {
|
|
|
317
317
|
async setLeadFeedback(leadId, body) {
|
|
318
318
|
return (await this.request(`/signals/leads/${leadId}/feedback`, { method: "POST", body })).json;
|
|
319
319
|
}
|
|
320
|
+
// --- Workers ---
|
|
321
|
+
async listWorkers(query = {}) {
|
|
322
|
+
return (await this.request("/workers", { query })).json;
|
|
323
|
+
}
|
|
324
|
+
/** The posts your Workers have written, newest first. */
|
|
325
|
+
async listWorkerSuggestions(query = {}) {
|
|
326
|
+
return (await this.request("/workers/suggestions", { query })).json;
|
|
327
|
+
}
|
|
328
|
+
/** Save one suggestion as a draft. Nothing is posted. */
|
|
329
|
+
async draftWorkerSuggestion(id, body) {
|
|
330
|
+
return (await this.request(`/workers/suggestions/${id}/draft`, { method: "POST", body })).json;
|
|
331
|
+
}
|
|
332
|
+
/** Save one suggestion as a scheduled post. */
|
|
333
|
+
async scheduleWorkerSuggestion(id, body) {
|
|
334
|
+
return (await this.request(`/workers/suggestions/${id}/schedule`, { method: "POST", body })).json;
|
|
335
|
+
}
|
|
336
|
+
/** Clear one suggestion out of the To review list. */
|
|
337
|
+
async dismissWorkerSuggestion(id, body) {
|
|
338
|
+
return (await this.request(`/workers/suggestions/${id}/dismiss`, { method: "POST", body })).json;
|
|
339
|
+
}
|
|
320
340
|
// --- Engage ---
|
|
321
341
|
async listEngageFeeds(query = {}) {
|
|
322
342
|
return (await this.request("/engage/feeds", { query })).json;
|
|
@@ -1189,6 +1209,9 @@ async function signalsSearch(argv) {
|
|
|
1189
1209
|
};
|
|
1190
1210
|
if (argv.precision) body.precision = argv.precision;
|
|
1191
1211
|
if (argv.max !== void 0) body.max_leads = argv.max;
|
|
1212
|
+
if (argv["max-age-days"] !== void 0) {
|
|
1213
|
+
body.max_post_age_days = argv["max-age-days"];
|
|
1214
|
+
}
|
|
1192
1215
|
if (argv.account) body.account_id = argv.account;
|
|
1193
1216
|
const api = new SuperXAPI(getConfig());
|
|
1194
1217
|
printJson(await api.searchLeads(body));
|
|
@@ -1318,6 +1341,47 @@ async function signalsExpandIcp(argv) {
|
|
|
1318
1341
|
printJson(url ? await api.expandIcpFromUrl(body) : await api.expandIcp(body));
|
|
1319
1342
|
}
|
|
1320
1343
|
|
|
1344
|
+
// src/commands/workers.ts
|
|
1345
|
+
async function workersList(argv) {
|
|
1346
|
+
const api = new SuperXAPI(getConfig());
|
|
1347
|
+
printJson(await api.listWorkers({ account_id: argv.account }));
|
|
1348
|
+
}
|
|
1349
|
+
async function workersSuggestions(argv) {
|
|
1350
|
+
const api = new SuperXAPI(getConfig());
|
|
1351
|
+
printJson(
|
|
1352
|
+
await api.listWorkerSuggestions({
|
|
1353
|
+
account_id: argv.account,
|
|
1354
|
+
status: argv.status,
|
|
1355
|
+
worker_id: argv.worker,
|
|
1356
|
+
limit: argv.limit,
|
|
1357
|
+
page: argv.page
|
|
1358
|
+
})
|
|
1359
|
+
);
|
|
1360
|
+
}
|
|
1361
|
+
async function workersDraft(argv) {
|
|
1362
|
+
const body = {};
|
|
1363
|
+
if (argv.account) body.account_id = argv.account;
|
|
1364
|
+
const api = new SuperXAPI(getConfig());
|
|
1365
|
+
printJson(await api.draftWorkerSuggestion(argv.id, body));
|
|
1366
|
+
}
|
|
1367
|
+
async function workersSchedule(argv) {
|
|
1368
|
+
if (typeof argv.at !== "string" || argv.at.length === 0) {
|
|
1369
|
+
note("--at is required: the UTC ISO-8601 time to post, for example 2026-09-15T14:00:00Z.");
|
|
1370
|
+
process.exit(1);
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
const body = { scheduled_for: argv.at };
|
|
1374
|
+
if (argv.account) body.account_id = argv.account;
|
|
1375
|
+
const api = new SuperXAPI(getConfig());
|
|
1376
|
+
printJson(await api.scheduleWorkerSuggestion(argv.id, body));
|
|
1377
|
+
}
|
|
1378
|
+
async function workersDismiss(argv) {
|
|
1379
|
+
const body = {};
|
|
1380
|
+
if (argv.account) body.account_id = argv.account;
|
|
1381
|
+
const api = new SuperXAPI(getConfig());
|
|
1382
|
+
printJson(await api.dismissWorkerSuggestion(argv.id, body));
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1321
1385
|
// src/commands/engage.ts
|
|
1322
1386
|
async function engageFeeds(argv) {
|
|
1323
1387
|
const api = new SuperXAPI(getConfig());
|
|
@@ -2354,7 +2418,7 @@ var advancedSettingsOptions = (y) => y.option("auto-retweet", {
|
|
|
2354
2418
|
describe: "How many drafts to write, 1 to 3 (default 1). Each one costs credits",
|
|
2355
2419
|
type: "number"
|
|
2356
2420
|
}).option("voice", {
|
|
2357
|
-
describe: "Whose voice to write in",
|
|
2421
|
+
describe: "Whose voice to write in; mine is the voice of the account passed in --account, or your main account if --account is omitted",
|
|
2358
2422
|
type: "string",
|
|
2359
2423
|
choices: ["mine", "creator", "hybrid"]
|
|
2360
2424
|
}).option("creator", {
|
|
@@ -2784,7 +2848,10 @@ var advancedSettingsOptions = (y) => y.option("auto-retweet", {
|
|
|
2784
2848
|
describe: "high = only confident matches; discovery (default) = broader adjacent matches",
|
|
2785
2849
|
type: "string",
|
|
2786
2850
|
choices: ["high", "discovery"]
|
|
2787
|
-
}).option("max", { describe: "Leads to return at most (1-30, default 10)", type: "number" }).
|
|
2851
|
+
}).option("max", { describe: "Leads to return at most (1-30, default 10)", type: "number" }).option("max-age-days", {
|
|
2852
|
+
describe: "Only posts from the last N days count (1-90, default 30). Use 7 to catch a fresh pain point",
|
|
2853
|
+
type: "number"
|
|
2854
|
+
}).example(
|
|
2788
2855
|
"$0 signals:search --keywords 'losing customers to churn' --icp 'B2B SaaS founders worried about retention'",
|
|
2789
2856
|
"Find people posting about churn right now"
|
|
2790
2857
|
).epilogue(
|
|
@@ -2916,6 +2983,49 @@ var advancedSettingsOptions = (y) => y.option("auto-retweet", {
|
|
|
2916
2983
|
"Delete a signal agent (its saved leads and contact list stay untouched)",
|
|
2917
2984
|
(y) => y.positional("id", { describe: "Agent id (from signals:agents)", type: "number" }),
|
|
2918
2985
|
run(signalsDeleteAgent)
|
|
2986
|
+
).command(
|
|
2987
|
+
"workers:list",
|
|
2988
|
+
"List your Workers (the agents that write posts for you on a schedule)",
|
|
2989
|
+
(y) => accountOption(y).example("$0 workers:list", "Your Workers, their schedules and next run times").epilogue(
|
|
2990
|
+
"Workers are created, edited and run in the SuperX app. This reads them so you can tell which Worker a suggestion came from."
|
|
2991
|
+
),
|
|
2992
|
+
run(workersList)
|
|
2993
|
+
).command(
|
|
2994
|
+
"workers:suggestions",
|
|
2995
|
+
"List the posts your Workers have written, newest first",
|
|
2996
|
+
(y) => paginationOptions(accountOption(y)).option("status", {
|
|
2997
|
+
describe: "to_review (default) = waiting on you; drafted / scheduled = already saved; dismissed = cleared; all = everything",
|
|
2998
|
+
type: "string",
|
|
2999
|
+
choices: ["to_review", "drafted", "scheduled", "dismissed", "all"]
|
|
3000
|
+
}).option("worker", { describe: "Narrow to one Worker by its numeric id (from workers:list)", type: "number" }).example("$0 workers:suggestions --limit 10", "Ten newest posts waiting for review").example("$0 workers:suggestions --worker 3 --status all", "Everything Worker 3 has written").epilogue(
|
|
3001
|
+
"Reading suggestions costs nothing and changes nothing. Act on one with workers:draft, workers:schedule or workers:dismiss."
|
|
3002
|
+
),
|
|
3003
|
+
run(workersSuggestions)
|
|
3004
|
+
).command(
|
|
3005
|
+
"workers:draft <id>",
|
|
3006
|
+
"Save one Worker suggestion as a draft (nothing is posted)",
|
|
3007
|
+
(y) => accountOption(y).positional("id", { describe: "Suggestion id (from workers:suggestions)", type: "number" }).example("$0 workers:draft 4821", "Move it into Drafts, where scheduled:list --status draft finds it").epilogue(
|
|
3008
|
+
"The draft keeps the Worker's text as written. Edit it with scheduled:update, or rewrite it first with posts:remix and then save your own version."
|
|
3009
|
+
),
|
|
3010
|
+
run(workersDraft)
|
|
3011
|
+
).command(
|
|
3012
|
+
"workers:schedule <id>",
|
|
3013
|
+
"Schedule one Worker suggestion to post at a given time",
|
|
3014
|
+
(y) => accountOption(y).positional("id", { describe: "Suggestion id (from workers:suggestions)", type: "number" }).option("at", {
|
|
3015
|
+
describe: "When to post, UTC ISO-8601 (for example 2026-09-15T14:00:00Z)",
|
|
3016
|
+
type: "string",
|
|
3017
|
+
demandOption: true
|
|
3018
|
+
}).example("$0 workers:schedule 4821 --at 2026-09-15T14:00:00Z", "Queue it for Tuesday afternoon").epilogue(
|
|
3019
|
+
"The post does not inherit your Default Post Settings: it carries only what this call passes, which is nothing beyond the time. Add auto retweet, auto plug or auto delete afterwards with scheduled:update, which also retimes it; scheduled:delete cancels it."
|
|
3020
|
+
),
|
|
3021
|
+
run(workersSchedule)
|
|
3022
|
+
).command(
|
|
3023
|
+
"workers:dismiss <id>",
|
|
3024
|
+
"Clear one Worker suggestion out of the To review list",
|
|
3025
|
+
(y) => accountOption(y).positional("id", { describe: "Suggestion id (from workers:suggestions)", type: "number" }).example("$0 workers:dismiss 4821", "Skip this one").epilogue(
|
|
3026
|
+
"Dismissing drops it from the default to_review list. It stays readable with --status dismissed, and nothing already drafted or scheduled is affected."
|
|
3027
|
+
),
|
|
3028
|
+
run(workersDismiss)
|
|
2919
3029
|
).command(
|
|
2920
3030
|
"engage:feeds",
|
|
2921
3031
|
"List the Engage feeds set up in the app",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "superx-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "SuperX CLI - command line interface to the SuperX API for Twitter/X growth: read posts and analytics, find engaged contacts, and schedule posts and threads",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|