@curviate/cli 0.18.0 → 0.19.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.
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ pageDelayFromFlags,
4
+ streamAll
5
+ } from "./chunk-EEMJDJ4W.js";
6
+ import {
7
+ createClient,
8
+ renderError,
9
+ renderSuccess,
10
+ renderUnexpectedError,
11
+ resolveEffectiveConfig
12
+ } from "./chunk-M33MI53G.js";
13
+ import {
14
+ GLOBAL_FLAGS,
15
+ READ_SINGLE_FLAGS
16
+ } from "./chunk-TMU3CSPR.js";
17
+
18
+ // src/commands/group.ts
19
+ import { defineCommand } from "citty";
20
+ function buildOutputStreams() {
21
+ return {
22
+ stdout: { write: (s) => process.stdout.write(s) },
23
+ stderr: { write: (s) => process.stderr.write(s) }
24
+ };
25
+ }
26
+ function requireAccount(account, out) {
27
+ if (!account) {
28
+ out.stderr.write("error: --account is required for this command. Set it via --account, CURVIATE_ACCOUNT, or `curviate config set-account`.\n");
29
+ process.exit(2);
30
+ }
31
+ return account;
32
+ }
33
+ function rejectPreviewOnRead(preview, out) {
34
+ if (preview) {
35
+ out.stderr.write("error: --preview is only valid on write commands (mutations). Reads just run.\n");
36
+ process.exit(2);
37
+ }
38
+ }
39
+ function rejectAllOnNonPaginated(all, out) {
40
+ if (all) {
41
+ out.stderr.write("error: --all is not supported on non-paginated commands.\n");
42
+ process.exit(2);
43
+ }
44
+ }
45
+ function resolveOutputOpts(flags) {
46
+ return {
47
+ json: (flags.json ?? false) || !process.stdout.isTTY,
48
+ isTTY: process.stdout.isTTY ?? false,
49
+ fields: flags.fields,
50
+ verbose: flags.verbose ?? false
51
+ };
52
+ }
53
+ async function handleSdkError(err, outOpts, out) {
54
+ const { CurviateError } = await import("@curviate/sdk");
55
+ if (err instanceof CurviateError) {
56
+ const { getExitCode } = await import("./exit-codes-63JE5GM5.js");
57
+ renderError(err, outOpts, out);
58
+ process.exit(getExitCode(err.code));
59
+ }
60
+ renderUnexpectedError(err, out);
61
+ process.exit(1);
62
+ }
63
+ async function runGroupList(client, flags, out) {
64
+ rejectPreviewOnRead(flags.preview, out);
65
+ const accountId = requireAccount(flags.account, out);
66
+ const ns = client.account(accountId);
67
+ const outOpts = resolveOutputOpts(flags);
68
+ const all = flags.all ?? false;
69
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
70
+ const params = {};
71
+ if (flags.target) params["profile"] = flags.target;
72
+ if (flags.limit) params["limit"] = parseInt(flags.limit, 10);
73
+ if (flags.cursor) params["cursor"] = flags.cursor;
74
+ try {
75
+ if (all) {
76
+ const fn = (p) => ns.groups.list(p);
77
+ for await (const item of streamAll(fn, params, {
78
+ maxPages,
79
+ out,
80
+ pageDelayMs: pageDelayFromFlags(flags)
81
+ })) {
82
+ out.stdout.write(JSON.stringify(item) + "\n");
83
+ }
84
+ } else {
85
+ const result = await ns.groups.list(params);
86
+ renderSuccess(result, outOpts, out);
87
+ }
88
+ } catch (err) {
89
+ await handleSdkError(err, outOpts, out);
90
+ }
91
+ }
92
+ async function runGroupGet(client, flags, out) {
93
+ rejectPreviewOnRead(flags.preview, out);
94
+ rejectAllOnNonPaginated(flags.all, out);
95
+ const accountId = requireAccount(flags.account, out);
96
+ const groupId = flags.groupId ?? "";
97
+ const ns = client.account(accountId);
98
+ const outOpts = resolveOutputOpts(flags);
99
+ try {
100
+ const result = await ns.groups.get(groupId);
101
+ renderSuccess(result, outOpts, out);
102
+ } catch (err) {
103
+ await handleSdkError(err, outOpts, out);
104
+ }
105
+ }
106
+ async function runGroupMembers(client, flags, out) {
107
+ rejectPreviewOnRead(flags.preview, out);
108
+ const accountId = requireAccount(flags.account, out);
109
+ const groupId = flags.groupId ?? "";
110
+ const ns = client.account(accountId);
111
+ const outOpts = resolveOutputOpts(flags);
112
+ const all = flags.all ?? false;
113
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
114
+ const params = {};
115
+ if (flags.name) params["name"] = flags.name;
116
+ if (flags.limit) params["limit"] = parseInt(flags.limit, 10);
117
+ if (flags.cursor) params["cursor"] = flags.cursor;
118
+ try {
119
+ if (all) {
120
+ const fn = (p) => ns.groups.members(groupId, p);
121
+ for await (const item of streamAll(fn, params, {
122
+ maxPages,
123
+ out,
124
+ pageDelayMs: pageDelayFromFlags(flags)
125
+ })) {
126
+ out.stdout.write(JSON.stringify(item) + "\n");
127
+ }
128
+ } else {
129
+ const result = await ns.groups.members(groupId, params);
130
+ renderSuccess(result, outOpts, out);
131
+ }
132
+ } catch (err) {
133
+ await handleSdkError(err, outOpts, out);
134
+ }
135
+ }
136
+ var groupListCommand = defineCommand({
137
+ meta: { name: "list", description: "List the groups the connected account belongs to. Pass --profile to enumerate another member's groups instead (a partial, interests-only read)." },
138
+ args: {
139
+ ...GLOBAL_FLAGS,
140
+ target: {
141
+ type: "string",
142
+ description: "Target another LinkedIn member's groups instead of your own: a vanity slug or full /in/{vanity} URL. Omit to enumerate your own groups (a complete read)."
143
+ }
144
+ },
145
+ async run({ args }) {
146
+ const flags = args;
147
+ const cfg = await resolveEffectiveConfig({
148
+ apiKey: flags["api-key"],
149
+ baseUrl: flags["base-url"],
150
+ timeout: flags.timeout,
151
+ account: flags.account,
152
+ profile: flags.profile
153
+ });
154
+ if (!cfg.apiKey) {
155
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
156
+ process.exit(3);
157
+ }
158
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
159
+ const out = buildOutputStreams();
160
+ await runGroupList(client, { ...flags, account: flags.account ?? cfg.account }, out);
161
+ }
162
+ });
163
+ var groupGetCommand = defineCommand({
164
+ meta: { name: "get", description: "Get one LinkedIn group's full detail: name, member count, description, admin contact, and write-feasibility gates." },
165
+ args: {
166
+ ...READ_SINGLE_FLAGS,
167
+ groupId: { type: "positional", description: "Numeric group id, or a full group URL (e.g. https://www.linkedin.com/groups/9123014/)." }
168
+ },
169
+ async run({ args }) {
170
+ const flags = args;
171
+ const cfg = await resolveEffectiveConfig({
172
+ apiKey: flags["api-key"],
173
+ baseUrl: flags["base-url"],
174
+ timeout: flags.timeout,
175
+ account: flags.account,
176
+ profile: flags.profile
177
+ });
178
+ if (!cfg.apiKey) {
179
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
180
+ process.exit(3);
181
+ }
182
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
183
+ const out = buildOutputStreams();
184
+ await runGroupGet(client, { ...flags, account: flags.account ?? cfg.account }, out);
185
+ }
186
+ });
187
+ var groupMembersCommand = defineCommand({
188
+ meta: {
189
+ name: "members",
190
+ description: "List (or search by name) a group's members: id, profile URL, name, headline, and relationship signal. Requires the connected account be a member of the group."
191
+ },
192
+ args: {
193
+ ...GLOBAL_FLAGS,
194
+ groupId: { type: "positional", description: "Numeric group id, or a full group URL." },
195
+ name: {
196
+ type: "string",
197
+ description: "Filter the roster by member name: prefix/substring, multi-word, case-insensitive. Omit for the full roster."
198
+ }
199
+ },
200
+ async run({ args }) {
201
+ const flags = args;
202
+ const cfg = await resolveEffectiveConfig({
203
+ apiKey: flags["api-key"],
204
+ baseUrl: flags["base-url"],
205
+ timeout: flags.timeout,
206
+ account: flags.account,
207
+ profile: flags.profile
208
+ });
209
+ if (!cfg.apiKey) {
210
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
211
+ process.exit(3);
212
+ }
213
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
214
+ const out = buildOutputStreams();
215
+ await runGroupMembers(client, { ...flags, account: flags.account ?? cfg.account }, out);
216
+ }
217
+ });
218
+ var groupCommand = defineCommand({
219
+ meta: { name: "group", description: "Read LinkedIn groups: your own membership list, one group's detail, and its member roster." },
220
+ subCommands: {
221
+ list: groupListCommand,
222
+ get: groupGetCommand,
223
+ members: groupMembersCommand
224
+ },
225
+ async run() {
226
+ process.stderr.write(
227
+ "Usage: curviate group <subcommand>\n list [--profile <target>]\n get <group_id>\n members <group_id> [--name <filter>]\n"
228
+ );
229
+ }
230
+ });
231
+ export {
232
+ groupCommand,
233
+ runGroupGet,
234
+ runGroupList,
235
+ runGroupMembers
236
+ };
@@ -189,6 +189,37 @@ async function runInboxMessages(client, flags, out) {
189
189
  await handleSdkError(err, outOpts, out);
190
190
  }
