@audienti/cli 0.1.97 → 0.1.99

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,18 @@ All notable changes to the Audienti CLI are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.99] - 2026-10-05
8
+
9
+ - List user-owned content plans and read scripts with `content plans` and `content plan --report`.
10
+ - Edit, approve, research, draft and generate visuals for a plan piece through the existing production services.
11
+ - Approve an explicit comment reply through the tracked post endpoint with `content post-reply`.
12
+
13
+ ## [0.1.98] - 2026-10-04
14
+
15
+ ### Added
16
+
17
+ - `content track <url>` submits an owned LinkedIn post for tracking. `content posts` lists tracked posts, and `content engagement <cpwi_id>` reads collected comments and reactions.
18
+
7
19
  ## [0.1.97] - 2026-10-04
8
20
 
9
21
  ### Added
package/README.md CHANGED
@@ -185,7 +185,18 @@ audienti motions update <motn_id> --payload motion-signals.json
185
185
  audienti motions activate <motn_id>
186
186
  audienti motions delete <motn_id> --confirm yes
187
187
  audienti content programs
188
+ audienti content track <linkedin_post_url>
189
+ audienti content posts
190
+ audienti content engagement <cpwi_id> --json
188
191
  audienti content plan <cprg_id>
192
+ audienti content plans --user me
193
+ audienti content plan <rprt_id> --report --user me
194
+ audienti content plan-update <rprt_id> --day 1 --payload edits.json
195
+ audienti content plan-approve <rprt_id> --day 1
196
+ audienti content plan-research <rprt_id> --day 1
197
+ audienti content plan-draft <rprt_id> --day 1 --feedback "Revise the opening"
198
+ audienti content plan-visuals <rprt_id> --day 1 --style <id>
199
+ audienti content post-reply <cpwi_id> --comment <task_id> --body "Approved reply"
189
200
  audienti content approve <cpwi_id>
190
201
  audienti content comments
191
202
  audienti social-cookies sync-messages <scok_id> [--folder <folder>] [--retry] --json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audienti/cli",
3
- "version": "0.1.97",
3
+ "version": "0.1.99",
4
4
  "description": "Agent-first command-line client for Audienti.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api-client.js CHANGED
@@ -695,10 +695,54 @@ export class AudientiClient {
695
695
  return this.requestJson(accountPath(accountId, ["content_ops", "programs", programId, "plan"], query));
696
696
  }
697
697
 
698
+ contentPlans(accountId, query = {}) {
699
+ return this.requestJson(accountPath(accountId, ["content_ops", "plans"], query));
700
+ }
701
+
702
+ contentPlanReport(accountId, reportId, query = {}) {
703
+ return this.requestJson(accountPath(accountId, ["content_ops", "plans", reportId], query));
704
+ }
705
+
706
+ contentPlanUpdate(accountId, reportId, day, body = {}) {
707
+ return this.requestJson(accountPath(accountId, ["content_ops", "plans", reportId, "items", day]), { method: "PATCH", body });
708
+ }
709
+
710
+ contentPlanApprove(accountId, reportId, day, body = {}) {
711
+ return this.requestJson(accountPath(accountId, ["content_ops", "plans", reportId, "items", day, "approve"]), { method: "POST", body });
712
+ }
713
+
714
+ contentPlanResearch(accountId, reportId, day, body = {}) {
715
+ return this.requestJson(accountPath(accountId, ["content_ops", "plans", reportId, "items", day, "research"]), { method: "POST", body });
716
+ }
717
+
718
+ contentPlanDraft(accountId, reportId, day, body = {}) {
719
+ return this.requestJson(accountPath(accountId, ["content_ops", "plans", reportId, "items", day, "draft"]), { method: "POST", body });
720
+ }
721
+
722
+ contentPlanVisuals(accountId, reportId, day, body = {}) {
723
+ return this.requestJson(accountPath(accountId, ["content_ops", "plans", reportId, "items", day, "visuals"]), { method: "POST", body });
724
+ }
725
+
726
+ contentPostReply(accountId, workItemId, taskId, body = {}) {
727
+ return this.requestJson(accountPath(accountId, ["content_ops", "tracked_posts", workItemId, "comments", taskId, "reply"]), { method: "POST", body });
728
+ }
729
+
698
730
  contentWorkItem(accountId, workItemId) {
699
731
  return this.requestJson(accountPath(accountId, ["content_ops", "work_items", workItemId]));
700
732
  }
