@series-a/cli 0.21.1 → 0.22.2

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
@@ -4,6 +4,19 @@ All notable changes to this package are documented here. This project follows
4
4
  [Semantic Versioning](https://semver.org/) and uses
5
5
  [Changesets](https://github.com/changesets/changesets) to manage releases.
6
6
 
7
+ ## 0.22.0 — Admin keys, analytics parity, safety hardening, Obsidian sync
8
+
9
+ - 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.
10
+ - 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.
11
+ - Safety and coverage hardening:
12
+ - `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.
13
+ - New `campaigns archive|clone|delete|remove-leads` and `sequences delete|update-step|delete-step`.
14
+ - Every destructive command prompts, and requires `--yes` when scripted; `--dry-run` previews.
15
+ - List actions now return honest `pagination` metadata (total, limit, offset, next_cursor) and allow up to 1000 rows.
16
+ - Not-found reads return 404 and a non-zero exit; unknown resources/actions return 400 with the supported list instead of a 500.
17
+ - 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).
18
+
19
+
7
20
  ## 0.21.0 — Automatic voice checks, real citations, grounded drafts
8
21
 
9
22
  - 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@series-a/cli",
3
- "version": "0.21.1",
3
+ "version": "0.22.2",
4
4
  "description": "AdvisorPro command-line interface — drive leads, campaigns, sequences and agents from your terminal.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1211,23 +1211,53 @@ export function registerContent(program) {
1211
1211
  .option("--signal <id...>", "intelligence_signals ids to ground on (repeatable)")
1212
1212
  .option("--reference <id...>", "knowledge_items ids to ground on (repeatable)")
1213
1213
  .option("--grounding-text <text>", "extra freeform grounding to append")
1214
- .option("--wait", "block until the job completes (up to 4 min)")
1214
+ .option("--wait", "poll until the job finishes (up to 10 min)")
1215
+ .option("--timeout <seconds>", "how long --wait polls before giving up", "600")
1215
1216
  .action(async function (opts) {
1216
1217
  try {
1218
+ // Always dispatch asynchronously and poll the returned job id. Holding
1219
+ // one long HTTP request open was what produced spurious timeouts, and
1220
+ // polling by the id the server handed back is what keeps --wait from
1221
+ // ever reporting job_not_found for a job that exists.
1222
+ const ctx = ctxFrom(this);
1217
1223
  const r = await call("content", "generate", {
1218
1224
  angle: opts.angle,
1219
1225
  format: opts.format,
1220
1226
  signal_ids: opts.signal,
1221
1227
  reference_item_ids: opts.reference,
1222
1228
  grounding_text: opts.groundingText,
1223
- async: !opts.wait,
1224
- }, ctxFrom(this));
1225
- emit(this, r, (d) => {
1226
- if (d.content) {
1227
- process.stdout.write(`✓ Draft ${d.content.id} (${d.content.type}, ${d.citations?.length ?? 0} citations)\n`);
1228
- } else {
1229
- process.stdout.write(`⏳ Queued job ${d.job_id} — poll with: advisoros agents job-status ${d.job_id}\n`);
1229
+ async: true,
1230
+ }, ctx);
1231
+ const jobId = r?.job_id || r?.job?.id || null;
1232
+ if (!opts.wait || !jobId) {
1233
+ emit(this, r, (d) => {
1234
+ if (d.content) process.stdout.write(`✓ Draft ${d.content.id} (${d.content.type}, ${d.citations?.length ?? 0} citations)\n`);
1235
+ else process.stdout.write(`⏳ Queued job ${d.job_id} — poll with: advisoros agents job-status ${d.job_id}\n`);
1236
+ });
1237
+ return;
1238
+ }
1239
+ const deadline = Date.now() + Number(opts.timeout || 600) * 1000;
1240
+ let last = null;
1241
+ while (Date.now() < deadline) {
1242
+ await new Promise((res) => setTimeout(res, 5000));
1243
+ let st;
1244
+ try {
1245
+ st = await call("agents", "job_status", { job_id: jobId }, ctx);
1246
+ } catch (e) {
1247
+ // A transient lookup failure must never end the wait — the job id
1248
+ // came from the server, so keep polling until the deadline.
1249
+ continue;
1230
1250
  }
1251
+ last = st?.job || st;
1252
+ const status = last?.status;
1253
+ if (status === "completed" || status === "succeeded" || status === "failed") break;
1254
+ }
1255
+ emit(this, { job_id: jobId, job: last }, (d) => {
1256
+ const st = d.job?.status || "unknown";
1257
+ const ids = d.job?.result?.content_ids || [];
1258
+ process.stdout.write(st === "completed" || st === "succeeded"
1259
+ ? `✓ Job ${d.job_id} ${st}${ids.length ? ` — draft ${ids[0]}` : ""}\n`
1260
+ : `⏳ Job ${d.job_id} is ${st} — check with: advisoros agents job-status ${d.job_id}\n`);
1231
1261
  });
1232
1262
  } catch (e) { fail(e); }
1233
1263
  });
@@ -1827,7 +1857,8 @@ export function registerAgents(program) {
1827
1857
  });
1828
1858
 
1829
1859
  withCommonOpts(a.command("job <id>"))
1830
- .description("Check agent_jobs status")
1860
+ .alias("job-status")
1861
+ .description("Check agent_jobs status (accepts a full or short job id)")
1831
1862
  .action(async function (id) {
1832
1863
  try {
1833
1864
  const r = await call("agents", "job_status", { job_id: id }, ctxFrom(this));