191
191
  }
192
+ async function runInboxSearch(client, flags, out) {
193
+ rejectPreviewOnRead(flags.preview, out);
194
+ const accountId = requireAccount(flags.account, out);
195
+ const query = flags.query ?? "";
196
+ if (!query) {
197
+ out.stderr.write("error: <query> is required.\n");
198
+ process.exit(2);
199
+ }
200
+ const ns = client.account(accountId);
201
+ const outOpts = resolveOutputOpts(flags);
202
+ const all = flags.all ?? false;
203
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
204
+ const params = { query, ...buildPaginationParams(flags) };
205
+ try {
206
+ if (all) {
207
+ const fn = (p) => ns.messaging.searchChats(p);
208
+ for await (const item of streamAll(fn, params, {
209
+ maxPages,
210
+ out,
211
+ pageDelayMs: pageDelayFromFlags(flags)
212
+ })) {
213
+ out.stdout.write(JSON.stringify(item) + "\n");
214
+ }
215
+ } else {
216
+ const result = await ns.messaging.searchChats(params);
217
+ renderSuccess(result, outOpts, out);
218
+ }
219
+ } catch (err) {
220
+ await handleSdkError(err, outOpts, out);
221
+ }
222
+ }
192
223
  var inboxListCommand = defineCommand({
193
224
  meta: { name: "list", description: "List inbox chats." },
194
225
  args: {
@@ -301,17 +332,43 @@ var inboxMessagesCommand = defineCommand({
301
332
  await runInboxMessages(client, { ...flags, account: flags.account ?? cfg.account }, out);
302
333
  }
303
334
  });
335
+ var inboxSearchCommand = defineCommand({
336
+ meta: { name: "search", description: "Free-text search the account's own inbox (matches participant names and message content)." },
337
+ args: {
338
+ ...GLOBAL_FLAGS,
339
+ limit: { type: "string", description: "Number of items to return per page (1-100, default 20)." },
340
+ query: { type: "positional", description: "Search term (e.g. a name or a phrase from a message)." }
341
+ },
342
+ async run({ args }) {
343
+ const flags = args;
344
+ const cfg = await resolveEffectiveConfig({
345
+ apiKey: flags["api-key"],
346
+ baseUrl: flags["base-url"],
347
+ timeout: flags.timeout,
348
+ account: flags.account,
349
+ profile: flags.profile
350
+ });
351
+ if (!cfg.apiKey) {
352
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
353
+ process.exit(3);
354
+ }
355
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
356
+ const out = buildOutputStreams();
357
+ await runInboxSearch(client, { ...flags, account: flags.account ?? cfg.account }, out);
358
+ }
359
+ });
304
360
  var inboxCommand = defineCommand({
305
361
  meta: { name: "inbox", description: "Read LinkedIn message inbox." },
306
362
  subCommands: {
307
363
  list: inboxListCommand,
308
364
  get: inboxGetCommand,
309
365
  "mark-read": inboxMarkReadCommand,
310
- messages: inboxMessagesCommand
366
+ messages: inboxMessagesCommand,
367
+ search: inboxSearchCommand
311
368
  },
312
369
  async run() {
313
370
  process.stderr.write(
314
- "Usage: curviate inbox <subcommand>\n list\n get <chat_id>\n mark-read <chat_id>\n messages <chat_id>\n"
371
+ "Usage: curviate inbox <subcommand>\n list\n get <chat_id>\n mark-read <chat_id>\n messages <chat_id>\n search <query>\n"
315
372
  );
316
373
  }
317
374
  });
@@ -320,5 +377,6 @@ export {
320
377
  runInboxGet,
321
378
  runInboxList,
322
379
  runInboxMarkRead,
323
- runInboxMessages
380
+ runInboxMessages,
381
+ runInboxSearch
324
382
  };
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ pageDelayFromFlags,
4
+ streamAll
5
+ } from "./chunk-EEMJDJ4W.js";
6
+ import {
7
+ buildPreviewOutput
8
+ } from "./chunk-R3VLWLVV.js";
9
+ import {
10
+ createClient,
11
+ renderError,
12
+ renderSuccess,
13
+ renderUnexpectedError,
14
+ resolveEffectiveConfig
15
+ } from "./chunk-M33MI53G.js";
16
+ import {
17
+ GLOBAL_FLAGS,
18
+ WRITE_SINGLE_FLAGS
19
+ } from "./chunk-TMU3CSPR.js";
20
+
21
+ // src/commands/notification.ts
22
+ import { defineCommand } from "citty";
23
+ function buildOutputStreams() {
24
+ return {
25
+ stdout: { write: (s) => process.stdout.write(s) },
26
+ stderr: { write: (s) => process.stderr.write(s) }
27
+ };
28
+ }
29
+ function requireAccount(account, out) {
30
+ if (!account) {
31
+ out.stderr.write("error: --account is required for this command. Set it via --account, CURVIATE_ACCOUNT, or `curviate config set-account`.\n");
32
+ process.exit(2);
33
+ }
34
+ return account;
35
+ }
36
+ function rejectPreviewOnRead(preview, out) {
37
+ if (preview) {
38
+ out.stderr.write("error: --preview is only valid on write commands (mutations). Reads just run.\n");
39
+ process.exit(2);
40
+ }
41
+ }
42
+ function resolveOutputOpts(flags) {
43
+ return {
44
+ json: (flags.json ?? false) || !process.stdout.isTTY,
45
+ isTTY: process.stdout.isTTY ?? false,
46
+ fields: flags.fields,
47
+ verbose: flags.verbose ?? false
48
+ };
49
+ }
50
+ async function handleSdkError(err, outOpts, out) {
51
+ const { CurviateError } = await import("@curviate/sdk");
52
+ if (err instanceof CurviateError) {
53
+ const { getExitCode } = await import("./exit-codes-63JE5GM5.js");
54
+ renderError(err, outOpts, out);
55
+ process.exit(getExitCode(err.code));
56
+ }
57
+ renderUnexpectedError(err, out);
58
+ process.exit(1);
59
+ }
60
+ async function runNotificationList(client, flags, out) {
61
+ rejectPreviewOnRead(flags.preview, out);
62
+ const accountId = requireAccount(flags.account, out);
63
+ const ns = client.account(accountId);
64
+ const outOpts = resolveOutputOpts(flags);
65
+ const all = flags.all ?? false;
66
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
67
+ const params = {};
68
+ if (flags.filter) params["filter"] = flags.filter;
69
+ if (flags.limit) params["limit"] = parseInt(flags.limit, 10);
70
+ if (flags.cursor) params["cursor"] = flags.cursor;
71
+ try {
72
+ if (all) {
73
+ const fn = (p) => ns.notifications.list(p);
74
+ for await (const item of streamAll(fn, params, {
75
+ maxPages,
76
+ out,
77
+ pageDelayMs: pageDelayFromFlags(flags)
78
+ })) {
79
+ out.stdout.write(JSON.stringify(item) + "\n");
80
+ }
81
+ } else {
82
+ const result = await ns.notifications.list(params);
83
+ renderSuccess(result, outOpts, out);
84
+ }
85
+ } catch (err) {
86
+ await handleSdkError(err, outOpts, out);
87
+ }
88
+ }
89
+ async function runNotificationDelete(client, flags, out) {
90
+ const accountId = requireAccount(flags.account, out);
91
+ const cardUrn = flags.cardUrn ?? "";
92
+ if (flags.preview) {
93
+ const preview = buildPreviewOutput({ method: "notifications.delete", args: { card_urn: cardUrn }, body: {}, account: accountId });
94
+ out.stdout.write(JSON.stringify(preview) + "\n");
95
+ return;
96
+ }
97
+ const ns = client.account(accountId);
98
+ const outOpts = resolveOutputOpts(flags);
99
+ try {
100
+ const result = await ns.notifications.delete(cardUrn);
101
+ renderSuccess(result, outOpts, out);
102
+ } catch (err) {
103
+ await handleSdkError(err, outOpts, out);
104
+ }
105
+ }
106
+ async function runNotificationShowLess(client, flags, out) {
107
+ const accountId = requireAccount(flags.account, out);
108
+ const cardUrn = flags.cardUrn ?? "";
109
+ if (flags.preview) {
110
+ const preview = buildPreviewOutput({ method: "notifications.showLess", args: { card_urn: cardUrn }, body: {}, account: accountId });
111
+ out.stdout.write(JSON.stringify(preview) + "\n");
112
+ return;
113
+ }
114
+ const ns = client.account(accountId);
115
+ const outOpts = resolveOutputOpts(flags);
116
+ try {
117
+ const result = await ns.notifications.showLess(cardUrn);
118
+ renderSuccess(result, outOpts, out);
119
+ } catch (err) {
120
+ await handleSdkError(err, outOpts, out);
121
+ }
122
+ }
123
+ var notificationListCommand = defineCommand({
124
+ meta: { name: "list", description: "List the connected account's notification cards, newest first, plus the unread badge and a poll watermark." },
125
+ args: {
126
+ ...GLOBAL_FLAGS,
127
+ filter: {
128
+ type: "string",
129
+ description: "Which notification stream to read (default all): all | jobs | mentions | my_posts | my_posts_comments | my_posts_reactions | my_posts_reposts."
130
+ }
131
+ },
132
+ async run({ args }) {
133
+ const flags = args;
134
+ const cfg = await resolveEffectiveConfig({
135
+ apiKey: flags["api-key"],
136
+ baseUrl: flags["base-url"],
137
+ timeout: flags.timeout,
138
+ account: flags.account,
139
+ profile: flags.profile
140
+ });
141
+ if (!cfg.apiKey) {
142
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
143
+ process.exit(3);
144
+ }
145
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
146
+ const out = buildOutputStreams();
147
+ await runNotificationList(client, { ...flags, account: flags.account ?? cfg.account }, out);
148
+ }
149
+ });
150
+ var notificationDeleteCommand = defineCommand({
151
+ meta: { name: "delete", description: "Delete one of your notification cards by its card urn. Self-action, idempotent, cannot be undone." },
152
+ args: {
153
+ ...WRITE_SINGLE_FLAGS,
154
+ cardUrn: { type: "positional", description: "The card_urn field of a `notification list` item (not object_urn)." }
155
+ },
156
+ async run({ args }) {
157
+ const flags = args;
158
+ const cfg = await resolveEffectiveConfig({
159
+ apiKey: flags["api-key"],
160
+ baseUrl: flags["base-url"],
161
+ timeout: flags.timeout,
162
+ account: flags.account,
163
+ profile: flags.profile
164
+ });
165
+ if (!cfg.apiKey) {
166
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
167
+ process.exit(3);
168
+ }
169
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
170
+ const out = buildOutputStreams();
171
+ await runNotificationDelete(client, { ...flags, account: flags.account ?? cfg.account }, out);
172
+ }
173
+ });
174
+ var notificationShowLessCommand = defineCommand({
175
+ meta: {
176
+ name: "show-less",
177
+ description: "Apply 'show less like this' to the source of one of your notification cards. For network-activity cards this removes the card, same as delete. Self-action, idempotent, cannot be undone."
178
+ },
179
+ args: {
180
+ ...WRITE_SINGLE_FLAGS,
181
+ cardUrn: { type: "positional", description: "The card_urn field of a `notification list` item (not object_urn)." }
182
+ },
183
+ async run({ args }) {
184
+ const flags = args;
185
+ const cfg = await resolveEffectiveConfig({
186
+ apiKey: flags["api-key"],
187
+ baseUrl: flags["base-url"],
188
+ timeout: flags.timeout,
189
+ account: flags.account,
190
+ profile: flags.profile
191
+ });
192
+ if (!cfg.apiKey) {
193
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
194
+ process.exit(3);
195
+ }
196
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
197
+ const out = buildOutputStreams();
198
+ await runNotificationShowLess(client, { ...flags, account: flags.account ?? cfg.account }, out);
199
+ }
200
+ });
201
+ var notificationCommand = defineCommand({
202
+ meta: { name: "notification", description: "Read and act on LinkedIn notification cards." },
203
+ subCommands: {
204
+ list: notificationListCommand,
205
+ delete: notificationDeleteCommand,
206
+ "show-less": notificationShowLessCommand
207
+ },
208
+ async run() {
209
+ process.stderr.write(
210
+ "Usage: curviate notification <subcommand>\n list [--filter <f>]\n delete <card_urn>\n show-less <card_urn>\n"
211
+ );
212
+ }
213
+ });
214
+ export {
215
+ notificationCommand,
216
+ runNotificationDelete,
217
+ runNotificationList,
218
+ runNotificationShowLess
219
+ };
@@ -208,6 +208,66 @@ async function runPostReactions(client, flags, out) {
208
208
  await handleSdkError(err, outOpts, out);
209
209
  }
210
210
  }
