@audienti/cli 0.1.69 → 0.1.73

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,36 @@ All notable changes to the Audienti CLI are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ### Added
8
+
9
+ - Add Motion-owned discovery signal tracking to `motions show` and the `motions signals` command, including attribution holds, source counts, and retained Agent provenance.
10
+
11
+ ## [0.1.73] - 2026-09-26
12
+
13
+ ### Added
14
+
15
+ - Add the account-scoped `motions signals` command for inspecting Motion-owned Topic and profile signals.
16
+
17
+ ## [0.1.72] - 2026-09-26
18
+
19
+ ### Added
20
+
21
+ - Add `social-cookies sync-messages` to request account-scoped email syncs with folder and explicit-retry controls, while printing the server's durable sync-slot status.
22
+
23
+ ## [0.1.71] - 2026-09-24
24
+
25
+ ### Changed
26
+
27
+ - Motion updates now honor the server's durable first-discovery Approach lock: edits remain available before the first accepted discovery launch and are rejected after the lock is set.
28
+
29
+ - Prospect replan API responses now use the canonical Planner contract for admitted memberships.
30
+
31
+ ## [0.1.70] - 2026-09-18
32
+
33
+ ### Added
34
+
35
+ - Automation-controls payloads now report `follow_autopilot_enabled` and `withdraw_connection_autopilot_enabled`, and `network-ops automation-controls` renders both as `follow` and `withdraw invitations` rows. Both default to enabled; set either to `false` to disable that action.
36
+
7
37
  ## [0.1.69] - 2026-09-17
8
38
 
9
39
  ### Added
package/README.md CHANGED
@@ -161,6 +161,7 @@ audienti content programs
161
161
  audienti content plan <cprg_id>
162
162
  audienti content approve <cpwi_id>
163
163
  audienti content comments
164
+ audienti social-cookies sync-messages <scok_id> [--folder <folder>] [--retry] --json
164
165
  audienti prospects show <prsp_id> --json
165
166
  audienti prospects list --profiles
166
167
  audienti prospects list --assigned-user unassigned
@@ -418,6 +419,12 @@ configuration, current outstanding inventory, any inventory blocker, and current
418
419
  invitation capacity calculated by the server. A `null` weekly quota means
419
420
  unlimited.
420
421
 
422
+ For an email social cookie, `social-cookies sync-messages` requests the shared
423
+ account-scoped cookie/folder sync slot and prints the server's durable status.
424
+ Pass `--folder` to select a provider folder and `--retry` only when an explicit
425
+ retry is intended. The command does not call a provider directly; `--json`
426
+ returns the accepted request and `sync_states` payload unchanged.
427
+
421
428
  Use `users automation` to inspect or change one account user's LinkedIn safety
422
429
  policy without changing the saved account selection:
423
430
 
@@ -435,6 +442,11 @@ omitted controls, returns the before and proposed/actual after states, and
435
442
  records an audit event only for an applied update. `--json` prints the server
436
443
  payload unchanged.
437
444
 
445
+ Follow (including unfollow) and invitation withdrawal are enabled by default. Set
446
+ `follow_autopilot_enabled` or `withdraw_connection_autopilot_enabled` to `false`
447
+ to disable that action. These preferences still respect automatic sending and
448
+ other execution limits; follows also require visibility automation.
449
+
438
450
  An `automation-controls.json` warm-up payload can use every automation gate,
439
451
  independent action limits, an aggregate visibility limit, and a weekly ramp:
440
452
 
