@curviate/cli 0.4.1 → 0.6.0

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
@@ -8,6 +8,41 @@ a new command or flag is a minor; a breaking command/flag/exit-code change is a
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.6.0] - 2026-06-30
12
+
13
+ ### Added
14
+
15
+ - `inbox list --unread` — filter the inbox to chats with unread messages.
16
+ - `messages` now accepts `--before` and `--after` to page a conversation by
17
+ timestamp window.
18
+ - `sync-chat --wait` — poll until a chat sync completes instead of returning
19
+ immediately.
20
+ - `message new --to` and `message inmail --to` now resolve a **LinkedIn profile
21
+ URL or vanity slug** (e.g. `linkedin.com/in/<slug>`) to the recipient, in
22
+ addition to provider ids and member URNs.
23
+ - Thread-URL `chat_id` normalization — a pasted conversation URL is normalized to
24
+ the underlying chat id wherever a `chat_id` is accepted.
25
+ - Write commands that take a TEXT positional accept `-` to read the value from
26
+ stdin (pipe message bodies in).
27
+ - `connect`: slim default projection + write-flag suppression + help text
28
+ (Invites-AX co-release).
29
+
30
+ ### Changed
31
+
32
+ - Pagination flags are suppressed from the help output of non-list commands.
33
+ - Updated `@curviate/sdk` dependency to `^0.4.0` (regenerated types:
34
+ `primary_locale` on profile, account-sync `status` field).
35
+
36
+ ## [0.5.0] - 2026-06-29
37
+
38
+ ### Added
39
+
40
+ - `message inmail --surface classic` — send an InMail from the account's own premium
41
+ InMail credits (in addition to `sales_nav` and `recruiter`). Use this to reach an
42
+ out-of-network member from a LinkedIn Premium/Core account.
43
+ - `message inmail --to` now accepts a member **provider id** (`ACoAAA…`) as well as a
44
+ member URN (`urn:li:member:<id>`). The server resolves the recipient either way.
45
+
11
46
  ## [0.4.1] - 2026-06-29
12
47
 
13
48
  ### Changed
@@ -11,10 +11,10 @@ import {
11
11
  renderSuccess,
12
12
  renderUnexpectedError,
13
13
  resolveEffectiveConfig
14
- } from "./chunk-U6ACUNLU.js";
14
+ } from "./chunk-47SYFQRF.js";
15
15
  import {
16
16
  GLOBAL_FLAGS
17
- } from "./chunk-52RZLSWP.js";
17
+ } from "./chunk-TDYIQHQX.js";
18
18
 
19
19
  // src/commands/account.ts
20
20
  import { defineCommand } from "citty";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readConfig
4
- } from "./chunk-52RZLSWP.js";
4
+ } from "./chunk-TDYIQHQX.js";
5
5
 
6
6
  // src/lib/resolve.ts
7
7
  var DEFAULT_BASE_URL = "https://api.curviate.com";
@@ -64,6 +64,48 @@ function slimProfile(data) {
64
64
  current_position: currentPosition
65
65
  };
66
66
  }
