@curviate/cli 0.13.0 → 0.15.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,799 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveMemberOrMeProviderId,
4
+ resolveMemberProviderId
5
+ } from "./chunk-QJZ3LWOX.js";
6
+ import {
7
+ AttachError,
8
+ readAttachment,
9
+ toAttachmentPayload
10
+ } from "./chunk-BGZW6B7G.js";
11
+ import {
12
+ buildPreviewOutput
13
+ } from "./chunk-R3VLWLVV.js";
14
+ import {
15
+ slimProfile,
16
+ slimProfileMe
17
+ } from "./chunk-45KHSWCV.js";
18
+ import {
19
+ resolveIdentifier
20
+ } from "./chunk-DMQZEPQE.js";
21
+ import {
22
+ streamAll
23
+ } from "./chunk-DNTRQZBT.js";
24
+ import {
25
+ createClient,
26
+ renderError,
27
+ renderSuccess,
28
+ renderUnexpectedError,
29
+ resolveEffectiveConfig
30
+ } from "./chunk-JXF47TRY.js";
31
+ import {
32
+ GLOBAL_FLAGS,
33
+ WRITE_SINGLE_FLAGS
34
+ } from "./chunk-4JHGVY7R.js";
35
+
36
+ // src/commands/profile.ts
37
+ import { defineCommand } from "citty";
38
+
39
+ // src/lib/sections.ts
40
+ var SECTION_BASE_NAMES = [
41
+ "experience",
42
+ "education",
43
+ "languages",
44
+ "skills",
45
+ "certifications",
46
+ "volunteer_experience",
47
+ "projects",
48
+ "recommendations",
49
+ "interests"
50
+ ];
51
+ var VALID_LINKEDIN_SECTIONS = /* @__PURE__ */ new Set([
52
+ "linkedin_*",
53
+ ...SECTION_BASE_NAMES.flatMap((n) => [`linkedin_${n}`, `linkedin_${n}_preview`])
54
+ ]);
55
+ var CANONICAL_SECTION_VALUES = [
56
+ "linkedin_*",
57
+ ...SECTION_BASE_NAMES.map((n) => `linkedin_${n}`)
58
+ ];
59
+ function parseSectionsFlag(raw) {
60
+ const values = raw.split(",").map((s) => s.trim()).filter(Boolean);
61
+ const sections = [];
62
+ for (const value of values) {
63
+ const canonical = value.startsWith("linkedin_") ? value : `linkedin_${value}`;
64
+ if (!VALID_LINKEDIN_SECTIONS.has(canonical)) {
65
+ return {
66
+ ok: false,
67
+ error: `error: --sections: unknown section "${value}". Valid values: ${CANONICAL_SECTION_VALUES.join(", ")} (each also has a _preview variant).
68
+ `
69
+ };
70
+ }
71
+ sections.push(canonical);
72
+ }
73
+ return { ok: true, sections };
74
+ }
75
+
76
+ // src/commands/profile.ts
77
+ function requireAccount(account, out) {
78
+ if (!account) {
79
+ out.stderr.write("error: --account is required for this command. Set it via --account, CURVIATE_ACCOUNT, or `curviate config set-account`.\n");
80
+ process.exit(2);
81
+ }
82
+ return account;
83
+ }
84
+ function rejectPreviewOnRead(preview, out) {
85
+ if (preview) {
86
+ out.stderr.write("error: --preview is only valid on write commands (mutations). Reads just run.\n");
87
+ process.exit(2);
88
+ }
89
+ }
90
+ function rejectAllOnNonPaginated(all, out) {
91
+ if (all) {
92
+ out.stderr.write("error: --all is not supported on non-paginated commands.\n");
93
+ process.exit(2);
94
+ }
95
+ }
96
+ function buildOutputStreams() {
97
+ return {
98
+ stdout: { write: (s) => process.stdout.write(s) },
99
+ stderr: { write: (s) => process.stderr.write(s) }
100
+ };
101
+ }
102
+ function resolveOutputOpts(flags) {
103
+ return {
104
+ json: (flags.json ?? false) || !process.stdout.isTTY,
105
+ isTTY: process.stdout.isTTY ?? false,
106
+ fields: flags.fields,
107
+ verbose: flags.verbose ?? false
108
+ };
109
+ }
110
+ async function runProfileMe(client, flags, out) {
111
+ rejectPreviewOnRead(flags.preview, out);
112
+ const hasActivityFlag = !!(flags.posts || flags.comments || flags.reactions || flags.followers);
113
+ if (!hasActivityFlag) {
114
+ rejectAllOnNonPaginated(flags.all, out);
115
+ }
116
+ if (flags.sections === "") {
117
+ out.stderr.write("error: --sections must not be empty. Omit the flag or provide section names.\n");
118
+ process.exit(2);
119
+ return;
120
+ }
121
+ const accountId = requireAccount(flags.account, out);
122
+ const ns = client.account(accountId);
123
+ const outOpts = resolveOutputOpts(flags);
124
+ if (hasActivityFlag) {
125
+ const all = flags.all ?? false;
126
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
127
+ const params2 = {};
128
+ if (flags.limit) params2.limit = parseInt(flags.limit, 10);
129
+ if (flags.cursor) params2.cursor = flags.cursor;
130
+ try {
131
+ if (flags.posts) {
132
+ if (all) {
133
+ const fn = (p) => ns.posts.listUserPosts("me", p);
134
+ for await (const item of streamAll(fn, params2, {
135
+ maxPages,
136
+ out
137
+ })) {
138
+ out.stdout.write(JSON.stringify(item) + "\n");
139
+ }
140
+ } else {
141
+ const result = await ns.posts.listUserPosts("me", params2);
142
+ renderSuccess(result, outOpts, out);
143
+ }
144
+ } else if (flags.comments) {
145
+ if (all) {
146
+ const fn = (p) => ns.comments.listUserComments("me", p);
147
+ for await (const item of streamAll(fn, params2, {
148
+ maxPages,
149
+ out
150
+ })) {
151
+ out.stdout.write(JSON.stringify(item) + "\n");
152
+ }
153
+ } else {
154
+ const result = await ns.comments.listUserComments("me", params2);
155
+ renderSuccess(result, outOpts, out);
156
+ }
157
+ } else if (flags.reactions) {
158
+ if (all) {
159
+ const fn = (p) => ns.posts.listUserReactions("me", p);
160
+ for await (const item of streamAll(fn, params2, {
161
+ maxPages,
162
+ out
163
+ })) {
164
+ out.stdout.write(JSON.stringify(item) + "\n");
165
+ }
166
+ } else {
167
+ const result = await ns.posts.listUserReactions("me", params2);
168
+ renderSuccess(result, outOpts, out);
169
+ }
170
+ } else if (flags.followers) {
171
+ if (all) {
172
+ const fn = (p) => ns.users.listFollowers("me", p);
173
+ for await (const item of streamAll(fn, params2, {
174
+ maxPages,
175
+ out
176
+ })) {
177
+ out.stdout.write(JSON.stringify(item) + "\n");
178
+ }
179
+ } else {
180
+ const result = await ns.users.listFollowers("me", params2);
181
+ renderSuccess(result, outOpts, out);
182
+ }
183
+ }
184
+ } catch (err) {
185
+ const { CurviateError } = await import("@curviate/sdk");
186
+ if (err instanceof CurviateError) {
187
+ const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
188
+ renderError(err, outOpts, out);
189
+ process.exit(getExitCode(err.code));
190
+ }
191
+ renderUnexpectedError(err, out);
192
+ process.exit(1);
193
+ }
194
+ return;
195
+ }
196
+ const params = {};
197
+ if (flags.sections) {
198
+ const parsedSections = parseSectionsFlag(flags.sections);
199
+ if (!parsedSections.ok) {
200
+ out.stderr.write(parsedSections.error);
201
+ process.exit(2);
202
+ return;
203
+ }
204
+ params.linkedin_sections = parsedSections.sections;
205
+ }
206
+ try {
207
+ const result = await ns.users.get("me", params);
208
+ const slimOutOpts = { ...outOpts, slim: slimProfileMe };
209
+ renderSuccess(result, slimOutOpts, out);
210
+ } catch (err) {
211
+ const { CurviateError } = await import("@curviate/sdk");
212
+ if (err instanceof CurviateError) {
213
+ const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
214
+ renderError(err, outOpts, out);
215
+ process.exit(getExitCode(err.code));
216
+ }
217
+ renderUnexpectedError(err, out);
218
+ process.exit(1);
219
+ }
220
+ }
221
+ async function runProfileGet(client, flags, out) {
222
+ rejectPreviewOnRead(flags.preview, out);
223
+ const isListCommand = flags.posts || flags.comments || flags.reactions || flags.followers;
224
+ if (!isListCommand && flags.sections === "") {
225
+ out.stderr.write("error: --sections must not be empty. Omit the flag or provide section names.\n");
226
+ process.exit(2);
227
+ return;
228
+ }
229
+ let parsedSections;
230
+ if (!isListCommand && flags.sections) {
231
+ const result = parseSectionsFlag(flags.sections);
232
+ if (!result.ok) {
233
+ out.stderr.write(result.error);
234
+ process.exit(2);
235
+ return;
236
+ }
237
+ parsedSections = result.sections;
238
+ }
239
+ const accountId = requireAccount(flags.account, out);
240
+ const rawId = flags.id ?? "";
241
+ const resolvedId = resolveIdentifier(rawId);
242
+ const ns = client.account(accountId);
243
+ const outOpts = resolveOutputOpts(flags);
244
+ const all = flags.all ?? false;
245
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
246
+ const limit = flags.limit ? parseInt(flags.limit, 10) : void 0;
247
+ const cursor = flags.cursor;
248
+ try {
249
+ if (flags.posts) {
250
+ const params = {};
251
+ if (limit !== void 0) params.limit = limit;
252
+ if (cursor) params.cursor = cursor;
253
+ let postId = resolvedId;
254
+ if (flags["is-company"]) {
255
+ const isNumericId = /^\d+$/.test(resolvedId);
256
+ if (!isNumericId) {
257
+ const companyData = await ns.companies.get(resolvedId);
258
+ postId = companyData.id;
259
+ }
260
+ }
261
+ if (all) {
262
+ const fn = (p) => ns.posts.listUserPosts(postId, p);
263
+ for await (const item of streamAll(fn, params, {
264
+ maxPages,
265
+ out
266
+ })) {
267
+ out.stdout.write(JSON.stringify(item) + "\n");
268
+ }
269
+ } else {
270
+ const result = await ns.posts.listUserPosts(postId, params);
271
+ renderSuccess(result, outOpts, out);
272
+ }
273
+ } else if (flags.comments) {
274
+ const params = {};
275
+ if (limit !== void 0) params.limit = limit;
276
+ if (cursor) params.cursor = cursor;
277
+ if (all) {
278
+ const fn = (p) => ns.comments.listUserComments(resolvedId, p);
279
+ for await (const item of streamAll(fn, params, {
280
+ maxPages,
281
+ out
282
+ })) {
283
+ out.stdout.write(JSON.stringify(item) + "\n");
284
+ }
285
+ } else {
286
+ const result = await ns.comments.listUserComments(resolvedId, params);
287
+ renderSuccess(result, outOpts, out);
288
+ }
289
+ } else if (flags.reactions) {
290
+ const params = {};
291
+ if (limit !== void 0) params.limit = limit;
292
+ if (cursor) params.cursor = cursor;
293
+ if (all) {
294
+ const fn = (p) => ns.posts.listUserReactions(resolvedId, p);
295
+ for await (const item of streamAll(fn, params, {
296
+ maxPages,
297
+ out
298
+ })) {
299
+ out.stdout.write(JSON.stringify(item) + "\n");
300
+ }
301
+ } else {
302
+ const result = await ns.posts.listUserReactions(resolvedId, params);
303
+ renderSuccess(result, outOpts, out);
304
+ }
305
+ } else if (flags.followers) {
306
+ const params = {};
307
+ if (limit !== void 0) params.limit = limit;
308
+ if (cursor) params.cursor = cursor;
309
+ if (all) {
310
+ const fn = (p) => ns.users.listFollowers(resolvedId, p);
311
+ for await (const item of streamAll(fn, params, {
312
+ maxPages,
313
+ out
314
+ })) {
315
+ out.stdout.write(JSON.stringify(item) + "\n");
316
+ }
317
+ } else {
318
+ const result = await ns.users.listFollowers(resolvedId, params);
319
+ renderSuccess(result, outOpts, out);
320
+ }
321
+ } else {
322
+ rejectAllOnNonPaginated(flags.all, out);
323
+ const params = {};
324
+ if (parsedSections) {
325
+ params.linkedin_sections = parsedSections;
326
+ }
327
+ const getId = flags.sections ? await resolveMemberOrMeProviderId(ns, rawId) : resolvedId;
328
+ const result = await ns.users.get(getId, params);
329
+ const getOutOpts = { ...outOpts, slim: slimProfile };
330
+ renderSuccess(result, getOutOpts, out);
331
+ }
332
+ } catch (err) {
333
+ const { CurviateError } = await import("@curviate/sdk");
334
+ if (err instanceof CurviateError) {
335
+ const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
336
+ renderError(err, outOpts, out);
337
+ process.exit(getExitCode(err.code));
338
+ }
339
+ renderUnexpectedError(err, out);
340
+ process.exit(1);
341
+ }
342
+ }
343
+ async function runProfileRelations(client, flags, out) {
344
+ rejectPreviewOnRead(flags.preview, out);
345
+ const accountId = requireAccount(flags.account, out);
346
+ const ns = client.account(accountId);
347
+ const outOpts = resolveOutputOpts(flags);
348
+ const all = flags.all ?? false;
349
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
350
+ const limit = flags.limit ? parseInt(flags.limit, 10) : void 0;
351
+ const cursor = flags.cursor;
352
+ const params = {};
353
+ if (limit !== void 0) params.limit = limit;
354
+ if (cursor) params.cursor = cursor;
355
+ try {
356
+ if (all) {
357
+ const fn = (p) => ns.users.listRelations(p);
358
+ for await (const item of streamAll(fn, params, {
359
+ maxPages,
360
+ out
361
+ })) {
362
+ out.stdout.write(JSON.stringify(item) + "\n");
363
+ }
364
+ } else {
365
+ const result = await ns.users.listRelations(params);
366
+ renderSuccess(result, outOpts, out);
367
+ }
368
+ } catch (err) {
369
+ const { CurviateError } = await import("@curviate/sdk");
370
+ if (err instanceof CurviateError) {
371
+ const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
372
+ renderError(err, outOpts, out);
373
+ process.exit(getExitCode(err.code));
374
+ }
375
+ renderUnexpectedError(err, out);
376
+ process.exit(1);
377
+ }
378
+ }
379
+ async function runProfileEndorse(client, flags, out) {
380
+ const accountId = requireAccount(flags.account, out);
381
+ const rawId = flags.id ?? "";
382
+ const resolvedId = resolveIdentifier(rawId);
383
+ const skillId = flags["endorsement-id"] ?? "";
384
+ const outOpts = resolveOutputOpts(flags);
385
+ if (flags.preview) {
386
+ const preview = buildPreviewOutput({
387
+ method: "users.endorseSkill",
388
+ args: { id: resolvedId },
389
+ body: { endorsement_id: skillId },
390
+ account: accountId
391
+ });
392
+ out.stdout.write(JSON.stringify(preview) + "\n");
393
+ return;
394
+ }
395
+ const ns = client.account(accountId);
396
+ try {
397
+ const result = await ns.users.endorseSkill(resolvedId, { endorsement_id: skillId });
398
+ renderSuccess(result, outOpts, out);
399
+ } catch (err) {
400
+ const { CurviateError } = await import("@curviate/sdk");
401
+ if (err instanceof CurviateError) {
402
+ const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
403
+ renderError(err, outOpts, out);
404
+ process.exit(getExitCode(err.code));
405
+ }
406
+ renderUnexpectedError(err, out);
407
+ process.exit(1);
408
+ }
409
+ }
410
+ async function handleSdkError(err, outOpts, out) {
411
+ const { CurviateError } = await import("@curviate/sdk");
412
+ if (err instanceof CurviateError) {
413
+ const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
414
+ renderError(err, outOpts, out);
415
+ process.exit(getExitCode(err.code));
416
+ }
417
+ renderUnexpectedError(err, out);
418
+ process.exit(1);
419
+ }
420
+ async function runProfileUpdate(client, flags, out) {
421
+ const accountId = requireAccount(flags.account, out);
422
+ const body = {};
423
+ if (flags["first-name"]) body.first_name = flags["first-name"];
424
+ if (flags["last-name"]) body.last_name = flags["last-name"];
425
+ if (flags.headline) body.headline = flags.headline;
426
+ if (flags.bio) body.bio = flags.bio;
427
+ if (flags.skills) {
428
+ body.skills = flags.skills.split(",").map((s) => s.trim()).filter(Boolean).map((name) => ({ name }));
429
+ }
430
+ try {
431
+ if (flags.picture) {
432
+ const buf = await readAttachment(flags.picture);
433
+ body.picture = toAttachmentPayload(flags.picture, buf);
434
+ }
435
+ if (flags["background-picture"]) {
436
+ const buf = await readAttachment(flags["background-picture"]);
437
+ body.background_picture = toAttachmentPayload(flags["background-picture"], buf);
438
+ }
439
+ } catch (err) {
440
+ if (err instanceof AttachError) {
441
+ out.stderr.write(`error: ${err.message}
442
+ `);
443
+ process.exit(err.exitCode);
444
+ }
445
+ throw err;
446
+ }
447
+ if (Object.keys(body).length === 0) {
448
+ out.stderr.write("error: nothing to update \u2014 pass at least one of --first-name, --last-name, --headline, --bio, --skills, --picture, --background-picture.\n");
449
+ process.exit(2);
450
+ }
451
+ if (flags.preview) {
452
+ const previewBody = { ...body };
453
+ if (previewBody.picture) previewBody.picture = "<base64 image>";
454
+ if (previewBody.background_picture) previewBody.background_picture = "<base64 image>";
455
+ const preview = buildPreviewOutput({ method: "users.update", args: { user_id: "me" }, body: previewBody, account: accountId });
456
+ out.stdout.write(JSON.stringify(preview) + "\n");
457
+ return;
458
+ }
459
+ const ns = client.account(accountId);
460
+ const outOpts = resolveOutputOpts(flags);
461
+ try {
462
+ const result = await ns.users.update("me", body);
463
+ renderSuccess(result, outOpts, out);
464
+ } catch (err) {
465
+ await handleSdkError(err, outOpts, out);
466
+ }
467
+ }
468
+ async function runProfileFollow(client, flags, out) {
469
+ const accountId = requireAccount(flags.account, out);
470
+ const ns = client.account(accountId);
471
+ const outOpts = resolveOutputOpts(flags);
472
+ let providerId;
473
+ try {
474
+ providerId = await resolveMemberProviderId(ns, flags.id ?? "");
475
+ } catch (err) {
476
+ await handleSdkError(err, outOpts, out);
477
+ return;
478
+ }
479
+ if (flags.preview) {
480
+ const preview = buildPreviewOutput({ method: "users.follow", args: { user_id: providerId }, body: {}, account: accountId });
481
+ out.stdout.write(JSON.stringify(preview) + "\n");
482
+ return;
483
+ }
484
+ try {
485
+ const result = await ns.users.follow(providerId);
486
+ renderSuccess(result, outOpts, out);
487
+ } catch (err) {
488
+ await handleSdkError(err, outOpts, out);
489
+ }
490
+ }
491
+ async function runProfileUnfollow(client, flags, out) {
492
+ const accountId = requireAccount(flags.account, out);
493
+ const ns = client.account(accountId);
494
+ const outOpts = resolveOutputOpts(flags);
495
+ let providerId;
496
+ try {
497
+ providerId = await resolveMemberProviderId(ns, flags.id ?? "");
498
+ } catch (err) {
499
+ await handleSdkError(err, outOpts, out);
500
+ return;
501
+ }
502
+ if (flags.preview) {
503
+ const preview = buildPreviewOutput({ method: "users.unfollow", args: { user_id: providerId }, body: {}, account: accountId });
504
+ out.stdout.write(JSON.stringify(preview) + "\n");
505
+ return;
506
+ }
507
+ try {
508
+ const result = await ns.users.unfollow(providerId);
509
+ renderSuccess(result, outOpts, out);
510
+ } catch (err) {
511
+ await handleSdkError(err, outOpts, out);
512
+ }
513
+ }
514
+ async function runProfileFollowers(client, flags, out) {
515
+ rejectPreviewOnRead(flags.preview, out);
516
+ const accountId = requireAccount(flags.account, out);
517
+ const resolvedId = resolveIdentifier(flags.id ?? "");
518
+ const ns = client.account(accountId);
519
+ const outOpts = resolveOutputOpts(flags);
520
+ const all = flags.all ?? false;
521
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
522
+ const params = {};
523
+ if (flags.limit) params.limit = parseInt(flags.limit, 10);
524
+ if (flags.cursor) params.cursor = flags.cursor;
525
+ try {
526
+ if (all) {
527
+ const fn = (p) => ns.users.listFollowers(resolvedId, p);
528
+ for await (const item of streamAll(fn, params, {
529
+ maxPages,
530
+ out
531
+ })) {
532
+ out.stdout.write(JSON.stringify(item) + "\n");
533
+ }
534
+ } else {
535
+ const result = await ns.users.listFollowers(resolvedId, params);
536
+ renderSuccess(result, outOpts, out);
537
+ }
538
+ } catch (err) {
539
+ await handleSdkError(err, outOpts, out);
540
+ }
541
+ }
542
+ async function runProfileFollowing(client, flags, out) {
543
+ rejectPreviewOnRead(flags.preview, out);
544
+ const accountId = requireAccount(flags.account, out);
545
+ const resolvedId = resolveIdentifier(flags.id ?? "");
546
+ const ns = client.account(accountId);
547
+ const outOpts = resolveOutputOpts(flags);
548
+ const all = flags.all ?? false;
549
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
550
+ const params = {};
551
+ if (flags.limit) params.limit = parseInt(flags.limit, 10);
552
+ if (flags.cursor) params.cursor = flags.cursor;
553
+ try {
554
+ if (all) {
555
+ const fn = (p) => ns.users.listFollowing(resolvedId, p);
556
+ for await (const item of streamAll(fn, params, {
557
+ maxPages,
558
+ out
559
+ })) {
560
+ out.stdout.write(JSON.stringify(item) + "\n");
561
+ }
562
+ } else {
563
+ const result = await ns.users.listFollowing(resolvedId, params);
564
+ renderSuccess(result, outOpts, out);
565
+ }
566
+ } catch (err) {
567
+ await handleSdkError(err, outOpts, out);
568
+ }
569
+ }
570
+ var profileMeCommand = defineCommand({
571
+ meta: { name: "me", description: "Get your own profile, or list own activity with --posts/--comments/--reactions/--followers." },
572
+ args: {
573
+ ...GLOBAL_FLAGS,
574
+ sections: {
575
+ type: "string",
576
+ description: "Comma-separated LinkedIn sections to fetch \u2014 linkedin_experience, linkedin_education, linkedin_languages, linkedin_skills, linkedin_certifications, linkedin_volunteer_experience, linkedin_projects, linkedin_recommendations, linkedin_interests, or linkedin_* for all (each also has a _preview variant). A bare value (e.g. skills) is auto-prefixed to linkedin_skills. Only applies to the base getMe call (no activity flag)."
577
+ },
578
+ posts: {
579
+ type: "boolean",
580
+ description: "List own activity feed (posts + reposts). For authored-only posts, use 'post list'.",
581
+ default: false
582
+ },
583
+ comments: {
584
+ type: "boolean",
585
+ description: "List own comments.",
586
+ default: false
587
+ },
588
+ reactions: {
589
+ type: "boolean",
590
+ description: "List own reactions.",
591
+ default: false
592
+ },
593
+ followers: {
594
+ type: "boolean",
595
+ description: "List own followers.",
596
+ default: false
597
+ }
598
+ },
599
+ async run({ args }) {
600
+ const flags = args;
601
+ const cfg = await resolveEffectiveConfig({
602
+ apiKey: flags["api-key"],
603
+ baseUrl: flags["base-url"],
604
+ timeout: flags.timeout,
605
+ account: flags.account,
606
+ profile: flags.profile
607
+ });
608
+ if (!cfg.apiKey) {
609
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
610
+ process.exit(3);
611
+ }
612
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
613
+ const out = buildOutputStreams();
614
+ await runProfileMe(client, { ...flags, account: flags.account ?? cfg.account }, out);
615
+ }
616
+ });
617
+ var profileRelationsCommand = defineCommand({
618
+ meta: { name: "relations", description: "List your 1st-degree connections." },
619
+ args: { ...GLOBAL_FLAGS },
620
+ async run({ args }) {
621
+ const flags = args;
622
+ const cfg = await resolveEffectiveConfig({
623
+ apiKey: flags["api-key"],
624
+ baseUrl: flags["base-url"],
625
+ timeout: flags.timeout,
626
+ account: flags.account,
627
+ profile: flags.profile
628
+ });
629
+ if (!cfg.apiKey) {
630
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
631
+ process.exit(3);
632
+ }
633
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
634
+ const out = buildOutputStreams();
635
+ await runProfileRelations(client, { ...flags, account: flags.account ?? cfg.account }, out);
636
+ }
637
+ });
638
+ var profileEndorseCommand = defineCommand({
639
+ meta: { name: "endorse", description: "Endorse a skill on a member's profile." },
640
+ args: {
641
+ ...GLOBAL_FLAGS,
642
+ id: { type: "positional", description: "Member identifier (URL, slug, or URN)." },
643
+ "endorsement-id": {
644
+ type: "string",
645
+ description: "Endorsement ID to endorse \u2014 get it from the target's skills section via `profile <id> --sections linkedin_skills`.",
646
+ required: true
647
+ }
648
+ },
649
+ async run({ args }) {
650
+ const flags = args;
651
+ const cfg = await resolveEffectiveConfig({
652
+ apiKey: args["api-key"],
653
+ baseUrl: args["base-url"],
654
+ timeout: args.timeout,
655
+ account: flags.account,
656
+ profile: args.profile
657
+ });
658
+ if (!cfg.apiKey) {
659
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
660
+ process.exit(3);
661
+ }
662
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
663
+ const out = buildOutputStreams();
664
+ await runProfileEndorse(client, { ...flags, account: flags.account ?? cfg.account }, out);
665
+ }
666
+ });
667
+ async function withClient(flags, fn) {
668
+ const cfg = await resolveEffectiveConfig({
669
+ apiKey: flags["api-key"],
670
+ baseUrl: flags["base-url"],
671
+ timeout: flags.timeout,
672
+ account: flags.account,
673
+ profile: flags.profile
674
+ });
675
+ if (!cfg.apiKey) {
676
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
677
+ process.exit(3);
678
+ }
679
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
680
+ const out = buildOutputStreams();
681
+ await fn(client, { ...flags, account: flags.account ?? cfg.account }, out);
682
+ }
683
+ var profileUpdateCommand = defineCommand({
684
+ meta: { name: "update", description: "Update your own profile (headline, bio, name, skills, photos)." },
685
+ args: {
686
+ ...WRITE_SINGLE_FLAGS,
687
+ headline: { type: "string", description: "New headline." },
688
+ bio: { type: "string", description: "New about/bio text." },
689
+ "first-name": { type: "string", description: "New first name." },
690
+ "last-name": { type: "string", description: "New last name." },
691
+ skills: { type: "string", description: "Comma-separated skill names to add (add-only)." },
692
+ picture: { type: "string", description: "New profile photo \u2014 path to an image file." },
693
+ "background-picture": { type: "string", description: "New cover/banner photo \u2014 path to an image file." }
694
+ },
695
+ async run({ args }) {
696
+ await withClient(args, runProfileUpdate);
697
+ }
698
+ });
699
+ var profileFollowCommand = defineCommand({
700
+ meta: { name: "follow", description: "Follow a member (sends a connect request if their profile is private)." },
701
+ args: {
702
+ ...WRITE_SINGLE_FLAGS,
703
+ id: { type: "positional", description: "Member identifier (URL, slug, provider id)." }
704
+ },
705
+ async run({ args }) {
706
+ await withClient(args, runProfileFollow);
707
+ }
708
+ });
709
+ var profileUnfollowCommand = defineCommand({
710
+ meta: { name: "unfollow", description: "Unfollow a member (idempotent)." },
711
+ args: {
712
+ ...WRITE_SINGLE_FLAGS,
713
+ id: { type: "positional", description: "Member identifier (URL, slug, provider id)." }
714
+ },
715
+ async run({ args }) {
716
+ await withClient(args, runProfileUnfollow);
717
+ }
718
+ });
719
+ var profileFollowersCommand = defineCommand({
720
+ meta: { name: "followers", description: "List a member's followers (accepts 'me')." },
721
+ args: {
722
+ ...GLOBAL_FLAGS,
723
+ id: { type: "positional", description: "Member identifier (URL, slug, provider id, or 'me')." }
724
+ },
725
+ async run({ args }) {
726
+ await withClient(args, runProfileFollowers);
727
+ }
728
+ });
729
+ var profileFollowingCommand = defineCommand({
730
+ meta: { name: "following", description: "List who a member follows (accepts 'me')." },
731
+ args: {
732
+ ...GLOBAL_FLAGS,
733
+ id: { type: "positional", description: "Member identifier (URL, slug, provider id, or 'me')." }
734
+ },
735
+ async run({ args }) {
736
+ await withClient(args, runProfileFollowing);
737
+ }
738
+ });
739
+ var profileCommand = defineCommand({
740
+ meta: { name: "profile", description: "LinkedIn profile operations." },
741
+ args: {
742
+ ...GLOBAL_FLAGS,
743
+ id: { type: "positional", description: "Member identifier (URL, slug, or URN). Optional for subcommands.", required: false },
744
+ posts: { type: "boolean", description: "List the profile's posts.", default: false },
745
+ comments: { type: "boolean", description: "List the profile's comments.", default: false },
746
+ reactions: { type: "boolean", description: "List the profile's reactions.", default: false },
747
+ followers: { type: "boolean", description: "List the profile's followers.", default: false },
748
+ "is-company": { type: "boolean", description: "When listing posts, treat the profile as a company page.", default: false },
749
+ sections: {
750
+ type: "string",
751
+ description: "Comma-separated LinkedIn sections to fetch \u2014 linkedin_experience, linkedin_education, linkedin_languages, linkedin_skills, linkedin_certifications, linkedin_volunteer_experience, linkedin_projects, linkedin_recommendations, linkedin_interests, or linkedin_* for all (each also has a _preview variant). A bare value (e.g. skills) is auto-prefixed to linkedin_skills."
752
+ }
753
+ },
754
+ subCommands: {
755
+ me: profileMeCommand,
756
+ relations: profileRelationsCommand,
757
+ endorse: profileEndorseCommand,
758
+ update: profileUpdateCommand,
759
+ follow: profileFollowCommand,
760
+ unfollow: profileUnfollowCommand,
761
+ followers: profileFollowersCommand,
762
+ following: profileFollowingCommand
763
+ },
764
+ async run({ args }) {
765
+ const flags = args;
766
+ if (!flags.id) {
767
+ process.stderr.write(
768
+ "Usage: curviate profile <id> [--posts|--comments|--reactions|--followers]\n curviate profile me\n curviate profile relations\n curviate profile followers <id> | following <id>\n curviate profile follow <id> | unfollow <id>\n curviate profile update [--headline|--bio|--first-name|--last-name|--skills|--picture]\n curviate profile endorse <id> --endorsement-id <id>\n"
769
+ );
770
+ process.exit(2);
771
+ }
772
+ const cfg = await resolveEffectiveConfig({
773
+ apiKey: flags["api-key"],
774
+ baseUrl: flags["base-url"],
775
+ timeout: flags.timeout,
776
+ account: flags.account,
777
+ profile: flags.profile
778
+ });
779
+ if (!cfg.apiKey) {
780
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
781
+ process.exit(3);
782
+ }
783
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
784
+ const out = buildOutputStreams();
785
+ await runProfileGet(client, { ...flags, account: flags.account ?? cfg.account }, out);
786
+ }
787
+ });
788
+ export {
789
+ profileCommand,
790
+ runProfileEndorse,
791
+ runProfileFollow,
792
+ runProfileFollowers,
793
+ runProfileFollowing,
794
+ runProfileGet,
795
+ runProfileMe,
796
+ runProfileRelations,
797
+ runProfileUnfollow,
798
+ runProfileUpdate
799
+ };