@audienti/cli 0.1.36 → 0.1.38

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,22 @@ All notable changes to the Audienti CLI are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.38] - 2026-08-24
8
+
9
+ ### Added
10
+
11
+ - Add `audienti tools humanize --file <path>` with optional tone and language controls, plain-text output for shell redirection, and normalized JSON output through the authenticated Audienti API.
12
+
13
+ ## [0.1.37] - 2026-08-23
14
+
15
+ ### Added
16
+
17
+ - Add motion start/end scheduling and maximum-company discovery-cap configuration to motion API readback and CLI create/update/show workflows.
18
+
19
+ ### Changed
20
+
21
+ - Show conversion totals, stage SLA, and oldest stage age in the default `audienti analytics stages` output so it matches the dashboard read model without requiring `--json`.
22
+
7
23
  ## [0.1.36] - 2026-08-22
8
24
 
9
25
  ### Added
package/README.md CHANGED
@@ -143,6 +143,7 @@ audienti motions quick-start --url https://example.com --wait --confirm
143
143
  audienti motions abm-companies <motn_id> add --file abm-domains.txt
144
144
  audienti motions abm-companies <motn_id> list
145
145
  audienti motions update <motn_id> --status paused
146
+ audienti motions update <motn_id> --start-date 2026-09-01 --end-date 2026-09-30 --maximum-company-count 25
146
147
  audienti motions update <motn_id> --own-post-engagement true
147
148
  audienti motions update <motn_id> --payload motion-signals.json
148
149
  audienti motions activate <motn_id>
@@ -173,12 +174,22 @@ audienti analytics users --user me --window 30d
173
174
  audienti analytics visibility --window 24h --user me
174
175
  audienti analytics content --window week
175
176
  audienti tools list
177
+ audienti tools humanize --file draft.txt --tone professional --language English
176
178
  audienti tools linkedin-review --url https://www.linkedin.com/in/example --icp <icp_id>
177
179
  audienti tools linkedin-review reports
178
180
  audienti tools linkedin-review show <rprt_id>
179
181
  audienti tools linkedin-review status <rprt_id>
