@series-a/cli 0.23.1 → 1.0.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/CHANGELOG.md CHANGED
@@ -1,149 +1,33 @@
1
- # @series-a/cli
1
+ # Changelog
2
2
 
3
- All notable changes to this package are documented here. This project follows
4
- [Semantic Versioning](https://semver.org/) and uses
5
- [Changesets](https://github.com/changesets/changesets) to manage releases.
3
+ All notable changes to `@series-a/cli` (and the paired `@series-a/mcp` server).
6
4
 
7
- ## 0.23.0 — Bulk lead upserts, named profiles, atomic mutations
5
+ ## 1.0.0 — first stable release
8
6
 
9
- - `leads bulk_upsert` works at scale again. The database now enforces one lead per LinkedIn URL per workspace, so bulk imports update existing leads in place instead of failing with a Postgres conflict error. Repeated URLs inside a single request are collapsed, and leads without a LinkedIn URL stay separate records.
10
- - Named workspace profiles: `login -p <name>` stores a profile per workspace, and logging into a new workspace no longer silently re-points your `default` profile — you are warned and can opt in with `--set-default` (or skip the prompt with `--force`).
11
- - Workspace isolation on agent reads and mutations: `agents show <name>` and every agent mutation now resolve strictly inside the authenticated workspace, so same-named agents in other workspaces can never be returned or changed.
12
- - Every mutation returns JSON. `voice card --rebuild`, `intel-prompts resync` and watchlist toggles now return the changed record, the workspace id and an explicit success/error status instead of exiting silently.
13
- - Watchlist operations are atomic and de-duplicated by workspace + normalised name + type; removed items stay removed (suppressions) and are no longer reintroduced by automatic prompt sync, which now only reads active, approved, human-authored knowledge records.
14
- - `agents pipeline [name]` (alias `inspect`) exposes an agent's configuration, pipeline stages, blocking gates and advisory gates for inspection — defaults to the Content Creator Agent.
15
- - Content pipeline quality: signals are retrieved workspace-wide (drafts no longer report "0 signals" when teammates persisted them), signal sources are integrity-checked and quarantined when URL, title, publisher, text and summary disagree, publication dates and source authority are required before evidence is accepted, and alignment + evidence + citation checks must all complete before an article is eligible.
16
- - P0 watchlist topics are treated as highest research priority, not mandatory inclusion — all P0s are searched, only relevant ones are used, and searched/selected/excluded topics are recorded with scores and reasons.
17
- - Voice benchmarks are built from cleaned document structure (PDF page furniture, headers/footers and hard line wraps removed), so paragraph and heading metrics are realistic, and generation and scoring share the same benchmark and reference set.
18
- - Image generation failures now surface the real reason (model, input or storage error) in the app instead of a generic non-2xx message.
7
+ First release marked stable for internal team use.
19
8
 
9
+ ### Commands
10
+ - `login` / `logout` — API key stored with owner-only permissions in `~/.config/setu/config.json`
11
+ - `practice create` — from a website URL, or from `--name` + `--town` with AI enrichment
12
+ - `practice import <file.csv>` — bulk create with validation, `--dry-run`, `--limit`, bounded concurrency, `--out` results file and `--resume`
13
+ - `practice review <draft-id>` / `practice publish <draft-id>`
14
+ - `practice claim-link <practice-id>` — generate or rotate a claim link
15
+ - `practice delete <id>` / `practice unpublish <id>` — refused for claimed or user-owned profiles
16
+ - `dentist create --practice <id> --name "..."`
17
+ - `status [<practice-id>]`
20
18
 
21
- ## 0.22.3 — Sales Navigator imports from the CLI
19
+ ### Reliability
20
+ - Request timeouts, retries with exponential backoff on network errors and 408/425/429/5xx, `Retry-After` support
21
+ - Request IDs and `--verbose` diagnostics
22
+ - Non-zero exit codes on failure; unknown commands fail loudly
23
+ - `--version` and `--help` on every command; `--json` for machine-readable output
22
24
 
23
- - Import Sales Navigator lead lists straight from the CLI: `leads import-from sales_nav_url --url "<search-url>"` or `sales_nav_keywords --query "..."`. These queue as cap-aware background imports that drip-feed inside your LinkedIn read limits instead of blocking live campaigns.
24
- - Track and control them: `leads import-schedules` (progress, ETA, waiting reason) and `leads import-schedule pause|resume|cancel <id>`. Resuming resets retries and nudges the scheduler immediately.
25
- - Idempotent: re-running an identical import reuses the active schedule instead of duplicating it; match is per-source (URL for url imports, keywords for keyword imports).
26
- - Options: `--limit` (1–1000, default 100), `--audience` (segment id or name; created if missing), `--priority normal|high|rush`.
27
- - Docs updated in README and SKILLS.md; MCP gains `lead_import_schedules` and extended `import_leads`.
25
+ ### MCP
26
+ - `@series-a/mcp` stdio server exposing practice create/review/publish, dentist create, claim-link, profile status and profile delete
27
+ - Server version now reported from the package version
28
28
 
29
- ## 0.22.0 — Admin keys, analytics parity, safety hardening, Obsidian sync
29
+ ## 0.2.0 — internal preview
30
+ - Retries, logout, CSV validation, delete/unpublish, MCP delete tool
30
31
 
31
- - Admin keys work end-to-end. `login --admin` persists admin scope and reports reachable workspace count, `whoami` shows `scope: admin (cross-workspace)` plus reachable workspaces, and the caller identity is no longer hardcoded — override with `--as-agent <name>` or `ADVISOROS_AGENT_NAME`, persisted per profile.
32
- - Full analytics, safety and resource parity: `campaigns stats|events|health|leads`, new `analytics`, `safety`, `ctas`, `audiences`, `notifications`, `newsletter`, `video`, `watchlist`, `meetings`, `activity`, `workspaces` groups, and a generic `export` command that writes any list action to CSV.
33
- - Safety and coverage hardening:
34
- - `campaigns preflight`, and `campaigns launch|resume` now dry-run by default and require `--confirm`; the API refuses to launch a campaign with no leads, no sequence, no steps or no sender.
35
- - New `campaigns archive|clone|delete|remove-leads` and `sequences delete|update-step|delete-step`.
36
- - Every destructive command prompts, and requires `--yes` when scripted; `--dry-run` previews.
37
- - List actions now return honest `pagination` metadata (total, limit, offset, next_cursor) and allow up to 1000 rows.
38
- - Not-found reads return 404 and a non-zero exit; unknown resources/actions return 400 with the supported list instead of a 500.
39
- - Add `advisoros kb link|sync|status|unlink` — two-way sync between a workspace Knowledge Base and a local offline Obsidian vault (Markdown + frontmatter + wikilinks, hash-based conflict detection).
40
-
41
-
42
- ## 0.21.0 — Automatic voice checks, real citations, grounded drafts
43
-
44
- - Voice results are always up to date: every draft now runs a voice check automatically the moment it is created or its text is edited, and the fresh score and report are stamped onto the draft. `content show` and release decisions always see the latest voice result — no manual scoring step. Drafts whose voice check cannot finish are held back (`needs_revision`) instead of being left in a hanging "pending" state.
45
- - `content citations` now writes a real citation record per source used: inline citation markers are inserted into the draft body where each source's findings appear, then persisted and returned with counts. Calling it on a draft with no citations syncs them automatically instead of returning empty.
46
- - Draft generation is evidence-locked: required source signals must be quoted and attributed with a distinctive finding (topic-only mentions fail), copied source wording is rejected, rhythm is compared against the author's own benchmark, and the pre-release gate now blocks drafts on grounding, citations, framework fidelity, and pending/timed-out voice checks. Publication stays blocked until all checks pass.
47
- - Restored Agent API actions: `graphics` accepts `refine` again, plus the platform/account listing operations; legacy sequence and campaign action names are accepted as aliases.
48
- - Fixed `meetings` / `integrations` reads in the Agent API returning 500s (wrong sync-timestamp column).
49
-
50
- ## 0.20.0 — Sequence migration fixes and hour-level waits
51
-
52
- - Hour- and minute-level waits from the terminal: `sequences add-step --delay-hours 3` and `--delay-minutes 45` (also on `update-step`), and in `replace-steps` JSON via `delay_hours` / `delay_minutes`. The step table now prints `3h` / `45m` instead of forcing days.
53
- - `replace-steps` now accepts a flat ordered list (no `parent` links) and treats it as a chain — HeyReach-style exports import directly.
54
- - Condition children without a `branch_label` default to the `yes` branch instead of failing validation.
55
- - Short ID prefixes (first characters of an ID) resolve for sequences and campaigns; invalid IDs return a structured 404 "not found" instead of a malformed-UUID 500.
56
- - `sequences show` works with both short and full IDs; alias actions (`show`, `get`) accepted.
57
- - `content generate` without `--wait` now returns a queued job id immediately instead of risking a gateway timeout; poll with `agents job-status <id>`. With `--wait` it blocks until the draft is ready. Finished drafts now reliably carry their final voice result and citation metadata.
58
- - Invite-withdraw and warm-up steps remain API-side only (not yet exposed); auto-withdraw stays off by default.
59
-
60
- ## 0.15.1 — Engine fixes and reliability patch
61
-
62
- - `voice set` / `voice pin-benchmark` no longer fail with a `user_id` null violation — the Agent API now resolves the actor from the API key, workspace member, or owner context automatically.
63
- - AI-generated invitations are truncated at sentence/word boundaries with `{{token}}` protection — no more messages cut off mid-placeholder or mid-URL.
64
- - 1st-degree leads no longer stall sequences: the DM step is skipped with a clear `dm_skipped_not_first_degree` audit reason and the lead continues to the next step.
65
- - Fixed misleading "completed" stats: leads that only had zero-read cached identity lookups are now finalized as `skipped` with an explicit finish reason instead of `completed`.
66
- - `agent-run` 403s resolved: workspace guard now matches both agent name and type, so scheduled agents fire reliably from CLI-triggered workspaces.
67
- - Newsletter metrics now fall back to send-time provider handoff for delivered counts when Resend webhooks are absent.
68
-
69
- ## 0.15.0 — Newsletter audiences and sending
70
-
71
- - `advisoros audiences create|edit|delete|add-leads|remove-leads` — full CRUD for smart audiences (lead segments), not just read + enrol.
72
- - `advisoros newsletter audience-create|audience-show|audience-edit|audience-delete` — manage mailing audiences; mirrored to Resend automatically when the workspace has it connected, local-only when it does not.
73
- - `advisoros newsletter contact-add|contacts-import|contact-remove|contact-unsubscribe` — contact management including CSV bulk import.
74
- - `advisoros newsletter sync-segment <segmentId> <audienceId>` — push a smart audience's leads into a mailing audience.
75
- - `advisoros newsletter send|test|render|metrics` — send now, schedule, test-send, render HTML, and read delivery totals, open/click/bounce rates and sending health.
76
- - New Agent API actions on `audiences` and `newsletter`; MCP gains `manage_audience` and `send_newsletter` (44 tools, manifest 0.12.0).
77
-
78
- ## 0.14.0 — Daily reports
79
-
80
- - `advisoros reports list` — browse persisted daily reports (past and present) per workspace, with status, activity totals and recipient/sent counts.
81
- - `advisoros reports show <id|YYYY-MM-DD>` — full report detail including stats and the shareable dashboard URL.
82
- - `advisoros reports generate` — run the daily-report engine on demand; dry-run by default, `--send` emails all workspace members, `--to <email>` sends a single test copy.
83
- - Backed by the new Agent API `daily_reports` resource (`list` / `get` / `generate`).
84
-
85
- ## 0.13.0 — Full lifecycle + scheduling engine
86
-
87
- - Campaign lifecycle is complete from the terminal: `campaigns update` (name, goal, sequence, sender accounts, daily send limit — no longer create-time-only), `launch`, `pause`, `resume`, `archive`, `clone`, and `delete` (dry-run preview by default, `--force` to execute, blocked when the campaign has dispatched activity unless forced).
88
- - Sequence editing: `sequences update-step`, `delete-step`, and `replace-steps` — steps are no longer append-only. Graph validation flags disconnected nodes and cycles before launch.
89
- - Scheduling engine awareness: calendar/schedule commands report whether a workspace will publish via Taplio (when connected) or the built-in cron scheduler, so automation targets the right engine.
90
- - Live counts after writes: campaign and sequence mutations re-read the record and return live stats, clearly separated from the stored snapshot which may lag.
91
- - Clearer errors under load: the API now returns a typed 429 with retry-after guidance instead of empty lists during heavy automation; the CLI surfaces this plainly.
92
-
93
- ## 0.12.0 — Agent audit trail
94
-
95
- - `advisoros audit list/show/stats` — query the durable per-workspace audit log of every CLI/MCP/Agent API action (actor, surface, action, outcome, duration, correlation ID).
96
- - CLI requests now send actor/client/version headers so audit records attribute actions to the right user and CLI version.
97
- - `login` persists the profile email for audit attribution.
98
-
99
- ## 0.11.0 — Video management
100
-
101
- - `videos` resource group: `list`, `show`, `create`, `generate`, `update`, `publish`, `unpublish`, `refresh`, `delete` against video projects, with workspace scoping and destructive-action confirmation.
102
-
103
- ## 0.10.0 — Calendar & Command Centre write access
104
-
105
- - Full content calendar read/write/delete/schedule via CLI, with bulk operations and engine-aware scheduling (Taplio when connected, built-in cron otherwise).
106
- - Command Centre content management: update, approve, schedule, unschedule, and publish-now actions.
107
-
108
- ## 0.9.0 — Tone of Voice
109
-
110
- - Full Tone of Voice support: workspace configuration, writing-sample references, benchmark pinning, voice cards, scoring/redrafting, and report CRUD.
111
-
112
- ## 0.8.0 — Content Strategy
113
-
114
- - Full content strategy read/write: create, list, show, update, delete strategies; manage strategy posts; retry/resume generation.
115
-
116
- ## 0.7.0 — Hardening & admin keys
117
-
118
- - Shared typed errors with machine-readable codes across all commands.
119
- - Cursor pagination up to 1,000 items per page.
120
- - Destructive actions require explicit confirmation (`--confirm` / `--force`).
121
- - `login --admin` for admin API keys, `--as-agent` impersonation flag, and `whoami` scope reporting.
122
- - Admin keys (`advos_admin_…`) authorize from key scope alone and work across all workspaces.
123
-
124
- ## 0.6.1 — Campaign editing
125
-
126
- - `campaigns` — added `update`/`edit` (name, description, goal, sequence, sender accounts, daily send limit, launch stage, status). Mirrors the new `update_campaign` MCP tool.
127
-
128
- ## 0.2.0 — Write coverage expansion
129
-
130
- - `inbox` — added `send`, `reply` (dry-run by default, `--confirm` to dispatch, 7,900 char guard), `mark-read` (bulk), `snooze` (`--for`, `--until`, `--clear`).
131
- - `sequences` — added `create`, `update`, `add-step` (per-action char limits: invite 200 / DM 8000 / comment 1250), `clone` (with branch remap), `validate`.
132
- - `content` — full CRUD: `create`, `update`, `delete` alongside existing `list`/`show`/`publish`.
133
- - `calendar` — new resource group: `list`, `create`, `update`, `delete` against `calendar_posts`.
134
- - `signals` — new resource group backed by `intelligence_signals`: `list`, `create`, `update`, `delete`.
135
- - `pipelines` — alias of `opportunities` with `list`, `create`, `update`, `delete`.
136
- - `agents` — added `create`, `update`, `set-status`, `delete`, `recent-runs`.
137
-
138
- ## 0.1.0 — Initial release
139
-
140
-
141
- - `advisoros login` / `logout` / `whoami` / `profiles` with multi-workspace profile support.
142
- - `leads` — `list`, `get`, `set-status`, `import` (CSV/JSON/JSONL, auto-chunked), `verify`.
143
- - `campaigns` — `list`, `show`, `create`, `add-leads`, `launch`, `pause`, `resume`.
144
- - `sequences` — `list`, `show` (ordered step table).
145
- - `inbox` — `threads` (read-only).
146
- - `content` — `list`, `show`, `publish`.
147
- - `agents` — `list`, `run`, `job`.
148
- - Global flags: `--json`, `--workspace`, `--profile`, `--api-key`.
149
- - Programmatic SDK via `@series-a/cli/src/api.mjs`.
32
+ ## 0.1.0 — internal alpha
33
+ - Initial CLI and MCP server
package/README.md CHANGED
@@ -1,316 +1,98 @@
1
- # @series-a/cli
1
+ # Setu CLI (internal)
2
2
 
3
- A command-line interface to the AdvisorPro platform — drive leads, campaigns, sequences and agents from your terminal. Built on top of the [`/agent-api`](https://github.com/series-a/advisoros/blob/main/docs/agent-api.md) M2M router, so anything the CLI does is auditable and workspace-scoped.
4
-
5
- ---
3
+ Build claimable practice and dentist profiles from the command line.
6
4
 
7
5
  ## Install
8
6
 
9
7
  ```bash
10
- # Run without installing — always fetches latest
11
- npx @series-a/cli@latest --help
12
-
13
- # Pin a version (recommended for CI)
14
- npx @series-a/cli@0.1.0 --help
15
-
16
- # Or install globally
17
- npm i -g @series-a/cli
18
- advisoros --help
19
- ```
20
-
21
- Requires **Node.js ≥ 20**.
22
-
23
- > Releases are tagged `cli-vX.Y.Z` in the repo and published to npm with [provenance](https://docs.npmjs.com/generating-provenance-statements). See [`CHANGELOG.md`](./CHANGELOG.md).
24
-
25
- ## 1. Get an API key
26
-
27
- 1. Sign in to AdvisorPro.
28
- 2. Open **Settings → API Keys**.
29
- 3. Click **New key** → choose **Workspace** scope (recommended).
30
- 4. Copy the key — you won't see it again.
31
-
32
- The **CLI quickstart** card on that page shows a copy-paste `npx` command pre-filled with your workspace ID.
33
-
34
- > Admin keys (cross-workspace) also work but are intentionally restricted. Default to workspace keys.
35
-
36
- ## 2. Log in
37
-
38
- ```bash
39
- npx @series-a/cli@latest login
40
- # Prompts for API key + workspace ID (the 6-char slug, e.g. dmw9wj)
41
- ```
42
-
43
- ### Admin login
44
-
45
- Admin keys (`advos_admin_…`) are detected automatically — no workspace prompt:
46
-
47
- ```bash
48
- advisoros login --admin
49
- # ✓ Logged in as admin profile "default" — N workspaces reachable
50
-
51
- advisoros workspaces list # admin-only, no workspace needed
52
- advisoros campaigns list --workspace dmw9wj # pass workspace per command
53
- advisoros whoami # shows scope: admin (cross-workspace)
54
- ```
55
-
56
- Multiple workspaces?
57
-
58
- ```bash
59
- advisoros login --profile acme # save as "acme"
60
- advisoros leads list --profile acme # use the named profile
61
- ```
62
-
63
- Config is stored at `~/.advisoros/config.json` with mode `0600`. You can also use env vars: `ADVISOROS_API_KEY`, `ADVISOROS_WORKSPACE_ID`, `ADVISOROS_PROFILE`, `ADVISOROS_BASE_URL`.
64
-
65
- ```bash
66
- advisoros whoami
67
- advisoros profiles
68
- advisoros logout --profile acme
69
- ```
70
-
71
- ## 3. Command reference
72
-
73
- Global flags (work on every subcommand):
74
-
75
- | Flag | Description |
76
- |---|---|
77
- | `--json` | Emit raw JSON instead of formatted tables. |
78
- | `-w, --workspace <id>` | Override the workspace from your profile. |
79
- | `-p, --profile <name>` | Pick a saved profile. |
80
- | `--api-key <key>` | Override the saved API key. |
81
-
82
- ### Leads
83
-
84
- ```bash
85
- advisoros leads list [--status new] [--persona founder] [--search acme] [--limit 50]
86
- advisoros leads get <id>
87
- advisoros leads set-status <id> <new|engaged|won|lost>
88
- advisoros leads import --file leads.csv [--persona founder]
89
- advisoros leads import-from <source> [--query ...] [--post <url>] [--file <path>] [--audience <name>] [--campaign <id>] [--limit 50] [--no-enrich]
90
- advisoros leads import-status <jobId>
91
- advisoros leads update <id> [--name ...] [--title ...] [--company ...] [--email ...] [--linkedin ...] [--persona ...] [--score ...] [--status ...] [--notes ...]
92
- advisoros leads delete <id>
93
- advisoros leads verify <id>
94
- ```
95
-
96
- `leads import` accepts CSV (header row), JSON array, or JSONL. Upserts on `(workspace_id, linkedin_url)`. Bulk requests are auto-chunked at 200/call (server cap: 500/call).
97
-
98
- `leads import-from` runs any of the import sources in **Get Leads → Import Leads**:
99
-
100
- | source | required params | what it does |
101
- |---|---|---|
102
- | `linkedin_search` | `--query` | keyword / title / company people search via Unipile |
103
- | `company_search` | `--query` | LinkedIn company search |
104
- | `post_reactors` | `--post <url>` | everyone who reacted to a LinkedIn post |
105
- | `paste_profiles` | `--file <path>` | name + LinkedIn URL lines; rest is enriched |
106
- | `csv` | `--file <path>` | same CSV parser the UI uses |
107
- | `heyreach` | `--file <path>` `--campaign <id>` | HeyReach campaign CSV, statuses preserved |
108
- | `sales_nav_url` | `--url <sales-nav-search-url>` | queues a background Sales Navigator import, drip-fed inside the LinkedIn read limits |
109
- | `sales_nav_keywords` | `--query` | same background queue, from Sales Navigator keywords |
110
-
111
- All sources accept `--audience` to attach leads to a segment (created if missing). LinkedIn-backed sources run at bulk read priority so live campaigns are not starved. Long-running imports return a `job_id`; poll with `advisoros leads import-status <jobId>`.
112
-
113
- Sales Navigator sources do not run inline — they create a **scheduled import** that the
114
- cap-aware scheduler drip-feeds over hours or days:
115
-
116
- ```bash
117
- advisoros leads import-from sales_nav_url --url "https://www.linkedin.com/sales/search/people?..." \
118
- --limit 500 --audience "Q3 ICP" --priority high
119
- advisoros leads import-schedules
120
- advisoros leads import-schedule pause|resume|cancel <id>
121
- ```
122
-
123
- Cancelling keeps the leads already imported.
124
-
125
- ### Campaigns
126
-
127
- ```bash
128
- advisoros campaigns list [--status active]
129
- advisoros campaigns show <id>
130
- advisoros campaigns create --name "Founder Pitch Club" \
131
- --sequence <sequenceId> \
132
- --senders acc_a,acc_b \
133
- --daily-limit 25
134
- advisoros campaigns add-leads <campaignId> --lead-ids id1,id2,id3
135
- advisoros campaigns add-leads <campaignId> --file lead-ids.txt
136
- advisoros campaigns launch <id>
137
- advisoros campaigns pause <id>
138
- advisoros campaigns resume <id>
8
+ cd packages/cli && npm link # gives you the `setu` command
9
+ setu login # paste the internal CLI key
139
10
  ```
140
11
 
141
- `launch` flips status to `active` — the `enforce_campaign_char_limits` trigger validates every step's copy against LinkedIn limits before allowing the transition.
12
+ The key is the `SETU_CLI_API_KEY` secret from the Setu backend. It is stored at
13
+ `~/.config/setu/config.json` (chmod 600). You can also set `SETU_CLI_API_KEY`
14
+ and `SETU_API_URL` as environment variables in CI.
142
15
 
143
- ### Sequences / Inbox / Content / Agents / Meetings / Newsletter / Integrations
16
+ ## Build one profile
144
17
 
145
18
  ```bash
146
- advisoros sequences list
147
- advisoros sequences show <id>
148
-
149
- advisoros inbox threads [--campaign <id>] [--lead <id>] [--needs-attention] [--limit 50]
150
-
151
- advisoros content list [--status published] [--type post] [--search ...]
152
- advisoros content show <id>
153
- advisoros content publish <id>
154
-
155
- advisoros agents list
156
- advisoros agents run <name> --input '{"foo":"bar"}'
157
- advisoros agents trigger <name> --input '{"foo":"bar"}'
158
- advisoros agents history [--agent <name>] [--days 30] [--limit 50]
159
- advisoros agents job <jobId>
160
-
161
- advisoros meetings list [--limit 50]
162
- advisoros meetings transcripts [--provider fireflies|roam] [--since 2026-01-01] [--limit 50]
163
- advisoros meetings transcript <transcriptId>
164
-
165
- advisoros newsletter list
166
- advisoros newsletter create --subject "Weekly roundup" --body "<html>..." [--preview-text "..."]
167
- advisoros newsletter edit <id> [--subject ...] [--body ...] [--preview-text ...] [--status draft|scheduled]
168
- advisoros newsletter delete <id>
169
-
170
- advisoros integrations status
171
- advisoros integrations check <platform>
19
+ setu practice create --url https://smiledental.co.uk
20
+ setu practice create --name "Smile Dental" --town Portsmouth
21
+ setu practice review <draft-id>
22
+ setu practice publish <draft-id>
172
23
  ```
173
24
 
174
- > **Heads-up:** `inbox send`/`reply` are intentionally **not** in v1. Outbound goes through `campaigns launch` (sender resolution + char limits + per-sender daily budget). For one-off DMs, use the web inbox.
25
+ `create` scrapes the practice website (services, pricing, hours, team, images),
26
+ pulls their Google listing (address, phone, rating, reviews, opening hours) and
27
+ returns a readiness score. Nothing is public until `publish`.
175
28
 
176
- `meetings transcript` only returns full text once the transcript has been anonymised; otherwise metadata is returned with the body redacted.
29
+ `publish` creates an **unclaimed** listing: it appears in patient search with an
30
+ "Unclaimed" badge, ranked below live subscribed practices, with enquiry capture
31
+ instead of booking. It also seeds any clinicians the AI detected (skip with
32
+ `--no-dentists`).
177
33
 
178
- `integrations status` is read-only and never returns credentials. `integrations check <platform>` runs a live health probe for the requested platform (e.g. `linkedin_tool`).
34
+ ## Bulk import
179
35
 
180
- ### Obsidian vault mirror (`kb`) — one-way
36
+ CSV with any of these columns: `name, website, town, postcode, email, phone`.
181
37
 
182
38
  ```bash
183
- advisoros kb link ./client-vault --workspace dmw9wj
184
- advisoros kb status ./client-vault # dry-run preview
185
- advisoros kb pull ./client-vault # mirror notes + graph entities
186
- advisoros kb pull ./client-vault --preserve-local
39
+ setu practice import practices.csv --publish
187
40
  ```
188
41
 
189
- One-way push, AdvisorPro → Obsidian. Markdown notes with frontmatter, `[[wikilinks]]` and an
190
- `## Entities` block, plus `Entities/<Type>/*.md` for graph nodes. Local edits are overwritten unless
191
- `--preserve-local` is used (remote copy lands as `<slug>.remote.md`). Nothing is pushed back.
192
-
42
+ Rows are processed one at a time (Firecrawl / Google rate limits) and failures
43
+ are listed at the end so you can retry them.
193
44
 
194
- ## Examples
195
-
196
- **Spin up a campaign from a fresh CSV:**
45
+ ## Claim links
197
46
 
198
47
  ```bash
199
- advisoros leads import --file ./prospects.csv --persona founder
200
- advisoros leads list --persona founder --limit 200 --json \
201
- | jq -r '.leads[].id' > lead-ids.txt
202
-
203
- advisoros campaigns create --name "Q3 Founder Outreach" \
204
- --sequence 1a2b3c4d-... --senders acc_milan --daily-limit 25
205
- # → ✓ Created campaign 8297f04d-...
206
-
207
- advisoros campaigns add-leads 8297f04d-... --file lead-ids.txt
208
- advisoros campaigns launch 8297f04d-...
48
+ setu practice claim-link <practice-id>
49
+ setu status # every seeded profile and its claim state
50
+ setu status <practice-id> # one profile plus its claim attempts
209
51
  ```
210
52
 
211
- **Tail a long-running agent job:**
53
+ Send the claim link in outreach. The practice signs in, and is verified either
54
+ by their email domain matching their website, or by a code sent to the public
55
+ contact address on their Google listing. On success the profile transfers to
56
+ them, pre-filled, and they continue through the normal onboarding and
57
+ subscription flow.
212
58
 
213
- ```bash
214
- JOB=$(advisoros agents run lead-intelligence --input '{}' --json | jq -r '.run.job_id')
215
- watch -n 5 "advisoros agents job $JOB --json | jq '{status,progress}'"
216
- ```
217
-
218
- ## Safety rails
219
-
220
- Anything that stops sending, un-enrols leads or deletes data now asks first.
59
+ ## Clinicians
221
60
 
222
61
  ```bash
223
- # Launch is a dry run until you confirm — preflight runs server-side.
224
- advisoros campaigns preflight 9884b9ec
225
- advisoros campaigns launch 9884b9ec # shows blockers, changes nothing
226
- advisoros campaigns launch 9884b9ec --confirm # actually launches
227
-
228
- # Destructive commands prompt; scripts must pass --yes.
229
- advisoros campaigns delete 9884b9ec --dry-run
230
- advisoros campaigns delete 9884b9ec --yes
231
- advisoros sequences delete-step 6b60d6ad --yes
62
+ setu dentist create --name "Dr Jane Roe" --practice <id> --profile-url https://…/team/jane
232
63
  ```
233
64
 
234
- A campaign with no leads, no sequence, no steps or no sender account is
235
- **refused**, not silently activated. `--force` overrides once you know why.
236
-
237
- New commands: `campaigns preflight|archive|clone|delete|remove-leads`,
238
- `sequences delete|update-step|delete-step`.
239
-
240
- ## Reading more than 200 rows
65
+ ## Flags
241
66
 
242
- List commands accept `--limit` up to 1000 and every list response carries
243
- `pagination` (`total`, `limit`, `offset`, `next_cursor`, `has_more`). If you ask
244
- for more than the maximum, the response says it was clamped instead of quietly
245
- truncating.
67
+ `--json` for machine-readable output, `--operator "Your Name"` to attribute
68
+ seeded profiles to you.
246
69
 
247
- ## Exit codes
248
-
249
- | Code | Meaning |
250
- |---|---|
251
- | 0 | Success |
252
- | 1 | Generic failure (`error` in JSON response or thrown). Stderr contains the message. |
253
-
254
- ## Programmatic use
255
-
256
- ```js
257
- import { call } from "@series-a/cli/src/api.mjs";
258
-
259
- const { campaigns } = await call("campaigns", "list", { status: "active" }, {
260
- apiKey: process.env.ADVISOROS_API_KEY,
261
- workspaceId: "dmw9wj",
262
- });
263
- ```
70
+ ## Reliability
264
71
 
265
- ## Troubleshooting
72
+ - Every request has a timeout (`SETU_TIMEOUT_MS`, default 240s) and retries
73
+ transient failures (network drops, 429, 5xx) with exponential backoff
74
+ (`SETU_RETRIES`, default 3). `Retry-After` is honoured.
75
+ - `--verbose` prints retry attempts and stack traces.
76
+ - `setu logout` removes the stored key from this machine.
77
+ - Unknown commands and failed bulk imports exit non-zero (safe for scripts/CI).
266
78
 
267
- - **401 Unauthorized** — key wrong / revoked / wrong base URL. Re-run `advisoros login`.
268
- - **403 not authorized for the requested workspace_id** — workspace-scoped key + `--workspace` to a different workspace. Use the matching key.
269
- - **CHAR_LIMIT_EXCEEDED on launch** — a sequence step exceeds LinkedIn limits (200 invitations / 8000 DMs / 1250 comments). Fix in web app.
270
- - **Network error** — check `ADVISOROS_BASE_URL` if you're pointing at a non-default deployment.
271
-
272
- ## Releasing (maintainers)
79
+ ## Bulk import
273
80
 
274
81
  ```bash
275
- cd tools/cli
276
- npx changeset # describe the change
277
- npm run version-packages # bump package.json + CHANGELOG.md
278
- git commit -am "chore(cli): release v$(node -p "require('./package.json').version")"
279
- git tag "cli-v$(node -p "require('./package.json').version")"
280
- git push --follow-tags
281
- # → .github/workflows/cli-release.yml publishes to npm with provenance
82
+ setu practice import practices.csv --dry-run # validate only
83
+ setu practice import practices.csv --publish \
84
+ --concurrency 3 --out results.json # run
85
+ setu practice import practices.csv --resume results.json # retry failures only
282
86
  ```
283
87
 
284
- `NPM_TOKEN` must be set in the repo's GitHub Actions secrets (automation token with publish access to the `@series-a` org).
285
-
286
- ## Roadmap (v1.1)
287
-
288
- - `inbox send` / `inbox reply` with explicit `--confirm` + per-sender budget enforcement.
289
- - `agents tail <jobId>` (SSE).
290
- - `admin workspaces …` (admin keys only).
291
- - Single-binary builds via `pkg`.
292
-
293
- ## Full API reference
294
-
295
- See [`docs/agent-api.md`](../../docs/agent-api.md) for the underlying `/agent-api` envelope.
88
+ Rows need either a `website`/`url`, or a `name` plus `town`/`city`; anything
89
+ else is reported and skipped before any API call is made.
296
90
 
297
-
298
-
299
- ## Admin keys
300
-
301
- Admin keys (`advos_admin_…`) are authorised by the key itself — they do **not** need an
302
- `agent_workspace_bindings` row. `agent_name` is an audit label only.
91
+ ## Removing seeded profiles
303
92
 
304
93
  ```bash
305
- advisoros login --admin --profile ops # no workspace prompt; prints reachable workspace count
306
- advisoros whoami --profile ops # scope: admin (cross-workspace) + reachable count
307
- advisoros workspaces list --profile ops # every reachable workspace (paginated, up to 1000)
308
- advisoros analytics overview --workspace dmw9wj --profile ops
94
+ setu practice delete <practice-id> --unpublish # hide from patients
95
+ setu practice delete <practice-id> # delete (unclaimed only)
309
96
  ```
310
97
 
311
- Caller identity is overridable: `--as-agent <name>` on any command, `ADVISOROS_AGENT_NAME`
312
- in the environment, or the `agentName` stored on the profile at login (default `advisoros-cli`).
313
-
314
- Workspace-scoped keys are unchanged: they can only reach their own workspace (403 otherwise)
315
- and cannot use the `workspaces` resource. An agent without bindings now gets a typed 403
316
- explaining to use an admin key, instead of a 500.
98
+ Claimed or user-owned profiles are always refused.