@series-a/cli 0.24.0 → 1.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/CHANGELOG.md CHANGED
@@ -1,158 +1,43 @@
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.24.0 — Meeting transcripts: fixed retrieval and permission-gated original text
5
+ ## 1.1.0 — editing, pricing and media
8
6
 
9
- - Fixed transcript retrieval returning `text: null` / `redacted: true` for meetings that were already processed. The reader accepted only one internal status while the writer recorded another; both are now accepted, so `meetings transcript <id>` returns the anonymised text as expected.
10
- - New retrieval modes: `advisoros meetings transcript <id>` returns anonymised text by default, and `--original` (or `--mode original`) returns the original text plus the speaker identities for the meeting.
11
- - Original access is permission-controlled, scoped to your own workspace and audited (caller, meeting, mode) — transcript text is never written to logs. All existing unrestricted keys already have access; explicitly scoped keys need `meetings:original`, `meetings:*` or `*`.
12
- - Original text does not wait for anonymisation to finish, and when text cannot be returned you now get an explicit reason instead of a silent empty result.
13
- - Same modes available through MCP (`list_transcripts` / transcript reads) and the Agent API; README, SKILLS.md and API docs updated.
7
+ ### Added
8
+ - `practice update` / `dentist update` — edit whitelisted fields on unclaimed seeded profiles (`--set field=value`, repeatable; `--fields` lists what's allowed)
9
+ - `practice images` / `dentist images` — add, remove (by URL or index), reorder, replace or clear gallery photos, and set the logo / main photo
10
+ - `practice pricing` / `dentist pricing` — read, set, remove or clear treatment prices
11
+ - `dentist delete` / `dentist delete --unpublish`
12
+ - Much wider field allowlists, including services, all private fee columns, specialties, languages and matching fields
13
+ - MCP tools `setu_profile_update`, `setu_profile_images` and `setu_profile_pricing`
14
14
 
15
- ## 0.23.0 — Bulk lead upserts, named profiles, atomic mutations
15
+ ## 1.0.0 — first stable release
16
16
 
17
+ First release marked stable for internal team use.
17
18
 
18
- - `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.
19
- - 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`).
20
- - 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.
21
- - 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.
22
- - 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.
23
- - `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.
24
- - 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.
25
- - 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.
26
- - 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.
27
- - Image generation failures now surface the real reason (model, input or storage error) in the app instead of a generic non-2xx message.
19
+ ### Commands
20
+ - `login` / `logout` — API key stored with owner-only permissions in `~/.config/setu/config.json`
21
+ - `practice create` — from a website URL, or from `--name` + `--town` with AI enrichment
22
+ - `practice import <file.csv>` — bulk create with validation, `--dry-run`, `--limit`, bounded concurrency, `--out` results file and `--resume`
23
+ - `practice review <draft-id>` / `practice publish <draft-id>`
24
+ - `practice claim-link <practice-id>` — generate or rotate a claim link
25
+ - `practice delete <id>` / `practice unpublish <id>` — refused for claimed or user-owned profiles
26
+ - `dentist create --practice <id> --name "..."`
27
+ - `status [<practice-id>]`
28
28
 
29
+ ### Reliability
30
+ - Request timeouts, retries with exponential backoff on network errors and 408/425/429/5xx, `Retry-After` support
31
+ - Request IDs and `--verbose` diagnostics
32
+ - Non-zero exit codes on failure; unknown commands fail loudly
33
+ - `--version` and `--help` on every command; `--json` for machine-readable output
29
34
 
30
- ## 0.22.3 — Sales Navigator imports from the CLI
35
+ ### MCP
36
+ - `@series-a/mcp` stdio server exposing practice create/review/publish, dentist create, claim-link, profile status and profile delete
37
+ - Server version now reported from the package version
31
38
 
32
- - 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.
33
- - 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.
34
- - 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).
35
- - Options: `--limit` (1–1000, default 100), `--audience` (segment id or name; created if missing), `--priority normal|high|rush`.
36
- - Docs updated in README and SKILLS.md; MCP gains `lead_import_schedules` and extended `import_leads`.
39
+ ## 0.2.0 — internal preview
40
+ - Retries, logout, CSV validation, delete/unpublish, MCP delete tool
37
41
 
38
- ## 0.22.0 — Admin keys, analytics parity, safety hardening, Obsidian sync
39
-
40
- - 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.
41
- - 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.
42
- - Safety and coverage hardening:
43
- - `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.
44
- - New `campaigns archive|clone|delete|remove-leads` and `sequences delete|update-step|delete-step`.
45
- - Every destructive command prompts, and requires `--yes` when scripted; `--dry-run` previews.
46
- - List actions now return honest `pagination` metadata (total, limit, offset, next_cursor) and allow up to 1000 rows.
47
- - Not-found reads return 404 and a non-zero exit; unknown resources/actions return 400 with the supported list instead of a 500.
48
- - 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).
49
-
50
-
51
- ## 0.21.0 — Automatic voice checks, real citations, grounded drafts
52
-
53
- - 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.
54
- - `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.
55
- - 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.
56
- - Restored Agent API actions: `graphics` accepts `refine` again, plus the platform/account listing operations; legacy sequence and campaign action names are accepted as aliases.
57
- - Fixed `meetings` / `integrations` reads in the Agent API returning 500s (wrong sync-timestamp column).
58
-
59
- ## 0.20.0 — Sequence migration fixes and hour-level waits
60
-
61
- - 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.
62
- - `replace-steps` now accepts a flat ordered list (no `parent` links) and treats it as a chain — HeyReach-style exports import directly.
63
- - Condition children without a `branch_label` default to the `yes` branch instead of failing validation.
64
- - 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.
65
- - `sequences show` works with both short and full IDs; alias actions (`show`, `get`) accepted.
66
- - `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.
67
- - Invite-withdraw and warm-up steps remain API-side only (not yet exposed); auto-withdraw stays off by default.
68
-
69
- ## 0.15.1 — Engine fixes and reliability patch
70
-
71
- - `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.
72
- - AI-generated invitations are truncated at sentence/word boundaries with `{{token}}` protection — no more messages cut off mid-placeholder or mid-URL.
73
- - 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.
74
- - 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`.
75
- - `agent-run` 403s resolved: workspace guard now matches both agent name and type, so scheduled agents fire reliably from CLI-triggered workspaces.
76
- - Newsletter metrics now fall back to send-time provider handoff for delivered counts when Resend webhooks are absent.
77
-
78
- ## 0.15.0 — Newsletter audiences and sending
79
-
80
- - `advisoros audiences create|edit|delete|add-leads|remove-leads` — full CRUD for smart audiences (lead segments), not just read + enrol.
81
- - `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.
82
- - `advisoros newsletter contact-add|contacts-import|contact-remove|contact-unsubscribe` — contact management including CSV bulk import.
83
- - `advisoros newsletter sync-segment <segmentId> <audienceId>` — push a smart audience's leads into a mailing audience.
84
- - `advisoros newsletter send|test|render|metrics` — send now, schedule, test-send, render HTML, and read delivery totals, open/click/bounce rates and sending health.
85
- - New Agent API actions on `audiences` and `newsletter`; MCP gains `manage_audience` and `send_newsletter` (44 tools, manifest 0.12.0).
86
-
87
- ## 0.14.0 — Daily reports
88
-
89
- - `advisoros reports list` — browse persisted daily reports (past and present) per workspace, with status, activity totals and recipient/sent counts.
90
- - `advisoros reports show <id|YYYY-MM-DD>` — full report detail including stats and the shareable dashboard URL.
91
- - `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.
92
- - Backed by the new Agent API `daily_reports` resource (`list` / `get` / `generate`).
93
-
94
- ## 0.13.0 — Full lifecycle + scheduling engine
95
-
96
- - 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).
97
- - 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.
98
- - 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.
99
- - 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.
100
- - 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.
101
-
102
- ## 0.12.0 — Agent audit trail
103
-
104
- - `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).
105
- - CLI requests now send actor/client/version headers so audit records attribute actions to the right user and CLI version.
106
- - `login` persists the profile email for audit attribution.
107
-
108
- ## 0.11.0 — Video management
109
-
110
- - `videos` resource group: `list`, `show`, `create`, `generate`, `update`, `publish`, `unpublish`, `refresh`, `delete` against video projects, with workspace scoping and destructive-action confirmation.
111
-
112
- ## 0.10.0 — Calendar & Command Centre write access
113
-
114
- - Full content calendar read/write/delete/schedule via CLI, with bulk operations and engine-aware scheduling (Taplio when connected, built-in cron otherwise).
115
- - Command Centre content management: update, approve, schedule, unschedule, and publish-now actions.
116
-
117
- ## 0.9.0 — Tone of Voice
118
-
119
- - Full Tone of Voice support: workspace configuration, writing-sample references, benchmark pinning, voice cards, scoring/redrafting, and report CRUD.
120
-
121
- ## 0.8.0 — Content Strategy
122
-
123
- - Full content strategy read/write: create, list, show, update, delete strategies; manage strategy posts; retry/resume generation.
124
-
125
- ## 0.7.0 — Hardening & admin keys
126
-
127
- - Shared typed errors with machine-readable codes across all commands.
128
- - Cursor pagination up to 1,000 items per page.
129
- - Destructive actions require explicit confirmation (`--confirm` / `--force`).
130
- - `login --admin` for admin API keys, `--as-agent` impersonation flag, and `whoami` scope reporting.
131
- - Admin keys (`advos_admin_…`) authorize from key scope alone and work across all workspaces.
132
-
133
- ## 0.6.1 — Campaign editing
134
-
135
- - `campaigns` — added `update`/`edit` (name, description, goal, sequence, sender accounts, daily send limit, launch stage, status). Mirrors the new `update_campaign` MCP tool.
136
-
137
- ## 0.2.0 — Write coverage expansion
138
-
139
- - `inbox` — added `send`, `reply` (dry-run by default, `--confirm` to dispatch, 7,900 char guard), `mark-read` (bulk), `snooze` (`--for`, `--until`, `--clear`).
140
- - `sequences` — added `create`, `update`, `add-step` (per-action char limits: invite 200 / DM 8000 / comment 1250), `clone` (with branch remap), `validate`.
141
- - `content` — full CRUD: `create`, `update`, `delete` alongside existing `list`/`show`/`publish`.
142
- - `calendar` — new resource group: `list`, `create`, `update`, `delete` against `calendar_posts`.
143
- - `signals` — new resource group backed by `intelligence_signals`: `list`, `create`, `update`, `delete`.
144
- - `pipelines` — alias of `opportunities` with `list`, `create`, `update`, `delete`.
145
- - `agents` — added `create`, `update`, `set-status`, `delete`, `recent-runs`.
146
-
147
- ## 0.1.0 — Initial release
148
-
149
-
150
- - `advisoros login` / `logout` / `whoami` / `profiles` with multi-workspace profile support.
151
- - `leads` — `list`, `get`, `set-status`, `import` (CSV/JSON/JSONL, auto-chunked), `verify`.
152
- - `campaigns` — `list`, `show`, `create`, `add-leads`, `launch`, `pause`, `resume`.
153
- - `sequences` — `list`, `show` (ordered step table).
154
- - `inbox` — `threads` (read-only).
155
- - `content` — `list`, `show`, `publish`.
156
- - `agents` — `list`, `run`, `job`.
157
- - Global flags: `--json`, `--workspace`, `--profile`, `--api-key`.
158
- - Programmatic SDK via `@series-a/cli/src/api.mjs`.
42
+ ## 0.1.0 — internal alpha
43
+ - Initial CLI and MCP server
package/README.md CHANGED
@@ -1,316 +1,135 @@
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
8
+ cd packages/cli && npm link # gives you the `setu` command
9
+ setu login # paste the internal CLI key
19
10
  ```
