@oxygen-agent/cli 1.1014.135 → 1.1014.618

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.
Files changed (292) hide show
  1. package/README.md +1 -1
  2. package/dist/admin-primary-providers-render.js +27 -19
  3. package/dist/cli-output.d.ts +12 -0
  4. package/dist/cli-output.js +395 -0
  5. package/dist/cli-paths.d.ts +1 -0
  6. package/dist/cli-paths.js +3 -0
  7. package/dist/cli-profile-context.d.ts +3 -0
  8. package/dist/cli-profile-context.js +13 -0
  9. package/dist/command-manifest.d.ts +15 -0
  10. package/dist/command-manifest.js +23 -1
  11. package/dist/command-support.d.ts +438 -0
  12. package/dist/command-support.js +1610 -0
  13. package/dist/commands/action-column.d.ts +3 -0
  14. package/dist/commands/action-column.js +43 -0
  15. package/dist/commands/activation.d.ts +3 -0
  16. package/dist/commands/activation.js +24 -0
  17. package/dist/commands/admin.d.ts +3 -0
  18. package/dist/commands/admin.js +347 -0
  19. package/dist/commands/ads.d.ts +3 -0
  20. package/dist/commands/ads.js +62 -0
  21. package/dist/commands/agent.d.ts +3 -0
  22. package/dist/commands/agent.js +274 -0
  23. package/dist/commands/api-keys.d.ts +3 -0
  24. package/dist/commands/api-keys.js +77 -0
  25. package/dist/commands/approvals.d.ts +3 -0
  26. package/dist/commands/approvals.js +518 -0
  27. package/dist/commands/auth.d.ts +3 -0
  28. package/dist/commands/auth.js +230 -0
  29. package/dist/commands/billing.d.ts +3 -0
  30. package/dist/commands/billing.js +357 -0
  31. package/dist/commands/blueprints.d.ts +3 -0
  32. package/dist/commands/blueprints.js +312 -0
  33. package/dist/commands/budget.d.ts +3 -0
  34. package/dist/commands/budget.js +55 -0
  35. package/dist/commands/callables.d.ts +3 -0
  36. package/dist/commands/callables.js +111 -0
  37. package/dist/commands/capabilities.d.ts +3 -0
  38. package/dist/commands/capabilities.js +44 -0
  39. package/dist/commands/cells.d.ts +3 -0
  40. package/dist/commands/cells.js +94 -0
  41. package/dist/commands/columns.d.ts +3 -0
  42. package/dist/commands/columns.js +1628 -0
  43. package/dist/commands/commands.d.ts +3 -0
  44. package/dist/commands/commands.js +45 -0
  45. package/dist/commands/comments.d.ts +3 -0
  46. package/dist/commands/comments.js +188 -0
  47. package/dist/commands/companies.d.ts +3 -0
  48. package/dist/commands/companies.js +312 -0
  49. package/dist/commands/connections.d.ts +3 -0
  50. package/dist/commands/connections.js +39 -0
  51. package/dist/commands/context.d.ts +3 -0
  52. package/dist/commands/context.js +170 -0
  53. package/dist/commands/copilot.d.ts +3 -0
  54. package/dist/commands/copilot.js +565 -0
  55. package/dist/commands/crm.d.ts +3 -0
  56. package/dist/commands/crm.js +1669 -0
  57. package/dist/commands/custom-integrations.d.ts +3 -0
  58. package/dist/commands/custom-integrations.js +140 -0
  59. package/dist/commands/dashboards.d.ts +3 -0
  60. package/dist/commands/dashboards.js +240 -0
  61. package/dist/commands/db.d.ts +3 -0
  62. package/dist/commands/db.js +190 -0
  63. package/dist/commands/deliverability.d.ts +3 -0
  64. package/dist/commands/deliverability.js +90 -0
  65. package/dist/commands/directory.d.ts +3 -0
  66. package/dist/commands/directory.js +101 -0
  67. package/dist/commands/domains.d.ts +3 -0
  68. package/dist/commands/domains.js +604 -0
  69. package/dist/commands/egress.d.ts +3 -0
  70. package/dist/commands/egress.js +130 -0
  71. package/dist/commands/email.d.ts +3 -0
  72. package/dist/commands/email.js +49 -0
  73. package/dist/commands/engagement.d.ts +3 -0
  74. package/dist/commands/engagement.js +189 -0
  75. package/dist/commands/enrich-column.d.ts +3 -0
  76. package/dist/commands/enrich-column.js +149 -0
  77. package/dist/commands/enrichment.d.ts +3 -0
  78. package/dist/commands/enrichment.js +49 -0
  79. package/dist/commands/feedback.d.ts +3 -0
  80. package/dist/commands/feedback.js +96 -0
  81. package/dist/commands/feeds.d.ts +3 -0
  82. package/dist/commands/feeds.js +486 -0
  83. package/dist/commands/find.d.ts +3 -0
  84. package/dist/commands/find.js +159 -0
  85. package/dist/commands/followers.d.ts +3 -0
  86. package/dist/commands/followers.js +39 -0
  87. package/dist/commands/formulas.d.ts +3 -0
  88. package/dist/commands/formulas.js +43 -0
  89. package/dist/commands/home.d.ts +3 -0
  90. package/dist/commands/home.js +22 -0
  91. package/dist/commands/inbox.d.ts +3 -0
  92. package/dist/commands/inbox.js +779 -0
  93. package/dist/commands/integrations.d.ts +3 -0
  94. package/dist/commands/integrations.js +290 -0
  95. package/dist/commands/knowledge.d.ts +3 -0
  96. package/dist/commands/knowledge.js +874 -0
  97. package/dist/commands/lead-sourcing.d.ts +3 -0
  98. package/dist/commands/lead-sourcing.js +52 -0
  99. package/dist/commands/limits.d.ts +3 -0
  100. package/dist/commands/limits.js +54 -0
  101. package/dist/commands/linkedin.d.ts +3 -0
  102. package/dist/commands/linkedin.js +275 -0
  103. package/dist/commands/login.d.ts +3 -0
  104. package/dist/commands/login.js +347 -0
  105. package/dist/commands/logout.d.ts +3 -0
  106. package/dist/commands/logout.js +12 -0
  107. package/dist/commands/mailboxes.d.ts +3 -0
  108. package/dist/commands/mailboxes.js +1290 -0
  109. package/dist/commands/managed-inboxes.d.ts +3 -0
  110. package/dist/commands/managed-inboxes.js +361 -0
  111. package/dist/commands/messages.d.ts +3 -0
  112. package/dist/commands/messages.js +78 -0
  113. package/dist/commands/notetaker.d.ts +3 -0
  114. package/dist/commands/notetaker.js +79 -0
  115. package/dist/commands/observability.d.ts +3 -0
  116. package/dist/commands/observability.js +125 -0
  117. package/dist/commands/orgs.d.ts +3 -0
  118. package/dist/commands/orgs.js +237 -0
  119. package/dist/commands/people.d.ts +3 -0
  120. package/dist/commands/people.js +353 -0
  121. package/dist/commands/posts.d.ts +3 -0
  122. package/dist/commands/posts.js +139 -0
  123. package/dist/commands/profiles.d.ts +3 -0
  124. package/dist/commands/profiles.js +250 -0
  125. package/dist/commands/projects.d.ts +3 -0
  126. package/dist/commands/projects.js +94 -0
  127. package/dist/commands/prompts.d.ts +3 -0
  128. package/dist/commands/prompts.js +84 -0
  129. package/dist/commands/publishing.d.ts +3 -0
  130. package/dist/commands/publishing.js +1419 -0
  131. package/dist/commands/recipes.d.ts +3 -0
  132. package/dist/commands/recipes.js +120 -0
  133. package/dist/commands/reviews.d.ts +3 -0
  134. package/dist/commands/reviews.js +75 -0
  135. package/dist/commands/rows.d.ts +3 -0
  136. package/dist/commands/rows.js +27 -0
  137. package/dist/commands/runs.d.ts +3 -0
  138. package/dist/commands/runs.js +37 -0
  139. package/dist/commands/search.d.ts +3 -0
  140. package/dist/commands/search.js +182 -0
  141. package/dist/commands/senders.d.ts +3 -0
  142. package/dist/commands/senders.js +393 -0
  143. package/dist/commands/sequences.d.ts +3 -0
  144. package/dist/commands/sequences.js +2322 -0
  145. package/dist/commands/session.d.ts +3 -0
  146. package/dist/commands/session.js +109 -0
  147. package/dist/commands/signals.d.ts +3 -0
  148. package/dist/commands/signals.js +289 -0
  149. package/dist/commands/signup-leads.d.ts +3 -0
  150. package/dist/commands/signup-leads.js +46 -0
  151. package/dist/commands/skills.d.ts +3 -0
  152. package/dist/commands/skills.js +50 -0
  153. package/dist/commands/sourcing.d.ts +3 -0
  154. package/dist/commands/sourcing.js +27 -0
  155. package/dist/commands/status.d.ts +3 -0
  156. package/dist/commands/status.js +51 -0
  157. package/dist/commands/supabase.d.ts +3 -0
  158. package/dist/commands/supabase.js +128 -0
  159. package/dist/commands/support.d.ts +3 -0
  160. package/dist/commands/support.js +651 -0
  161. package/dist/commands/suppressions.d.ts +3 -0
  162. package/dist/commands/suppressions.js +577 -0
  163. package/dist/commands/table-ingestions.d.ts +3 -0
  164. package/dist/commands/table-ingestions.js +145 -0
  165. package/dist/commands/table-runs.d.ts +3 -0
  166. package/dist/commands/table-runs.js +277 -0
  167. package/dist/commands/tables.d.ts +3 -0
  168. package/dist/commands/tables.js +3492 -0
  169. package/dist/commands/tags.d.ts +3 -0
  170. package/dist/commands/tags.js +147 -0
  171. package/dist/commands/tools.d.ts +3 -0
  172. package/dist/commands/tools.js +246 -0
  173. package/dist/commands/update.d.ts +3 -0
  174. package/dist/commands/update.js +106 -0
  175. package/dist/commands/verify.d.ts +3 -0
  176. package/dist/commands/verify.js +27 -0
  177. package/dist/commands/viewers.d.ts +3 -0
  178. package/dist/commands/viewers.js +72 -0
  179. package/dist/commands/voice.d.ts +3 -0
  180. package/dist/commands/voice.js +351 -0
  181. package/dist/commands/whatsapp.d.ts +3 -0
  182. package/dist/commands/whatsapp.js +226 -0
  183. package/dist/commands/whoami.d.ts +3 -0
  184. package/dist/commands/whoami.js +110 -0
  185. package/dist/commands/worker.d.ts +3 -0
  186. package/dist/commands/worker.js +60 -0
  187. package/dist/commands/workflows.d.ts +3 -0
  188. package/dist/commands/workflows.js +1752 -0
  189. package/dist/commands/workspace.d.ts +3 -0
  190. package/dist/commands/workspace.js +94 -0
  191. package/dist/compact-list-flags.d.ts +7 -0
  192. package/dist/compact-list-flags.js +12 -0
  193. package/dist/crm-support-flags.js +14 -5
  194. package/dist/customer-operation-commands.js +8 -6
  195. package/dist/diagnostic-uploader.d.ts +3 -1
  196. package/dist/diagnostic-uploader.js +29 -8
  197. package/dist/help.d.ts +5 -0
  198. package/dist/help.js +22 -0
  199. package/dist/index.d.ts +98 -1
  200. package/dist/index.js +331 -30719
  201. package/dist/local-module-loader.d.ts +4 -0
  202. package/dist/local-module-loader.js +156 -0
  203. package/dist/visual-commands.js +9 -5
  204. package/node_modules/@oxygen/cli-ugc/dist/commands.js +2 -2
  205. package/node_modules/@oxygen/shared/dist/agent-session-schedule.d.ts +36 -0
  206. package/node_modules/@oxygen/shared/dist/agent-session-schedule.js +69 -0
  207. package/node_modules/@oxygen/shared/dist/agent-sessions.d.ts +14 -5
  208. package/node_modules/@oxygen/shared/dist/agent-sessions.js +14 -3
  209. package/node_modules/@oxygen/shared/dist/capability-discovery.js +175 -14
  210. package/node_modules/@oxygen/shared/dist/compact-list-result.d.ts +6 -0
  211. package/node_modules/@oxygen/shared/dist/compact-list-result.js +27 -0
  212. package/node_modules/@oxygen/shared/dist/contracts/agent-sessions.d.ts +12 -1
  213. package/node_modules/@oxygen/shared/dist/contracts/agent-sessions.js +5 -2
  214. package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +4 -2
  215. package/node_modules/@oxygen/shared/dist/contracts/compact-list-reads.d.ts +57 -0
  216. package/node_modules/@oxygen/shared/dist/contracts/compact-list-reads.js +23 -0
  217. package/node_modules/@oxygen/shared/dist/contracts/crm-support.d.ts +52 -0
  218. package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +43 -2
  219. package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +17 -14
  220. package/node_modules/@oxygen/shared/dist/contracts/knowledge-content-reads.js +1 -1
  221. package/node_modules/@oxygen/shared/dist/contracts/knowledge-proposal-reads.d.ts +49 -0
  222. package/node_modules/@oxygen/shared/dist/contracts/knowledge-proposal-reads.js +14 -0
  223. package/node_modules/@oxygen/shared/dist/contracts/knowledge-sync.js +1 -1
  224. package/node_modules/@oxygen/shared/dist/contracts/limits-read.js +60 -7
  225. package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +9 -1
  226. package/node_modules/@oxygen/shared/dist/contracts/operations.js +13 -5
  227. package/node_modules/@oxygen/shared/dist/contracts/publishing-reads.js +1 -1
  228. package/node_modules/@oxygen/shared/dist/contracts/teammates.d.ts +16 -0
  229. package/node_modules/@oxygen/shared/dist/contracts/teammates.js +115 -0
  230. package/node_modules/@oxygen/shared/dist/cost-estimate-view.js +21 -3
  231. package/node_modules/@oxygen/shared/dist/cost-estimate.d.ts +31 -1
  232. package/node_modules/@oxygen/shared/dist/cost-estimate.js +56 -15
  233. package/node_modules/@oxygen/shared/dist/diagnostic-credentials.d.ts +2 -0
  234. package/node_modules/@oxygen/shared/dist/diagnostic-credentials.js +2 -0
  235. package/node_modules/@oxygen/shared/dist/diagnostic-lock.js +71 -44
  236. package/node_modules/@oxygen/shared/dist/diagnostic-spool.d.ts +18 -0
  237. package/node_modules/@oxygen/shared/dist/diagnostic-spool.js +348 -0
  238. package/node_modules/@oxygen/shared/dist/diagnostic-storage-failure.d.ts +10 -0
  239. package/node_modules/@oxygen/shared/dist/diagnostic-storage-failure.js +42 -0
  240. package/node_modules/@oxygen/shared/dist/diagnostic-storage.d.ts +1 -1
  241. package/node_modules/@oxygen/shared/dist/diagnostic-storage.js +59 -213
  242. package/node_modules/@oxygen/shared/dist/diagnostics.js +3 -2
  243. package/node_modules/@oxygen/shared/dist/email-dsn.d.ts +16 -5
  244. package/node_modules/@oxygen/shared/dist/email-dsn.js +97 -1
  245. package/node_modules/@oxygen/shared/dist/emailguard-placement-probe.js +5 -0
  246. package/node_modules/@oxygen/shared/dist/enrichment-intents.js +4 -5
  247. package/node_modules/@oxygen/shared/dist/file-import.js +5 -2
  248. package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +30 -0
  249. package/node_modules/@oxygen/shared/dist/hosted-ai.js +20 -0
  250. package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +6 -2
  251. package/node_modules/@oxygen/shared/dist/knowledge-seed-content.d.ts +17 -7
  252. package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +81 -17
  253. package/node_modules/@oxygen/shared/dist/langfuse.js +8 -4
  254. package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.d.ts +1 -1
  255. package/node_modules/@oxygen/shared/dist/mailbox-import.d.ts +6 -3
  256. package/node_modules/@oxygen/shared/dist/mailbox-import.js +9 -9
  257. package/node_modules/@oxygen/shared/dist/mcp-server-info.d.ts +8 -0
  258. package/node_modules/@oxygen/shared/dist/mcp-server-info.js +10 -0
  259. package/node_modules/@oxygen/shared/dist/object-storage.d.ts +10 -0
  260. package/node_modules/@oxygen/shared/dist/object-storage.js +14 -0
  261. package/node_modules/@oxygen/shared/dist/plan-limits-view.d.ts +5 -0
  262. package/node_modules/@oxygen/shared/dist/plan-limits-view.js +17 -1
  263. package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +1 -1
  264. package/node_modules/@oxygen/shared/dist/pricing-sheet.js +1 -1
  265. package/node_modules/@oxygen/shared/dist/provider-selection.d.ts +15 -0
  266. package/node_modules/@oxygen/shared/dist/provider-selection.js +3 -0
  267. package/node_modules/@oxygen/shared/dist/repricing.d.ts +1 -1
  268. package/node_modules/@oxygen/shared/dist/repricing.js +2 -2
  269. package/node_modules/@oxygen/shared/dist/schedule-label.d.ts +6 -0
  270. package/node_modules/@oxygen/shared/dist/schedule-label.js +12 -0
  271. package/node_modules/@oxygen/shared/dist/sequence-failures.d.ts +1 -0
  272. package/node_modules/@oxygen/shared/dist/sequence-failures.js +20 -6
  273. package/node_modules/@oxygen/shared/dist/teammate-groups.d.ts +55 -0
  274. package/node_modules/@oxygen/shared/dist/teammate-groups.js +74 -0
  275. package/node_modules/@oxygen/shared/dist/teammate-messages.d.ts +52 -0
  276. package/node_modules/@oxygen/shared/dist/teammate-messages.js +88 -0
  277. package/node_modules/@oxygen/shared/dist/teammate-notes.d.ts +58 -0
  278. package/node_modules/@oxygen/shared/dist/teammate-notes.js +73 -0
  279. package/node_modules/@oxygen/shared/dist/teammate-routines.d.ts +95 -0
  280. package/node_modules/@oxygen/shared/dist/teammate-routines.js +266 -0
  281. package/node_modules/@oxygen/shared/dist/teammate-tasks.d.ts +56 -0
  282. package/node_modules/@oxygen/shared/dist/teammate-tasks.js +114 -0
  283. package/node_modules/@oxygen/shared/dist/teammates.d.ts +78 -0
  284. package/node_modules/@oxygen/shared/dist/teammates.js +140 -0
  285. package/node_modules/@oxygen/shared/dist/user-capability-routing.js +120 -0
  286. package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
  287. package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
  288. package/node_modules/@oxygen/shared/dist/visual-render.d.ts +9 -1
  289. package/node_modules/@oxygen/shared/dist/visual-render.js +12 -5
  290. package/node_modules/@oxygen/shared/dist/warmup-metrics.d.ts +5 -0
  291. package/node_modules/@oxygen/shared/dist/warmup-metrics.js +44 -0
  292. package/package.json +1 -1
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerLeadSourcingFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,52 @@
1
+ import { parseJsonObject } from "../cli-values.js";
2
+ import { readFileIfPresent } from "../command-support.js";
3
+ import { requestOxygen } from "../http-client.js";
4
+ import { OxygenError } from "@oxygen/shared/cli-result";
5
+ import { Command } from "commander";
6
+ import { readFileSync } from "node:fs";
7
+ import { resolve } from "node:path";
8
+ function readSpecFileBody(path) {
9
+ const text = readFileSync(resolve(path), "utf8");
10
+ try {
11
+ return { spec: parseJsonObject(text) };
12
+ }
13
+ catch (error) {
14
+ if (error instanceof OxygenError && error.code === "invalid_json") {
15
+ return { spec_prompt: text };
16
+ }
17
+ throw error;
18
+ }
19
+ }
20
+ export function registerLeadSourcingFamily(program, handleAsyncAction) {
21
+ program
22
+ .command("lead-sourcing")
23
+ .description("ICP-gated lead sourcing planning and audit commands.")
24
+ .addCommand(new Command("plan")
25
+ .description("Compile a natural-language ICP into an account-first lead sourcing plan.")
26
+ .requiredOption("--prompt <file|text>", "ICP prompt text, or a local file path containing the prompt.")
27
+ .option("--materialize-preview", "Create a preview table for the plan. Defaults to no table side effect.")
28
+ .option("--json", "Print a JSON envelope.")
29
+ .action(async (options) => {
30
+ await handleAsyncAction("lead-sourcing plan", options, () => requestOxygen("/api/cli/lead-sourcing/plan", {
31
+ method: "POST",
32
+ body: {
33
+ prompt: readFileIfPresent(options.prompt),
34
+ ...(options.materializePreview ? { materialize_preview: true } : {}),
35
+ },
36
+ }));
37
+ }))
38
+ .addCommand(new Command("audit")
39
+ .description("Audit a sourced lead table against a lead-sourcing spec.")
40
+ .argument("<table>", "Table id or slug.")
41
+ .requiredOption("--spec <file>", "JSON LeadSourcingSpec file, or a text prompt file to compile into a spec.")
42
+ .option("--json", "Print a JSON envelope.")
43
+ .action(async (table, options) => {
44
+ await handleAsyncAction("lead-sourcing audit", options, () => requestOxygen("/api/cli/lead-sourcing/audit", {
45
+ method: "POST",
46
+ body: {
47
+ table,
48
+ ...readSpecFileBody(options.spec),
49
+ },
50
+ }));
51
+ }));
52
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerLimitsFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler, billingDocsUrl: string): void;
@@ -0,0 +1,54 @@
1
+ import { addContractFlags, readContractFlags } from "../contract-flags.js";
2
+ import { requestOxygen } from "../http-client.js";
3
+ import { addProviderLimitFlags, providerLimitBody, providerLimitQuery } from "../workspace-utility-flags.js";
4
+ import { OxygenError } from "@oxygen/shared/cli-result";
5
+ import { LIMITS_READ_QUERY_CONTRACT, limitsReadQueryIssue } from "@oxygen/shared/contracts/limits-read";
6
+ import { Command } from "commander";
7
+ export function registerLimitsFamily(program, handleAsyncAction, billingDocsUrl) {
8
+ program
9
+ .command("limits")
10
+ .description("Plan-tier limits, spend-safety defaults, per-channel sending limits, and storage capacity posture. `limits show --section capacity` returns storage alone, including which Table is full.")
11
+ .addHelpText("after", "\nRun `oxygen limits show --json` to see your current plan's API and webhook rates, Table and workspace storage headroom, and the next scheduled change. The $999 and $1,999 rows-per-Table increases remain held until capacity testing passes.\n")
12
+ .addCommand(addContractFlags(new Command("show")
13
+ .description("Compare every plan size: price, monthly credits, volume bonus and price per 100 credits (`plan_bands`). Show your plan band and its limits beside every plan size's (API rate, webhook ingress, storage, import file size, columns per auto-run, signals feed, spend defaults incl. Agent and Copilot caps, fastest workflow schedule), the per-channel sending limits every plan shares (emails per mailbox, WhatsApp, LinkedIn, calls) and its workflow Code-step and run-attempt limits, plus Tables capacity usage naming the largest Table. Each plan size's storage says whether it is in force, scheduled to change on a date, or awaiting its rows-per-Table capacity test, with the values it moves to. `spend_safety_defaults.enterprise_agent_run_default` gives Enterprise the $1,999 band’s in-force Agent default with no contract override; `agent_run_approved_max_credits` is the maximum for an explicitly approved higher run. `spend_safety_defaults.applies_to` says what each spend default bounds: an unattended trigger delivery, a table auto-run batch, one Agent run, or the attended Copilot. `web_url` opens the same view in the web app (Settings → Plan limits), including any scheduled change. Read-only; spends no credits. Recovery: " + billingDocsUrl + "."), LIMITS_READ_QUERY_CONTRACT)
14
+ .option("--json", "Print a JSON envelope.")
15
+ .action(async (options) => {
16
+ await handleAsyncAction("limits show", options, () => {
17
+ const projection = readContractFlags(options, LIMITS_READ_QUERY_CONTRACT);
18
+ const issue = limitsReadQueryIssue(projection);
19
+ if (issue)
20
+ throw new OxygenError("invalid_request", issue);
21
+ const params = new URLSearchParams();
22
+ for (const [key, value] of Object.entries(projection))
23
+ if (value !== undefined)
24
+ params.set(key, String(value));
25
+ const suffix = params.toString();
26
+ return requestOxygen(`/api/cli/limits${suffix ? `?${suffix}` : ""}`);
27
+ });
28
+ }))
29
+ .addCommand(new Command("provider")
30
+ .description("Per-provider call-rate overrides and BYOK daily warning thresholds. With no subcommand, lists policies (same as `limits provider list`).")
31
+ .addCommand(addProviderLimitFlags(new Command("list")
32
+ .description("List enforced workspace provider overrides and the plan-tier BYOK daily threshold with its enforcement mode; read-only, 0 credits."), "list")
33
+ .option("--json", "Print a JSON envelope.")
34
+ .action(async (options) => {
35
+ const suffix = providerLimitQuery(options, "list");
36
+ await handleAsyncAction("limits provider list", options, () => requestOxygen(`/api/cli/limits/provider${suffix ? `?${suffix}` : ""}`));
37
+ }), { isDefault: true })
38
+ .addCommand(addProviderLimitFlags(new Command("set")
39
+ .description("Set an enforced provider request limit; admin/owner only. Approve the exact provider, operation and window before running; execution saves the policy. Raising a cap can permit more use. 0 credits."), "set")
40
+ .option("--json", "Print a JSON envelope.")
41
+ .action(async (options) => {
42
+ await handleAsyncAction("limits provider set", options, () => requestOxygen("/api/cli/limits/provider", {
43
+ method: "POST",
44
+ body: providerLimitBody(options),
45
+ }));
46
+ }))
47
+ .addCommand(addProviderLimitFlags(new Command("delete")
48
+ .description("Delete one provider override after approving its selector; admin/owner only, 0 credits; remaining matches apply, otherwise a code default if defined. Upstream and other limits remain. Read the separate BYOK plan threshold and enforcement mode with limits provider list."), "delete")
49
+ .option("--json", "Print a JSON envelope.")
50
+ .action(async (options) => {
51
+ const query = providerLimitQuery(options, "delete");
52
+ await handleAsyncAction("limits provider delete", options, () => requestOxygen(`/api/cli/limits/provider?${query.toString()}`, { method: "DELETE" }));
53
+ })));
54
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerLinkedinFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,275 @@
1
+ import { readPositiveInt } from "../cli-values.js";
2
+ import { readCsvOption, readPositiveNumber } from "../command-support.js";
3
+ import { addContractFlags, readContractFlags } from "../contract-flags.js";
4
+ import { requestOxygen } from "../http-client.js";
5
+ import { readOption } from "../util.js";
6
+ import { OxygenError } from "@oxygen/shared/cli-result";
7
+ import { LINKEDIN_SENT_INVITES_QUERY_CONTRACT } from "@oxygen/shared/contracts/linkedin-invites-list";
8
+ import { Command } from "commander";
9
+ const LINKEDIN_SENT_INVITES_FLAG_OVERLAY = {
10
+ account: { valueName: "<ref>", help: "Scope to one sender account (sender id, connection id, or Unipile account id).", parse: readOption },
11
+ limit: { valueName: "<n>", help: "Maximum invitations to return.", parse: readPositiveInt },
12
+ cursor: { valueName: "<cursor>", parse: readOption },
13
+ };
14
+ // `linkedin intent autoenroll` request body. The route reads `captures` (the wire
15
+ // name of the capture kinds) plus `post_id`/`post`, so the CSV `--kinds` flag maps
16
+ // onto `captures` here rather than inventing a second server field.
17
+ //
18
+ // An omitted `--kinds` sends NO captures key at all: the server then defaults to the
19
+ // captures `linkedin intent setup` already provisioned for this sender, and a
20
+ // client-side default list would instead CREATE captures the user never agreed to.
21
+ // Same reasoning for the caps — omitted means "inherit the plan-tier ceiling and the
22
+ // sender's ramped daily cap", which only the server can resolve.
23
+ function buildLinkedinIntentAutoenrollBody(options) {
24
+ const account = readOption(options.account);
25
+ if (!account)
26
+ throw new Error("--account is required.");
27
+ if (options.disable && options.approved) {
28
+ throw new OxygenError("conflicting_flags", "Pass either --disable (revoke the standing grant) or --approved (arm it), not both.", { exitCode: 1 });
29
+ }
30
+ // Revoking only ever narrows authority, so it carries the scope and nothing else —
31
+ // forwarding caps or a sequence on a disable would imply they still bind something.
32
+ const kinds = readCsvOption(options.kinds);
33
+ const post = readOption(options.post);
34
+ if (options.disable) {
35
+ return {
36
+ account,
37
+ disable: true,
38
+ ...(kinds.length > 0 ? { captures: kinds } : {}),
39
+ ...(post ? { post } : {}),
40
+ };
41
+ }
42
+ const sequence = readOption(options.sequence);
43
+ const postUrl = readOption(options.postUrl);
44
+ // Both readers THROW on a typed-but-unusable cap (0, negative, non-numeric) rather
45
+ // than returning undefined, which matters here: undefined means "inherit the server
46
+ // default", so coercing a typed `--max-enrolls-per-day 0` to absent would answer a
47
+ // request to enrol NOBODY by granting the sender's full ramped daily cap. Narrowing
48
+ // must never widen. Pinned by the cap tests in index.test.ts.
49
+ const maxCreditsPerCycle = readPositiveNumber(options.maxCreditsPerCycle);
50
+ const maxEnrollsPerDay = readPositiveInt(options.maxEnrollsPerDay);
51
+ return {
52
+ account,
53
+ ...(sequence ? { sequence } : {}),
54
+ ...(kinds.length > 0 ? { captures: kinds } : {}),
55
+ ...(maxCreditsPerCycle !== undefined ? { max_credits_per_cycle: maxCreditsPerCycle } : {}),
56
+ ...(maxEnrollsPerDay !== undefined ? { max_enrolls_per_day: maxEnrollsPerDay } : {}),
57
+ ...(options.includeExistingNetwork ? { include_existing_network: true } : {}),
58
+ ...(post ? { post } : {}),
59
+ ...(postUrl ? { post_url: postUrl } : {}),
60
+ ...(options.approved ? { approved: true } : {}),
61
+ };
62
+ }
63
+ export function registerLinkedinFamily(program, handleAsyncAction) {
64
+ program.addCommand(new Command("linkedin")
65
+ .description("Put your own LinkedIn network in a table and keep it current. `linkedin network setup` captures everyone you are connected to and everyone who follows you into one self-refreshing 'LinkedIn Network' table (free, read-only on your account, paced so the account is never at risk); `linkedin network status` reports the pace and `linkedin network pause` switches it off. `linkedin invitations setup` does the same for open connection requests — received and sent — in one self-updating table. Also home to `linkedin intent` (engagement capture) and `linkedin ingestion status` (every LinkedIn read drip and each account's remaining read budget).")
66
+ .addCommand(new Command("network")
67
+ .description("Capture everyone already in your LinkedIn network \u2014 the people you are connected to and the people who follow you \u2014 into one self-refreshing workspace table you can filter, enrich and enroll from. READ-ONLY on your LinkedIn account: it lists your own connections and followers and nothing else. It sends no messages, no connection requests, and does not visit anyone's profile. Runs as a slow background drip on its OWN per-account read budget, so it cannot slow down or starve anything else the account does: about 2,000 people a day while it first walks your network (40 reads of up to 50 people), then a light check a few times a day for new arrivals. Only inside each account's own 07:00-22:00 working hours, spaced minutes apart, never in a burst; a newly armed account eases in over its first two weeks. LinkedIn does not say how big a network is until the walk has been through it, so a large network takes days \u2014 `status` reports the rate, not a completion date it cannot know. Free \u2014 no Oxygen credits for this read; it uses your connected LinkedIn account, whose seat or credit reservation has its own terms.")
68
+ .addCommand(new Command("setup")
69
+ .description("Arm (or re-arm) network capture. Creates or reuses one merged 'LinkedIn Network' table and starts a connections drip and a followers drip per account, both writing into that one table deduped on LinkedIn member id \u2014 somebody who is both shows as 'both' in the Relationship column. This is a STANDING permission: capture keeps running until you switch it off with `linkedin network pause`, and a LinkedIn account you connect later is armed automatically. A newly connected account eases into full read speed over its first two weeks. Nothing is sent and no credits are charged. The response names each account it armed (`senders[].display_name`) \u2014 check it is yours before leaving it running.")
70
+ .option("--account <ref>", "Account to capture (sender id, connection id, or Unipile account id). Omit to capture every connected LinkedIn account.")
71
+ .option("--table <ref>", "Existing workspace table (id or slug) to capture into. Omit to create or reuse 'LinkedIn Network'.")
72
+ .option("--json", "Print a JSON envelope.")
73
+ .action(async (options) => {
74
+ await handleAsyncAction("linkedin network setup", options, () => {
75
+ const account = readOption(options.account);
76
+ const table = readOption(options.table);
77
+ return requestOxygen("/api/cli/tables/linkedin-network", {
78
+ method: "POST",
79
+ body: {
80
+ ...(account ? { account } : {}),
81
+ ...(table ? { table } : {}),
82
+ },
83
+ });
84
+ });
85
+ }))
86
+ .addCommand(new Command("status")
87
+ .description("Show network capture progress: `accounts[]` lists every connected LinkedIn account with its headline, `on` (switched on or not), and state (off|collecting|waiting|paused|attention); which accounts are armed, what each one may actually read TODAY after its warm-up ramp (`reads_per_day_now` / `people_per_day_now`), and per-drip state \u2014 including whether each half is still doing its first full walk ('backfill') or has switched to the light check ('delta'). `pace` states the rate in people per day and says plainly that no completion date exists until the first walk finishes, rather than inventing one. Also previews the table and deep-links to it. A capture sitting in 'backfill' for days is working as designed, not stuck.")
88
+ .option("--json", "Print a JSON envelope.")
89
+ .action(async (options) => {
90
+ await handleAsyncAction("linkedin network status", options, () => requestOxygen("/api/cli/tables/linkedin-network"));
91
+ }))
92
+ .addCommand(new Command("pause")
93
+ .description("Switch network capture off: the worker stops reading that account's connections and followers until you run `linkedin network setup` again. Pass --account to pause one account (the one you armed by mistake, say); omit it to pause every armed account. The table and its rows stay exactly as they are, and re-arming continues the walk where it stopped rather than starting over. A standalone `connections import` or `followers import` is not touched. Free.")
94
+ .option("--account <ref>", "Account to pause (sender id, connection id, or Unipile account id). Omit to pause every armed LinkedIn account.")
95
+ .option("--json", "Print a JSON envelope.")
96
+ .action(async (options) => {
97
+ await handleAsyncAction("linkedin network pause", options, () => {
98
+ const account = readOption(options.account);
99
+ return requestOxygen("/api/cli/tables/linkedin-network/pause", {
100
+ method: "POST",
101
+ body: { ...(account ? { account } : {}) },
102
+ });
103
+ });
104
+ })))
105
+ .addCommand(new Command("intent")
106
+ .description("Capture organic LinkedIn intent in durable OXYGEN Workflows + linked Tables. People are deduped; every reaction, comment, weekly profile view, new follower, and new connection is retained as a touchpoint. Engagement does not create CRM leads.")
107
+ .addCommand(new Command("setup")
108
+ .description("Create/reuse the canonical OXYGEN Tables, link them, and arm capture-only worker-backed engagement workflows for profile viewers, followers, and connections. Optionally add a recurring post-engager workflow with --post.")
109
+ .requiredOption("--account <ref>", "Connected LinkedIn sender to read through.")
110
+ .option("--post <social_id>", "Optional composite social_id for a post whose reactions + comments should be watched.")
111
+ .option("--post-url <url>", "Optional public post URL retained with the post watch.")
112
+ .option("--json", "Print a JSON envelope.")
113
+ .action(async (options) => {
114
+ await handleAsyncAction("linkedin intent setup", options, () => {
115
+ const account = readOption(options.account);
116
+ const post = readOption(options.post);
117
+ const postUrl = readOption(options.postUrl);
118
+ return requestOxygen("/api/cli/linkedin/intent", {
119
+ method: "POST",
120
+ body: {
121
+ ...(account ? { account } : {}),
122
+ ...(post ? { post } : {}),
123
+ ...(postUrl ? { post_url: postUrl } : {}),
124
+ },
125
+ });
126
+ });
127
+ }))
128
+ .addCommand(new Command("status")
129
+ .description("Show the canonical intent tables, their linked-table deep-links, and the capture feeds filling them. Workspace-wide: it lists every sender's captures and takes no --account; filter by the sender_account_id on each capture instead.")
130
+ .option("--json", "Print a JSON envelope.")
131
+ .action(async (options) => {
132
+ await handleAsyncAction("linkedin intent status", options, () => requestOxygen("/api/cli/linkedin/intent"));
133
+ }))
134
+ // A sibling of `setup`, not a flag on it: setup is free, idempotent and
135
+ // needs no approval ("make sure these captures and tables exist"), while
136
+ // this is a STANDING authorization to contact people on every future
137
+ // cycle. One verb carrying both postures would make the safe default
138
+ // ambiguous on the surface a founder reads first.
139
+ .addCommand(new Command("autoenroll")
140
+ .description("Authorize the captures armed by `linkedin intent setup` to enroll the people they capture into a sequence — the step that turns captured rows into outreach. PREVIEWS BY DEFAULT and writes nothing: it prints the resolved sender and its effective daily caps, the sequence, per-capture create-vs-patch, the live audience split (already 1st-degree / needs an invite / suppressed / already owned by another sender, and — while a capture still baselines — how many are recorded rather than contacted), anything that would make --approved fail before it writes, the resolved spend + enroll caps and where each came from, and a 7-day send forecast. Re-run with --approved to arm a STANDING grant: every later cycle enrolls newly captured people under those caps without asking again, including people you have never seen. This play is a drip, not a blast — a connections import walks LinkedIn on a metered budget (15 relations reads a day by default, ~50 people a read), so a real network lands over days, and a sender on the warm-up ramp is floored at 5 invites and 5 messages a day for its first three days no matter what caps you set. Revoke at any time with `--disable`.")
141
+ .requiredOption("--account <ref>", "Connected LinkedIn sender whose captures are authorized (sender id, connection id, or Unipile account id).")
142
+ .option("--sequence <ref>", "Sequence (id or slug) the captured people are enrolled into. Required to arm: a standing grant has to name the journey it puts people in.")
143
+ .option("--kinds <csv>", "Captures to authorize: connections, followers, profile_viewers, own_posts, post. Defaults to every capture `linkedin intent setup` already provisioned for this sender; naming a kind it never provisioned creates that capture.")
144
+ .option("--max-credits-per-cycle <n>", "Hard credit ceiling for one cycle of this grant. Omit to inherit your plan tier's per-delivery default (the preview prints which applied). Capturing through a connected account costs 0 credits; a cookieless harvest does not.")
145
+ .option("--max-enrolls-per-day <n>", "Cap on new people enrolled per UTC day. Omit to inherit the sender's effective — warm-up-ramped — daily message cap.")
146
+ .option("--include-existing-network", "Also reach the connections you ALREADY have. Without this flag the first cycle records everyone already captured as a silent baseline and only enrolls people who connect, follow, view, or engage from now on.")
147
+ .option("--post <social_id>", "Composite post social_id from `oxygen posts get`. Required when the `post` capture is authorized.")
148
+ .option("--post-url <url>", "Public LinkedIn post URL retained with the post capture.")
149
+ .option("--approved", "Arm the standing grant. Without it nothing is written and nobody is contacted.")
150
+ .option("--disable", "Revoke the standing grant for this sender. Needs no approval — it only narrows authority. The captures and their tables keep filling; only the permission to contact people is cleared.")
151
+ .option("--json", "Print a JSON envelope.")
152
+ .action(async (options) => {
153
+ await handleAsyncAction("linkedin intent autoenroll", options, () => requestOxygen("/api/cli/linkedin/intent/autoenroll", {
154
+ method: "POST",
155
+ body: buildLinkedinIntentAutoenrollBody(options),
156
+ }));
157
+ })))
158
+ .addCommand(new Command("ingestion")
159
+ .description("Inspect the LinkedIn ingestion drips that read your network, post engagers, and message history into the workspace.")
160
+ .addCommand(new Command("status")
161
+ .description("Unified status of every LinkedIn ingestion drip (connections import, engagement harvest, message-history backfill) plus each account's remaining ingest read budget for the day.")
162
+ .option("--account <ref>", "Scope to one sender account (sender id, connection id, or Unipile account id).")
163
+ .option("--json", "Print a JSON envelope.")
164
+ .action(async (options) => {
165
+ await handleAsyncAction("linkedin ingestion status", options, () => {
166
+ const account = readOption(options.account);
167
+ const params = new URLSearchParams();
168
+ if (account)
169
+ params.set("account", account);
170
+ const suffix = params.toString();
171
+ return requestOxygen(`/api/cli/linkedin/ingestion/status${suffix ? `?${suffix}` : ""}`);
172
+ });
173
+ })))
174
+ .addCommand(new Command("connections")
175
+ .description("Send LinkedIn connection invitations from a sender account.")
176
+ .addCommand(new Command("invite")
177
+ .description("Send a LinkedIn connection invitation. A real external social action gated behind approval: prints a preview by default and only sends when you pass --approved. The recipient can be a member provider id (ACo…) or a profile URL / public identifier. The per-account invite quota and warm-up ramp are enforced server-side, and already-invited recipients are de-duplicated automatically.")
178
+ .requiredOption("--recipient <id_or_url>", "Recipient LinkedIn provider id (ACo…) or profile URL / public identifier.")
179
+ .option("--account <ref>", "Sender account that sends the invite (sender id, connection id, or Unipile account id). Omit for the org default.")
180
+ .option("--message <text>", "Optional invitation note (~300 chars max).")
181
+ .option("--approved", "Actually send the invite. Omit to preview only.")
182
+ .option("--json", "Print a JSON envelope.")
183
+ .action(async (options) => {
184
+ await handleAsyncAction("linkedin connections invite", options, () => {
185
+ const recipient = readOption(options.recipient);
186
+ const account = readOption(options.account);
187
+ const message = readOption(options.message);
188
+ return requestOxygen("/api/cli/linkedin/connections/invite", {
189
+ method: "POST",
190
+ body: {
191
+ ...(recipient ? { recipient } : {}),
192
+ ...(account ? { account } : {}),
193
+ ...(message ? { message } : {}),
194
+ ...(options.approved ? { approved: true } : {}),
195
+ },
196
+ });
197
+ });
198
+ })))
199
+ .addCommand(new Command("invitations")
200
+ .description("Open LinkedIn connection requests on your own accounts. `setup` keeps one self-updating 'LinkedIn Open Connection Requests' table of every pending request — people who asked to connect with you (received) and requests you sent (sent) — and marks each one accepted or no_longer_pending when it disappears; `status` and `pause` manage it. `list` and `withdraw` act on the sent requests directly.")
201
+ .addCommand(new Command("setup")
202
+ .description("Switch on the open connection requests table. Creates or reuses one 'LinkedIn Open Connection Requests' table and checks each chosen account about twice a day, inside that account's working hours: every pending request, received and sent, is a row with the person, the account it is on (`account`), its `direction` and its `status`. A request that disappears is marked `accepted` when the person is now a connection, otherwise `no_longer_pending` (LinkedIn does not say whether it was declined, withdrawn or expired); acceptances seen live are marked within minutes. READ-ONLY on LinkedIn: nothing is accepted, declined, withdrawn or sent. Free — no Oxygen credits; the reads count against each account's daily LinkedIn read budget. Accounts connected later stay off until you switch them on.")
203
+ .option("--account <ref>", "Account to switch on (sender id, connection id, or Unipile account id). Omit to switch on every connected LinkedIn account.")
204
+ .option("--table <ref>", "Existing workspace table (id or slug) to write into. Omit to create or reuse 'LinkedIn Open Connection Requests'.")
205
+ .option("--json", "Print a JSON envelope.")
206
+ .action(async (options) => {
207
+ await handleAsyncAction("linkedin invitations setup", options, () => {
208
+ const account = readOption(options.account);
209
+ const table = readOption(options.table);
210
+ return requestOxygen("/api/cli/tables/linkedin-open-invites", {
211
+ method: "POST",
212
+ body: {
213
+ ...(account ? { account } : {}),
214
+ ...(table ? { table } : {}),
215
+ },
216
+ });
217
+ });
218
+ }))
219
+ .addCommand(new Command("status")
220
+ .description("Show the open connection requests table: `accounts[]` lists every connected LinkedIn account with `on`, its state (off|collecting|waiting|paused|attention), and when it was last and will next be checked. Also previews the table and deep-links to it.")
221
+ .option("--json", "Print a JSON envelope.")
222
+ .action(async (options) => {
223
+ await handleAsyncAction("linkedin invitations status", options, () => requestOxygen("/api/cli/tables/linkedin-open-invites"));
224
+ }))
225
+ .addCommand(new Command("pause")
226
+ .description("Stop checking open connection requests for one account (--account) or every account. The table and its rows stay; `linkedin invitations setup` switches it back on. Free.")
227
+ .option("--account <ref>", "Account to pause (sender id, connection id, or Unipile account id). Omit to pause every account.")
228
+ .option("--json", "Print a JSON envelope.")
229
+ .action(async (options) => {
230
+ await handleAsyncAction("linkedin invitations pause", options, () => {
231
+ const account = readOption(options.account);
232
+ return requestOxygen("/api/cli/tables/linkedin-open-invites/pause", {
233
+ method: "POST",
234
+ body: { ...(account ? { account } : {}) },
235
+ });
236
+ });
237
+ }))
238
+ .addCommand(new Command("withdraw")
239
+ .description("Withdraw pending sent LinkedIn invitations. A real external social action gated behind approval: prints the resolved target list by default and only withdraws when you pass --approved. Select targets with --ids (a comma-separated id list from `linkedin invitations list`) OR --older-than <days> (pending invites older than N days, among the 100 most recent sent) — not both. Idempotent: an invite that is already gone counts as withdrawn.")
240
+ .option("--ids <a,b>", "Comma-separated invitation ids to withdraw (from `linkedin invitations list`).")
241
+ .option("--older-than <days>", "Withdraw pending sent invites older than this many days (among the 100 most recent sent) instead of an explicit id list.")
242
+ .option("--account <ref>", "Sender account (sender id, connection id, or Unipile account id). Omit for the org default.")
243
+ .option("--approved", "Actually withdraw. Omit to preview the target list only.")
244
+ .option("--json", "Print a JSON envelope.")
245
+ .action(async (options) => {
246
+ await handleAsyncAction("linkedin invitations withdraw", options, () => {
247
+ const ids = (options.ids ?? "").split(",").map((id) => id.trim()).filter(Boolean);
248
+ const olderThan = readPositiveInt(options.olderThan);
249
+ const account = readOption(options.account);
250
+ return requestOxygen("/api/cli/linkedin/connections/invite/withdraw", {
251
+ method: "POST",
252
+ body: {
253
+ ...(ids.length > 0 ? { invitation_ids: ids } : {}),
254
+ ...(olderThan !== undefined ? { older_than_days: olderThan } : {}),
255
+ ...(account ? { account } : {}),
256
+ ...(options.approved ? { approved: true } : {}),
257
+ },
258
+ });
259
+ });
260
+ }))
261
+ .addCommand(addContractFlags(new Command("list")
262
+ .description("List the account's pending sent LinkedIn invitations with their invitation ids — the ids `linkedin invitations withdraw --ids` cancels. Read-only provider fetch: no provider write or credits. --cursor resumes the same sender's returned continuation. For received requests too, kept in a table that updates itself, use `linkedin invitations setup`."), LINKEDIN_SENT_INVITES_QUERY_CONTRACT, LINKEDIN_SENT_INVITES_FLAG_OVERLAY)
263
+ .option("--json", "Print a JSON envelope.")
264
+ .action(async (options) => {
265
+ await handleAsyncAction("linkedin invitations list", options, () => {
266
+ const selectors = readContractFlags(options, LINKEDIN_SENT_INVITES_QUERY_CONTRACT, LINKEDIN_SENT_INVITES_FLAG_OVERLAY);
267
+ const params = new URLSearchParams();
268
+ for (const [key, value] of Object.entries(selectors))
269
+ if (value !== undefined && value !== null)
270
+ params.set(key, String(value));
271
+ const suffix = params.toString();
272
+ return requestOxygen(`/api/cli/linkedin/connections/invites-sent${suffix ? `?${suffix}` : ""}`);
273
+ });
274
+ }))));
275
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerLoginFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;