@@ -443,6 +455,8 @@ independent action limits, an aggregate visibility limit, and a weekly ramp:
443
455
  "automation_controls": {
444
456
  "automatic_sending_enabled": false,
445
457
  "visibility_operations_autopilot_enabled": true,
458
+ "follow_autopilot_enabled": true,
459
+ "withdraw_connection_autopilot_enabled": true,
446
460
  "post_comment_autopilot_enabled": false,
447
461
  "connection_request_autopilot_enabled": false,
448
462
  "inmail_autopilot_enabled": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audienti/cli",
3
- "version": "0.1.69",
3
+ "version": "0.1.73",
4
4
  "description": "Agent-first command-line client for Audienti.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -122,6 +122,7 @@ audienti users activity me --window 7d --json
122
122
  audienti users automation show <account_user_id|me> --platform linkedin --json --account <acct_id>
123
123
  audienti users automation update <account_user_id|me> --payload automation-controls.json --json --account <acct_id>
124
124
  audienti users automation update <account_user_id|me> --payload automation-controls.json --apply --json --account <acct_id>
125
+ audienti social-cookies sync-messages <scok_id> [--folder <folder>] [--retry] --json
125
126
  audienti prospects import-batch --file prospects.csv --motion <motn_id> --assigned-user me --json
126
127
  audienti lists create --name "Target list" --json
127
128
  audienti lists routing-rules <list_id> list --json
package/src/api-client.js CHANGED
@@ -66,6 +66,13 @@ export class AudientiClient {
66
66
  return this.requestJson(accountPath(accountId, ["social_cookies"], query));
67
67
  }
68
68
 
69
+ syncSocialCookieMessages(accountId, socialCookieId, body = {}) {
70
+ return this.requestJson(accountPath(accountId, ["social_cookies", socialCookieId, "sync_messages"]), {
71
+ method: "POST",
72
+ body
73
+ });
74
+ }
75
+
69
76
  userActivity(accountId, userId, query = {}) {
70
77
  return this.requestJson(accountPath(accountId, ["operations", "users", userId, "activity"], query));
71
78
  }
@@ -339,6 +346,10 @@ export class AudientiClient {
339
346
  return this.requestJson(accountPath(accountId, ["motions", motionId]));
340
347
  }
341
348
 
349
+ motionSignals(accountId, motionId) {
350
+ return this.requestJson(accountPath(accountId, ["motions", motionId, "signals"]));
351
+ }
352
+
342
353
  createMotion(accountId, body) {
343
354
  return this.requestJson(accountPath(accountId, ["motions"]), {
344
355
  method: "POST",
package/src/cli.js CHANGED
@@ -176,6 +176,7 @@ const TOOLS_LINKEDIN_REVIEW_USAGE = "Usage: audienti tools linkedin-review --url
176
176
  const TOOLS_LINKEDIN_REVIEW_REPORTS_USAGE = "Usage: audienti tools linkedin-review reports [--limit <n>] [--json] [--account <acct_id>]";
177
177
  const TOOLS_LINKEDIN_REVIEW_SHOW_USAGE = "Usage: audienti tools linkedin-review show <rprt_id> [--json] [--account <acct_id>]";
178
178
  const TOOLS_LINKEDIN_REVIEW_STATUS_USAGE = "Usage: audienti tools linkedin-review status <rprt_id> [--json] [--account <acct_id>]";
179
+ const SOCIAL_COOKIES_SYNC_MESSAGES_USAGE = "Usage: audienti social-cookies sync-messages <scok_id> [--folder <folder>] [--retry] [--json] [--account <acct_id>]";
179
180
  const COHORT_STAGE_ORDER = [
180
181
  "identified",
181
182
  "pre_connect",
@@ -269,6 +270,7 @@ async function dispatch(argv, context) {
269
270
  if (normalizedResource === "users" && action === "activity") return usersActivity(rest, context, { accountOverride });
270
271
  if (normalizedResource === "users" && action === "automation") return usersAutomation(rest, context, { accountOverride });
271
272
  if (normalizedResource === "setup" && action === "play" && rest[0] === "preflight") return setupPlayPreflight(rest.slice(1), context, { accountOverride });
273
+ if (normalizedResource === "social-cookies" && action === "sync-messages") return socialCookiesSyncMessages(rest, context, { accountOverride });
272
274
  if (normalizedResource === "offers" && action === "list") return offersList(rest, context, { accountOverride });
273
275
  if (normalizedResource === "offers" && action === "show") return offersShow(rest, context, { accountOverride });
274
276
  if (normalizedResource === "offers" && action === "create") return offersCreate(rest, context, { accountOverride });
@@ -311,6 +313,7 @@ async function dispatch(argv, context) {
311
313
  if (normalizedResource === "lists" && ["routing-rules", "rules"].includes(action)) return listsRoutingRules(rest, context, { accountOverride });
312
314
  if (normalizedResource === "motions" && action === "list") return motionsList(rest, context, { accountOverride });
313
315
  if (normalizedResource === "motions" && action === "show") return motionsShow(rest, context, { accountOverride });
316
+ if (normalizedResource === "motions" && action === "signals") return motionsSignals(rest, context, { accountOverride });
314
317
  if (normalizedResource === "motions" && action === "status") return motionsStatus(rest, context, { accountOverride });
315
318
  if (normalizedResource === "motions" && ["abm-companies", "company-filters"].includes(action)) return motionsAbmCompanies(rest, context, { accountOverride });
316
319
  if (normalizedResource === "motions" && action === "analytics") return motionsAnalytics(rest, context, { accountOverride });
@@ -479,6 +482,7 @@ function normalizeResource(resource) {
479
482
  if (resource === "principals") return "users";
480
483
  if (resource === "writers") return "writer";
481
484
  if (resource === "company_rules" || resource === "company-rules") return "company-rules";
485
+ if (resource === "social_cookie" || resource === "social_cookies") return "social-cookies";
482
486
  return resource === "plays" ? "motions" : resource;
483
487
  }
484
488
 
@@ -1033,6 +1037,26 @@ async function setupPlayPreflight(args, context, { accountOverride } = {}) {
1033
1037
  renderSetupPlayPreflight(payload, context);
1034
1038
  }
1035
1039
 
1040
+ async function socialCookiesSyncMessages(args, context, { accountOverride } = {}) {
1041
+ const { values, positionals } = parseCommandArgs(args, {
1042
+ ...jsonOptions(),
1043
+ folder: { type: "string" },
1044
+ retry: { type: "boolean" }
1045
+ });
1046
+ if (positionals.length !== 1 || (values.folder !== undefined && !String(values.folder).trim())) {
1047
+ throw new CommandError(SOCIAL_COOKIES_SYNC_MESSAGES_USAGE);
1048
+ }
1049
+
1050
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
1051
+ const payload = await client.syncSocialCookieMessages(accountId, positionals[0], compactObject({
1052
+ folder: values.folder,
1053
+ retry: values.retry ? true : undefined
1054
+ }));
1055
+ if (values.json) return writeJson(context.stdout, payload);
1056
+
1057
+ renderSocialCookieSync(payload, context);
1058
+ }
1059
+
1036
1060
  async function offersList(args, context, { accountOverride } = {}) {
1037
1061
  const { values, positionals } = parseCommandArgs(args, jsonOptions());
1038
1062
  if (positionals.length > 0) throw new CommandError("Usage: audienti offers list [--json] [--account <acct_id>]");
@@ -1774,6 +1798,17 @@ async function motionsShow(args, context, { accountOverride } = {}) {
1774
1798
  renderMotion(motion, context);
1775
1799
  }
1776
1800
 
1801
+ async function motionsSignals(args, context, { accountOverride } = {}) {
1802
+ const { values, positionals } = parseCommandArgs(args, jsonOptions());
1803
+ if (positionals.length !== 1) throw new CommandError("Usage: audienti motions signals <motn_id> [--json] [--account <acct_id>]");
1804
+
1805
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
1806
+ const payload = await client.motionSignals(accountId, positionals[0]);
1807
+ if (values.json) return writeJson(context.stdout, payload);
1808
+
1809
+ renderMotionDiscoverySignals(payload, context);
1810
+ }
1811
+
1777
1812
  async function motionsStatus(args, context, { accountOverride } = {}) {
1778
1813
  const { values, positionals } = parseCommandArgs(args, jsonOptions());
1779
1814
  if (positionals.length !== 1) throw new CommandError("Usage: audienti motions status <motn_id> [--json] [--account <acct_id>]");
@@ -5366,6 +5401,8 @@ function renderUserAutomationControls(snapshot, context) {
5366
5401
  const entries = [
5367
5402
  ["automatic sending", controls.automatic_sending_enabled],
5368
5403
  ["visibility operations", controls.visibility_operations_autopilot_enabled],
5404
+ ["follow", controls.follow_autopilot_enabled],
5405
+ ["withdraw invitations", controls.withdraw_connection_autopilot_enabled],
5369
5406
  ["risk cooldown", snapshot?.risk_cooldown_enabled]
5370
5407
  ].filter(([, enabled]) => enabled !== undefined);
5371
5408
  if (entries.length === 0) return;
@@ -5439,6 +5476,30 @@ function renderSetupPlayPreflight(payload, context) {
5439
5476
  }
5440
5477
  }
5441
5478
 
5479
+ function renderSocialCookieSync(payload, context) {
5480
+ const requestStatus = payload?.requested ? "accepted" : "not requested";
5481
+ const coalesced = payload?.coalesced ? " (coalesced)" : "";
5482
+ writeLine(context.stdout, `Email sync: ${requestStatus}${coalesced} for ${display(payload?.social_cookie_id)}`);
5483
+ if (payload?.reason) writeLine(context.stdout, `Reason: ${payload.reason}`);
5484
+
5485
+ const states = Array.isArray(payload?.sync_states) ? payload.sync_states : [];
5486
+ if (states.length === 0) return writeLine(context.stdout, "No durable sync state returned.");
5487
+
5488
+ writeLine(context.stdout, "FOLDER\tSTATUS\tGENERATION\tATTEMPTS\tDUE\tLAST SUCCESS\tLAST ERROR\tSYNCED THROUGH");
5489
+ for (const state of states) {
5490
+ writeLine(context.stdout, [
5491
+ display(state?.canonical_folder),
5492
+ display(state?.status),
5493
+ display(state?.generation, "0"),
5494
+ display(state?.attempts, "0"),
5495
+ display(state?.due_at),
5496
+ display(state?.last_success_at),
5497
+ display(state?.last_error_code),
5498
+ display(state?.last_synced_through_at)
5499
+ ].join("\t"));
5500
+ }
5501
+ }
5502
+
5442
5503
  function renderSetupLinkedInCapabilities(capabilities, context) {
5443
5504
  const storedBoolean = (value) => value === true ? "yes" : value === false ? "no" : "unknown";
5444
5505
  writeLine(
@@ -5831,6 +5892,7 @@ function renderMotion(motion, context) {
5831
5892
  if (Array.isArray(motion?.inbound_channels)) writeLine(context.stdout, `Inbound channels: ${display(motion.inbound_channels.join(", "), "-")}`);
5832
5893
  renderMotionLopaProfiles(motion?.lopa_profiles, context);
5833
5894
  renderMotionSignalRows(motion?.signal_rows, context);
5895
+ renderMotionDiscoverySignals(motion?.discovery_signals, context);
5834
5896
  renderMotionAbmCompanies(motion, context, { showEmpty: false });
5835
5897
  if (Array.isArray(motion?.play_tags)) writeLine(context.stdout, `Tags: ${display(motion.play_tags.join(", "), "-")}`);
5836
5898
  if (motion?.principal_account_user?.id) {
@@ -5865,6 +5927,32 @@ function renderMotionSignalRows(rows, context) {
5865
5927
  }
5866
5928
  }
5867
5929
 
5930
+ function renderMotionDiscoverySignals(payload, context) {
5931
+ if (!payload || typeof payload !== "object") return;
5932
+
5933
+ const rows = Array.isArray(payload?.signals) ? payload.signals : [];
5934
+ const counts = payload?.counts || {};
5935
+ const motionId = payload?.prefix_id ? ` (${display(payload.prefix_id)})` : "";
5936
+
5937
+ writeLine(context.stdout, `Motion-owned discovery signals${motionId}: ${display(counts.total, "0")} total, ${display(counts.actionable, "0")} actionable, ${display(counts.pending, "0")} pending, ${display(counts.held, "0")} held`);
5938
+ if (rows.length === 0) return;
5939
+
5940
+ for (const row of rows) {
5941
+ const provenance = Array.isArray(row.agent_provenance)
5942
+ ? row.agent_provenance.map((entry) => [entry.agent_name, entry.agent_id].filter(Boolean).join(" · ")).filter(Boolean).join(", ")
5943
+ : "";
5944
+ const status = row.actionable ? "actionable" : display(row.status, "pending");
5945
+ const sourceCounts = row.source_counts || {};
5946
+ const detail = [
5947
+ row.canonical_url || row.topic?.slug || row.source_key,
5948
+ `sources=${display(sourceCounts.total, "0")}/${display(sourceCounts.accepted, "0")}/${display(sourceCounts.rejected, "0")}`,
5949
+ provenance ? `agents=${provenance}` : null,
5950
+ !row.actionable && row.motion_attribution_reason ? `reason=${singleLine(row.motion_attribution_reason)}` : null
5951
+ ].filter(Boolean).join("; ");
5952
+ writeLine(context.stdout, `- [${status}] ${display(row.type, "signal")}: ${display(row.label, "unnamed")} (${detail})`);
5953
+ }
5954
+ }
5955
+
5868
5956
  function renderMotionAbmCompanies(payload, context, { showEmpty = true } = {}) {
5869
5957
  const rows = Array.isArray(payload?.abm_companies) ? payload.abm_companies : [];
5870
5958
  if (rows.length === 0) {
@@ -6052,16 +6140,32 @@ function renderProspectReplan(payload, context) {
6052
6140
  const current = payload?.current || {};
6053
6141
  const replanned = payload?.replanned || {};
6054
6142
  const status = replanStatusLabel(payload);
6143
+ const reason = payload?.reason_code || payload?.refresh?.reason;
6055
6144
 
6056
6145
  writeLine(context.stdout, `Replan ${status} for ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)}).`);
6057
6146
  writeLine(context.stdout, `Changed: ${payload?.changed ? "yes" : "no"}`);
6058
- if (payload?.reason_code) writeLine(context.stdout, `Reason: ${payload.reason_code}`);
6147
+ if (reason) writeLine(context.stdout, `Reason: ${reason}`);
6059
6148
  writeLine(context.stdout, `Current: ${formatCoachAction(current.next_action)}`);
6060
6149
  writeLine(context.stdout, `Replanned: ${formatCoachAction(replanned.next_action)}`);
6061
6150
  if (replanned.rationale) writeLine(context.stdout, `Rationale: ${replanned.rationale}`);
6062
6151
  if (replanned.guidance) writeLine(context.stdout, `Guidance: ${replanned.guidance}`);
6063
- if (payload?.status === "dry_run") writeLine(context.stdout, "Run again with --apply to persist this plan.");
6064
- if (payload?.status === "coach_error") writeLine(context.stdout, "The plan was not persisted. Fix the coach error and rerun with --apply.");
6152
+ if (payload?.status === "dry_run") {
6153
+ writeLine(context.stdout, "Run again with --apply to persist this plan.");
6154
+ } else if (payload?.status === "coach_error") {
6155
+ writeLine(context.stdout, "The plan was not persisted. Fix the coach error and rerun with --apply.");
6156
+ } else if (payload?.status === "pending") {
6157
+ writeLine(context.stdout, "The replan request was recorded but is not applied yet. Retry after the refresh reason clears.");
6158
+ } else if (payload?.status === "busy") {
6159
+ writeLine(context.stdout, "Planner execution is busy. No replan was applied; retry later.");
6160
+ } else if (payload?.status === "failed") {
6161
+ writeLine(context.stdout, "The request was recorded, but the Planner could not apply it. Review the reason before retrying.");
6162
+ } else if (payload?.status === "evaluation_error") {
6163
+ writeLine(context.stdout, "Planner evaluation failed. Fix the evaluation error and rerun with --apply.");
6164
+ } else if (payload?.status === "unsupported_plan_version") {
6165
+ writeLine(context.stdout, "This membership uses an unsupported Planner version. Migrate it before retrying.");
6166
+ } else if (payload?.status === "not_applied") {
6167
+ writeLine(context.stdout, "The plan was not persisted. Review the reason before retrying.");
6168
+ }
6065
6169
  }
6066
6170
 
6067
6171
  function renderProspectReenrich(payload, context) {
@@ -6119,12 +6223,24 @@ function formatObjectCounts(value) {
6119
6223
  .join(", ");
6120
6224
  }
6121
6225
 
6226
+ const REPLAN_STATUS_LABELS = Object.freeze({
6227
+ dry_run: "dry run",
6228
+ coach_error: "coach error",
6229
+ not_applied: "not applied",
6230
+ pending: "pending",
6231
+ busy: "busy",
6232
+ failed: "failed",
6233
+ evaluation_error: "evaluation error",
6234
+ unsupported_plan_version: "unsupported plan version"
6235
+ });
6236
+
6122
6237
  function replanStatusLabel(payload) {
6123
- if (payload?.status === "dry_run") return "dry run";
6124
- if (payload?.status === "coach_error") return "coach error";
6125
- if (payload?.status === "not_applied") return "not applied";
6238
+ const rawStatus = payload?.status;
6239
+ if (Object.prototype.hasOwnProperty.call(REPLAN_STATUS_LABELS, rawStatus)) {
6240
+ return REPLAN_STATUS_LABELS[rawStatus];
6241
+ }
6126
6242
 
6127
- return payload?.applied ? "applied" : "dry run";
6243
+ return payload?.applied ? "applied" : "not applied";
6128
6244
  }
6129
6245
 
6130
6246
  function formatCoachAction(nextAction = {}) {
@@ -8303,6 +8419,9 @@ const HELP_TOPICS = new Map([
8303
8419
  " audienti users automation show <account_user_id|me>",
8304
8420
  " audienti users automation update <account_user_id|me> --payload <file.json> [--apply]",
8305
8421
  "",
8422
+ " Email sync",
8423
+ " audienti social-cookies sync-messages <scok_id> [--folder <folder>] [--retry]",
8424
+ "",
8306
8425
  " Motions / plays",
8307
8426
  " audienti motions list",
8308
8427
  " audienti motions show <motn_id>",
@@ -8614,6 +8733,41 @@ const HELP_TOPICS = new Map([
8614
8733
  " acct_id: string Account prefix id, for example acct_abc123"
8615
8734
  ].join("\n")],
8616
8735
 
8736
+ ["social-cookies", [
8737
+ "Usage:",
8738
+ " audienti social-cookies sync-messages <scok_id> [--folder <folder>] [--retry] [--json] [--account <acct_id>]",
8739
+ "",
8740
+ "Status: implemented",
8741
+ "",
8742
+ "Commands:",
8743
+ " audienti social-cookies sync-messages Request the shared durable email sync slot",
8744
+ "",
8745
+ "Run `audienti social-cookies sync-messages help` for the request and output contract."
8746
+ ].join("\n")],
8747
+
8748
+ ["social-cookies sync-messages", [
8749
+ "Usage:",
8750
+ " audienti social-cookies sync-messages <scok_id> [--folder <folder>] [--retry] [--json] [--account <acct_id>]",
8751
+ "",
8752
+ "Status: implemented",
8753
+ "",
8754
+ "Purpose:",
8755
+ " Request one account-scoped email sync through the server's durable cookie/folder slot.",
8756
+ "",
8757
+ "Input shape:",
8758
+ " scok_id: string Social cookie prefix id or numeric id",
8759
+ " folder: string Provider folder; omitted means the server's INBOX default",
8760
+ " retry: flag Explicitly reopen an exhausted or credential-held slot",
8761
+ "",
8762
+ "Output shape:",
8763
+ " requested, coalesced, reason, sync_states Server response and durable slot status",
8764
+ " sync_states Includes status, generation, attempts, due, last error, and watermark",
8765
+ "",
8766
+ "API:",
8767
+ " POST /api/v1/accounts/:account_id/social_cookies/:id/sync_messages.json",
8768
+ " The CLI only requests work; provider traversal remains owned by the server worker."
8769
+ ].join("\n")],
8770
+
8617
8771
  ["accounts list", [
8618
8772
  "Usage:",
8619
8773
  " audienti accounts list [--json] [--account <acct_id>]",
@@ -9772,6 +9926,7 @@ const HELP_TOPICS = new Map([
9772
9926
  "Usage:",
9773
9927
  " audienti motions list [--tag <tag>] [--json]",
9774
9928
  " audienti motions show <motn_id> [--json]",
9929
+ " audienti motions signals <motn_id> [--json]",
9775
9930
  " audienti motions status <motn_id> [--json]",
9776
9931
  " audienti motions run-discovery <motn_id> [--target-count <n>] [--json]",
9777
9932
  " audienti motions quick-start --url <company_url> [--confirm] [--wait] [--json]",
@@ -9867,12 +10022,30 @@ const HELP_TOPICS = new Map([
9867
10022
  " inbound_channels: enabled inbound collectors for inbound motions",
9868
10023
  " lopa_profiles[]: tracked LinkedIn profile rows for LOPA motions",
9869
10024
  " signal_rows[]: outbound signal configuration rows",
10025
+ " discovery_signals: Motion-owned Topic/profile signals with attribution state and Agent provenance",
9870
10026
  " abm_companies[]: motion-scoped positive company filter rows",
9871
10027
  "",
9872
10028
  "API:",
9873
10029
  " GET /api/v1/accounts/:account_id/motions/:id.json"
9874
10030
  ].join("\n")],
9875
10031
 
10032
+ ["motions signals", [
10033
+ "Usage:",
10034
+ " audienti motions signals <motn_id> [--json] [--account <acct_id>]",
10035
+ "",
10036
+ "Status: implemented",
10037
+ "",
10038
+ "Purpose:",
10039
+ " Read the Topic and tracked-profile signals owned by one Motion.",
10040
+ " Actionable rows have exact Motion attribution; pending and held rows remain inspectable with their reason and evidence.",
10041
+ "",
10042
+ "Output:",
10043
+ " Shows attribution state, canonical source URL or Topic, accepted/rejected source counts, and retained Agent provenance.",
10044
+ "",
10045
+ "API:",
10046
+ " GET /api/v1/accounts/:account_id/motions/:id/signals.json"
10047
+ ].join("\n")],
10048
+
9876
10049
  ["motions abm-companies", [
9877
10050
  "Usage:",
9878
10051
  ` ${MOTIONS_ABM_COMPANIES_LIST_USAGE.slice("Usage: ".length)}`,