211
+ async function runPostSaved(client, flags, out) {
212
+ rejectPreviewOnRead(flags.preview, out);
213
+ const accountId = requireAccount(flags.account, out);
214
+ const ns = client.account(accountId);
215
+ const outOpts = resolveOutputOpts(flags);
216
+ const all = flags.all ?? false;
217
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
218
+ const params = buildPaginationParams(flags);
219
+ try {
220
+ if (all) {
221
+ const fn = (p) => ns.posts.listSaved(p);
222
+ for await (const item of streamAll(fn, params, {
223
+ maxPages,
224
+ out,
225
+ pageDelayMs: pageDelayFromFlags(flags)
226
+ })) {
227
+ out.stdout.write(JSON.stringify(item) + "\n");
228
+ }
229
+ } else {
230
+ const result = await ns.posts.listSaved(params);
231
+ renderSuccess(result, outOpts, out);
232
+ }
233
+ } catch (err) {
234
+ await handleSdkError(err, outOpts, out);
235
+ }
236
+ }
237
+ async function runPostSave(client, flags, out) {
238
+ const accountId = requireAccount(flags.account, out);
239
+ const postId = flags.postId ?? "";
240
+ if (flags.preview) {
241
+ const preview = buildPreviewOutput({ method: "posts.save", args: { post_id: postId }, body: {}, account: accountId });
242
+ out.stdout.write(JSON.stringify(preview) + "\n");
243
+ return;
244
+ }
245
+ const ns = client.account(accountId);
246
+ const outOpts = resolveOutputOpts(flags);
247
+ try {
248
+ const result = await ns.posts.save(postId);
249
+ renderSuccess(result, outOpts, out);
250
+ } catch (err) {
251
+ await handleSdkError(err, outOpts, out);
252
+ }
253
+ }
254
+ async function runPostUnsave(client, flags, out) {
255
+ const accountId = requireAccount(flags.account, out);
256
+ const postId = flags.postId ?? "";
257
+ if (flags.preview) {
258
+ const preview = buildPreviewOutput({ method: "posts.unsave", args: { post_id: postId }, body: {}, account: accountId });
259
+ out.stdout.write(JSON.stringify(preview) + "\n");
260
+ return;
261
+ }
262
+ const ns = client.account(accountId);
263
+ const outOpts = resolveOutputOpts(flags);
264
+ try {
265
+ const result = await ns.posts.unsave(postId);
266
+ renderSuccess(result, outOpts, out);
267
+ } catch (err) {
268
+ await handleSdkError(err, outOpts, out);
269
+ }
270
+ }
211
271
  async function runPostDelete(client, flags, out) {
212
272
  const accountId = requireAccount(flags.account, out);
213
273
  const postId = flags.postId ?? "";
@@ -482,6 +542,33 @@ var postUnreactCommand = defineCommand({
482
542
  await withClient(args, runPostUnreact);
483
543
  }
484
544
  });