701
733
 
734
+ contentTrackedPosts(accountId, query = {}) {
735
+ return this.requestJson(accountPath(accountId, ["content_ops", "tracked_posts"], query));
736
+ }
737
+
738
+ contentTrackPost(accountId, body) {
739
+ return this.requestJson(accountPath(accountId, ["content_ops", "tracked_posts"]), { method: "POST", body });
740
+ }
741
+
742
+ contentTrackedPost(accountId, workItemId) {
743
+ return this.requestJson(accountPath(accountId, ["content_ops", "tracked_posts", workItemId]));
744
+ }
745
+
702
746
  contentFeedback(accountId, workItemId, body) {
703
747
  return this.requestJson(accountPath(accountId, ["content_ops", "work_items", workItemId, "feedback"]), { method: "POST", body });
704
748
  }
package/src/cli.js CHANGED
@@ -166,8 +166,13 @@ const WRITER_TEST_RUN_SHOW_USAGE = "Usage: audienti writer test-run show <prsp_i
166
166
  const MOTIONS_ANALYTICS_USAGE = "Usage: audienti motions analytics <motn_id> [--window 30d] [--json] [--account <acct_id>]";
167
167
  const MOTIONS_UPDATE_USAGE = "Usage: audienti motions update <motn_id> ([--status <draft|preparing|active|closing|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>] [--approach <text>] [--gift <gift_id|none>] | --payload <file.json>) [--json] [--account <acct_id>]";
168
168
  const CONTENT_PROGRAMS_USAGE = "Usage: audienti content programs [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
169
- const CONTENT_PLAN_USAGE = "Usage: audienti content plan <cprg_id> [--week <n>] [--due] [--json] [--account <acct_id>]";
169
+ const CONTENT_PLAN_USAGE = "Usage: audienti content plan <cprg_id|rprt_id> [--report] [--user <id|me>] [--week <n>] [--due] [--json] [--account <acct_id>]";
170
+ const CONTENT_PLANS_USAGE = "Usage: audienti content plans [--user <id|me>] [--page <n>] [--json] [--account <acct_id>]";
171
+ const CONTENT_POST_REPLY_USAGE = "Usage: audienti content post-reply <cpwi_id> --comment <cctk_id> --body <text> [--user <id|me>] [--json] [--account <acct_id>]";
170
172
  const CONTENT_SHOW_USAGE = "Usage: audienti content show <cpwi_id> [--json] [--account <acct_id>]";
173
+ const CONTENT_POSTS_USAGE = "Usage: audienti content posts [--user <account_user_id|email|name|me>] [--page <n>] [--json] [--account <acct_id>]";
174
+ const CONTENT_TRACK_USAGE = "Usage: audienti content track <linkedin_post_url> [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
175
+ const CONTENT_ENGAGEMENT_USAGE = "Usage: audienti content engagement <cpwi_id> [--json] [--account <acct_id>]";
171
176
  const CONTENT_FEEDBACK_USAGE = "Usage: audienti content feedback <cpwi_id> (--message <text> | --payload <file.json>) [--json] [--account <acct_id>]";
172
177
  const CONTENT_APPROVE_USAGE = "Usage: audienti content approve <cpwi_id> [--json] [--account <acct_id>]";
173
178
  const CONTENT_SCHEDULE_USAGE = "Usage: audienti content schedule <cpwi_id> --at <time> [--json] [--account <acct_id>]";