180
182
  ```
181
183
 
184
+ To humanize arbitrary text without exposing the underlying provider key, pass a
185
+ UTF-8 file. Plain output contains only the transformed text, so it can be
186
+ redirected directly to another file:
187
+
188
+ ```bash
189
+ audienti tools humanize --file draft.txt --tone professional > revised.txt
190
+ audienti tools humanize --file draft.txt --language English --json
191
+ ```
192
+
182
193
  To let an agent or operator check whether the local CLI is behind the latest
183
194
  published package:
184
195
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audienti/cli",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "Agent-first command-line client for Audienti.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -110,14 +110,17 @@ audienti motions quick-start --url https://example.com --wait --confirm --json
110
110
  audienti motions abm-companies <motn_id> add --file abm-domains.txt --json
111
111
  audienti motions abm-companies <motn_id> list --json
112
112
  audienti motions update <motn_id> --status paused --json
113
+ audienti motions update <motn_id> --start-date 2026-09-01 --end-date 2026-09-30 --maximum-company-count 25 --json
113
114
  audienti motions activate <motn_id> --json
114
115
  audienti motions delete <motn_id> --confirm yes --json
115
116
  audienti operator next --json
116
117
  audienti operator next --plan
117
118
  audienti analytics prospects --window 24h --json
119
+ audienti analytics stages --window 30d
118
120
  audienti analytics visibility --window 24h --user me --json
119
121
  audienti analytics content --window week --json
120
122
  audienti tools list --json
123
+ audienti tools humanize --file draft.txt --tone professional --json
121
124
  audienti tools linkedin-review --url https://www.linkedin.com/in/example --icp <icp_id> --json
122
125
  audienti tools linkedin-review reports --json
123
126
  audienti tools linkedin-review show <rprt_id> --json
@@ -135,6 +138,13 @@ condition and action data as the list UI. Inspect the ordered rules first, use
135
138
  as an asynchronous relaunch: it queues the existing routing job and does not
136
139
  mean every list member has finished routing.
137
140
 
141
+ Motion start and end dates are optional lifecycle controls. A due start can
142
+ activate a configured preparing or paused motion; an end date is the final
143
+ active day and pauses the motion afterward. `--maximum-company-count` caps
144
+ durable company admissions only: research and people discovery for admitted
145
+ companies, prospect intake, and automation continue. Use `none` to clear any
146
+ of these settings.
147
+
138
148
  `audienti writer test-run <prsp_id>` starts a report-backed writing session and
139
149
  builds the campaign timeline without drafting every message. The printed
140
150
  `Report: rprt_...` id is the session handle. Pass `--report <rprt_id>` when
package/src/api-client.js CHANGED
@@ -614,6 +614,13 @@ export class AudientiClient {
614
614
  return this.requestJson(accountPath(accountId, ["tools", "linkedin-review", "reports", reportId]));
615
615
  }
616
616
 
617
+ humanizeText(accountId, body) {
618
+ return this.requestJson(accountPath(accountId, ["tools", "humanize"]), {
619
+ method: "POST",
620
+ body: { humanization: body }
621
+ });
622
+ }
623
+
617
624
  operatorQueue(accountId, query = {}) {
618
625
  return this.requestJson(accountPath(accountId, ["operator"], query));
619
626
  }
package/src/cli.js CHANGED
@@ -72,7 +72,7 @@ const OFFERS_DELETE_USAGE = "Usage: audienti offers delete <offr_id> --confirm <
72
72
  const WRITER_TEST_RUN_USAGE = "Usage: audienti writer test-run <prsp_id> [--json] [--mode <plan|report|step>] [--branch <both|no-accept|accepted>] [--step <step_key|row_number>] [--report <rprt_id>] [--no-wait] [--timeout-seconds <n>] [--poll-interval-seconds <n>] [--account <acct_id>]";
73
73
  const WRITER_TEST_RUN_SHOW_USAGE = "Usage: audienti writer test-run show <prsp_id> <rprt_id> [--json] [--account <acct_id>]";
74
74
  const MOTIONS_ANALYTICS_USAGE = "Usage: audienti motions analytics <motn_id> [--window 30d] [--json] [--account <acct_id>]";
75
- const MOTIONS_UPDATE_USAGE = "Usage: audienti motions update <motn_id> ([--status <draft|preparing|active|paused|archived>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>] | --payload <file.json>) [--json] [--account <acct_id>]";
75
+ const MOTIONS_UPDATE_USAGE = "Usage: audienti motions update <motn_id> ([--status <draft|preparing|active|paused|archived>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>] [--start-date <YYYY-MM-DD|none>] [--end-date <YYYY-MM-DD|none>] [--maximum-company-count <n|none>] | --payload <file.json>) [--json] [--account <acct_id>]";
76
76
  const CONTENT_PROGRAMS_USAGE = "Usage: audienti content programs [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
77
77
  const CONTENT_PLAN_USAGE = "Usage: audienti content plan <cprg_id> [--week <n>] [--due] [--json] [--account <acct_id>]";
78
78
  const CONTENT_SHOW_USAGE = "Usage: audienti content show <cpwi_id> [--json] [--account <acct_id>]";
@@ -112,6 +112,7 @@ const ANALYTICS_DASHBOARD_USAGE = "Usage: audienti analytics dashboard [--cohort
112
112
  const ANALYTICS_STAGES_USAGE = "Usage: audienti analytics stages [--interval weekly|monthly] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--list <list_id>] [--offer <offr_id>] [--icp <icp_id>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
113
113
  const ANALYTICS_COHORT_LIST_USAGE = "Usage: audienti analytics cohorts create-list --name <text> --start YYYY-MM-DD --end YYYY-MM-DD [--event connection_request_sent] [--user <account_user_id|email|name|me>] [--note-mode <any|with_note|blank>] [--motion <motn_id>] [--offer <offr_id>] [--icp <icp_id>] [--play-tag <tag>] [--json] [--account <acct_id>]";
114
114
  const TOOLS_LIST_USAGE = "Usage: audienti tools list [--json]";
115
+ const TOOLS_HUMANIZE_USAGE = "Usage: audienti tools humanize --file <path> [--tone <professional|academic|blog|casual|creative|scientific|technical>] [--language <language>] [--json] [--account <acct_id>]";
115
116
  const TOOLS_LINKEDIN_REVIEW_USAGE = "Usage: audienti tools linkedin-review --url <linkedin_url> [--icp <icp_id>] [--json] [--account <acct_id>]";
116
117
  const TOOLS_LINKEDIN_REVIEW_REPORTS_USAGE = "Usage: audienti tools linkedin-review reports [--limit <n>] [--json] [--account <acct_id>]";
117
118
  const TOOLS_LINKEDIN_REVIEW_SHOW_USAGE = "Usage: audienti tools linkedin-review show <rprt_id> [--json] [--account <acct_id>]";
@@ -299,6 +300,7 @@ async function dispatch(argv, context) {
299
300
  if (normalizedResource === "writer" && action === "test-run") return writerTestRun(rest, context, { accountOverride });
300
301
  if (normalizedResource === "tools" && action === "list") return toolsList(rest, context);
301
302
  if (normalizedResource === "tools" && action === "get") return toolsGet(rest, context, { accountOverride });
303
+ if (normalizedResource === "tools" && action === "humanize") return toolsHumanize(rest, context, { accountOverride });
302
304
  if (normalizedResource === "tools" && action === "linkedin-review") return toolsLinkedinReview(rest, context, { accountOverride });
303
305
  if (normalizedResource === "operator" && action === "failed-drafts") return operatorFailedDrafts(rest, context, { accountOverride });
304
306
  if (normalizedResource === "operator" && action === "queue") return operatorQueue(rest, context, { accountOverride });
@@ -1881,7 +1883,10 @@ async function motionsUpdate(args, context, { accountOverride } = {}) {
1881
1883
  payload: { type: "string" },
1882
1884
  status: { type: "string" },
1883
1885
  tags: { type: "string" },
1884
- "own-post-engagement": { type: "string" }
1886
+ "own-post-engagement": { type: "string" },
1887
+ "start-date": { type: "string" },
1888
+ "end-date": { type: "string" },
1889
+ "maximum-company-count": { type: "string" }
1885
1890
  });
1886
1891
  const hasUpdateField = values.payload || motionSimpleFieldsPresent(values);
1887
1892
  if (positionals.length !== 1 || !hasUpdateField) {
@@ -1899,7 +1904,7 @@ async function motionsUpdate(args, context, { accountOverride } = {}) {
1899
1904
  async function motionUpdatePayload(values) {
1900
1905
  if (values.payload) {
1901
1906
  if (motionSimpleFieldsPresent(values)) {
1902
- throw new CommandError("Choose one motion input mode: either --payload <file.json> or the simple --status/--tags/--own-post-engagement flags.");
1907
+ throw new CommandError("Choose one motion input mode: either --payload <file.json> or the simple motion update flags.");
1903
1908
  }
1904
1909
 
1905
1910
  const payload = await readJsonPayload(values.payload);
@@ -1907,15 +1912,54 @@ async function motionUpdatePayload(values) {
1907
1912
  return payload;
1908
1913
  }
1909
1914
 
1910
- return compactObject({
1915
+ const payload = compactObject({
1911
1916
  status: normalizeMotionStatus(values.status),
1912
1917
  play_tags: values.tags !== undefined ? tagList(values.tags) : undefined,
1913
1918
  own_post_engagement: values["own-post-engagement"] !== undefined ? parseBooleanString(values["own-post-engagement"], "--own-post-engagement") : undefined
1914
1919
  });
1920
+ const nullableSettings = {
1921
+ starts_on: normalizeMotionDate(values["start-date"], "--start-date"),
1922
+ ends_on: normalizeMotionDate(values["end-date"], "--end-date"),
1923
+ maximum_company_count: normalizeMotionMaximumCompanyCount(values["maximum-company-count"])
1924
+ };
1925
+ for (const [key, value] of Object.entries(nullableSettings)) {
1926
+ if (value !== undefined) payload[key] = value;
1927
+ }
1928
+
1929
+ return payload;
1915
1930
  }
1916
1931
 
1917
1932
  function motionSimpleFieldsPresent(values) {
1918
- return Boolean(values.status) || values.tags !== undefined || values["own-post-engagement"] !== undefined;
1933
+ return Boolean(values.status) ||
1934
+ values.tags !== undefined ||
1935
+ values["own-post-engagement"] !== undefined ||
1936
+ values["start-date"] !== undefined ||
1937
+ values["end-date"] !== undefined ||
1938
+ values["maximum-company-count"] !== undefined;
1939
+ }
1940
+
1941
+ function normalizeMotionDate(value, flagName) {
1942
+ if (value === undefined) return undefined;
1943
+
1944
+ const normalized = String(value || "").trim().toLowerCase();
1945
+ if (normalized === "none") return null;
1946
+ const match = normalized.match(/^(\d{4})-(\d{2})-(\d{2})$/);
1947
+ if (!match) throw new CommandError(`${flagName} must be YYYY-MM-DD or none.`);
1948
+
1949
+ const [, year, month, day] = match.map(Number);
1950
+ const parsed = new Date(Date.UTC(year, month - 1, day));
1951
+ if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== day) {
1952
+ throw new CommandError(`${flagName} must be YYYY-MM-DD or none.`);
1953
+ }
1954
+
1955
+ return normalized;
1956
+ }
1957
+
1958
+ function normalizeMotionMaximumCompanyCount(value) {
1959
+ if (value === undefined) return undefined;
1960
+ if (String(value || "").trim().toLowerCase() === "none") return null;
1961
+
1962
+ return normalizeOptionalPositiveInteger(value, "--maximum-company-count");
1919
1963
  }
1920
1964
 
1921
1965
  function validateMotionSignalRows(payload) {
@@ -2935,6 +2979,36 @@ async function toolsList(args, context) {
2935
2979
  renderToolsList(payload.tools, context);
2936
2980
  }
2937
2981
 
2982
+ async function toolsHumanize(args, context, { accountOverride } = {}) {
2983
+ const { values, positionals } = parseCommandArgs(args, {
2984
+ ...jsonOptions(),
2985
+ file: { type: "string" },
2986
+ tone: { type: "string" },
2987
+ language: { type: "string" }
2988
+ });
2989
+
2990
+ if (positionals.length > 0 || !values.file) {
2991
+ throw new CommandError(TOOLS_HUMANIZE_USAGE);
2992
+ }
2993
+
2994
+ const text = await readHumanizerFile(values.file);
2995
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
2996
+ const payload = await client.humanizeText(accountId, {
2997
+ text,
2998
+ tone: values.tone,
2999
+ language: values.language
3000
+ });
3001
+
3002
+ if (values.json) return writeJson(context.stdout, payload);
3003
+
3004
+ const humanizedText = String(payload?.humanized_text || "");
3005
+ if (!humanizedText.trim()) {
3006
+ throw new CommandError("The humanizer response did not include humanized_text.");
3007
+ }
3008
+ context.stdout.write(humanizedText);
3009
+ if (!humanizedText.endsWith("\n")) context.stdout.write("\n");
3010
+ }
3011
+
2938
3012
  async function toolsLinkedinReviewReports(args, context, { accountOverride } = {}) {
2939
3013
  const { values, positionals } = parseCommandArgs(args, {
2940
3014
  ...jsonOptions(),
@@ -4086,6 +4160,26 @@ async function readJsonPayload(filePath) {
4086
4160
  }
4087
4161
  }
4088
4162
 
4163
+ async function readHumanizerFile(filePath) {
4164
+ let bytes;
4165
+ try {
4166
+ bytes = await readFile(filePath);
4167
+ } catch (error) {
4168
+ throw new CommandError(`Could not read humanizer file ${filePath}: ${error.message}`);
4169
+ }
4170
+
4171
+ let contents;
4172
+ try {
4173
+ contents = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
4174
+ } catch {
4175
+ throw new CommandError(`Humanizer file ${filePath} must be valid UTF-8 text.`);
4176
+ }
4177
+
4178
+ if (!contents.trim()) throw new CommandError("Humanizer file cannot be blank.");
4179
+
4180
+ return contents;
4181
+ }
4182
+
4089
4183
  async function readProspectImportBatchFile(filePath) {
4090
4184
  let contents;
4091
4185
  try {
@@ -4588,6 +4682,9 @@ function renderMotion(motion, context) {
4588
4682
  writeLine(context.stdout, `Motion: ${display(motion?.name)} (${display(motion?.prefix_id)})`);
4589
4683
  writeLine(context.stdout, `Status: ${display(motion?.status)}`);
4590
4684
  writeLine(context.stdout, `Kind: ${display(motion?.kind)}`);
4685
+ writeLine(context.stdout, `Start date: ${display(motion?.starts_on, "not set")}`);
4686
+ writeLine(context.stdout, `End date: ${display(motion?.ends_on, "not set")}`);
4687
+ writeLine(context.stdout, `Maximum companies: ${display(motion?.maximum_company_count, "not set")}`);
4591
4688
  renderExecutableConfiguration(motion?.executable_configuration, context);
4592
4689
  if (motion?.offer?.name) writeLine(context.stdout, `Offer: ${motion.offer.name} (${display(motion.offer.prefix_id)})`);
4593
4690
  if (motion?.icp?.name) writeLine(context.stdout, `ICP: ${motion.icp.name} (${display(motion.icp.prefix_id)})`);
@@ -5486,6 +5583,13 @@ function availableTools() {
5486
5583
  reports_command: null,
5487
5584
  status_command: null
5488
5585
  },
5586
+ {
5587
+ id: "humanize",
5588
+ command: "audienti tools humanize --file <path> [--tone <tone>] [--language <language>]",
5589
+ description: "Humanize arbitrary text from a UTF-8 file and print the transformed result.",
5590
+ reports_command: null,
5591
+ status_command: null
5592
+ },
5489
5593
  {
5490
5594
  id: "linkedin-review",
5491
5595
  command: "audienti tools linkedin-review --url <linkedin_url> [--icp <icp_id>]",
@@ -5780,6 +5884,7 @@ function writeStageConversionTable(conversionGrid, context) {
5780
5884
  const rows = Array.isArray(conversionGrid?.rows) ? conversionGrid.rows : [];
5781
5885
  const definitions = Array.isArray(conversionGrid?.stage_definitions) ? conversionGrid.stage_definitions : [];
5782
5886
  const columns = definitions.filter((definition) => definition?.key);
5887
+ const totalValues = conversionGrid?.total_values || {};
5783
5888
 
5784
5889
  writeLine(context.stdout, "");
5785
5890
  writeLine(context.stdout, display(conversionGrid?.window_description, "Conversion cohorts"));
@@ -5790,6 +5895,12 @@ function writeStageConversionTable(conversionGrid, context) {
5790
5895
  display(row?.label),
5791
5896
  ...columns.map((column) => stageMetricValueLabel(row?.values?.[column.key]))
5792
5897
  ]);
5898
+ if (Object.keys(totalValues).length > 0) {
5899
+ tableRows.push([
5900
+ "TOTAL",
5901
+ ...columns.map((column) => stageMetricValueLabel(totalValues[column.key]))
5902
+ ]);
5903
+ }
5793
5904
 
5794
5905
  writeAlignedTable(context, headers, tableRows);
5795
5906
  }
@@ -5807,20 +5918,22 @@ function writeStageAgingTable(stageAging, context) {
5807
5918
  );
5808
5919
  writeAlignedTable(
5809
5920
  context,
5810
- ["STAGE", "CURRENT", "DUE SOON", "OVERDUE", "OVERDUE %", "MED AGE", "OLDEST IDLE"],
5921
+ ["STAGE", "SLA", "CURRENT", "DUE SOON", "OVERDUE", "OVERDUE %", "MED AGE", "OLDEST AGE", "OLDEST IDLE"],
5811
5922
  rows.map(stageAgingRow),
5812
- { numericColumns: [false, true, true, true, true, true, true] }
5923
+ { numericColumns: [false, true, true, true, true, true, true, true, true] }
5813
5924
  );
5814
5925
  }
5815
5926
 
5816
5927
  function stageAgingRow(row) {
5817
5928
  return [
5818
5929
  display(row?.label || row?.key),
5930
+ dayCountLabel(row?.due_after_days),
5819
5931
  display(row?.current_count, 0),
5820
5932
  display(row?.due_soon_count, 0),
5821
5933
  display(row?.overdue_count, 0),
5822
5934
  percentageLabel(row?.overdue_rate),
5823
5935
  dayCountLabel(row?.median_stage_age_days),
5936
+ dayCountLabel(row?.oldest_stage_age_days),
5824
5937
  dayCountLabel(row?.oldest_idle_days)
5825
5938
  ];
5826
5939
  }
@@ -6576,7 +6689,7 @@ const HELP_TOPICS = new Map([
6576
6689
  " audienti motions abm-companies <motn_id> list",
6577
6690
  " audienti motions abm-companies <motn_id> add <domain_or_linkedin_url>...",
6578
6691
  " audienti motions create --payload <file.json>",
6579
- " audienti motions update <motn_id> [--status <state>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>]",
6692
+ " audienti motions update <motn_id> [--status <state>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>] [--start-date <date|none>] [--end-date <date|none>] [--maximum-company-count <n|none>]",
6580
6693
  " audienti motions update <motn_id> --payload <file.json>",
6581
6694
  " audienti motions add-tag <motn_id> <tag>",
6582
6695
  " audienti motions remove-tag <motn_id> <tag>",
@@ -6670,6 +6783,7 @@ const HELP_TOPICS = new Map([
6670
6783
  " audienti tools list",
6671
6784
  " audienti tools get email --url <linkedin_url>",
6672
6785
  " audienti tools get phone --url <linkedin_url>",
6786
+ " audienti tools humanize --file <path>",
6673
6787
  " audienti tools linkedin-review --url <linkedin_url> [--icp <icp_id>]",
6674
6788
  " audienti tools linkedin-review reports",
6675
6789
  " audienti tools linkedin-review show <rprt_id>",
@@ -7899,7 +8013,7 @@ const HELP_TOPICS = new Map([
7899
8013
  " audienti motions abm-companies <motn_id> add (<domain_or_linkedin_url>... | --file <txt|json>) [--json]",
7900
8014
  " audienti motions abm-companies <motn_id> remove <row_id> [--json]",
7901
8015
  " audienti motions create --payload <file.json> [--json]",
7902
- " audienti motions update <motn_id> ([--status <draft|preparing|active|paused|archived>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>] | --payload <file.json>) [--json]",
8016
+ ` ${MOTIONS_UPDATE_USAGE.slice("Usage: ".length).replace(" [--account <acct_id>]", "")}`,
7903
8017
  " audienti motions add-tag <motn_id> <tag> [--json]",
7904
8018
  " audienti motions remove-tag <motn_id> <tag> [--json]",
7905
8019
  " audienti motions activate <motn_id> [--json]",
@@ -8177,6 +8291,9 @@ const HELP_TOPICS = new Map([
8177
8291
  " icp_id: icpp_ prefix id | optional",
8178
8292
  " list_id: list_ prefix id | optional",
8179
8293
  " play_tags: [string] | optional",
8294
+ " starts_on: YYYY-MM-DD | null | optional scheduled activation date",
8295
+ " ends_on: YYYY-MM-DD | null | optional final active date",
8296
+ " maximum_company_count: positive integer | null | optional new-company discovery cap",
8180
8297
  " signal_rows: [{ scope: company | person | both, question: string, company_signal_category: string | optional, role_terms: string | optional, posting_language: hiring-only string | optional, topics: string | optional }] | optional for outbound motions",
8181
8298
  " signal_questions: newline-delimited company::, person::, or both:: legacy question text | optional for outbound motions",
8182
8299
  " inbound_channels: [linkedin | reddit] | optional; defaults to [linkedin] for inbound motions",
@@ -8191,6 +8308,9 @@ const HELP_TOPICS = new Map([
8191
8308
  " \"offer_id\": \"offr_abc123\",",
8192
8309
  " \"principal_account_user_id\": 42,",
8193
8310
  " \"list_id\": \"list_abc123\",",
8311
+ " \"starts_on\": \"2026-09-01\",",
8312
+ " \"ends_on\": \"2026-09-30\",",
8313
+ " \"maximum_company_count\": 25,",
8194
8314
  " \"play_tags\": [\"sarit\", \"pj\"]",
8195
8315
  " }",
8196
8316
  "",
@@ -8214,8 +8334,8 @@ const HELP_TOPICS = new Map([
8214
8334
  " name: new motion name",
8215
8335
  "",
8216
8336
  "Behavior:",
8217
- " Copies the motion kind, offer, ICP, principal, premise, approach, targeting profile, suppression policy, secondary roles, and active signal rows.",
8218
- " The clone starts as draft with a new empty backing list.",
8337
+ " Copies the motion kind, offer, ICP, principal, premise, approach, maximum company count, targeting profile, suppression policy, secondary roles, and active signal rows.",
8338
+ " The clone starts as draft with a new empty backing list and no inherited schedule dates.",
8219
8339
  "",
8220
8340
  "API:",
8221
8341
  " POST /api/v1/accounts/:account_id/motions/:id/clone.json",
@@ -8241,10 +8361,14 @@ const HELP_TOPICS = new Map([
8241
8361
  " motn_id: motn_ prefix id",
8242
8362
  " status: draft | preparing | active | paused | archived | optional",
8243
8363
  " tags: comma-separated tag list | optional",
8364
+ " start-date: YYYY-MM-DD | none | optional",
8365
+ " end-date: YYYY-MM-DD | none | optional",
8366
+ " maximum-company-count: positive integer | none | optional",
8244
8367
  " payload: file.json | optional full or partial motion object using the account API shape",
8245
8368
  "",
8246
8369
  "Behavior:",
8247
- " Choose either --payload or simple flags. Updates only the provided fields. Sending --tags replaces the motion's full tag set.",
8370
+ " Choose either --payload or simple flags. Updates only the provided fields. Use none to clear a schedule date or company cap. Sending --tags replaces the motion's full tag set.",
8371
+ " The company cap stops only new company discovery; existing company research, people discovery, prospect intake, and automation continue.",
8248
8372
  " Payload mode supports outbound signal_rows or legacy signal_questions; supplied rows replace the motion's active ready signals.",
8249
8373
  " posting_language is only supported on company-scope hiring signal rows; use topics for person discussion evidence.",
8250
8374
  "",
@@ -9134,6 +9258,7 @@ const HELP_TOPICS = new Map([
9134
9258
  "Usage:",
9135
9259
  " audienti tools list [--json]",
9136
9260
  " audienti tools get <email|phone> --url <linkedin_url> [--json]",
9261
+ " audienti tools humanize --file <path> [--tone <tone>] [--language <language>] [--json]",
9137
9262
  " audienti tools linkedin-review --url <linkedin_url> [--icp <icp_id>] [--json]",
9138
9263
  " audienti tools linkedin-review reports [--limit <n>] [--json]",
9139
9264
  " audienti tools linkedin-review show <rprt_id> [--json]",
@@ -9144,6 +9269,7 @@ const HELP_TOPICS = new Map([
9144
9269
  "Commands:",
9145
9270
  " audienti tools list Show available CLI tools and the report commands they support.",
9146
9271
  " audienti tools get Run a LinkedIn URL through the existing import and contact-enrichment pipeline, then return the first selected email or phone.",
9272
+ " audienti tools humanize Humanize arbitrary UTF-8 text and print the result.",
9147
9273
  " audienti tools linkedin-review Queue a LinkedIn personal profile authority review and ICP-fit positioning blueprint.",
9148
9274
  " audienti tools linkedin-review reports List recent LinkedIn Review reports for the active account.",
9149
9275
  " audienti tools linkedin-review show View the completed report content in the terminal.",
@@ -9190,6 +9316,28 @@ const HELP_TOPICS = new Map([
9190
9316
  " JSON: { kind, url, found, value, import_id, status, ready, prospect, pipeline }"
9191
9317
  ].join("\n")],
9192
9318
 
9319
+ ["tools humanize", [
9320
+ "Usage:",
9321
+ ` ${TOOLS_HUMANIZE_USAGE.slice("Usage: ".length)}`,
9322
+ "",
9323
+ "Status: implemented",
9324
+ "",
9325
+ "Purpose:",
9326
+ " Sends arbitrary UTF-8 text to Audienti's server-side humanizer without exposing the provider key.",
9327
+ "",
9328
+ "Options:",
9329
+ " --file <path> Required UTF-8 text file",
9330
+ " --tone <professional|academic|blog|casual|creative|scientific|technical>",
9331
+ " --language <name> Optional language hint, for example English",
9332
+ "",
9333
+ "Output:",
9334
+ " Plain text: only the humanized text, suitable for redirecting to a file",
9335
+ " JSON: { humanized_text, id, input_words }",
9336
+ "",
9337
+ "API:",
9338
+ " POST /api/v1/accounts/:account_id/tools/humanize.json"
9339
+ ].join("\n")],
9340
+
9193
9341
  ["tools linkedin-review", [
9194
9342
  "Usage:",
9195
9343
  " audienti tools linkedin-review --url <linkedin_url> [--icp <icp_id>] [--json] [--account <acct_id>]",