67
+ function slimInviteSentItem(item) {
68
+ return {
69
+ id: item["id"] ?? null,
70
+ invited_user: item["invited_user"] ?? null,
71
+ invited_user_id: item["invited_user_id"] ?? null,
72
+ invited_user_public_id: item["invited_user_public_id"] ?? null,
73
+ invited_user_description: item["invited_user_description"] ?? null,
74
+ date: item["date"] ?? null,
75
+ parsed_datetime: item["parsed_datetime"] ?? null,
76
+ invitation_text: item["invitation_text"] ?? null
77
+ };
78
+ }
79
+ function slimInviteSent(data) {
80
+ const d = data !== null && data !== void 0 && typeof data === "object" ? data : {};
81
+ const items = Array.isArray(d["items"]) ? d["items"].map(slimInviteSentItem) : [];
82
+ return {
83
+ object: d["object"] ?? null,
84
+ items,
85
+ cursor: d["cursor"] ?? null
86
+ };
87
+ }
88
+ function slimInviteReceivedItem(item) {
89
+ const rawSpecifics = item["specifics"] !== null && item["specifics"] !== void 0 && typeof item["specifics"] === "object" ? item["specifics"] : null;
90
+ const specifics = rawSpecifics !== null ? { shared_secret: rawSpecifics["shared_secret"] ?? null } : null;
91
+ return {
92
+ id: item["id"] ?? null,
93
+ inviter: item["inviter"] ?? null,
94
+ date: item["date"] ?? null,
95
+ parsed_datetime: item["parsed_datetime"] ?? null,
96
+ invitation_text: item["invitation_text"] ?? null,
97
+ specifics
98
+ };
99
+ }
100
+ function slimInviteReceived(data) {
101
+ const d = data !== null && data !== void 0 && typeof data === "object" ? data : {};
102
+ const items = Array.isArray(d["items"]) ? d["items"].map(slimInviteReceivedItem) : [];
103
+ return {
104
+ object: d["object"] ?? null,
105
+ items,
106
+ cursor: d["cursor"] ?? null
107
+ };
108
+ }
67
109
  function slimCompany(data) {
68
110
  const d = data !== null && data !== void 0 && typeof data === "object" ? data : {};
69
111
  const rawMessaging = d["messaging"] !== null && d["messaging"] !== void 0 && typeof d["messaging"] === "object" ? d["messaging"] : null;
@@ -91,5 +133,9 @@ function slimCompany(data) {
91
133
  export {
92
134
  slimProfileMe,
93
135
  slimProfile,
136
+ slimInviteSentItem,
137
+ slimInviteSent,
138
+ slimInviteReceivedItem,
139
+ slimInviteReceived,
94
140
  slimCompany
95
141
  };
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/lib/stdin.ts
4
+ var STDIN_SENTINEL = "__curviate_stdin__";
5
+ async function defaultReadStdin() {
6
+ return new Promise((resolve, reject) => {
7
+ const chunks = [];
8
+ process.stdin.on("data", (chunk) => {
9
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
10
+ });
11
+ process.stdin.on("end", () => {
12
+ const full = Buffer.concat(chunks).toString("utf8");
13
+ resolve(full.replace(/\n+$/, ""));
14
+ });
15
+ process.stdin.on("error", reject);
16
+ });
17
+ }
18
+ async function resolveTextOrStdin(rawText, out, readStdin) {
19
+ if (rawText !== "-" && rawText !== STDIN_SENTINEL) return rawText;
20
+ const reader = readStdin ?? defaultReadStdin;
21
+ const text = await reader();
22
+ if (!text) {
23
+ out.stderr.write("error: stdin: empty input\n");
24
+ process.exit(2);
25
+ }
26
+ return text;
27
+ }
28
+
29
+ export {
30
+ STDIN_SENTINEL,
31
+ resolveTextOrStdin
32
+ };
@@ -27,7 +27,14 @@ function resolveIdentifier(raw) {
27
27
  function stripTrailingSlash(s) {
28
28
  return s.endsWith("/") ? s.slice(0, -1) : s;
29
29
  }
30
+ var MESSAGING_THREAD_URL_RE = /messaging\/thread\/([^/?]+)/;
31
+ function normalizeChatId(raw) {
32
+ const match = MESSAGING_THREAD_URL_RE.exec(raw);
33
+ if (match?.[1]) return match[1];
34
+ return raw;
35
+ }
30
36
 
31
37
  export {
32
- resolveIdentifier
38
+ resolveIdentifier,
39
+ normalizeChatId
33
40
  };
@@ -197,6 +197,17 @@ var WRITE_FLAGS = {
197
197
  preview: GLOBAL_FLAGS.preview,
198
198
  verbose: GLOBAL_FLAGS.verbose
199
199
  };
200
+ var READ_SINGLE_FLAGS = {
201
+ "api-key": GLOBAL_FLAGS["api-key"],
202
+ profile: GLOBAL_FLAGS.profile,
203
+ account: GLOBAL_FLAGS.account,
204
+ "base-url": GLOBAL_FLAGS["base-url"],
205
+ timeout: GLOBAL_FLAGS.timeout,
206
+ json: GLOBAL_FLAGS.json,
207
+ fields: GLOBAL_FLAGS.fields,
208
+ preview: GLOBAL_FLAGS.preview,
209
+ verbose: GLOBAL_FLAGS.verbose
210
+ };
200
211
 
201
212
  export {
202
213
  getConfigPath,
@@ -207,5 +218,6 @@ export {
207
218
  removeProfile,
208
219
  updateProfileField,
209
220
  GLOBAL_FLAGS,
210
- WRITE_FLAGS
221
+ WRITE_FLAGS,
222
+ READ_SINGLE_FLAGS
211
223
  };
package/dist/cli.js CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ STDIN_SENTINEL
4
+ } from "./chunk-CHFKVAEI.js";
2
5
 
3
6
  // src/cli.ts
4
7
  import { defineCommand } from "citty";
@@ -108,8 +111,9 @@ async function dispatch(root, rawArgs) {
108
111
  if (unknown !== null) {
109
112
  usageError(`unknown flag \`${unknown}\`.`);
110
113
  }
114
+ const processedLeafArgs = leafArgs.map((a) => a === "-" ? STDIN_SENTINEL : a);
111
115
  const leafToRun = { ...leaf, subCommands: void 0 };
112
- await runCommand(leafToRun, { rawArgs: leafArgs });
116
+ await runCommand(leafToRun, { rawArgs: processedLeafArgs });
113
117
  } catch (err) {
114
118
  const message = err instanceof Error ? err.message : String(err);
115
119
  const code = err?.code;
@@ -134,22 +138,22 @@ var main = defineCommand({
134
138
  // Subcommand registry — names and descriptions are static for help rendering;
135
139
  // the handler implementation is loaded lazily on first invocation.
136
140
  subCommands: {
137
- login: () => import("./login-UJQGIP7S.js").then((m) => m.loginCommand),
138
- config: () => import("./config-6PNGYL5E.js").then((m) => m.configCommand),
141
+ login: () => import("./login-POKHNDYX.js").then((m) => m.loginCommand),
142
+ config: () => import("./config-2GBLD4GN.js").then((m) => m.configCommand),
139
143
  // ---------------------------------------------------------------------------
140
144
  // Noun groups — lazy-loaded on first invocation.
141
145
  // ---------------------------------------------------------------------------
142
- profile: () => import("./profile-CUVVESMY.js").then((m) => m.profileCommand),
143
- company: () => import("./company-4MUABENR.js").then((m) => m.companyCommand),
144
- connect: () => import("./connect-ZXD7P5CA.js").then((m) => m.connectCommand),
145
- search: () => import("./search-M4WK3PDC.js").then((m) => m.searchCommand),
146
- inbox: () => import("./inbox-ME4TXGFV.js").then((m) => m.inboxCommand),
147
- message: () => import("./message-KAESYHVJ.js").then((m) => m.messageCommand),
148
- post: () => import("./post-VDQF23WS.js").then((m) => m.postCommand),
149
- account: () => import("./account-47TRPUKL.js").then((m) => m.accountCommand),
150
- webhook: () => import("./webhook-2SSNW25K.js").then((m) => m.webhookCommand),
151
- "sales-nav": () => import("./sales-nav-UL2H6J6V.js").then((m) => m.salesNavCommand),
152
- recruiter: () => import("./recruiter-QKJKOWD7.js").then((m) => m.recruiterCommand)
146
+ profile: () => import("./profile-NDDG26PL.js").then((m) => m.profileCommand),
147
+ company: () => import("./company-SZPGJE3M.js").then((m) => m.companyCommand),
148
+ connect: () => import("./connect-RMT7OS3I.js").then((m) => m.connectCommand),
149
+ search: () => import("./search-QO237C4O.js").then((m) => m.searchCommand),
150
+ inbox: () => import("./inbox-MIKI4HU3.js").then((m) => m.inboxCommand),
151
+ message: () => import("./message-YRMLMHK7.js").then((m) => m.messageCommand),
152
+ post: () => import("./post-2FYHZAKC.js").then((m) => m.postCommand),
153
+ account: () => import("./account-ZWBNNQKQ.js").then((m) => m.accountCommand),
154
+ webhook: () => import("./webhook-FDIERREB.js").then((m) => m.webhookCommand),
155
+ "sales-nav": () => import("./sales-nav-7WPN7BT4.js").then((m) => m.salesNavCommand),
156
+ recruiter: () => import("./recruiter-3DRGDOVV.js").then((m) => m.recruiterCommand)
153
157
  },
154
158
  async run() {
155
159
  const { runMain } = await import("citty");
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  slimCompany
4
- } from "./chunk-5NS2G4WQ.js";
4
+ } from "./chunk-6VBOKOQJ.js";
5
5
  import {
6
6
  resolveIdentifier
7
- } from "./chunk-BNUTM6KD.js";
7
+ } from "./chunk-SZB3CFRZ.js";
8
8
  import {
9
9
  createClient,
10
10
  renderError,
11
11
  renderSuccess,
12
12
  renderUnexpectedError,
13
13
  resolveEffectiveConfig
14
- } from "./chunk-U6ACUNLU.js";
14
+ } from "./chunk-47SYFQRF.js";
15
15
  import {
16
16
  GLOBAL_FLAGS
17
- } from "./chunk-52RZLSWP.js";
17
+ } from "./chunk-TDYIQHQX.js";
18
18
 
19
19
  // src/commands/company.ts
20
20
  import { defineCommand } from "citty";
@@ -7,7 +7,7 @@ import {
7
7
  renameProfile,
8
8
  setActiveProfile,
9
9
  updateProfileField
10
- } from "./chunk-52RZLSWP.js";
10
+ } from "./chunk-TDYIQHQX.js";
11
11
 
12
12
  // src/commands/config.ts
13
13
  import { defineCommand } from "citty";
@@ -2,9 +2,15 @@
2
2
  import {
3
3
  buildPreviewOutput
4
4
  } from "./chunk-R3VLWLVV.js";
5
+ import {
6
+ slimInviteReceived,
7
+ slimInviteReceivedItem,
8
+ slimInviteSent,
9
+ slimInviteSentItem
10
+ } from "./chunk-6VBOKOQJ.js";
5
11
  import {
6
12
  resolveIdentifier
7
- } from "./chunk-BNUTM6KD.js";
13
+ } from "./chunk-SZB3CFRZ.js";
8
14
  import {
9
15
  streamAll
10
16
  } from "./chunk-SND3NHCT.js";