20
11
 
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.
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.
35
15
 
36
- ## 2. Log in
16
+ ## Build one profile
37
17
 
38
18
  ```bash
39
- npx @series-a/cli@latest login
40
- # Prompts for API key + workspace ID (the 6-char slug, e.g. dmw9wj)
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>
41
23
  ```
42
24
 
43
- ### Admin login
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`.
44
28
 
45
- Admin keys (`advos_admin_…`) are detected automatically — no workspace prompt:
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`).
46
33
 
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?
34
+ ## Bulk import
57
35
 
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`.
36
+ CSV with any of these columns: `name, website, town, postcode, email, phone`.
64
37
 
65
38
  ```bash
66
- advisoros whoami
67
- advisoros profiles
68
- advisoros logout --profile acme
39
+ setu practice import practices.csv --publish
69
40
  ```
70
41
 
71
- ## 3. Command reference
72
-
73
- Global flags (work on every subcommand):
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.
74
44
 
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
45
+ ## Claim links
83
46
 
84
47
  ```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>
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
94
51
  ```
95
52
 
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>`.
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.
112
58
 
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:
59
+ ## Clinicians
115
60
 
116
61
  ```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>
62
+ setu dentist create --name "Dr Jane Roe" --practice <id> --profile-url https://…/team/jane
121
63
  ```