545
+ var postSavedCommand = defineCommand({
546
+ meta: { name: "saved", description: "List your own saved posts (a private bookmark list, newest-saved-first). Each item is a preview (snippet capped at 140 chars)." },
547
+ args: { ...GLOBAL_FLAGS },
548
+ async run({ args }) {
549
+ await withClient(args, runPostSaved);
550
+ }
551
+ });
552
+ var postSaveCommand = defineCommand({
553
+ meta: { name: "save", description: "Save a post to your private bookmark list. Never notifies the author, never visible to third parties. Idempotent." },
554
+ args: {
555
+ ...WRITE_SINGLE_FLAGS,
556
+ postId: { type: "positional", description: "Post id (urn:li:activity:N or a bare numeric id)." }
557
+ },
558
+ async run({ args }) {
559
+ await withClient(args, runPostSave);
560
+ }
561
+ });
562
+ var postUnsaveCommand = defineCommand({
563
+ meta: { name: "unsave", description: "Remove a post from your saved-posts bookmark list. Idempotent." },
564
+ args: {
565
+ ...WRITE_SINGLE_FLAGS,
566
+ postId: { type: "positional", description: "Post id (urn:li:activity:N or a bare numeric id)." }
567
+ },
568
+ async run({ args }) {
569
+ await withClient(args, runPostUnsave);
570
+ }
571
+ });
485
572
  var postUserPostsCommand = defineCommand({
486
573
  meta: { name: "user-posts", description: "List a member's own posts (accepts 'me'). A very recent create/delete may take a few minutes to appear or clear here (LinkedIn-side indexing); `post get <post_id>` reflects it immediately." },
487
574
  args: {
@@ -511,12 +598,15 @@ var postCommand = defineCommand({
511
598
  reactions: postReactionsCommand,
512
599
  delete: postDeleteCommand,
513
600
  unreact: postUnreactCommand,
601
+ saved: postSavedCommand,
602
+ save: postSaveCommand,
603
+ unsave: postUnsaveCommand,
514
604
  "user-posts": postUserPostsCommand,
515
605
  "user-reactions": postUserReactionsCommand
516
606
  },
517
607
  async run() {
518
608
  process.stderr.write(
519
- 'Usage: curviate post <subcommand>\n get <post_id>\n create "<text>" [--attach <file>\u2026]\n react <post_id> <reaction> [--as-organization <org_id>]\n reactions <post_id>\n delete <post_id>\n unreact <post_id> <reaction>\n user-posts <user_id>\n user-reactions <user_id>\n\nComment operations moved to the `comment` command group.\n'
609
+ 'Usage: curviate post <subcommand>\n get <post_id>\n create "<text>" [--attach <file>\u2026]\n react <post_id> <reaction> [--as-organization <org_id>]\n reactions <post_id>\n delete <post_id>\n unreact <post_id> <reaction>\n saved\n save <post_id>\n unsave <post_id>\n user-posts <user_id>\n user-reactions <user_id>\n\nComment operations moved to the `comment` command group.\n'
520
610
  );
521
611
  }
522
612
  });
@@ -527,7 +617,10 @@ export {
527
617
  runPostGet,
528
618
  runPostReact,
529
619
  runPostReactions,
620
+ runPostSave,
621
+ runPostSaved,
530
622
  runPostUnreact,
623
+ runPostUnsave,
531
624
  runPostUserPosts,
532
625
  runPostUserReactions
533
626
  };