@@ -14,10 +20,11 @@ import {
14
20
  renderSuccess,
15
21
  renderUnexpectedError,
16
22
  resolveEffectiveConfig
17
- } from "./chunk-U6ACUNLU.js";
23
+ } from "./chunk-47SYFQRF.js";
18
24
  import {
19
- GLOBAL_FLAGS
20
- } from "./chunk-52RZLSWP.js";
25
+ GLOBAL_FLAGS,
26
+ WRITE_FLAGS
27
+ } from "./chunk-TDYIQHQX.js";
21
28
 
22
29
  // src/commands/connect.ts
23
30
  import { defineCommand } from "citty";
@@ -44,7 +51,8 @@ function resolveOutputOpts(flags) {
44
51
  return {
45
52
  json: (flags.json ?? false) || !process.stdout.isTTY,
46
53
  isTTY: process.stdout.isTTY ?? false,
47
- fields: flags.fields
54
+ fields: flags.fields,
55
+ verbose: flags.verbose ?? false
48
56
  };
49
57
  }
50
58
  async function runConnectSend(client, flags, out) {
@@ -98,11 +106,12 @@ async function runConnectSent(client, flags, out) {
98
106
  maxPages,
99
107
  onTruncated: (msg) => out.stderr.write(msg + "\n")
100
108
  })) {
101
- out.stdout.write(JSON.stringify(item) + "\n");
109
+ const projected = !flags.verbose ? slimInviteSentItem(item) : item;
110
+ out.stdout.write(JSON.stringify(projected) + "\n");
102
111
  }
103
112
  } else {
104
113
  const result = await ns.invites.listSent(params);
105
- renderSuccess(result, outOpts, out);
114
+ renderSuccess(result, { ...outOpts, slim: slimInviteSent }, out);
106
115
  }
107
116
  } catch (err) {
108
117
  const { CurviateError } = await import("@curviate/sdk");
@@ -134,11 +143,12 @@ async function runConnectReceived(client, flags, out) {
134
143
  maxPages,
135
144
  onTruncated: (msg) => out.stderr.write(msg + "\n")
136
145
  })) {
137
- out.stdout.write(JSON.stringify(item) + "\n");
146
+ const projected = !flags.verbose ? slimInviteReceivedItem(item) : item;
147
+ out.stdout.write(JSON.stringify(projected) + "\n");
138
148
  }
139
149
  } else {
140
150
  const result = await ns.invites.listReceived(params);
141
- renderSuccess(result, outOpts, out);
151
+ renderSuccess(result, { ...outOpts, slim: slimInviteReceived }, out);
142
152
  }
143
153
  } catch (err) {
144
154
  const { CurviateError } = await import("@curviate/sdk");
@@ -219,7 +229,10 @@ async function runConnectCancel(client, flags, out) {
219
229
  }
220
230
  }