122
64
 
123
- Cancelling keeps the leads already imported.
65
+ ## Flags
124
66
 
125
- ### Campaigns
67
+ `--json` for machine-readable output, `--operator "Your Name"` to attribute
68
+ seeded profiles to you.
126
69
 
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>
139
- ```
70
+ ## Reliability
140
71
 
141
- `launch` flips status to `active` — the `enforce_campaign_char_limits` trigger validates every step's copy against LinkedIn limits before allowing the transition.
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).
142
78
 
143
- ### Sequences / Inbox / Content / Agents / Meetings / Newsletter / Integrations
79
+ ## Bulk import
144
80
 
145
81
  ```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> [--original | --mode anonymised|original]
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>
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
172
86
  ```
173
87
 
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.
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.
175
90
 
176
- `meetings transcript` returns anonymised text by default, once anonymisation is ready; otherwise metadata is returned with an explicit reason. Add `--original` to get the original text and speaker identities — your key needs this permission (all unrestricted keys already have it) and every original read is audited.
177
-
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`).
179
-
180
- ### Obsidian vault mirror (`kb`) — one-way
91
+ ## Editing seeded profiles
181
92
 
182
93
  ```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
94
+ setu practice update <practice-id> --fields # what you can set
95
+ setu practice update <practice-id> --set tagline="Gentle care" --set emergency_available=true
96
+ setu dentist update <dentist-id> --set bio="20 years in implants"
187
97
  ```