@@ -448,8 +453,14 @@ async function dispatch(argv, context) {
448
453
  if (normalizedResource === "motions" && action === "quick-start") return motionsQuickStart(rest, context, { accountOverride });
449
454
  if (normalizedResource === "motions" && action === "setup-state") return motionsSetupState(rest, context, { accountOverride });
450
455
  if (normalizedResource === "content" && action === "programs") return contentPrograms(rest, context, { accountOverride });
456
+ if (normalizedResource === "content" && action === "plans") return contentPlans(rest, context, { accountOverride });
457
+ if (normalizedResource === "content" && ["plan-update", "plan-approve", "plan-research", "plan-draft", "plan-visuals"].includes(action)) return contentPlanAction(action, rest, context, { accountOverride });
458
+ if (normalizedResource === "content" && action === "post-reply") return contentPostReply(rest, context, { accountOverride });
451
459
  if (normalizedResource === "content" && action === "plan") return contentPlan(rest, context, { accountOverride });
452
460
  if (normalizedResource === "content" && action === "show") return contentShow(rest, context, { accountOverride });
461
+ if (normalizedResource === "content" && action === "posts") return contentPosts(rest, context, { accountOverride });
462
+ if (normalizedResource === "content" && action === "track") return contentTrack(rest, context, { accountOverride });
463
+ if (normalizedResource === "content" && action === "engagement") return contentEngagement(rest, context, { accountOverride });
453
464
  if (normalizedResource === "content" && action === "feedback") return contentFeedback(rest, context, { accountOverride });
454
465
  if (normalizedResource === "content" && action === "approve") return contentApprove(rest, context, { accountOverride });
455
466
  if (normalizedResource === "content" && action === "schedule") return contentSchedule(rest, context, { accountOverride });
@@ -3847,18 +3858,71 @@ async function contentPrograms(args, context, { accountOverride } = {}) {
3847
3858
  renderContentPrograms(programs, context);
3848
3859
  }
3849
3860
 
3861
+ async function contentPlans(args, context, { accountOverride } = {}) {
3862
+ const { values, positionals } = parseCommandArgs(args, { ...jsonOptions(), user: { type: "string" }, page: { type: "string" } });
3863
+ if (positionals.length) throw new CommandError(CONTENT_PLANS_USAGE);
3864
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
3865
+ const payload = await client.contentPlans(accountId, compactObject({ user: values.user, page: values.page }));
3866
+ if (values.json) return writeJson(context.stdout, payload);
3867
+ for (const plan of payload.plans || []) context.stdout.write(`${plan.prefix_id} ${plan.channel} ${plan.status} ${plan.title}\n`);
3868
+ context.stdout.write("Open a plan: content plan <rprt_id> --report\n");
3869
+ if (payload.next_page) context.stdout.write(`More plans: content plans --page ${payload.next_page}\n`);
3870
+ }
3871
+
3872
+ async function contentPlanAction(action, args, context, { accountOverride } = {}) {
3873
+ const usage = `Usage: audienti content ${action} <rprt_id> --day <n> [--user <id|me>] [--payload <file.json>] [--feedback <text>] [--style <id>] [--aspect-ratio <w:h>] [--json] [--account <acct_id>]`;
3874
+ const { values, positionals } = parseCommandArgs(args, { ...jsonOptions(), day: { type: "string" }, user: { type: "string" }, payload: { type: "string" }, feedback: { type: "string" }, style: { type: "string" }, "aspect-ratio": { type: "string" } });
3875
+ const day = Number(values.day);
3876
+ if (positionals.length !== 1 || !Number.isInteger(day) || day < 1 || (action === "plan-update" && !values.payload)) throw new CommandError(usage);
3877
+ if (values["aspect-ratio"] && !/^\d+:\d+$/.test(values["aspect-ratio"])) throw new CommandError("Aspect ratio must be w:h.");
3878
+ const body = compactObject({ user: values.user });
3879
+ if (action === "plan-update") {
3880
+ body.item = await readJsonPayload(values.payload);
3881
+ if (!body.item || typeof body.item !== "object" || Array.isArray(body.item)) throw new CommandError("Plan update payload must be a JSON object.");
3882
+ }
3883
+ if (action === "plan-draft") body.draft_feedback = values.feedback || "";
3884
+ if (action === "plan-visuals") body.visual_generation = compactObject({ ad_style_id: values.style, aspect_ratio_option: values["aspect-ratio"] });
3885
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
3886
+ let result;
3887
+ if (action === "plan-update") result = await client.contentPlanUpdate(accountId, positionals[0], day, body);
3888
+ else if (action === "plan-approve") result = await client.contentPlanApprove(accountId, positionals[0], day, body);
3889
+ else if (action === "plan-research") result = await client.contentPlanResearch(accountId, positionals[0], day, body);
3890
+ else if (action === "plan-draft") result = await client.contentPlanDraft(accountId, positionals[0], day, body);
3891
+ else result = await client.contentPlanVisuals(accountId, positionals[0], day, body);
3892
+ if (values.json) return writeJson(context.stdout, result);
3893
+ context.stdout.write(`${result.title || "Content plan"}: ${result.status}\n`);
3894
+ }
3895
+
3896
+ async function contentPostReply(args, context, { accountOverride } = {}) {
3897
+ const { values, positionals } = parseCommandArgs(args, { ...jsonOptions(), comment: { type: "string" }, body: { type: "string" }, user: { type: "string" } });
3898
+ if (positionals.length !== 1 || !values.comment || !values.body?.trim()) throw new CommandError(CONTENT_POST_REPLY_USAGE);
3899
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
3900
+ const result = await client.contentPostReply(accountId, positionals[0], values.comment, compactObject({ reply_body: values.body, user: values.user }));
3901
+ if (values.json) return writeJson(context.stdout, result);
3902
+ context.stdout.write(`Reply approved for post ${result.prefix_id}; check engagement for delivery status.\n`);
3903
+ }
3904
+
3850
3905
  async function contentPlan(args, context, { accountOverride } = {}) {
3851
3906
  const { values, positionals } = parseCommandArgs(args, {
3852
3907
  ...jsonOptions(),
3853
3908
  week: { type: "string" },
3854
- due: { type: "boolean" }
3909
+ due: { type: "boolean" },
3910
+ report: { type: "boolean" },
3911
+ user: { type: "string" }
3855
3912
  });
3856
3913
  if (positionals.length !== 1) throw new CommandError(CONTENT_PLAN_USAGE);
3857
3914
 
3858
3915
  const { client, accountId } = await requireAccountContext(context, { accountOverride });
3859
- const payload = await client.contentPlan(accountId, positionals[0]);
3916
+ const payload = values.report
3917
+ ? await client.contentPlanReport(accountId, positionals[0], compactObject({ user: values.user }))
3918
+ : await client.contentPlan(accountId, positionals[0]);
3860
3919
  if (values.json) return writeJson(context.stdout, payload);
3861
3920
 
3921
+ if (values.report) {
3922
+ context.stdout.write(`${payload.title || "Content plan"}: ${payload.status}\n`);
3923
+ for (const row of payload.content_plan || []) context.stdout.write(`Day ${row.day_number} ${row.channel} ${row.title} ${row.execution?.workflow_phase || "Not started"}\n${row.finalized_content || ""}\n`);
3924
+ return;
3925
+ }
3862
3926
  const week = values.week ? Number.parseInt(values.week, 10) : null;
3863
3927
  let rows = Array.isArray(payload?.rows) ? payload.rows : [];
3864
3928
  if (week) rows = rows.filter((row) => Number(row.week_number) === week);
@@ -3877,6 +3941,47 @@ async function contentShow(args, context, { accountOverride } = {}) {
3877
3941
  renderContentWorkItem(item, context);
3878
3942
  }
3879
3943
 
3944
+ async function contentPosts(args, context, { accountOverride } = {}) {
3945
+ const { values, positionals } = parseCommandArgs(args, { ...jsonOptions(), user: { type: "string" }, page: { type: "string" } });
3946
+ if (positionals.length) throw new CommandError(CONTENT_POSTS_USAGE);
3947
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
3948
+ const payload = await client.contentTrackedPosts(accountId, { ...(values.user ? { user: values.user } : {}), ...(values.page ? { page: values.page } : {}) });
3949
+ if (values.json) return writeJson(context.stdout, payload);
3950
+ for (const post of payload.posts || []) context.stdout.write(`${post.prefix_id} ${post.status} ${post.published_at || "Publication time unavailable"} ${post.url}\n`);
3951
+ if (payload.next_page) context.stdout.write(`More posts: content posts --page ${payload.next_page}\n`);
3952
+ }
3953
+
3954
+ async function contentTrack(args, context, { accountOverride } = {}) {
3955
+ const { values, positionals } = parseCommandArgs(args, { ...jsonOptions(), user: { type: "string" } });
3956
+ if (positionals.length !== 1) throw new CommandError(CONTENT_TRACK_USAGE);
3957
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
3958
+ const post = await client.contentTrackPost(accountId, { url: positionals[0], ...(values.user ? { user: values.user } : {}) });
3959
+ if (values.json) return writeJson(context.stdout, post);
3960
+ context.stdout.write(`Tracking ${post.prefix_id}: ${post.status}\n${post.url}\n`);
3961
+ }
3962
+
3963
+ async function contentEngagement(args, context, { accountOverride } = {}) {
3964
+ const { values, positionals } = parseCommandArgs(args, jsonOptions());
3965
+ if (positionals.length !== 1) throw new CommandError(CONTENT_ENGAGEMENT_USAGE);
3966
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
3967
+ const post = await client.contentTrackedPost(accountId, positionals[0]);
3968
+ if (values.json) return writeJson(context.stdout, post);
3969
+ context.stdout.write(`${post.title || "LinkedIn post"}: ${post.status}\n${post.url}\n`);
3970
+ if (post.error) context.stdout.write(`Tracking error: ${post.error}\n`);
3971
+ context.stdout.write(`Reposts reported: ${post.repost_count ?? "unavailable"}; reposter identities unavailable\n`);
3972
+ for (const category of ["comments", "reactions"]) {
3973
+ const state = post.categories?.[category] || {};
3974
+ context.stdout.write(`${category}: ${state.status || "pending"}, ${state.collected_count ?? 0} collected\n`);
3975
+ if (state.error) context.stdout.write(` ${state.error}\n`);
3976
+ for (const engagement of post[category] || []) {
3977
+ const person = engagement.profile || {};
3978
+ context.stdout.write(` ${person.name || "Unknown person"} | ${person.title || "Title unavailable"} | ${person.company || "Company unavailable"} | ${person.url || "Profile unavailable"}\n`);
3979
+ if (engagement.text) context.stdout.write(` ${engagement.commented_at || "Time unavailable"}: ${engagement.text}\n`);
3980
+ if (engagement.task?.id) context.stdout.write(` Reply task: ${engagement.task.id} (${engagement.task.delivery_state || engagement.task.status})\n`);
3981
+ }
3982
+ }
3983
+ }
3984
+
3880
3985
  async function contentFeedback(args, context, { accountOverride } = {}) {
3881
3986
  const { values, positionals } = parseCommandArgs(args, {
3882
3987
  ...jsonOptions(),
@@ -10216,6 +10321,9 @@ const HELP_TOPICS = new Map([
10216
10321
  " audienti content programs",
10217
10322
  " audienti content plan <cprg_id>",
10218
10323
  " audienti content show <cpwi_id>",
10324
+ " audienti content track <linkedin_post_url>",
10325
+ " audienti content posts",
10326
+ " audienti content engagement <cpwi_id>",
10219
10327
  " audienti content feedback <cpwi_id> --message <text>",
10220
10328
  " audienti content approve <cpwi_id>",
10221
10329
  " audienti content publish <cpwi_id> --url <permalink>",
@@ -12558,6 +12666,9 @@ const HELP_TOPICS = new Map([
12558
12666
  " audienti content programs [--user <account_user_id|email|name|me>] [--json]",
12559
12667
  " audienti content plan <cprg_id> [--week <n>] [--due] [--json]",
12560
12668
  " audienti content show <cpwi_id> [--json]",
12669
+ " audienti content track <linkedin_post_url> [--user <account_user_id|email|name|me>] [--json]",
12670
+ " audienti content posts [--user <account_user_id|email|name|me>] [--json]",
12671
+ " audienti content engagement <cpwi_id> [--json]",
12561
12672
  " audienti content feedback <cpwi_id> --message <text> [--json]",
12562
12673
  " audienti content approve <cpwi_id> [--json]",
12563
12674
  " audienti content schedule <cpwi_id> --at <time> [--json]",
@@ -12572,7 +12683,13 @@ const HELP_TOPICS = new Map([
12572
12683
 
12573
12684
  ["content programs", [CONTENT_PROGRAMS_USAGE].join("\n")],
12574
12685
  ["content plan", [CONTENT_PLAN_USAGE].join("\n")],
12686
+ ["content plans", CONTENT_PLANS_USAGE],
12687
+ ["content post-reply", CONTENT_POST_REPLY_USAGE],
12688
+ ...["plan-update", "plan-approve", "plan-research", "plan-draft", "plan-visuals"].map((action) => [`content ${action}`, `Usage: audienti content ${action} <rprt_id> --day <n> [--user <id|me>] [--payload <file.json>] [--feedback <text>] [--style <id>] [--aspect-ratio <w:h>] [--json] [--account <acct_id>]`]),
12575
12689
  ["content show", [CONTENT_SHOW_USAGE].join("\n")],
12690
+ ["content posts", [CONTENT_POSTS_USAGE].join("\n")],
12691
+ ["content track", [CONTENT_TRACK_USAGE].join("\n")],
12692
+ ["content engagement", [CONTENT_ENGAGEMENT_USAGE].join("\n")],
12576
12693
  ["content feedback", [CONTENT_FEEDBACK_USAGE].join("\n")],
12577
12694
  ["content approve", [CONTENT_APPROVE_USAGE].join("\n")],
12578
12695
  ["content schedule", [CONTENT_SCHEDULE_USAGE].join("\n")],