221
231
  var connectSentCommand = defineCommand({
222
- meta: { name: "sent", description: "List sent connection invitations." },
232
+ meta: {
233
+ name: "sent",
234
+ description: "Returns pending sent invitations only \u2014 accepted and declined invitations are not returned (LinkedIn API limitation). Use `id` with `connect cancel`; use `invited_user_public_id` or `invited_user_id` with `curviate profile`. `parsed_datetime` is approximate \u2014 derived from LinkedIn's relative date label; invitations sharing a label get the same computed time. No total count is available; use `connect sent --all` and count client-side."
235
+ },
223
236
  args: { ...GLOBAL_FLAGS },
224
237
  async run({ args }) {
225
238
  const flags = args;
@@ -242,7 +255,7 @@ var connectSentCommand = defineCommand({
242
255
  var connectReceivedCommand = defineCommand({
243
256
  meta: {
244
257
  name: "received",
245
- description: "List received connection invitations. Each item carries a shared_secret \u2014 pass it to `connect respond --shared-secret`."
258
+ description: "Returns pending received invitations only \u2014 already-handled invitations are not returned. The `inviter.*` fields identify who sent the request. `specifics.shared_secret` is required for `connect respond`."
246
259
  },
247
260
  args: { ...GLOBAL_FLAGS },
248
261
  async run({ args }) {
@@ -266,12 +279,15 @@ var connectReceivedCommand = defineCommand({
266
279
  var connectRespondCommand = defineCommand({
267
280
  meta: { name: "respond", description: "Accept or decline a received invitation." },
268
281
  args: {
269
- ...GLOBAL_FLAGS,
270
- id: { type: "positional", description: "Invitation id to respond to." },
282
+ ...WRITE_FLAGS,
283
+ id: {
284
+ type: "positional",
285
+ description: "Invitation id to respond to \u2014 use the `id` field from `connect received`."
286
+ },
271
287
  action: { type: "string", description: "Response action: accept or decline.", required: true },
272
288
  "shared-secret": {
273
289
  type: "string",
274
- description: "Per-invitation shared secret \u2014 read it from `connect received`.",
290
+ description: "Per-invitation shared secret \u2014 use `specifics.shared_secret` from the same `connect received` item.",
275
291
  required: true
276
292
  }
277
293
  },
@@ -296,7 +312,7 @@ var connectRespondCommand = defineCommand({
296
312
  var connectCancelCommand = defineCommand({
297
313
  meta: { name: "cancel", description: "Cancel a sent invitation." },
298
314
  args: {
299
- ...GLOBAL_FLAGS,
315
+ ...WRITE_FLAGS,
300
316
  id: { type: "positional", description: "Invitation id to cancel." }
301
317
  },
302
318
  async run({ args }) {
@@ -318,11 +334,21 @@ var connectCancelCommand = defineCommand({
318
334
  }
319
335
  });
320
336
  var connectCommand = defineCommand({
321
- meta: { name: "connect", description: "Send or manage connection invitations." },
337
+ meta: {
338
+ name: "connect",
339
+ description: "Send or manage connection invitations. Connection requests may take 10\u201330 seconds to appear in the recipient's received list (LinkedIn propagation delay)."
340
+ },
322
341
  args: {
323
- ...GLOBAL_FLAGS,
324
- id: { type: "positional", description: "Member identifier (URL, slug, or URN).", required: false },
325
- note: { type: "string", description: "Optional invitation note (\u2264300 characters)." }
342
+ ...WRITE_FLAGS,
343
+ id: {
344
+ type: "positional",
345
+ description: "Recipient's LinkedIn URL, public slug, or provider_id (ACoAAA\u2026 from `curviate profile`). LinkedIn URN (`urn:li:member:N`) also accepted but the numeric member ID is not exposed by this API.",
346
+ required: false
347
+ },
348
+ note: {
349
+ type: "string",
350
+ description: "Personalized message shown to the recipient alongside the connection request (\u2264300 chars; LinkedIn cap). Omit to send a generic note. Personalized messages increase acceptance rates."
351
+ }
326
352
  },
327
353
  subCommands: {
328
354
  sent: connectSentCommand,
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ normalizeChatId
4
+ } from "./chunk-SZB3CFRZ.js";
2
5
  import {
3
6
  streamAll
4
7
  } from "./chunk-SND3NHCT.js";
@@ -8,10 +11,11 @@ import {
8
11
  renderSuccess,
9
12
  renderUnexpectedError,
10
13
  resolveEffectiveConfig
11
- } from "./chunk-U6ACUNLU.js";
14
+ } from "./chunk-47SYFQRF.js";
12
15
  import {
13
- GLOBAL_FLAGS
14
- } from "./chunk-52RZLSWP.js";
16
+ GLOBAL_FLAGS,
17
+ READ_SINGLE_FLAGS
18
+ } from "./chunk-TDYIQHQX.js";
15
19
 
16
20
  // src/commands/inbox.ts
17
21
  import { defineCommand } from "citty";
@@ -53,6 +57,15 @@ function buildPaginationParams(flags) {
53
57
  if (flags.cursor) params["cursor"] = flags.cursor;
54
58
  return params;
55
59
  }
60
+ function validateIsoZTimestamp(value, flagName, out) {
61
+ if (Number.isNaN(new Date(value).getTime()) || !value.endsWith("Z")) {
62
+ out.stderr.write(
63
+ `error: --${flagName}: must be a UTC ISO-8601 timestamp ending in 'Z' (e.g. 2025-01-01T00:00:00Z).
64
+ `
65
+ );
66
+ process.exit(2);
67
+ }
68
+ }
56
69
  async function handleSdkError(err, outOpts, out) {
57
70
  const { CurviateError } = await import("@curviate/sdk");
58
71
  if (err instanceof CurviateError) {
@@ -71,6 +84,9 @@ async function runInboxList(client, flags, out) {
71
84
  const all = flags.all ?? false;
72
85
  const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
73
86
  const params = buildPaginationParams(flags);
87
+ if (flags.unread !== void 0) {
88
+ params.unread = flags.unread;
89
+ }
74
90
  try {
75
91
  if (all) {
76
92
  const fn = (p) => ns.messaging.listChats(p);
@@ -92,7 +108,7 @@ async function runInboxGet(client, flags, out) {
92
108
  rejectPreviewOnRead(flags.preview, out);
93
109
  rejectAllOnNonPaginated(flags.all, out);
94
110
  const accountId = requireAccount(flags.account, out);
95
- const chatId = flags.chatId ?? "";
111
+ const chatId = normalizeChatId(flags.chatId ?? "");
96
112
  const ns = client.account(accountId);
97
113
  const outOpts = resolveOutputOpts(flags);
98
114
  try {
@@ -105,12 +121,20 @@ async function runInboxGet(client, flags, out) {
105
121
  async function runInboxMessages(client, flags, out) {
106
122
  rejectPreviewOnRead(flags.preview, out);
107
123
  const accountId = requireAccount(flags.account, out);
108
- const chatId = flags.chatId ?? "";
124
+ const chatId = normalizeChatId(flags.chatId ?? "");
109
125
  const ns = client.account(accountId);
110
126
  const outOpts = resolveOutputOpts(flags);
111
127
  const all = flags.all ?? false;
112
128
  const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
113
129
  const params = buildPaginationParams(flags);
130
+ if (flags.before !== void 0) {
131
+ validateIsoZTimestamp(flags.before, "before", out);
132
+ params.before = flags.before;
133
+ }
134
+ if (flags.after !== void 0) {
135
+ validateIsoZTimestamp(flags.after, "after", out);
136
+ params.after = flags.after;
137
+ }
114
138
  try {
115
139
  if (all) {
116
140
  const fn = (p) => ns.messaging.listMessages(chatId, p);
@@ -141,23 +165,58 @@ async function runInboxSync(client, flags, out) {
141
165
  await handleSdkError(err, outOpts, out);
142
166
  }
143
167
  }
144
- async function runInboxSyncChat(client, flags, out) {
168
+ var SYNC_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["done", "error", "chat_deleted"]);
169
+ var SYNC_POLL_INTERVAL_MS = 2e3;
170
+ async function runInboxSyncChat(client, flags, out, _sleep) {
145
171
  rejectPreviewOnRead(flags.preview, out);
146
172
  rejectAllOnNonPaginated(flags.all, out);
147
173
  const accountId = requireAccount(flags.account, out);
148
- const chatId = flags.chatId ?? "";
174
+ const chatId = normalizeChatId(flags.chatId ?? "");
149
175
  const ns = client.account(accountId);
150
176
  const outOpts = resolveOutputOpts(flags);
151
- try {
152
- const result = await ns.messaging.syncChat(chatId);
153
- renderSuccess(result, outOpts, out);
154
- } catch (err) {
155
- await handleSdkError(err, outOpts, out);
177
+ if (!flags.wait) {
178
+ try {
179
+ const result = await ns.messaging.syncChat(chatId);
180
+ renderSuccess(result, outOpts, out);
181
+ } catch (err) {
182
+ await handleSdkError(err, outOpts, out);
183
+ }
184
+ return;
185
+ }
186
+ const sleep = _sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
187
+ const timeoutSecs = parseInt(flags.timeout ?? "30", 10);
188
+ const timeoutMs = (Number.isNaN(timeoutSecs) ? 30 : timeoutSecs) * 1e3;
189
+ const startTime = Date.now();
190
+ while (true) {
191
+ let result;
192
+ try {
193
+ result = await ns.messaging.syncChat(chatId);
194
+ } catch (err) {
195
+ await handleSdkError(err, outOpts, out);
196
+ }
197
+ const resp = result;
198
+ if (resp.status !== void 0 && SYNC_TERMINAL_STATUSES.has(resp.status)) {
199
+ renderSuccess(result, outOpts, out);
200
+ return;
201
+ }
202
+ if (Date.now() - startTime >= timeoutMs) {
203
+ renderSuccess(result, outOpts, out);
204
+ process.exit(3);
205
+ return;
206
+ }
207
+ await sleep(SYNC_POLL_INTERVAL_MS);
156
208
  }
157
209
  }
158
210
  var inboxListCommand = defineCommand({
159
211
  meta: { name: "list", description: "List inbox chats." },
160
- args: { ...GLOBAL_FLAGS },
212
+ args: {
213
+ ...GLOBAL_FLAGS,
214
+ unread: {
215
+ type: "boolean",
216
+ description: "Show unread chats only (--no-unread for read-only; omit for all)."
217
+ // No default → three-way semantics: undefined when omitted, true for --unread, false for --no-unread
218
+ }
219
+ },
161
220
  async run({ args }) {
162
221
  const flags = args;
163
222
  const cfg = await resolveEffectiveConfig({
@@ -179,7 +238,8 @@ var inboxListCommand = defineCommand({
179
238
  var inboxGetCommand = defineCommand({
180
239
  meta: { name: "get", description: "Get details of a single chat." },
181
240
  args: {
182
- ...GLOBAL_FLAGS,
241
+ // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
242
+ ...READ_SINGLE_FLAGS,
183
243
  chatId: { type: "positional", description: "Chat ID." }
184
244
  },
185
245
  async run({ args }) {
@@ -204,7 +264,15 @@ var inboxMessagesCommand = defineCommand({
204
264
  meta: { name: "messages", description: "List messages in a chat." },
205
265
  args: {
206
266
  ...GLOBAL_FLAGS,
207
- chatId: { type: "positional", description: "Chat ID." }
267
+ chatId: { type: "positional", description: "Chat ID." },
268
+ before: {
269
+ type: "string",
270
+ description: "Return messages before this timestamp (ISO-8601, UTC \u2014 Z suffix required, e.g. 2025-01-01T00:00:00Z)."
271
+ },
272
+ after: {
273
+ type: "string",
274
+ description: "Return messages after this timestamp (ISO-8601, UTC \u2014 Z suffix required, e.g. 2025-01-01T00:00:00Z)."
275
+ }
208
276
  },
209
277
  async run({ args }) {
210
278
  const flags = args;
@@ -226,7 +294,10 @@ var inboxMessagesCommand = defineCommand({
226
294
  });
227
295
  var inboxSyncCommand = defineCommand({
228
296
  meta: { name: "sync", description: "Re-sync account message history." },
229
- args: { ...GLOBAL_FLAGS },
297
+ args: {
298
+ // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
299
+ ...READ_SINGLE_FLAGS
300
+ },
230
301
  async run({ args }) {
231
302
  const flags = args;
232
303
  const cfg = await resolveEffectiveConfig({
@@ -248,15 +319,27 @@ var inboxSyncCommand = defineCommand({
248
319
  var inboxSyncChatCommand = defineCommand({
249
320
  meta: { name: "sync-chat", description: "Re-sync a specific chat's message history." },
250
321
  args: {
251
- ...GLOBAL_FLAGS,
252
- chatId: { type: "positional", description: "Chat ID." }
322
+ // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields.
323
+ // The timeout below overrides READ_SINGLE_FLAGS.timeout with a command-specific description.
324
+ ...READ_SINGLE_FLAGS,
325
+ chatId: { type: "positional", description: "Chat ID." },
326
+ wait: {
327
+ type: "boolean",
328
+ description: "Poll until sync completes (or --timeout elapses).",
329
+ default: false
330
+ },
331
+ // Override READ_SINGLE_FLAGS.timeout: here --timeout is the polling wait timeout
332
+ // in seconds (default: 30), not the SDK request timeout.
333
+ timeout: {
334
+ type: "string",
335
+ description: "Polling timeout in seconds (default: 30, requires --wait)."
336
+ }
253
337
  },
254
338
  async run({ args }) {
255
339
  const flags = args;
256
340
  const cfg = await resolveEffectiveConfig({
257
341
  apiKey: flags["api-key"],
258
342
  baseUrl: flags["base-url"],
259
- timeout: flags.timeout,
260
343
  account: flags.account,
261
344
  profile: flags.profile
262
345
  });
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  GLOBAL_FLAGS,
4
4
  writeProfile
5
- } from "./chunk-52RZLSWP.js";
5
+ } from "./chunk-TDYIQHQX.js";
6
6
 
7
7
  // src/commands/login.ts
8
8
  import { defineCommand } from "citty";
@@ -7,22 +7,27 @@ import {
7
7
  AttachError,
8
8
  readAttachment
9
9
  } from "./chunk-Q43HZUN3.js";
10
+ import {
11
+ resolveTextOrStdin
12
+ } from "./chunk-CHFKVAEI.js";
10
13
  import {
11
14
  buildPreviewOutput
12
15
  } from "./chunk-R3VLWLVV.js";
13
16
  import {
17
+ normalizeChatId,
14
18
  resolveIdentifier
15
- } from "./chunk-BNUTM6KD.js";
19
+ } from "./chunk-SZB3CFRZ.js";
16
20
  import {
17
21
  createClient,
18
22
  renderError,
19
23
  renderSuccess,
20
24
  renderUnexpectedError,
21
25
  resolveEffectiveConfig
22
- } from "./chunk-U6ACUNLU.js";
26
+ } from "./chunk-47SYFQRF.js";
23
27
  import {
24
- GLOBAL_FLAGS
25
- } from "./chunk-52RZLSWP.js";
28
+ READ_SINGLE_FLAGS,
29
+ WRITE_FLAGS
30
+ } from "./chunk-TDYIQHQX.js";
26
31
 
27
32
  // src/commands/message.ts
28
33
  import { defineCommand } from "citty";
@@ -62,8 +67,9 @@ function normalizeAttachPaths(attach) {
62
67
  if (!attach) return [];
63
68
  return Array.isArray(attach) ? attach : [attach];
64
69
  }
65
- var INMAIL_SURFACES = ["sales_nav", "recruiter"];
70
+ var INMAIL_SURFACES = ["sales_nav", "recruiter", "classic"];
66
71
  var MEMBER_URN_RE = /^urn:li:member:\d+$/;
72
+ var MEMBER_PROVIDER_ID_RE = /^A[CDE][A-Za-z0-9_-]{4,}$/;
67
73
  async function handleSdkError(err, outOpts, out) {
68
74
  const { CurviateError } = await import("@curviate/sdk");
69
75
  if (err instanceof CurviateError) {
@@ -74,10 +80,10 @@ async function handleSdkError(err, outOpts, out) {
74
80
  renderUnexpectedError(err, out);
75
81
  process.exit(1);
76
82
  }
77
- async function runMessageNew(client, flags, out) {
83
+ async function runMessageNew(client, flags, out, _readStdin) {
78
84
  const accountId = requireAccount(flags.account, out);
79
- const attendeeId = flags.to ?? "";
80
- const text = flags.text ?? "";
85
+ const rawTo = flags.to ?? "";
86
+ const rawText = flags.text ?? "";
81
87
  const attachPaths = normalizeAttachPaths(flags.attach);
82
88
  let attachBuffers = [];
83
89
  try {
@@ -90,14 +96,30 @@ async function runMessageNew(client, flags, out) {
90
96
  }
91
97
  throw err;
92
98
  }
99
+ const ns = client.account(accountId);
100
+ const outOpts = resolveOutputOpts(flags);
101
+ const text = await resolveTextOrStdin(rawText, out, _readStdin);
102
+ const resolvedSlugOrId = resolveIdentifier(rawTo);
103
+ let providerId;
104
+ if (MEMBER_PROVIDER_ID_RE.test(resolvedSlugOrId)) {
105
+ providerId = resolvedSlugOrId;
106
+ } else {
107
+ try {
108
+ const profileData = await ns.profiles.get(resolvedSlugOrId, {});
109
+ providerId = profileData["provider_id"];
110
+ } catch (err) {
111
+ await handleSdkError(err, outOpts, out);
112
+ return;
113
+ }
114
+ }
93
115
  const body = {
94
- attendees_ids: [attendeeId],
116
+ attendees_ids: [providerId],
95
117
  text
96
118
  };
97
119
  if (flags.preview) {
98
120
  const preview = buildPreviewOutput({
99
121
  method: "messaging.startChat",
100
- args: { attendees_ids: [attendeeId] },
122
+ args: { attendees_ids: [providerId] },
101
123
  body: { ...body },
102
124
  account: accountId,
103
125
  attachments: attachBuffers.map((buf, i) => ({
@@ -111,8 +133,6 @@ async function runMessageNew(client, flags, out) {
111
133
  if (attachBuffers.length > 0) {
112
134
  body["attachments"] = attachBuffers;
113
135
  }
114
- const ns = client.account(accountId);
115
- const outOpts = resolveOutputOpts(flags);
116
136
  try {
117
137
  const result = await ns.messaging.startChat(body);
118
138
  renderSuccess(result, outOpts, out);
@@ -120,11 +140,12 @@ async function runMessageNew(client, flags, out) {
120
140
  await handleSdkError(err, outOpts, out);
121
141
  }
122
142
  }
123
- async function runMessageSend(client, flags, out) {
143
+ async function runMessageSend(client, flags, out, _readStdin) {
124
144
  const accountId = requireAccount(flags.account, out);
125
- const chatId = flags.chatId ?? "";
126
- const text = flags.text ?? "";
145
+ const chatId = normalizeChatId(flags.chatId ?? "");
146
+ const rawText = flags.text ?? "";
127
147
  const attachPaths = normalizeAttachPaths(flags.attach);
148
+ const text = await resolveTextOrStdin(rawText, out, _readStdin);
128
149
  let attachBuffers = [];
129
150
  try {
130
151
  attachBuffers = await Promise.all(attachPaths.map((p) => readAttachment(p)));
@@ -177,10 +198,11 @@ async function runMessageGet(client, flags, out) {
177
198
  await handleSdkError(err, outOpts, out);
178
199
  }
179
200
  }
180
- async function runMessageEdit(client, flags, out) {
201
+ async function runMessageEdit(client, flags, out, _readStdin) {
181
202
  const accountId = requireAccount(flags.account, out);
182
203
  const messageId = flags.messageId ?? "";
183
- const text = flags.text ?? "";
204
+ const rawText = flags.text ?? "";
205
+ const text = await resolveTextOrStdin(rawText, out, _readStdin);
184
206
  if (flags.preview) {
185
207
  const preview = buildPreviewOutput({
186
208
  method: "messaging.editMessage",
@@ -268,7 +290,7 @@ async function runMessageAttachment(client, flags, out, isTTY) {
268
290
  await handleSdkError(err, outOpts, out);
269
291
  }
270
292
  }
271
- async function runMessageInMail(client, flags, out) {
293
+ async function runMessageInMail(client, flags, out, _readStdin) {
272
294
  const accountId = requireAccount(flags.account, out);
273
295
  const surface = flags.surface ?? "";
274
296
  if (!INMAIL_SURFACES.includes(surface)) {
@@ -278,15 +300,34 @@ async function runMessageInMail(client, flags, out) {
278
300
  );
279
301
  process.exit(2);
280
302
  }
281
- const recipientUrn = resolveIdentifier(flags.to ?? "");
282
- if (!MEMBER_URN_RE.test(recipientUrn)) {
303
+ const rawTo = flags.to ?? "";
304
+ if (!rawTo) {
283
305
  out.stderr.write(
284
- "error: --to must be a LinkedIn member URN (e.g. urn:li:member:99999), not a URL or slug.\n"
306
+ "error: --to: not a valid LinkedIn URL, slug, provider-id, or URN.\n"
285
307
  );
286
308
  process.exit(2);
309
+ return;
310
+ }
311
+ const ns = client.account(accountId);
312
+ const outOpts = resolveOutputOpts(flags);
313
+ const resolvedSlugOrId = resolveIdentifier(rawTo);
314
+ let recipientUrn;
315
+ if (MEMBER_URN_RE.test(resolvedSlugOrId)) {
316
+ recipientUrn = resolvedSlugOrId;
317
+ } else if (MEMBER_PROVIDER_ID_RE.test(resolvedSlugOrId)) {
318
+ recipientUrn = resolvedSlugOrId;
319
+ } else {
320
+ try {
321
+ const profileData = await ns.profiles.get(resolvedSlugOrId, {});
322
+ recipientUrn = profileData["provider_id"];
323
+ } catch (err) {
324
+ await handleSdkError(err, outOpts, out);
325
+ return;
326
+ }
287
327
  }
288
328
  const subject = flags.subject ?? "";
289
- const text = flags.text ?? "";
329
+ const rawText = flags.text ?? "";
330
+ const text = await resolveTextOrStdin(rawText, out, _readStdin);
290
331
  const body = {
291
332
  recipient_urn: recipientUrn,
292
333
  surface,
@@ -303,8 +344,6 @@ async function runMessageInMail(client, flags, out) {
303
344
  out.stdout.write(JSON.stringify(preview) + "\n");
304
345
  return;
305
346
  }
306
- const ns = client.account(accountId);
307
- const outOpts = resolveOutputOpts(flags);
308
347
  try {
309
348
  const result = await ns.messaging.sendInMail(body);
310
349
  renderSuccess(result, outOpts, out);
@@ -328,9 +367,14 @@ async function runMessageInMailBalance(client, flags, out) {
328
367
  var messageNewCommand = defineCommand({
329
368
  meta: { name: "new", description: "Start a new chat with one or more members." },
330
369
  args: {
331
- ...GLOBAL_FLAGS,
332
- to: { type: "string", description: "Attendee provider ID (e.g. ACo\u2026).", required: true },
333
- text: { type: "positional", description: "Opening message text." },
370
+ // Write command: WRITE_FLAGS omits pagination/projection flags
371
+ ...WRITE_FLAGS,
372
+ to: {
373
+ type: "string",
374
+ description: "Recipient: LinkedIn profile URL (e.g. https://www.linkedin.com/in/some-slug), bare slug (e.g. some-slug), or provider ID (e.g. ACoAAA\u2026). URL and slug inputs resolve the provider ID automatically.",
375
+ required: true
376
+ },
377
+ text: { type: "positional", description: "Opening message text. Pass - to read from stdin (e.g. via heredoc or pipe)." },
334
378
  attach: { type: "string", description: "File to attach (repeatable)." }
335
379
  },
336
380
  async run({ args }) {
@@ -354,7 +398,8 @@ var messageNewCommand = defineCommand({
354
398
  var messageGetCommand = defineCommand({
355
399
  meta: { name: "get", description: "Get a message by ID." },
356
400
  args: {
357
- ...GLOBAL_FLAGS,
401
+ // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
402
+ ...READ_SINGLE_FLAGS,
358
403
  messageId: { type: "positional", description: "Message ID." }
359
404
  },
360
405
  async run({ args }) {
@@ -378,9 +423,10 @@ var messageGetCommand = defineCommand({
378
423
  var messageEditCommand = defineCommand({
379
424
  meta: { name: "edit", description: "Edit a message (within the allowed window)." },
380
425
  args: {
381
- ...GLOBAL_FLAGS,
426
+ // Write command: WRITE_FLAGS omits pagination/projection flags
427
+ ...WRITE_FLAGS,
382
428
  messageId: { type: "positional", description: "Message ID." },
383
- text: { type: "positional", description: "Replacement text." }
429
+ text: { type: "positional", description: "Replacement text. Pass - to read from stdin." }
384
430
  },
385
431
  async run({ args }) {
386
432
  const flags = args;
@@ -403,7 +449,8 @@ var messageEditCommand = defineCommand({
403
449
  var messageDeleteCommand = defineCommand({
404
450
  meta: { name: "delete", description: "Delete a message." },
405
451
  args: {
406
- ...GLOBAL_FLAGS,
452
+ // Write command: WRITE_FLAGS omits pagination/projection flags
453
+ ...WRITE_FLAGS,
407
454
  messageId: { type: "positional", description: "Message ID." }
408
455
  },
409
456
  async run({ args }) {
@@ -427,7 +474,8 @@ var messageDeleteCommand = defineCommand({
427
474
  var messageReactCommand = defineCommand({
428
475
  meta: { name: "react", description: "Add an emoji reaction to a message." },
429
476
  args: {
430
- ...GLOBAL_FLAGS,
477
+ // Write command: WRITE_FLAGS omits pagination/projection flags
478
+ ...WRITE_FLAGS,
431
479
  messageId: { type: "positional", description: "Message ID." },
432
480
  emoji: { type: "string", description: "Native emoji reaction value (e.g. \u{1F44D}).", required: true }
433
481
  },
@@ -452,7 +500,8 @@ var messageReactCommand = defineCommand({
452
500
  var messageAttachmentCommand = defineCommand({
453
501
  meta: { name: "attachment", description: "Download a message attachment." },
454
502
  args: {
455
- ...GLOBAL_FLAGS,
503
+ // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
504
+ ...READ_SINGLE_FLAGS,
456
505
  messageId: { type: "positional", description: "Message ID." },
457
506
  attachmentId: { type: "positional", description: "Attachment ID." },
458
507
  output: { type: "string", alias: "o", description: "Path to write the file to." }
@@ -483,11 +532,16 @@ var messageAttachmentCommand = defineCommand({
483
532
  var messageInMailCommand = defineCommand({
484
533
  meta: { name: "inmail", description: "Send an InMail to a member." },
485
534
  args: {
486
- ...GLOBAL_FLAGS,
487
- to: { type: "string", description: "Recipient member URN (urn:li:member:<id>). Must be a URN, not a URL or slug.", required: true },
488
- surface: { type: "string", description: "InMail surface: sales_nav or recruiter.", required: true },
535
+ // Write command: WRITE_FLAGS omits pagination/projection flags
536
+ ...WRITE_FLAGS,
537
+ to: {
538
+ type: "string",
539
+ description: "Recipient: LinkedIn profile URL, bare slug, provider-id (ACoAAA\u2026), or member URN (urn:li:member:<id>). URL and slug inputs resolve the provider ID automatically.",
540
+ required: true
541
+ },
542
+ surface: { type: "string", description: "InMail surface: sales_nav, recruiter, or classic (classic uses the account's own premium InMail credits).", required: true },
489
543
  subject: { type: "string", description: "InMail subject line.", required: true },
490
- text: { type: "positional", description: "InMail body text." }
544
+ text: { type: "positional", description: "InMail body text. Pass - to read from stdin." }
491
545
  },
492
546
  async run({ args }) {
493
547
  const flags = args;
@@ -507,9 +561,39 @@ var messageInMailCommand = defineCommand({
507
561
  await runMessageInMail(client, { ...flags, account: flags.account ?? cfg.account }, out);
508
562
  }
509
563
  });
564
+ var messageSendCommand = defineCommand({
565
+ meta: { name: "send", description: "Send a message to an existing chat." },
566
+ args: {
567
+ // Write command: WRITE_FLAGS omits pagination/projection flags
568
+ ...WRITE_FLAGS,
569
+ chatId: { type: "positional", description: "Chat ID or LinkedIn messaging thread URL." },
570
+ text: { type: "positional", description: "Message text. Pass - to read from stdin (e.g. via heredoc or pipe)." },
571
+ attach: { type: "string", description: "File to attach (repeatable)." }
572
+ },
573
+ async run({ args }) {
574
+ const flags = args;
575
+ const cfg = await resolveEffectiveConfig({
576
+ apiKey: flags["api-key"],
577
+ baseUrl: flags["base-url"],
578
+ timeout: flags.timeout,
579
+ account: flags.account,
580
+ profile: flags.profile
581
+ });
582
+ if (!cfg.apiKey) {
583
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
584
+ process.exit(3);
585
+ }
586
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
587
+ const out = buildOutputStreams();
588
+ await runMessageSend(client, { ...flags, account: flags.account ?? cfg.account }, out);
589
+ }
590
+ });
510
591
  var messageInMailBalanceCommand = defineCommand({
511
592
  meta: { name: "inmail-balance", description: "Get InMail credit balance." },
512
- args: { ...GLOBAL_FLAGS },
593
+ args: {
594
+ // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
595
+ ...READ_SINGLE_FLAGS
596
+ },
513
597
  async run({ args }) {
514
598
  const flags = args;
515
599
  const cfg = await resolveEffectiveConfig({
@@ -531,13 +615,15 @@ var messageInMailBalanceCommand = defineCommand({
531
615
  var messageCommand = defineCommand({
532
616
  meta: { name: "message", description: "Send and manage LinkedIn messages." },
533
617
  args: {
534
- ...GLOBAL_FLAGS,
618
+ // Write command (message send): WRITE_FLAGS omits pagination/projection flags
619
+ ...WRITE_FLAGS,
535
620
  chatId: { type: "positional", description: "Chat ID to send a message to.", required: false },
536
- text: { type: "positional", description: "Message text.", required: false },
621
+ text: { type: "positional", description: "Message text. Pass - to read from stdin.", required: false },
537
622
  attach: { type: "string", description: "File to attach (repeatable)." }
538
623
  },
539
624
  subCommands: {
540
625
  new: messageNewCommand,
626
+ send: messageSendCommand,
541
627
  get: messageGetCommand,
542
628
  edit: messageEditCommand,
543
629
  delete: messageDeleteCommand,
@@ -3,6 +3,9 @@ import {
3
3
  AttachError,
4
4
  readAttachment
5
5
  } from "./chunk-Q43HZUN3.js";
6
+ import {
7
+ resolveTextOrStdin
8
+ } from "./chunk-CHFKVAEI.js";
6
9
  import {
7
10
  buildPreviewOutput
8
11
  } from "./chunk-R3VLWLVV.js";
@@ -15,11 +18,11 @@ import {
15
18
  renderSuccess,
16
19
  renderUnexpectedError,
17
20
  resolveEffectiveConfig
18
- } from "./chunk-U6ACUNLU.js";
21
+ } from "./chunk-47SYFQRF.js";
19
22
  import {
20
23
  GLOBAL_FLAGS,
21
24
  WRITE_FLAGS
22
- } from "./chunk-52RZLSWP.js";
25
+ } from "./chunk-TDYIQHQX.js";
23
26
 
24
27
  // src/commands/post.ts
25
28
  import { defineCommand } from "citty";
@@ -115,11 +118,12 @@ async function runPostGet(client, flags, out) {
115
118
  await handleSdkError(err, outOpts, out);
116
119
  }
117
120
  }
118
- async function runPostCreate(client, flags, out) {
121
+ async function runPostCreate(client, flags, out, _readStdin) {
119
122
  const accountId = requireAccount(flags.account, out);
120
- const text = flags.text ?? "";
123
+ const rawText = flags.text ?? "";
121
124
  const attachPaths = normalizeAttachPaths(flags.attach);
122
125
  const thumbPath = flags["video-thumbnail"];
126
+ const text = await resolveTextOrStdin(rawText, out, _readStdin);
123
127
  let attachBuffers = [];
124
128
  try {
125
129
  attachBuffers = await Promise.all(attachPaths.map((p) => readAttachment(p)));
@@ -181,11 +185,12 @@ async function runPostCreate(client, flags, out) {
181
185
  await handleSdkError(err, outOpts, out);
182
186
  }
183
187
  }
184
- async function runPostComment(client, flags, out) {
188
+ async function runPostComment(client, flags, out, _readStdin) {
185
189
  const accountId = requireAccount(flags.account, out);
186
190
  const postId = flags.postId ?? "";
187
- const text = flags.text ?? "";
191
+ const rawText = flags.text ?? "";
188
192
  const replyTo = flags["reply-to"];
193
+ const text = await resolveTextOrStdin(rawText, out, _readStdin);
189
194
  const attachPaths = normalizeAttachPaths(flags.attach);
190
195
  let attachBuffers = [];
191
196
  try {
@@ -368,7 +373,7 @@ var postCreateCommand = defineCommand({
368
373
  args: {
369
374
  // Write command: WRITE_FLAGS omits pagination/projection flags
370
375
  ...WRITE_FLAGS,
371
- text: { type: "positional", description: "Post body text." },
376
+ text: { type: "positional", description: "Post body text. Pass - to read from stdin (enables multiline via heredoc or pipe)." },
372
377
  attach: {
373
378
  type: "string",
374
379
  description: "Image/video/document to attach (repeatable for images; use --video-thumbnail when attaching a video). Supported: jpg, png, gif, mp4, pdf."
@@ -405,7 +410,7 @@ var postCommentCommand = defineCommand({
405
410
  type: "positional",
406
411
  description: "Numeric post id, urn:li:activity:N, or full LinkedIn share URL (activity-<N>- extracted). POSTID is always the post's id; use --reply-to <comment_id> to reply to a specific comment within this post."
407
412
  },
408
- text: { type: "positional", description: "Comment text (max ~1,250 characters per LinkedIn limits)." },
413
+ text: { type: "positional", description: "Comment text (max ~1,250 characters per LinkedIn limits). Pass - to read from stdin." },
409
414
  attach: { type: "string", description: "Image to attach to the comment (optional; one image per comment)." },
410
415
  "reply-to": {
411
416
  type: "string",
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- slimProfile,
4
- slimProfileMe
5
- } from "./chunk-5NS2G4WQ.js";
6
2
  import {
7
3
  buildPreviewOutput
8
4
  } from "./chunk-R3VLWLVV.js";
5
+ import {
6
+ slimProfile,
7
+ slimProfileMe
8
+ } from "./chunk-6VBOKOQJ.js";
9
9
  import {
10
10
  resolveIdentifier
11
- } from "./chunk-BNUTM6KD.js";
11
+ } from "./chunk-SZB3CFRZ.js";
12
12
  import {
13
13
  streamAll
14
14
  } from "./chunk-SND3NHCT.js";
@@ -18,10 +18,10 @@ import {
18
18
  renderSuccess,
19
19
  renderUnexpectedError,
20
20
  resolveEffectiveConfig
21
- } from "./chunk-U6ACUNLU.js";
21
+ } from "./chunk-47SYFQRF.js";
22
22
  import {
23
23
  GLOBAL_FLAGS
24
- } from "./chunk-52RZLSWP.js";
24
+ } from "./chunk-TDYIQHQX.js";
25
25
 
26
26
  // src/commands/profile.ts
27
27
  import { defineCommand } from "citty";
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-R3VLWLVV.js";
13
13
  import {
14
14
  resolveIdentifier
15
- } from "./chunk-BNUTM6KD.js";
15
+ } from "./chunk-SZB3CFRZ.js";
16
16
  import {
17
17
  DEFAULT_FILTER_READERS,
18
18
  assembleFilters,
@@ -27,10 +27,10 @@ import {
27
27
  renderSuccess,
28
28
  renderUnexpectedError,
29
29
  resolveEffectiveConfig
30
- } from "./chunk-U6ACUNLU.js";
30
+ } from "./chunk-47SYFQRF.js";
31
31
  import {
32
32
  GLOBAL_FLAGS
33
- } from "./chunk-52RZLSWP.js";
33
+ } from "./chunk-TDYIQHQX.js";
34
34
 
35
35
  // src/commands/recruiter.ts
36
36
  import { defineCommand } from "citty";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-R3VLWLVV.js";
9
9
  import {
10
10
  resolveIdentifier
11
- } from "./chunk-BNUTM6KD.js";
11
+ } from "./chunk-SZB3CFRZ.js";
12
12
  import {
13
13
  DEFAULT_FILTER_READERS,
14
14
  assembleFilters,
@@ -24,10 +24,10 @@ import {
24
24
  renderSuccess,
25
25
  renderUnexpectedError,
26
26
  resolveEffectiveConfig
27
- } from "./chunk-U6ACUNLU.js";
27
+ } from "./chunk-47SYFQRF.js";
28
28
  import {
29
29
  GLOBAL_FLAGS
30
- } from "./chunk-52RZLSWP.js";
30
+ } from "./chunk-TDYIQHQX.js";
31
31
 
32
32
  // src/commands/sales-nav.ts
33
33
  import { defineCommand } from "citty";
@@ -14,10 +14,10 @@ import {
14
14
  renderSuccess,
15
15
  renderUnexpectedError,
16
16
  resolveEffectiveConfig
17
- } from "./chunk-U6ACUNLU.js";
17
+ } from "./chunk-47SYFQRF.js";
18
18
  import {
19
19
  GLOBAL_FLAGS
20
- } from "./chunk-52RZLSWP.js";
20
+ } from "./chunk-TDYIQHQX.js";
21
21
 
22
22
  // src/commands/search.ts
23
23
  import { defineCommand } from "citty";
@@ -11,10 +11,10 @@ import {
11
11
  renderSuccess,
12
12
  renderUnexpectedError,
13
13
  resolveEffectiveConfig
14
- } from "./chunk-U6ACUNLU.js";
14
+ } from "./chunk-47SYFQRF.js";
15
15
  import {
16
16
  GLOBAL_FLAGS
17
- } from "./chunk-52RZLSWP.js";
17
+ } from "./chunk-TDYIQHQX.js";
18
18
 
19
19
  // src/commands/webhook.ts
20
20
  import { defineCommand } from "citty";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curviate/cli",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "description": "Official command-line interface for the Curviate API.",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "clean": "rm -rf dist *.tsbuildinfo"
41
41
  },
42
42
  "dependencies": {
43
- "@curviate/sdk": "^0.2.1",
43
+ "@curviate/sdk": "^0.4.0",
44
44
  "citty": "^0.1.6"
45
45
  },
46
46
  "devDependencies": {