188
98
 
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
-
193
-
194
- ## Examples
99
+ Lists take comma-separated values, e.g. `--set services="Implants,Whitening"`.
195
100
 
196
- **Spin up a campaign from a fresh CSV:**
101
+ ## Photos and logos
197
102
 
198
103
  ```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-...
104
+ setu practice images <practice-id> --list
105
+ setu practice images <practice-id> --add https://.../photo.jpg
106
+ setu practice images <practice-id> --remove 2 # by index, or pass the URL
107
+ setu practice images <practice-id> --order "https://.../hero.jpg" # move these to the front
108
+ setu practice images <practice-id> --replace "https://a.jpg,https://b.jpg"
109
+ setu practice images <practice-id> --logo https://.../logo.png
110
+ setu dentist images <dentist-id> --logo https://.../headshot.jpg # main photo
209
111
  ```
210
112
 
211
- **Tail a long-running agent job:**
113
+ ## Prices and services
212
114
 
213
115
  ```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}'"
116
+ setu practice pricing <practice-id> --list
117
+ setu practice pricing <practice-id> --set "Dental implant=1200" --set "Whitening=300-450"
118
+ setu practice pricing <practice-id> --remove "Whitening"
119
+ setu dentist pricing <dentist-id> --set "Hygiene visit=75"
120
+ setu practice update <practice-id> --set services="Implants,Whitening,Invisalign"
216
121
  ```
217
122
 
218
- ## Safety rails
123
+ Practice prices update the practice's treatment list too. Dentist prices are
124
+ saved as individual treatment rows shown on the clinician's profile.
219
125
 
220
- Anything that stops sending, un-enrols leads or deletes data now asks first.
126
+ ## Removing seeded profiles
221
127
 
222
128
  ```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
232
- ```
233
-
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
241
-
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.
246
-
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
- });
129
+ setu practice delete <practice-id> --unpublish # hide from patients
130
+ setu practice delete <practice-id> # delete (unclaimed only)
131
+ setu dentist delete <dentist-id> --unpublish
132
+ setu dentist delete <dentist-id>
263
133
  ```
264
134
 
265
- ## Troubleshooting
266
-
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)
273
-
274
- ```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
282
- ```
283
-
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.
296
-
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.
303
-
304
- ```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
309
- ```
310
-
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.
135
+ Claimed or user-owned profiles are always refused.