@curviate/cli 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/README.md +52 -79
  3. package/dist/{account-7AUDAMIK.js → account-FM473HEK.js} +38 -371
  4. package/dist/{chunk-SSPILTKF.js → chunk-45KHSWCV.js} +56 -48
  5. package/dist/chunk-BGZW6B7G.js +59 -0
  6. package/dist/chunk-EEMJDJ4W.js +80 -0
  7. package/dist/{chunk-JXF47TRY.js → chunk-M33MI53G.js} +33 -1
  8. package/dist/chunk-QJZ3LWOX.js +24 -0
  9. package/dist/{chunk-4JHGVY7R.js → chunk-TMU3CSPR.js} +4 -0
  10. package/dist/{chunk-HMAGEMF7.js → chunk-ZE7QGR3F.js} +4 -0
  11. package/dist/cli.js +127 -15
  12. package/dist/comment-NCDXERSI.js +555 -0
  13. package/dist/{company-RU2CA5DY.js → company-IYTMW64G.js} +27 -74
  14. package/dist/{config-Q2AEWSEC.js → config-P5CPF5WC.js} +1 -1
  15. package/dist/{connect-QT6ZOS75.js → connect-TTJHMBUP.js} +91 -45
  16. package/dist/{exit-codes-ZTY2NY3X.js → exit-codes-SL3GQF7W.js} +1 -1
  17. package/dist/{inbox-DN7X7CM2.js → inbox-EOOGJ3ZN.js} +55 -124
  18. package/dist/job-YARGTHUY.js +631 -0
  19. package/dist/{login-BBVQLXM7.js → login-MFB45PVZ.js} +1 -1
  20. package/dist/{message-6K5E3CUF.js → message-2DLIQIE6.js} +61 -51
  21. package/dist/{post-2JQZ3OSF.js → post-GRIJ7X52.js} +188 -221
  22. package/dist/profile-57RJEL7H.js +809 -0
  23. package/dist/{recruiter-XHVMQWK6.js → recruiter-CTYH7AYG.js} +740 -226
  24. package/dist/{sales-nav-QTSTJMKA.js → sales-nav-NUMEYOEO.js} +119 -77
  25. package/dist/{search-ZGTS45BT.js → search-RD4TXNV7.js} +103 -39
  26. package/dist/{webhook-EIY5WWTE.js → webhook-CEP7SGP5.js} +8 -45
  27. package/package.json +4 -3
  28. package/dist/chunk-GXTZION6.js +0 -45
  29. package/dist/chunk-Q43HZUN3.js +0 -29
  30. package/dist/job-FGGQEXSU.js +0 -105
  31. package/dist/profile-DD5GMGNL.js +0 -501
@@ -1,8 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- BinaryOutputError,
4
- writeBinaryOutput
5
- } from "./chunk-UWO2D4HW.js";
6
2
  import {
7
3
  DEFAULT_FILTER_READERS,
8
4
  assembleFilters,
@@ -10,33 +6,40 @@ import {
10
6
  } from "./chunk-42VUUKQ3.js";
11
7
  import {
12
8
  AttachError,
13
- readAttachment
14
- } from "./chunk-Q43HZUN3.js";
9
+ readAttachment,
10
+ toAttachmentPayload
11
+ } from "./chunk-BGZW6B7G.js";
12
+ import {
13
+ BinaryOutputError,
14
+ writeBinaryOutput
15
+ } from "./chunk-UWO2D4HW.js";
15
16
  import {
16
17
  buildPreviewOutput
17
18
  } from "./chunk-R3VLWLVV.js";
18
- import {
19
- streamAll
20
- } from "./chunk-GXTZION6.js";
21
19
  import {
22
20
  slimJob
23
- } from "./chunk-SSPILTKF.js";
21
+ } from "./chunk-45KHSWCV.js";
24
22
  import {
25
23
  resolveIdentifier,
26
24
  resolveJobIdentifier
27
25
  } from "./chunk-DMQZEPQE.js";
26
+ import {
27
+ pageDelayFromFlags,
28
+ streamAll
29
+ } from "./chunk-EEMJDJ4W.js";
28
30
  import {
29
31
  createClient,
30
32
  renderError,
31
33
  renderSuccess,
32
34
  renderUnexpectedError,
33
35
  resolveEffectiveConfig
34
- } from "./chunk-JXF47TRY.js";
36
+ } from "./chunk-M33MI53G.js";
35
37
  import {
36
38
  GLOBAL_FLAGS,
37
39
  READ_SINGLE_FLAGS,
38
- WRITE_FLAGS
39
- } from "./chunk-4JHGVY7R.js";
40
+ WRITE_FLAGS,
41
+ WRITE_SINGLE_FLAGS
42
+ } from "./chunk-TMU3CSPR.js";
40
43
 
41
44
  // src/commands/recruiter.ts
42
45
  import { defineCommand } from "citty";
@@ -75,13 +78,18 @@ function normalizeAttachPaths(attach) {
75
78
  async function handleSdkError(err, outOpts, out) {
76
79
  const { CurviateError } = await import("@curviate/sdk");
77
80
  if (err instanceof CurviateError) {
78
- const { getExitCode } = await import("./exit-codes-ZTY2NY3X.js");
81
+ const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
79
82
  renderError(err, outOpts, out);
80
83
  process.exit(getExitCode(err.code));
81
84
  }
82
85
  renderUnexpectedError(err, out);
83
86
  process.exit(1);
84
87
  }
88
+ function buildRecruiterRef(idValue, nameValue) {
89
+ if (idValue) return { id: idValue };
90
+ if (nameValue) return { name: nameValue };
91
+ return void 0;
92
+ }
85
93
  async function readStdin() {
86
94
  const chunks = [];
87
95
  for await (const chunk of process.stdin) {
@@ -93,7 +101,7 @@ var DEFAULT_JOB_CREATE_READERS = {
93
101
  readFile: (path) => readFile(path, "utf8"),
94
102
  readStdin
95
103
  };
96
- async function assembleJobCreateBody(flags, readers) {
104
+ async function assembleRecruiterJobBody(flags, readers) {
97
105
  let base = {};
98
106
  let raw;
99
107
  let source;
@@ -122,33 +130,72 @@ async function assembleJobCreateBody(flags, readers) {
122
130
  }
123
131
  base = parsed;
124
132
  }
125
- if (flags["job-title"] !== void 0) base["job_title"] = { text: flags["job-title"] };
133
+ if (flags["job-title-id"] !== void 0 || flags["job-title"] !== void 0) {
134
+ base["job_title"] = {
135
+ ...flags["job-title-id"] !== void 0 ? { id: flags["job-title-id"] } : {},
136
+ ...flags["job-title"] !== void 0 ? { name: flags["job-title"] } : {}
137
+ };
138
+ }
139
+ const company = buildRecruiterRef(flags["company-id"], flags["company-name"]);
140
+ if (company) base["company"] = company;
141
+ if (flags["workplace-type"] !== void 0) base["workplace_type"] = flags["workplace-type"];
142
+ if (flags.location !== void 0) base["location"] = flags.location;
143
+ if (flags["employment-status"] !== void 0) base["employment_status"] = flags["employment-status"];
144
+ if (flags["seniority-level"] !== void 0) base["seniority_level"] = flags["seniority-level"];
126
145
  if (flags.description !== void 0) base["description"] = flags.description;
127
- if (flags["employment-type"] !== void 0) base["employment_type"] = flags["employment-type"];
146
+ if (flags.industry !== void 0) base["industry"] = splitCsv(flags.industry);
147
+ if (flags["job-function"] !== void 0) base["job_function"] = splitCsv(flags["job-function"]);
148
+ if (flags["apply-method"] !== void 0) {
149
+ const method = flags["apply-method"];
150
+ base["apply_method"] = {
151
+ method,
152
+ ...method === "linkedin" && flags["notification-email"] !== void 0 ? { notification_email: flags["notification-email"] } : {},
153
+ ...method === "external" && flags["website-url"] !== void 0 ? { website_url: flags["website-url"] } : {}
154
+ };
155
+ }
156
+ if (flags["project-name"] !== void 0) base["project_name"] = flags["project-name"];
128
157
  return { body: base };
129
158
  }
130
- async function runRecruiterSync(client, flags, out) {
131
- rejectPreviewOnRead(flags.preview, out);
132
- const accountId = requireAccount(flags.account, out);
133
- const ns = client.account(accountId);
134
- const outOpts = resolveOutputOpts(flags);
135
- const params = {};
136
- if (flags.cursor) params["cursor"] = flags.cursor;
137
- if (flags.limit) params["limit"] = parseInt(flags.limit, 10);
138
- try {
139
- const result = await ns.recruiter.syncMessages(params);
140
- renderSuccess(result, outOpts, out);
141
- } catch (err) {
142
- await handleSdkError(err, outOpts, out);
159
+ var RECRUITER_JOB_REQUIRED_FIELDS = [
160
+ ["job_title", "--job-title-id (paired with --job-title)"],
161
+ ["company", "--company-id or --company-name"],
162
+ ["workplace_type", "--workplace-type"],
163
+ ["location", "--location"],
164
+ ["employment_status", "--employment-status"],
165
+ ["seniority_level", "--seniority-level"],
166
+ ["description", "--description"],
167
+ ["industry", "--industry"],
168
+ ["job_function", "--job-function"],
169
+ ["apply_method", "--apply-method"]
170
+ ];
171
+ function requireRecruiterJobFields(body, extra, out) {
172
+ for (const [key, flagDesc] of [...RECRUITER_JOB_REQUIRED_FIELDS, ...extra]) {
173
+ const value = body[key];
174
+ const missing = value === void 0 || value === null || Array.isArray(value) && value.length === 0;
175
+ if (missing) {
176
+ out.stderr.write(`error: ${flagDesc} is required (or ${key} in --body-file/--body -).
177
+ `);
178
+ process.exit(2);
179
+ }
143
180
  }
144
181
  }
145
182
  async function runRecruiterMessageNew(client, flags, out) {
146
183
  const accountId = requireAccount(flags.account, out);
147
184
  const to = flags.to ?? "";
148
185
  const text = flags.text ?? "";
186
+ const subject = flags.subject ?? "";
187
+ const signature = flags.signature ?? "";
149
188
  const attachPaths = normalizeAttachPaths(flags.attach);
150
189
  const voicePath = flags.voice;
151
190
  const videoPath = flags.video;
191
+ if (!subject) {
192
+ out.stderr.write("error: --subject is required (v2: REQUIRED for Recruiter messaging).\n");
193
+ process.exit(2);
194
+ }
195
+ if (!signature) {
196
+ out.stderr.write("error: --signature is required (v2: REQUIRED for Recruiter messaging).\n");
197
+ process.exit(2);
198
+ }
152
199
  let attachBuffers = [];
153
200
  let voiceBuffer;
154
201
  let videoBuffer;
@@ -164,15 +211,11 @@ async function runRecruiterMessageNew(client, flags, out) {
164
211
  }
165
212
  throw err;
166
213
  }
167
- const body = {
168
- attendees_ids: [to],
169
- text
170
- };
171
214
  if (flags.preview) {
172
215
  const preview = buildPreviewOutput({
173
216
  method: "recruiter.startChat",
174
217
  args: { attendees_ids: [to] },
175
- body: { ...body },
218
+ body: { attendees_ids: [to], text, subject, signature },
176
219
  account: accountId,
177
220
  attachments: [
178
221
  ...attachBuffers.map((buf, i) => ({
@@ -186,9 +229,18 @@ async function runRecruiterMessageNew(client, flags, out) {
186
229
  out.stdout.write(JSON.stringify(preview) + "\n");
187
230
  return;
188
231
  }
189
- if (attachBuffers.length > 0) body["attachments"] = attachBuffers;
190
- if (voiceBuffer) body["voice_message"] = voiceBuffer;
191
- if (videoBuffer) body["video_message"] = videoBuffer;
232
+ const attachments = [
233
+ ...attachPaths.map((p, i) => toAttachmentPayload(p, attachBuffers[i])),
234
+ ...voiceBuffer && voicePath ? [{ ...toAttachmentPayload(voicePath, voiceBuffer), send_mode: "native" }] : [],
235
+ ...videoBuffer && videoPath ? [{ ...toAttachmentPayload(videoPath, videoBuffer), send_mode: "native" }] : []
236
+ ];
237
+ const body = {
238
+ attendees_ids: [to],
239
+ text,
240
+ subject,
241
+ signature,
242
+ ...attachments.length > 0 ? { attachments } : {}
243
+ };
192
244
  const ns = client.account(accountId);
193
245
  const outOpts = resolveOutputOpts(flags);
194
246
  try {
@@ -249,8 +301,8 @@ async function runRecruiterSearchPeople(client, flags, out, readers = DEFAULT_FI
249
301
  };
250
302
  for await (const item of streamAll(fn, params, {
251
303
  maxPages,
252
- onTruncated: (n) => out.stderr.write(`Streaming truncated at ${n} page(s). Use --all --max-pages or --cursor for manual paging.
253
- `)
304
+ out,
305
+ pageDelayMs: pageDelayFromFlags(flags)
254
306
  })) {
255
307
  out.stdout.write(JSON.stringify(item) + "\n");
256
308
  }
@@ -262,22 +314,74 @@ async function runRecruiterSearchPeople(client, flags, out, readers = DEFAULT_FI
262
314
  await handleSdkError(err, outOpts, out);
263
315
  }
264
316
  }
265
- async function runRecruiterGetParameters(client, flags, out) {
317
+ async function runRecruiterSearchParameters(client, flags, out) {
266
318
  rejectPreviewOnRead(flags.preview, out);
319
+ if (!flags.source) {
320
+ out.stderr.write("error: --source is required (APPLICANTS, PIPELINE, SEARCH, JOB_POSTING, or JOBS).\n");
321
+ process.exit(2);
322
+ }
323
+ if (!flags.type) {
324
+ out.stderr.write("error: --type is required.\n");
325
+ process.exit(2);
326
+ }
267
327
  const accountId = requireAccount(flags.account, out);
268
328
  const ns = client.account(accountId);
269
329
  const outOpts = resolveOutputOpts(flags);
330
+ const body = {
331
+ source: flags.source,
332
+ type: flags.type,
333
+ ...flags.keywords ? { keywords: flags.keywords } : {},
334
+ ...flags["project-id"] ? { project_id: flags["project-id"] } : {},
335
+ ...flags["stage-id"] ? { stage_id: flags["stage-id"] } : {}
336
+ };
270
337
  const params = {};
271
- if (flags.type) params["type"] = flags.type;
272
- if (flags.keywords) params["keywords"] = flags.keywords;
273
338
  if (flags.limit) params["limit"] = parseInt(flags.limit, 10);
274
339
  try {
275
- const result = await ns.recruiter.getParameters(params);
340
+ const result = await ns.recruiter.searchParameters(body, Object.keys(params).length > 0 ? params : void 0);
276
341
  renderSuccess(result, outOpts, out);
277
342
  } catch (err) {
278
343
  await handleSdkError(err, outOpts, out);
279
344
  }
280
345
  }
346
+ async function runRecruiterSearchFromUrl(client, flags, out) {
347
+ rejectPreviewOnRead(flags.preview, out);
348
+ const accountId = requireAccount(flags.account, out);
349
+ const url = flags.url ?? "";
350
+ const ns = client.account(accountId);
351
+ const outOpts = resolveOutputOpts(flags);
352
+ const all = flags.all ?? false;
353
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
354
+ const limit = flags.limit ? parseInt(flags.limit, 10) : void 0;
355
+ const cursor = flags.cursor;
356
+ const body = { url };
357
+ const params = {};
358
+ if (limit !== void 0) params["limit"] = limit;
359
+ if (cursor) params["cursor"] = cursor;
360
+ try {
361
+ if (all) {
362
+ const fn = (p) => {
363
+ const { cursor: c, limit: l, ...restP } = p;
364
+ const callParams = {};
365
+ if (c) callParams["cursor"] = c;
366
+ if (l) callParams["limit"] = l;
367
+ void restP;
368
+ return ns.recruiter.searchFromUrl(body, callParams);
369
+ };
370
+ for await (const item of streamAll(fn, params, {
371
+ maxPages,
372
+ out,
373
+ pageDelayMs: pageDelayFromFlags(flags)
374
+ })) {
375
+ out.stdout.write(JSON.stringify(item) + "\n");
376
+ }
377
+ } else {
378
+ const result = await ns.recruiter.searchFromUrl(body, Object.keys(params).length > 0 ? params : void 0);
379
+ renderSuccess(result, outOpts, out);
380
+ }
381
+ } catch (err) {
382
+ await handleSdkError(err, outOpts, out);
383
+ }
384
+ }
281
385
  async function runRecruiterListProjects(client, flags, out) {
282
386
  rejectPreviewOnRead(flags.preview, out);
283
387
  const accountId = requireAccount(flags.account, out);
@@ -295,8 +399,8 @@ async function runRecruiterListProjects(client, flags, out) {
295
399
  const fn = (p) => ns.recruiter.listProjects(p);
296
400
  for await (const item of streamAll(fn, params, {
297
401
  maxPages,
298
- onTruncated: (n) => out.stderr.write(`Streaming truncated at ${n} page(s). Use --all --max-pages or --cursor for manual paging.
299
- `)
402
+ out,
403
+ pageDelayMs: pageDelayFromFlags(flags)
300
404
  })) {
301
405
  out.stdout.write(JSON.stringify(item) + "\n");
302
406
  }
@@ -321,17 +425,28 @@ async function runRecruiterGetProject(client, flags, out) {
321
425
  await handleSdkError(err, outOpts, out);
322
426
  }
323
427
  }
324
- async function runRecruiterAddCandidate(client, flags, out) {
428
+ async function runRecruiterUpdateProject(client, flags, out) {
325
429
  const accountId = requireAccount(flags.account, out);
326
- const userId = flags.userId ?? "";
430
+ const projectId = flags.projectId ?? "";
327
431
  const outOpts = resolveOutputOpts(flags);
328
432
  const body = {};
329
- if (flags["hiring-project-id"]) body["hiring_project_id"] = flags["hiring-project-id"];
330
- if (flags.stage) body["stage"] = flags.stage;
433
+ if (flags.name !== void 0) body["name"] = flags.name;
434
+ if (flags.visibility !== void 0) body["visibility"] = flags.visibility;
435
+ if (flags.description !== void 0) body["description"] = flags.description;
436
+ const company = buildRecruiterRef(flags["company-id"], flags["company-name"]);
437
+ if (company) body["company"] = company;
438
+ if (flags["job-title-id"] !== void 0 || flags["job-title"] !== void 0) {
439
+ body["job_title"] = {
440
+ ...flags["job-title-id"] !== void 0 ? { id: flags["job-title-id"] } : {},
441
+ ...flags["job-title"] !== void 0 ? { name: flags["job-title"] } : {}
442
+ };
443
+ }
444
+ if (flags.location !== void 0) body["location"] = flags.location;
445
+ if (flags["seniority-level"] !== void 0) body["seniority_level"] = flags["seniority-level"];
331
446
  if (flags.preview) {
332
447
  const preview = buildPreviewOutput({
333
- method: "recruiter.addCandidate",
334
- args: { user_id: userId },
448
+ method: "recruiter.updateProject",
449
+ args: { project_id: projectId },
335
450
  body,
336
451
  account: accountId
337
452
  });
@@ -340,67 +455,98 @@ async function runRecruiterAddCandidate(client, flags, out) {
340
455
  }
341
456
  const ns = client.account(accountId);
342
457
  try {
343
- const result = await ns.recruiter.addCandidate(userId, body);
458
+ const result = await ns.recruiter.updateProject(projectId, body);
344
459
  renderSuccess(result, outOpts, out);
345
460
  } catch (err) {
346
461
  await handleSdkError(err, outOpts, out);
347
462
  }
348
463
  }
349
- async function runRecruiterAddApplicant(client, flags, out) {
464
+ async function runRecruiterListPipeline(client, flags, out) {
465
+ rejectPreviewOnRead(flags.preview, out);
350
466
  const accountId = requireAccount(flags.account, out);
351
- const userId = flags.userId ?? "";
467
+ const projectId = flags.projectId ?? "";
468
+ const ns = client.account(accountId);
352
469
  const outOpts = resolveOutputOpts(flags);
470
+ const all = flags.all ?? false;
471
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
472
+ const limit = flags.limit ? parseInt(flags.limit, 10) : void 0;
473
+ const cursor = flags.cursor;
353
474
  const body = {};
354
- if (flags["hiring-project-id"]) body["hiring_project_id"] = flags["hiring-project-id"];
355
- if (flags.stage) body["stage"] = flags.stage;
356
- if (flags.preview) {
357
- const preview = buildPreviewOutput({
358
- method: "recruiter.addApplicant",
359
- args: { user_id: userId },
360
- body,
361
- account: accountId
362
- });
363
- out.stdout.write(JSON.stringify(preview) + "\n");
364
- return;
475
+ if (flags.keywords) body["keywords"] = flags.keywords;
476
+ if (flags["stage-id"]) body["stage_id"] = flags["stage-id"];
477
+ if (flags["sort-by"]) body["sort_by"] = flags["sort-by"];
478
+ if (flags.spotlights) body["spotlights"] = splitCsv(flags.spotlights);
479
+ const params = {};
480
+ if (limit !== void 0) params["limit"] = limit;
481
+ if (cursor) params["cursor"] = cursor;
482
+ try {
483
+ if (all) {
484
+ const fn = (p) => {
485
+ const { cursor: c, limit: l, ...restP } = p;
486
+ const callParams = {};
487
+ if (c) callParams["cursor"] = c;
488
+ if (l) callParams["limit"] = l;
489
+ void restP;
490
+ return ns.recruiter.listPipeline(projectId, body, callParams);
491
+ };
492
+ for await (const item of streamAll(fn, params, {
493
+ maxPages,
494
+ out,
495
+ pageDelayMs: pageDelayFromFlags(flags)
496
+ })) {
497
+ out.stdout.write(JSON.stringify(item) + "\n");
498
+ }
499
+ } else {
500
+ const result = await ns.recruiter.listPipeline(
501
+ projectId,
502
+ Object.keys(body).length > 0 ? body : void 0,
503
+ Object.keys(params).length > 0 ? params : void 0
504
+ );
505
+ renderSuccess(result, outOpts, out);
506
+ }
507
+ } catch (err) {
508
+ await handleSdkError(err, outOpts, out);
365
509
  }
510
+ }
511
+ async function runRecruiterGetProjectJob(client, flags, out) {
512
+ rejectPreviewOnRead(flags.preview, out);
513
+ const accountId = requireAccount(flags.account, out);
514
+ const projectId = flags.projectId ?? "";
366
515
  const ns = client.account(accountId);
516
+ const outOpts = resolveOutputOpts(flags);
367
517
  try {
368
- const result = await ns.recruiter.addApplicant(userId, body);
518
+ const result = await ns.recruiter.getProjectJob(projectId);
369
519
  renderSuccess(result, outOpts, out);
370
520
  } catch (err) {
371
521
  await handleSdkError(err, outOpts, out);
372
522
  }
373
523
  }
374
- async function runRecruiterRejectApplicant(client, flags, out) {
524
+ async function runRecruiterGetProjectJobBudget(client, flags, out) {
525
+ rejectPreviewOnRead(flags.preview, out);
375
526
  const accountId = requireAccount(flags.account, out);
376
- const userId = flags.userId ?? "";
527
+ const projectId = flags.projectId ?? "";
528
+ const jobId = flags.jobId ?? "";
529
+ const ns = client.account(accountId);
377
530
  const outOpts = resolveOutputOpts(flags);
378
- if (flags["notify-at"] && !flags.message) {
379
- out.stderr.write(
380
- "error: --notify-at requires --message (rejection_notification.message is required to send a notification).\n"
381
- );
382
- process.exit(2);
383
- }
384
- let notifyAt;
385
- if (flags["notify-at"]) {
386
- notifyAt = Number(flags["notify-at"]);
387
- if (!Number.isFinite(notifyAt)) {
388
- out.stderr.write("error: --notify-at must be a UNIX milliseconds timestamp (a number).\n");
389
- process.exit(2);
390
- }
391
- }
392
- const body = {};
393
- if (flags["hiring-project-id"]) body["hiring_project_id"] = flags["hiring-project-id"];
394
- if (flags.reason) body["reason"] = flags.reason;
395
- if (flags.message) {
396
- const rejectionNotification = { message: flags.message };
397
- if (notifyAt !== void 0) rejectionNotification["send_notification_at"] = notifyAt;
398
- body["rejection_notification"] = rejectionNotification;
531
+ try {
532
+ const result = await ns.recruiter.getProjectJobBudget(projectId, jobId);
533
+ renderSuccess(result, outOpts, out);
534
+ } catch (err) {
535
+ await handleSdkError(err, outOpts, out);
399
536
  }
537
+ }
538
+ async function runRecruiterSaveCandidate(client, flags, out) {
539
+ const accountId = requireAccount(flags.account, out);
540
+ const projectId = flags.projectId ?? "";
541
+ const outOpts = resolveOutputOpts(flags);
542
+ const body = {
543
+ stage_id: flags["stage-id"] ?? "",
544
+ candidate_id: flags["candidate-id"] ?? ""
545
+ };
400
546
  if (flags.preview) {
401
547
  const preview = buildPreviewOutput({
402
- method: "recruiter.rejectApplicant",
403
- args: { user_id: userId },
548
+ method: "recruiter.saveCandidate",
549
+ args: { project_id: projectId },
404
550
  body,
405
551
  account: accountId
406
552
  });
@@ -409,7 +555,7 @@ async function runRecruiterRejectApplicant(client, flags, out) {
409
555
  }
410
556
  const ns = client.account(accountId);
411
557
  try {
412
- const result = await ns.recruiter.rejectApplicant(userId, body);
558
+ const result = await ns.recruiter.saveCandidate(projectId, body);
413
559
  renderSuccess(result, outOpts, out);
414
560
  } catch (err) {
415
561
  await handleSdkError(err, outOpts, out);
@@ -432,8 +578,8 @@ async function runRecruiterListJobs(client, flags, out) {
432
578
  const fn = (p) => ns.recruiter.listJobs(p);
433
579
  for await (const item of streamAll(fn, params, {
434
580
  maxPages,
435
- onTruncated: (n) => out.stderr.write(`Streaming truncated at ${n} page(s). Use --all --max-pages or --cursor for manual paging.
436
- `)
581
+ out,
582
+ pageDelayMs: pageDelayFromFlags(flags)
437
583
  })) {
438
584
  out.stdout.write(JSON.stringify(item) + "\n");
439
585
  }
@@ -448,13 +594,14 @@ async function runRecruiterListJobs(client, flags, out) {
448
594
  async function runRecruiterCreateJob(client, flags, out, readers = DEFAULT_JOB_CREATE_READERS) {
449
595
  const accountId = requireAccount(flags.account, out);
450
596
  const outOpts = resolveOutputOpts(flags);
451
- const assembled = await assembleJobCreateBody(flags, readers);
597
+ const assembled = await assembleRecruiterJobBody(flags, readers);
452
598
  if ("error" in assembled) {
453
599
  out.stderr.write(`error: ${assembled.error}
454
600
  `);
455
601
  process.exit(2);
456
602
  }
457
603
  const body = assembled.body;
604
+ requireRecruiterJobFields(body, [["project_name", "--project-name"]], out);
458
605
  if (flags.preview) {
459
606
  const preview = buildPreviewOutput({
460
607
  method: "recruiter.createJob",
@@ -473,16 +620,52 @@ async function runRecruiterCreateJob(client, flags, out, readers = DEFAULT_JOB_C
473
620
  await handleSdkError(err, outOpts, out);
474
621
  }
475
622
  }
476
- async function runRecruiterPublishJob(client, flags, out) {
623
+ async function runRecruiterCreateProjectJob(client, flags, out, readers = DEFAULT_JOB_CREATE_READERS) {
624
+ const accountId = requireAccount(flags.account, out);
625
+ const projectId = flags.projectId ?? "";
626
+ const outOpts = resolveOutputOpts(flags);
627
+ const assembled = await assembleRecruiterJobBody(flags, readers);
628
+ if ("error" in assembled) {
629
+ out.stderr.write(`error: ${assembled.error}
630
+ `);
631
+ process.exit(2);
632
+ }
633
+ const body = assembled.body;
634
+ requireRecruiterJobFields(body, [], out);
635
+ if (flags.preview) {
636
+ const preview = buildPreviewOutput({
637
+ method: "recruiter.createProjectJob",
638
+ args: { project_id: projectId },
639
+ body,
640
+ account: accountId
641
+ });
642
+ out.stdout.write(JSON.stringify(preview) + "\n");
643
+ return;
644
+ }
645
+ const ns = client.account(accountId);
646
+ try {
647
+ const result = await ns.recruiter.createProjectJob(projectId, body);
648
+ renderSuccess(result, outOpts, out);
649
+ } catch (err) {
650
+ await handleSdkError(err, outOpts, out);
651
+ }
652
+ }
653
+ async function runRecruiterUpdateProjectJob(client, flags, out, readers = DEFAULT_JOB_CREATE_READERS) {
477
654
  const accountId = requireAccount(flags.account, out);
655
+ const projectId = flags.projectId ?? "";
478
656
  const jobId = flags.jobId ?? "";
479
657
  const outOpts = resolveOutputOpts(flags);
480
- const body = {};
481
- if (flags.mode) body["mode"] = flags.mode;
658
+ const assembled = await assembleRecruiterJobBody(flags, readers);
659
+ if ("error" in assembled) {
660
+ out.stderr.write(`error: ${assembled.error}
661
+ `);
662
+ process.exit(2);
663
+ }
664
+ const body = assembled.body;
482
665
  if (flags.preview) {
483
666
  const preview = buildPreviewOutput({
484
- method: "recruiter.publishJob",
485
- args: { job_id: jobId },
667
+ method: "recruiter.updateProjectJob",
668
+ args: { project_id: projectId, job_id: jobId },
486
669
  body,
487
670
  account: accountId
488
671
  });
@@ -491,22 +674,59 @@ async function runRecruiterPublishJob(client, flags, out) {
491
674
  }
492
675
  const ns = client.account(accountId);
493
676
  try {
494
- const result = await ns.recruiter.publishJob(jobId, body);
677
+ const result = await ns.recruiter.updateProjectJob(projectId, jobId, body);
495
678
  renderSuccess(result, outOpts, out);
496
679
  } catch (err) {
497
680
  await handleSdkError(err, outOpts, out);
498
681
  }
499
682
  }
500
- async function runRecruiterJobCheckpoint(client, flags, out) {
683
+ var RECRUITER_PUBLISH_MODES = ["FREE", "PROMOTED", "PROMOTED_PLUS"];
684
+ var RECRUITER_BUDGET_SCOPES = ["DAILY", "TOTAL"];
685
+ async function runRecruiterPublishJob(client, flags, out) {
501
686
  const accountId = requireAccount(flags.account, out);
687
+ const projectId = flags.projectId ?? "";
502
688
  const jobId = flags.jobId ?? "";
503
689
  const outOpts = resolveOutputOpts(flags);
504
- const body = {};
505
- if (flags.input) body["input"] = flags.input;
690
+ if (!flags.mode) {
691
+ out.stderr.write("error: --mode is required (FREE, PROMOTED, or PROMOTED_PLUS).\n");
692
+ process.exit(2);
693
+ }
694
+ if (!RECRUITER_PUBLISH_MODES.includes(flags.mode)) {
695
+ out.stderr.write(`error: --mode must be one of: ${RECRUITER_PUBLISH_MODES.join(", ")}. Got "${flags.mode}".
696
+ `);
697
+ process.exit(2);
698
+ }
699
+ const mode = flags.mode;
700
+ let body = { mode };
701
+ if (mode === "PROMOTED" || mode === "PROMOTED_PLUS") {
702
+ if (!flags["budget-currency"]) {
703
+ out.stderr.write("error: --budget-currency is required for a paid publish (PROMOTED/PROMOTED_PLUS).\n");
704
+ process.exit(2);
705
+ }
706
+ if (!flags["budget-amount"]) {
707
+ out.stderr.write("error: --budget-amount is required for a paid publish (PROMOTED/PROMOTED_PLUS).\n");
708
+ process.exit(2);
709
+ }
710
+ if (!flags["budget-scope"]) {
711
+ out.stderr.write("error: --budget-scope is required for a paid publish (PROMOTED/PROMOTED_PLUS).\n");
712
+ process.exit(2);
713
+ }
714
+ if (!RECRUITER_BUDGET_SCOPES.includes(flags["budget-scope"])) {
715
+ out.stderr.write(`error: --budget-scope must be one of: ${RECRUITER_BUDGET_SCOPES.join(", ")}. Got "${flags["budget-scope"]}".
716
+ `);
717
+ process.exit(2);
718
+ }
719
+ const amount = Number(flags["budget-amount"]);
720
+ if (!Number.isFinite(amount) || amount < 0) {
721
+ out.stderr.write("error: --budget-amount must be a non-negative number.\n");
722
+ process.exit(2);
723
+ }
724
+ body = { mode, budget: { currency: flags["budget-currency"], amount, scope: flags["budget-scope"] } };
725
+ }
506
726
  if (flags.preview) {
507
727
  const preview = buildPreviewOutput({
508
- method: "recruiter.solveJobCheckpoint",
509
- args: { job_id: jobId },
728
+ method: "recruiter.publishJob",
729
+ args: { project_id: projectId, job_id: jobId },
510
730
  body,
511
731
  account: accountId
512
732
  });
@@ -515,23 +735,102 @@ async function runRecruiterJobCheckpoint(client, flags, out) {
515
735
  }
516
736
  const ns = client.account(accountId);
517
737
  try {
518
- const result = await ns.recruiter.solveJobCheckpoint(jobId, body);
738
+ const result = await ns.recruiter.publishJob(projectId, jobId, body);
519
739
  renderSuccess(result, outOpts, out);
520
740
  } catch (err) {
521
741
  await handleSdkError(err, outOpts, out);
522
742
  }
523
743
  }
744
+ async function runRecruiterCloseJob(client, flags, out) {
745
+ const accountId = requireAccount(flags.account, out);
746
+ const projectId = flags.projectId ?? "";
747
+ const jobId = flags.jobId ?? "";
748
+ if (flags.preview) {
749
+ const preview = buildPreviewOutput({
750
+ method: "recruiter.closeJob",
751
+ args: { project_id: projectId, job_id: jobId },
752
+ body: {},
753
+ account: accountId
754
+ });
755
+ out.stdout.write(JSON.stringify(preview) + "\n");
756
+ return;
757
+ }
758
+ const ns = client.account(accountId);
759
+ const outOpts = resolveOutputOpts(flags);
760
+ try {
761
+ const result = await ns.recruiter.closeJob(projectId, jobId);
762
+ renderSuccess(result, outOpts, out);
763
+ } catch (err) {
764
+ await handleSdkError(err, outOpts, out);
765
+ }
766
+ }
767
+ async function runRecruiterSearchTalentPool(client, flags, out, readers = DEFAULT_FILTER_READERS) {
768
+ rejectPreviewOnRead(flags.preview, out);
769
+ if (!flags["channel-id"]) {
770
+ out.stderr.write("error: --channel-id is required.\n");
771
+ process.exit(2);
772
+ }
773
+ const accountId = requireAccount(flags.account, out);
774
+ const projectId = flags.projectId ?? "";
775
+ const ns = client.account(accountId);
776
+ const outOpts = resolveOutputOpts(flags);
777
+ const all = flags.all ?? false;
778
+ const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
779
+ const limit = flags.limit ? parseInt(flags.limit, 10) : void 0;
780
+ const cursor = flags.cursor;
781
+ const assembled = await assembleFilters(flags, readers);
782
+ if ("error" in assembled) {
783
+ out.stderr.write(`error: ${assembled.error}
784
+ `);
785
+ process.exit(2);
786
+ }
787
+ const body = assembled.body;
788
+ body["channel_id"] = flags["channel-id"];
789
+ if (flags.keywords) body["keywords"] = flags.keywords;
790
+ const params = {};
791
+ if (limit !== void 0) params["limit"] = limit;
792
+ if (cursor) params["cursor"] = cursor;
793
+ try {
794
+ if (all) {
795
+ const fn = (p) => {
796
+ const { cursor: c, limit: l, ...restP } = p;
797
+ const callParams = {};
798
+ if (c) callParams["cursor"] = c;
799
+ if (l) callParams["limit"] = l;
800
+ void restP;
801
+ return ns.recruiter.searchTalentPool(projectId, body, callParams);
802
+ };
803
+ for await (const item of streamAll(fn, params, {
804
+ maxPages,
805
+ out,
806
+ pageDelayMs: pageDelayFromFlags(flags)
807
+ })) {
808
+ out.stdout.write(JSON.stringify(item) + "\n");
809
+ }
810
+ } else {
811
+ const result = await ns.recruiter.searchTalentPool(projectId, body, Object.keys(params).length > 0 ? params : void 0);
812
+ renderSuccess(result, outOpts, out);
813
+ }
814
+ } catch (err) {
815
+ await handleSdkError(err, outOpts, out);
816
+ }
817
+ }
524
818
  async function runRecruiterListApplicants(client, flags, out) {
525
819
  rejectPreviewOnRead(flags.preview, out);
820
+ if (!flags["channel-id"]) {
821
+ out.stderr.write("error: --channel-id is required.\n");
822
+ process.exit(2);
823
+ }
526
824
  const accountId = requireAccount(flags.account, out);
527
- const jobId = flags.jobId ?? "";
825
+ const projectId = flags.projectId ?? "";
528
826
  const ns = client.account(accountId);
529
827
  const outOpts = resolveOutputOpts(flags);
828
+ const body = { channel_id: flags["channel-id"] };
530
829
  const params = {};
531
830
  if (flags.limit) params["limit"] = parseInt(flags.limit, 10);
532
831
  if (flags.cursor) params["cursor"] = flags.cursor;
533
832
  try {
534
- const result = await ns.recruiter.listApplicants(jobId, Object.keys(params).length > 0 ? params : void 0);
833
+ const result = await ns.recruiter.listApplicants(projectId, body, Object.keys(params).length > 0 ? params : void 0);
535
834
  renderSuccess(result, outOpts, out);
536
835
  } catch (err) {
537
836
  await handleSdkError(err, outOpts, out);
@@ -554,11 +853,12 @@ async function runRecruiterGetJob(client, flags, out) {
554
853
  async function runRecruiterGetApplicant(client, flags, out) {
555
854
  rejectPreviewOnRead(flags.preview, out);
556
855
  const accountId = requireAccount(flags.account, out);
856
+ const projectId = flags.projectId ?? "";
557
857
  const applicantId = flags.applicantId ?? "";
558
858
  const ns = client.account(accountId);
559
859
  const outOpts = resolveOutputOpts(flags);
560
860
  try {
561
- const result = await ns.recruiter.getApplicant(applicantId);
861
+ const result = await ns.recruiter.getApplicant(projectId, applicantId);
562
862
  renderSuccess(result, outOpts, out);
563
863
  } catch (err) {
564
864
  await handleSdkError(err, outOpts, out);
@@ -567,10 +867,11 @@ async function runRecruiterGetApplicant(client, flags, out) {
567
867
  async function runRecruiterDownloadResume(client, flags, out, isTTY) {
568
868
  rejectPreviewOnRead(flags.preview, out);
569
869
  const accountId = requireAccount(flags.account, out);
870
+ const projectId = flags.projectId ?? "";
570
871
  const applicantId = flags.applicantId ?? "";
571
872
  const ns = client.account(accountId);
572
873
  try {
573
- const data = await ns.recruiter.downloadResume(applicantId);
874
+ const data = await ns.recruiter.downloadResume(projectId, applicantId);
574
875
  await writeBinaryOutput(data, {
575
876
  outputPath: flags.output,
576
877
  isTTY,
@@ -586,27 +887,6 @@ async function runRecruiterDownloadResume(client, flags, out, isTTY) {
586
887
  await handleSdkError(err, outOpts, out);
587
888
  }
588
889
  }
589
- var recruiterSyncCommand = defineCommand({
590
- meta: { name: "sync", description: "Sync Recruiter message history for an account." },
591
- args: { ...GLOBAL_FLAGS },
592
- async run({ args }) {
593
- const flags = args;
594
- const cfg = await resolveEffectiveConfig({
595
- apiKey: flags["api-key"],
596
- baseUrl: flags["base-url"],
597
- timeout: flags.timeout,
598
- account: flags.account,
599
- profile: flags.profile
600
- });
601
- if (!cfg.apiKey) {
602
- process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
603
- process.exit(3);
604
- }
605
- const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
606
- const out = buildOutputStreams();
607
- await runRecruiterSync(client, { ...flags, account: flags.account ?? cfg.account }, out);
608
- }
609
- });
610
890
  var recruiterMessageNewCommand = defineCommand({
611
891
  meta: { name: "new", description: "Start a new Recruiter chat with a member." },
612
892
  args: {
@@ -617,6 +897,8 @@ var recruiterMessageNewCommand = defineCommand({
617
897
  description: "Recipient's LinkedIn provider ID (AE\u2026 format, e.g. from a Recruiter search result or profile). Not resolved from a URL/slug \u2014 pass the provider ID directly.",
618
898
  required: true
619
899
  },
900
+ subject: { type: "string", description: "Message subject line (required for Recruiter InMail).", required: true },
901
+ signature: { type: "string", description: "Sender signature (required for Recruiter InMail).", required: true },
620
902
  text: { type: "positional", description: "Opening message text." },
621
903
  attach: { type: "string", description: "File to attach (repeatable, max 7 MiB each)." },
622
904
  voice: { type: "string", description: "Voice message file (max 7 MiB)." },
@@ -706,15 +988,22 @@ var recruiterSearchPeopleCommand = defineCommand({
706
988
  }
707
989
  });
708
990
  var recruiterSearchParametersCommand = defineCommand({
709
- meta: { name: "parameters", description: "Resolve Recruiter filter parameter IDs." },
991
+ meta: { name: "parameters", description: "Resolve Recruiter filter parameter IDs (POST \u2014 source-scoped)." },
710
992
  args: {
711
993
  ...GLOBAL_FLAGS,
994
+ source: {
995
+ type: "string",
996
+ description: "Filter family to resolve within: APPLICANTS or PIPELINE (both require --project-id), SEARCH, JOB_POSTING, or JOBS.",
997
+ required: true
998
+ },
712
999
  type: {
713
1000
  type: "string",
714
- description: "Parameter type to resolve. One of: GROUPS, DEPARTMENT, HIRING_PROJECTS, SAVED_SEARCHES, SAVED_FILTERS, DEGREE.",
1001
+ description: "Parameter type to resolve; the valid set depends on --source (e.g. SKILL/LOCATION/JOB_TITLE for APPLICANTS, CONTRACT/SEAT/LOCATION for JOBS).",
715
1002
  required: true
716
1003
  },
717
- keywords: { type: "string", description: "Human term to resolve (e.g. Berlin)." }
1004
+ keywords: { type: "string", description: "Human term to resolve (e.g. Berlin)." },
1005
+ "project-id": { type: "string", description: "Recruiter project ID (required for --source APPLICANTS or PIPELINE)." },
1006
+ "stage-id": { type: "string", description: "Pipeline stage ID to filter to (only meaningful for --source PIPELINE)." }
718
1007
  },
719
1008
  async run({ args }) {
720
1009
  const flags = args;
@@ -731,20 +1020,45 @@ var recruiterSearchParametersCommand = defineCommand({
731
1020
  }
732
1021
  const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
733
1022
  const out = buildOutputStreams();
734
- await runRecruiterGetParameters(client, { ...flags, account: flags.account ?? cfg.account }, out);
1023
+ await runRecruiterSearchParameters(client, { ...flags, account: flags.account ?? cfg.account }, out);
735
1024
  }
736
1025
  });
737
1026
  var recruiterSearchCommand = defineCommand({
738
- meta: { name: "search", description: "Recruiter search operations." },
739
- args: { ...GLOBAL_FLAGS },
1027
+ meta: { name: "search", description: "Recruiter search operations. Also runs a pasted Recruiter search/talent-pool/applicant URL directly." },
1028
+ args: {
1029
+ ...GLOBAL_FLAGS,
1030
+ url: {
1031
+ type: "positional",
1032
+ required: false,
1033
+ description: "A pasted Recruiter search, talent-pool, or applicant URL. Runs it directly (recruiter.searchFromUrl)."
1034
+ }
1035
+ },
740
1036
  subCommands: {
741
1037
  people: recruiterSearchPeopleCommand,
742
1038
  parameters: recruiterSearchParametersCommand
743
1039
  },
744
- async run() {
745
- process.stderr.write(
746
- "Usage: curviate recruiter search people [--keywords <k>]\n curviate recruiter search parameters --type <t>\n"
747
- );
1040
+ async run({ args }) {
1041
+ const flags = args;
1042
+ if (!flags.url) {
1043
+ process.stderr.write(
1044
+ "Usage: curviate recruiter search <url>\n curviate recruiter search people [--keywords <k>]\n curviate recruiter search parameters --source <s> --type <t>\n"
1045
+ );
1046
+ return;
1047
+ }
1048
+ const cfg = await resolveEffectiveConfig({
1049
+ apiKey: flags["api-key"],
1050
+ baseUrl: flags["base-url"],
1051
+ timeout: flags.timeout,
1052
+ account: flags.account,
1053
+ profile: flags.profile
1054
+ });
1055
+ if (!cfg.apiKey) {
1056
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
1057
+ process.exit(3);
1058
+ }
1059
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
1060
+ const out = buildOutputStreams();
1061
+ await runRecruiterSearchFromUrl(client, { ...flags, account: flags.account ?? cfg.account }, out);
748
1062
  }
749
1063
  });
750
1064
  var recruiterProjectsCommand = defineCommand({
@@ -768,12 +1082,21 @@ var recruiterProjectsCommand = defineCommand({
768
1082
  await runRecruiterListProjects(client, { ...flags, account: flags.account ?? cfg.account }, out);
769
1083
  }
770
1084
  });
771
- var recruiterProjectCommand = defineCommand({
772
- meta: { name: "project", description: "Get a Recruiter hiring project by ID." },
1085
+ var recruiterProjectUpdateCommand = defineCommand({
1086
+ meta: { name: "update", description: "Edit a Recruiter project's config. All fields optional \u2014 omitted fields are left unchanged." },
773
1087
  args: {
774
- // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
775
- ...READ_SINGLE_FLAGS,
776
- projectId: { type: "positional", description: "Recruiter project ID." }
1088
+ // Write command: WRITE_SINGLE_FLAGS omits pagination flags, keeps --fields
1089
+ ...WRITE_SINGLE_FLAGS,
1090
+ projectId: { type: "positional", description: "Recruiter project ID." },
1091
+ name: { type: "string", description: "New project name." },
1092
+ visibility: { type: "string", description: "New project visibility: PRIVATE or PUBLIC." },
1093
+ description: { type: "string", description: "New project description." },
1094
+ "company-id": { type: "string", description: "Target company id." },
1095
+ "company-name": { type: "string", description: "Target company as free text (used when no id is given)." },
1096
+ "job-title-id": { type: "string", description: "Target job-title parameter id." },
1097
+ "job-title": { type: "string", description: "Target job-title display name." },
1098
+ location: { type: "string", description: "A LOCATION parameter id (resolve via search parameters)." },
1099
+ "seniority-level": { type: "string", description: "Target seniority level: INTERNSHIP|ENTRY_LEVEL|ASSOCIATE|MID_SENIOR_LEVEL|DIRECTOR|EXECUTIVE|NOT_APPLICABLE." }
777
1100
  },
778
1101
  async run({ args }) {
779
1102
  const flags = args;
@@ -790,20 +1113,27 @@ var recruiterProjectCommand = defineCommand({
790
1113
  }
791
1114
  const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
792
1115
  const out = buildOutputStreams();
793
- await runRecruiterGetProject(client, { ...flags, account: flags.account ?? cfg.account }, out);
1116
+ await runRecruiterUpdateProject(client, { ...flags, account: flags.account ?? cfg.account }, out);
794
1117
  }
795
1118
  });
796
- var recruiterAddCandidateCommand = defineCommand({
797
- meta: { name: "add-candidate", description: "Add a member as a candidate in a hiring project." },
1119
+ var recruiterProjectCommand = defineCommand({
1120
+ meta: { name: "project", description: "Get a Recruiter hiring project by ID." },
798
1121
  args: {
799
- // Write command: WRITE_FLAGS omits pagination/projection flags
800
- ...WRITE_FLAGS,
801
- userId: { type: "positional", description: "Member ID (AEM\u2026 format)." },
802
- "hiring-project-id": { type: "string", description: "Recruiter hiring project ID.", required: true },
803
- stage: { type: "string", description: "Pipeline stage (UNCONTACTED, CONTACTED, REPLIED)." }
1122
+ // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
1123
+ ...READ_SINGLE_FLAGS,
1124
+ projectId: { type: "positional", description: "Recruiter project ID." }
1125
+ },
1126
+ subCommands: {
1127
+ update: recruiterProjectUpdateCommand
804
1128
  },
805
1129
  async run({ args }) {
806
1130
  const flags = args;
1131
+ if (!flags.projectId) {
1132
+ process.stderr.write(
1133
+ "Usage: curviate recruiter project <project_id>\n curviate recruiter project update <project_id> [flags\u2026]\n"
1134
+ );
1135
+ return;
1136
+ }
807
1137
  const cfg = await resolveEffectiveConfig({
808
1138
  apiKey: flags["api-key"],
809
1139
  baseUrl: flags["base-url"],
@@ -817,17 +1147,18 @@ var recruiterAddCandidateCommand = defineCommand({
817
1147
  }
818
1148
  const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
819
1149
  const out = buildOutputStreams();
820
- await runRecruiterAddCandidate(client, { ...flags, account: flags.account ?? cfg.account }, out);
1150
+ await runRecruiterGetProject(client, { ...flags, account: flags.account ?? cfg.account }, out);
821
1151
  }
822
1152
  });
823
- var recruiterAddApplicantCommand = defineCommand({
824
- meta: { name: "add-applicant", description: "Add a member as an applicant in a hiring project." },
1153
+ var recruiterPipelineCommand = defineCommand({
1154
+ meta: { name: "pipeline", description: "List candidates in a project's pipeline (POST-as-list)." },
825
1155
  args: {
826
- // Write command: WRITE_FLAGS omits pagination/projection flags
827
- ...WRITE_FLAGS,
828
- userId: { type: "positional", description: "Member ID (AEM\u2026 format)." },
829
- "hiring-project-id": { type: "string", description: "Recruiter hiring project ID.", required: true },
830
- stage: { type: "string", description: "Pipeline stage (UNCONTACTED, CONTACTED, REPLIED)." }
1156
+ ...GLOBAL_FLAGS,
1157
+ projectId: { type: "positional", description: "Recruiter project ID." },
1158
+ keywords: { type: "string", description: "Free-text keyword search." },
1159
+ "stage-id": { type: "string", description: "Filter to a single pipeline stage id." },
1160
+ "sort-by": { type: "string", description: "Sort field: LAST_MODIFIED or ALPHABETICAL." },
1161
+ spotlights: { type: "string", description: "Spotlight tags (comma-separated): OPEN_TO_WORK, ACTIVE_TALENT, MISSED_CANDIDATES." }
831
1162
  },
832
1163
  async run({ args }) {
833
1164
  const flags = args;
@@ -844,29 +1175,17 @@ var recruiterAddApplicantCommand = defineCommand({
844
1175
  }
845
1176
  const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
846
1177
  const out = buildOutputStreams();
847
- await runRecruiterAddApplicant(client, { ...flags, account: flags.account ?? cfg.account }, out);
1178
+ await runRecruiterListPipeline(client, { ...flags, account: flags.account ?? cfg.account }, out);
848
1179
  }
849
1180
  });
850
- var recruiterRejectApplicantCommand = defineCommand({
851
- meta: { name: "reject-applicant", description: "Reject an applicant from a hiring project." },
1181
+ var recruiterSaveCandidateCommand = defineCommand({
1182
+ meta: { name: "save-candidate", description: "Save a candidate to a project's pipeline at a given stage." },
852
1183
  args: {
853
1184
  // Write command: WRITE_FLAGS omits pagination/projection flags
854
1185
  ...WRITE_FLAGS,
855
- userId: { type: "positional", description: "Member ID (AEM\u2026 format)." },
856
- "hiring-project-id": { type: "string", description: "Recruiter hiring project ID.", required: true },
857
- reason: {
858
- type: "string",
859
- description: "Rejection reason (NOT_MEET_BASIC_QUALIFICATIONS, NOT_IN_DESIRED_LOCATION, MORE_QUALIFIED_CANDIDATES, WITHDREW_APPLICATION, NOT_CONSIDERED_OR_REASON_NOT_SPECIFIED).",
860
- required: true
861
- },
862
- message: {
863
- type: "string",
864
- description: "Rejection notification text. The applicant is only notified when --message is provided; omit it to reject silently."
865
- },
866
- "notify-at": {
867
- type: "string",
868
- description: "UNIX milliseconds timestamp to schedule the notification (default: now). Requires --message."
869
- }
1186
+ projectId: { type: "positional", description: "Recruiter project ID." },
1187
+ "stage-id": { type: "string", description: "Pipeline stage ID to save the candidate into.", required: true },
1188
+ "candidate-id": { type: "string", description: "Candidate id or user-profile id to save.", required: true }
870
1189
  },
871
1190
  async run({ args }) {
872
1191
  const flags = args;
@@ -883,7 +1202,7 @@ var recruiterRejectApplicantCommand = defineCommand({
883
1202
  }
884
1203
  const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
885
1204
  const out = buildOutputStreams();
886
- await runRecruiterRejectApplicant(client, { ...flags, account: flags.account ?? cfg.account }, out);
1205
+ await runRecruiterSaveCandidate(client, { ...flags, account: flags.account ?? cfg.account }, out);
887
1206
  }
888
1207
  });
889
1208
  var recruiterJobsCommand = defineCommand({
@@ -907,16 +1226,31 @@ var recruiterJobsCommand = defineCommand({
907
1226
  await runRecruiterListJobs(client, { ...flags, account: flags.account ?? cfg.account }, out);
908
1227
  }
909
1228
  });
1229
+ var RECRUITER_JOB_BODY_FLAGS = {
1230
+ "body-file": { type: "string", description: "Path to a JSON file with the full job body." },
1231
+ body: { type: "string", description: "Read the JSON job body from stdin (pass '-')." },
1232
+ "job-title-id": { type: "string", description: "Resolved job-title parameter id (merged with --job-title into job_title:{id,name})." },
1233
+ "job-title": { type: "string", description: "Job title display name (merged with --job-title-id into job_title:{id,name})." },
1234
+ "company-id": { type: "string", description: "Resolved company id (or use --company-name for free text)." },
1235
+ "company-name": { type: "string", description: "Company as free text (used when no resolved id is available)." },
1236
+ "workplace-type": { type: "string", description: "Workplace arrangement: ON_SITE|HYBRID|REMOTE." },
1237
+ location: { type: "string", description: "A resolved LOCATION parameter id." },
1238
+ "employment-status": { type: "string", description: "Employment type: FULL_TIME|PART_TIME|CONTRACT|TEMPORARY|OTHER|VOLUNTEER|INTERNSHIP." },
1239
+ "seniority-level": { type: "string", description: "Seniority level: INTERNSHIP|ENTRY_LEVEL|ASSOCIATE|MID_SENIOR_LEVEL|DIRECTOR|EXECUTIVE|NOT_APPLICABLE." },
1240
+ description: { type: "string", description: "Full job description (min 200 chars; merged over the JSON)." },
1241
+ industry: { type: "string", description: "Industry parameter ids, 1-3 (comma-separated)." },
1242
+ "job-function": { type: "string", description: "Job-function parameter ids, 1-3 (comma-separated)." },
1243
+ "apply-method": { type: "string", description: "How candidates apply: linkedin|external." },
1244
+ "notification-email": { type: "string", description: "Email notified of new applicants (used when --apply-method is linkedin)." },
1245
+ "website-url": { type: "string", description: "External apply URL (used when --apply-method is external)." }
1246
+ };
910
1247
  var recruiterJobCreateCommand = defineCommand({
911
- meta: { name: "create", description: "Create a Recruiter job posting draft." },
1248
+ meta: { name: "create", description: "Create a Recruiter job posting draft, opening a brand-new hiring project." },
912
1249
  args: {
913
1250
  // Write command: WRITE_FLAGS omits pagination/projection flags
914
1251
  ...WRITE_FLAGS,
915
- "body-file": { type: "string", description: "Path to a JSON file with the full job-create body." },
916
- body: { type: "string", description: "Read the JSON job-create body from stdin (pass '-')." },
917
- "job-title": { type: "string", description: "Job title text (merged over the JSON as job_title.text)." },
918
- description: { type: "string", description: "Job description (merged over the JSON)." },
919
- "employment-type": { type: "string", description: "Employment type, e.g. FULL_TIME (merged over the JSON)." }
1252
+ ...RECRUITER_JOB_BODY_FLAGS,
1253
+ "project-name": { type: "string", description: "Name for the new hiring project this job opens (required).", required: true }
920
1254
  },
921
1255
  async run({ args }) {
922
1256
  const flags = args;
@@ -937,12 +1271,16 @@ var recruiterJobCreateCommand = defineCommand({
937
1271
  }
938
1272
  });
939
1273
  var recruiterJobPublishCommand = defineCommand({
940
- meta: { name: "publish", description: "Publish a Recruiter job posting draft." },
1274
+ meta: { name: "publish", description: "Publish a Recruiter job posting draft. PROMOTED/PROMOTED_PLUS spend real money and require --budget-*." },
941
1275
  args: {
942
- // Write command: WRITE_FLAGS omits pagination/projection flags
943
- ...WRITE_FLAGS,
1276
+ // Write command: WRITE_SINGLE_FLAGS omits pagination flags, keeps --fields
1277
+ ...WRITE_SINGLE_FLAGS,
1278
+ projectId: { type: "positional", description: "Recruiter project ID." },
944
1279
  jobId: { type: "positional", description: "Job posting ID." },
945
- mode: { type: "string", description: "Publish mode: FREE (default), PROMOTED, or PROMOTED_PLUS." }
1280
+ mode: { type: "string", description: "Publish mode (required): FREE|PROMOTED|PROMOTED_PLUS.", required: true },
1281
+ "budget-currency": { type: "string", description: "ISO-4217 currency (required for a paid publish), e.g. EUR." },
1282
+ "budget-amount": { type: "string", description: "Budget amount (required for a paid publish)." },
1283
+ "budget-scope": { type: "string", description: "Budget scope (required for a paid publish): DAILY|TOTAL." }
946
1284
  },
947
1285
  async run({ args }) {
948
1286
  const flags = args;
@@ -962,13 +1300,12 @@ var recruiterJobPublishCommand = defineCommand({
962
1300
  await runRecruiterPublishJob(client, { ...flags, account: flags.account ?? cfg.account }, out);
963
1301
  }
964
1302
  });
965
- var recruiterJobCheckpointCommand = defineCommand({
966
- meta: { name: "checkpoint", description: "Solve a job posting publish verification checkpoint." },
1303
+ var recruiterApplicantsCommand = defineCommand({
1304
+ meta: { name: "applicants", description: "List applicants in a Recruiter project's talent pool." },
967
1305
  args: {
968
- // Write command: WRITE_FLAGS omits pagination/projection flags
969
- ...WRITE_FLAGS,
970
- jobId: { type: "positional", description: "Job posting ID." },
971
- input: { type: "string", description: "Verification value (OTP or email confirmation).", required: true }
1306
+ ...GLOBAL_FLAGS,
1307
+ projectId: { type: "positional", description: "Recruiter project ID." },
1308
+ "channel-id": { type: "string", description: "The project's JOB_POSTING talent-pool channel ID (required).", required: true }
972
1309
  },
973
1310
  async run({ args }) {
974
1311
  const flags = args;
@@ -985,14 +1322,14 @@ var recruiterJobCheckpointCommand = defineCommand({
985
1322
  }
986
1323
  const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
987
1324
  const out = buildOutputStreams();
988
- await runRecruiterJobCheckpoint(client, { ...flags, account: flags.account ?? cfg.account }, out);
1325
+ await runRecruiterListApplicants(client, { ...flags, account: flags.account ?? cfg.account }, out);
989
1326
  }
990
1327
  });
991
- var recruiterJobApplicantsCommand = defineCommand({
992
- meta: { name: "applicants", description: "List applicants for a Recruiter job posting." },
1328
+ var recruiterJobGetCommand = defineCommand({
1329
+ meta: { name: "get", description: "Get a job posting via the Recruiter lens (any public posting, not only your own)." },
993
1330
  args: {
994
- ...GLOBAL_FLAGS,
995
- jobId: { type: "positional", description: "Job posting ID." }
1331
+ ...READ_SINGLE_FLAGS,
1332
+ jobId: { type: "positional", description: "Job URL (e.g. https://www.linkedin.com/jobs/view/4428113858) or a bare numeric job id." }
996
1333
  },
997
1334
  async run({ args }) {
998
1335
  const flags = args;
@@ -1009,14 +1346,16 @@ var recruiterJobApplicantsCommand = defineCommand({
1009
1346
  }
1010
1347
  const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
1011
1348
  const out = buildOutputStreams();
1012
- await runRecruiterListApplicants(client, { ...flags, account: flags.account ?? cfg.account }, out);
1349
+ await runRecruiterGetJob(client, { ...flags, account: flags.account ?? cfg.account }, out);
1013
1350
  }
1014
1351
  });
1015
- var recruiterJobGetCommand = defineCommand({
1016
- meta: { name: "get", description: "Get a job posting via the Recruiter lens (any public posting, not only your own)." },
1352
+ var recruiterJobCloseCommand = defineCommand({
1353
+ meta: { name: "close", description: "Stop a project's job posting from accepting applications (irreversible once LISTED)." },
1017
1354
  args: {
1018
- ...READ_SINGLE_FLAGS,
1019
- jobId: { type: "positional", description: "Job URL (e.g. https://www.linkedin.com/jobs/view/4428113858) or a bare numeric job id." }
1355
+ // Write command: WRITE_SINGLE_FLAGS omits pagination flags, keeps --fields
1356
+ ...WRITE_SINGLE_FLAGS,
1357
+ projectId: { type: "positional", description: "Recruiter project ID." },
1358
+ jobId: { type: "positional", description: "Job posting ID." }
1020
1359
  },
1021
1360
  async run({ args }) {
1022
1361
  const flags = args;
@@ -1033,7 +1372,7 @@ var recruiterJobGetCommand = defineCommand({
1033
1372
  }
1034
1373
  const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
1035
1374
  const out = buildOutputStreams();
1036
- await runRecruiterGetJob(client, { ...flags, account: flags.account ?? cfg.account }, out);
1375
+ await runRecruiterCloseJob(client, { ...flags, account: flags.account ?? cfg.account }, out);
1037
1376
  }
1038
1377
  });
1039
1378
  var recruiterJobCommand = defineCommand({
@@ -1042,21 +1381,189 @@ var recruiterJobCommand = defineCommand({
1042
1381
  subCommands: {
1043
1382
  create: recruiterJobCreateCommand,
1044
1383
  publish: recruiterJobPublishCommand,
1045
- checkpoint: recruiterJobCheckpointCommand,
1046
- applicants: recruiterJobApplicantsCommand,
1384
+ close: recruiterJobCloseCommand,
1047
1385
  get: recruiterJobGetCommand
1048
1386
  },
1049
1387
  async run() {
1050
1388
  process.stderr.write(
1051
- "Usage: curviate recruiter job create [flags\u2026]\n curviate recruiter job publish <job_id> [--mode <m>]\n curviate recruiter job checkpoint <job_id> --input <v>\n curviate recruiter job applicants <job_id>\n curviate recruiter job get <url|id>\n"
1389
+ "Usage: curviate recruiter job create [flags\u2026]\n curviate recruiter job publish <project_id> <job_id> --mode <FREE|PROMOTED|PROMOTED_PLUS>\n curviate recruiter job close <project_id> <job_id>\n curviate recruiter job get <url|id>\n"
1052
1390
  );
1053
1391
  }
1054
1392
  });
1393
+ var recruiterProjectJobGetCommand = defineCommand({
1394
+ meta: { name: "get", description: "Get the single job posting attached to a project (404 when none is attached)." },
1395
+ args: {
1396
+ // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
1397
+ ...READ_SINGLE_FLAGS,
1398
+ projectId: { type: "positional", description: "Recruiter project ID." }
1399
+ },
1400
+ async run({ args }) {
1401
+ const flags = args;
1402
+ const cfg = await resolveEffectiveConfig({
1403
+ apiKey: flags["api-key"],
1404
+ baseUrl: flags["base-url"],
1405
+ timeout: flags.timeout,
1406
+ account: flags.account,
1407
+ profile: flags.profile
1408
+ });
1409
+ if (!cfg.apiKey) {
1410
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
1411
+ process.exit(3);
1412
+ }
1413
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
1414
+ const out = buildOutputStreams();
1415
+ await runRecruiterGetProjectJob(client, { ...flags, account: flags.account ?? cfg.account }, out);
1416
+ }
1417
+ });
1418
+ var recruiterProjectJobCreateCommand = defineCommand({
1419
+ meta: { name: "create", description: "Create a job-posting draft attached to an existing project." },
1420
+ args: {
1421
+ // Write command: WRITE_SINGLE_FLAGS omits pagination flags, keeps --fields
1422
+ ...WRITE_SINGLE_FLAGS,
1423
+ ...RECRUITER_JOB_BODY_FLAGS,
1424
+ projectId: { type: "positional", description: "Recruiter project ID." }
1425
+ },
1426
+ async run({ args }) {
1427
+ const flags = args;
1428
+ const cfg = await resolveEffectiveConfig({
1429
+ apiKey: flags["api-key"],
1430
+ baseUrl: flags["base-url"],
1431
+ timeout: flags.timeout,
1432
+ account: flags.account,
1433
+ profile: flags.profile
1434
+ });
1435
+ if (!cfg.apiKey) {
1436
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
1437
+ process.exit(3);
1438
+ }
1439
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
1440
+ const out = buildOutputStreams();
1441
+ await runRecruiterCreateProjectJob(client, { ...flags, account: flags.account ?? cfg.account }, out);
1442
+ }
1443
+ });
1444
+ var recruiterProjectJobBudgetCommand = defineCommand({
1445
+ meta: { name: "budget", description: "Get pricing to publish a project's job posting." },
1446
+ args: {
1447
+ // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
1448
+ ...READ_SINGLE_FLAGS,
1449
+ projectId: { type: "positional", description: "Recruiter project ID." },
1450
+ jobId: { type: "positional", description: "Job posting ID." }
1451
+ },
1452
+ async run({ args }) {
1453
+ const flags = args;
1454
+ const cfg = await resolveEffectiveConfig({
1455
+ apiKey: flags["api-key"],
1456
+ baseUrl: flags["base-url"],
1457
+ timeout: flags.timeout,
1458
+ account: flags.account,
1459
+ profile: flags.profile
1460
+ });
1461
+ if (!cfg.apiKey) {
1462
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
1463
+ process.exit(3);
1464
+ }
1465
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
1466
+ const out = buildOutputStreams();
1467
+ await runRecruiterGetProjectJobBudget(client, { ...flags, account: flags.account ?? cfg.account }, out);
1468
+ }
1469
+ });
1470
+ var recruiterProjectJobUpdateCommand = defineCommand({
1471
+ meta: { name: "update", description: "Apply a partial update to a project's job posting." },
1472
+ args: {
1473
+ // Write command: WRITE_SINGLE_FLAGS omits pagination flags, keeps --fields
1474
+ ...WRITE_SINGLE_FLAGS,
1475
+ ...RECRUITER_JOB_BODY_FLAGS,
1476
+ projectId: { type: "positional", description: "Recruiter project ID." },
1477
+ jobId: { type: "positional", description: "Job posting ID." }
1478
+ },
1479
+ async run({ args }) {
1480
+ const flags = args;
1481
+ const cfg = await resolveEffectiveConfig({
1482
+ apiKey: flags["api-key"],
1483
+ baseUrl: flags["base-url"],
1484
+ timeout: flags.timeout,
1485
+ account: flags.account,
1486
+ profile: flags.profile
1487
+ });
1488
+ if (!cfg.apiKey) {
1489
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
1490
+ process.exit(3);
1491
+ }
1492
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
1493
+ const out = buildOutputStreams();
1494
+ await runRecruiterUpdateProjectJob(client, { ...flags, account: flags.account ?? cfg.account }, out);
1495
+ }
1496
+ });
1497
+ var recruiterProjectJobCommand = defineCommand({
1498
+ meta: { name: "project-job", description: "The single job posting attached to a Recruiter project." },
1499
+ args: {
1500
+ ...READ_SINGLE_FLAGS,
1501
+ projectId: { type: "positional", description: "Recruiter project ID.", required: false }
1502
+ },
1503
+ subCommands: {
1504
+ get: recruiterProjectJobGetCommand,
1505
+ create: recruiterProjectJobCreateCommand,
1506
+ budget: recruiterProjectJobBudgetCommand,
1507
+ update: recruiterProjectJobUpdateCommand
1508
+ },
1509
+ async run({ args }) {
1510
+ const flags = args;
1511
+ if (!flags.projectId) {
1512
+ process.stderr.write(
1513
+ "Usage: curviate recruiter project-job get <project_id>\n curviate recruiter project-job create <project_id> [flags\u2026]\n curviate recruiter project-job budget <project_id> <job_id>\n curviate recruiter project-job update <project_id> <job_id> [flags\u2026]\n"
1514
+ );
1515
+ return;
1516
+ }
1517
+ const cfg = await resolveEffectiveConfig({
1518
+ apiKey: flags["api-key"],
1519
+ baseUrl: flags["base-url"],
1520
+ timeout: flags.timeout,
1521
+ account: flags.account,
1522
+ profile: flags.profile
1523
+ });
1524
+ if (!cfg.apiKey) {
1525
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
1526
+ process.exit(3);
1527
+ }
1528
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
1529
+ const out = buildOutputStreams();
1530
+ await runRecruiterGetProjectJob(client, { ...flags, account: flags.account ?? cfg.account }, out);
1531
+ }
1532
+ });
1533
+ var recruiterTalentSearchCommand = defineCommand({
1534
+ meta: { name: "talent-search", description: "Search a project's talent pool." },
1535
+ args: {
1536
+ ...GLOBAL_FLAGS,
1537
+ projectId: { type: "positional", description: "Recruiter project ID." },
1538
+ "channel-id": { type: "string", description: "The project's RECRUITER_SEARCH talent-pool channel ID (required).", required: true },
1539
+ keywords: { type: "string", description: "Free-text keyword search." },
1540
+ filters: { type: "string", description: "Filter body as a JSON object (escape hatch for the full filter surface); '-' reads JSON from stdin." },
1541
+ "filters-file": { type: "string", description: "Path to a JSON file with the filter body." }
1542
+ },
1543
+ async run({ args }) {
1544
+ const flags = args;
1545
+ const cfg = await resolveEffectiveConfig({
1546
+ apiKey: flags["api-key"],
1547
+ baseUrl: flags["base-url"],
1548
+ timeout: flags.timeout,
1549
+ account: flags.account,
1550
+ profile: flags.profile
1551
+ });
1552
+ if (!cfg.apiKey) {
1553
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
1554
+ process.exit(3);
1555
+ }
1556
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
1557
+ const out = buildOutputStreams();
1558
+ await runRecruiterSearchTalentPool(client, { ...flags, account: flags.account ?? cfg.account }, out);
1559
+ }
1560
+ });
1055
1561
  var recruiterApplicantResumeCommand = defineCommand({
1056
1562
  meta: { name: "resume", description: "Download a job applicant's resume." },
1057
1563
  args: {
1058
1564
  // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
1059
1565
  ...READ_SINGLE_FLAGS,
1566
+ projectId: { type: "positional", description: "Recruiter project ID." },
1060
1567
  applicantId: { type: "positional", description: "Applicant ID." },
1061
1568
  output: { type: "string", alias: "o", description: "Path to write the resume file." }
1062
1569
  },
@@ -1088,6 +1595,7 @@ var recruiterApplicantCommand = defineCommand({
1088
1595
  args: {
1089
1596
  // Single-object read: READ_SINGLE_FLAGS omits pagination flags, keeps --fields
1090
1597
  ...READ_SINGLE_FLAGS,
1598
+ projectId: { type: "positional", description: "Recruiter project ID.", required: false },
1091
1599
  applicantId: { type: "positional", description: "Applicant ID.", required: false }
1092
1600
  },
1093
1601
  subCommands: {
@@ -1095,9 +1603,9 @@ var recruiterApplicantCommand = defineCommand({
1095
1603
  },
1096
1604
  async run({ args }) {
1097
1605
  const flags = args;
1098
- if (!flags.applicantId) {
1606
+ if (!flags.projectId || !flags.applicantId) {
1099
1607
  process.stderr.write(
1100
- "Usage: curviate recruiter applicant <applicant_id>\n curviate recruiter applicant resume <applicant_id> -o <file>\n"
1608
+ "Usage: curviate recruiter applicant <project_id> <applicant_id>\n curviate recruiter applicant resume <project_id> <applicant_id> -o <file>\n"
1101
1609
  );
1102
1610
  return;
1103
1611
  }
@@ -1121,43 +1629,49 @@ var recruiterCommand = defineCommand({
1121
1629
  meta: { name: "recruiter", description: "LinkedIn Recruiter operations (requires the Recruiter add-on)." },
1122
1630
  args: { ...GLOBAL_FLAGS },
1123
1631
  subCommands: {
1124
- sync: recruiterSyncCommand,
1125
1632
  message: recruiterMessageCommand,
1126
1633
  profile: recruiterProfileCommand,
1127
1634
  search: recruiterSearchCommand,
1128
1635
  projects: recruiterProjectsCommand,
1129
1636
  project: recruiterProjectCommand,
1130
- "add-candidate": recruiterAddCandidateCommand,
1131
- "add-applicant": recruiterAddApplicantCommand,
1132
- "reject-applicant": recruiterRejectApplicantCommand,
1637
+ pipeline: recruiterPipelineCommand,
1638
+ "project-job": recruiterProjectJobCommand,
1639
+ "talent-search": recruiterTalentSearchCommand,
1640
+ "save-candidate": recruiterSaveCandidateCommand,
1641
+ applicants: recruiterApplicantsCommand,
1133
1642
  jobs: recruiterJobsCommand,
1134
1643
  job: recruiterJobCommand,
1135
1644
  applicant: recruiterApplicantCommand
1136
1645
  },
1137
1646
  async run() {
1138
1647
  process.stderr.write(
1139
- 'Usage: curviate recruiter sync\n curviate recruiter message new --to <id> "<text>"\n curviate recruiter profile <identifier>\n curviate recruiter search people [--keywords <k>]\n curviate recruiter search parameters --type <t>\n curviate recruiter projects\n curviate recruiter project <project_id>\n curviate recruiter add-candidate <user_id> --hiring-project-id <id>\n curviate recruiter add-applicant <user_id> --hiring-project-id <id>\n curviate recruiter reject-applicant <user_id> --hiring-project-id <id> --reason <r>\n curviate recruiter jobs\n curviate recruiter job create [flags\u2026]\n curviate recruiter job publish <job_id> [--mode <m>]\n curviate recruiter job checkpoint <job_id> --input <v>\n curviate recruiter job applicants <job_id>\n curviate recruiter job get <url|id>\n curviate recruiter applicant <applicant_id>\n curviate recruiter applicant resume <applicant_id> -o <file>\n'
1648
+ 'Usage: curviate recruiter message new --to <id> "<text>"\n curviate recruiter profile <identifier>\n curviate recruiter search people [--keywords <k>]\n curviate recruiter search parameters --source <s> --type <t>\n curviate recruiter search <url>\n curviate recruiter projects\n curviate recruiter project <project_id>\n curviate recruiter project update <project_id> [flags\u2026]\n curviate recruiter pipeline <project_id>\n curviate recruiter project-job get <project_id>\n curviate recruiter project-job create <project_id> [flags\u2026]\n curviate recruiter project-job budget <project_id> <job_id>\n curviate recruiter project-job update <project_id> <job_id> [flags\u2026]\n curviate recruiter talent-search <project_id> --channel-id <id>\n curviate recruiter save-candidate <project_id> --stage-id <id> --candidate-id <id>\n curviate recruiter applicants <project_id> --channel-id <id>\n curviate recruiter jobs\n curviate recruiter job create [flags\u2026]\n curviate recruiter job publish <project_id> <job_id> --mode <FREE|PROMOTED|PROMOTED_PLUS>\n curviate recruiter job close <project_id> <job_id>\n curviate recruiter job get <url|id>\n curviate recruiter applicant <project_id> <applicant_id>\n curviate recruiter applicant resume <project_id> <applicant_id> -o <file>\n'
1140
1649
  );
1141
1650
  }
1142
1651
  });
1143
1652
  export {
1144
1653
  recruiterCommand,
1145
- runRecruiterAddApplicant,
1146
- runRecruiterAddCandidate,
1654
+ runRecruiterCloseJob,
1147
1655
  runRecruiterCreateJob,
1656
+ runRecruiterCreateProjectJob,
1148
1657
  runRecruiterDownloadResume,
1149
1658
  runRecruiterGetApplicant,
1150
1659
  runRecruiterGetJob,
1151
- runRecruiterGetParameters,
1152
1660
  runRecruiterGetProject,
1153
- runRecruiterJobCheckpoint,
1661
+ runRecruiterGetProjectJob,
1662
+ runRecruiterGetProjectJobBudget,
1154
1663
  runRecruiterListApplicants,
1155
1664
  runRecruiterListJobs,
1665
+ runRecruiterListPipeline,
1156
1666
  runRecruiterListProjects,
1157
1667
  runRecruiterMessageNew,
1158
1668
  runRecruiterProfile,
1159
1669
  runRecruiterPublishJob,
1160
- runRecruiterRejectApplicant,
1670
+ runRecruiterSaveCandidate,
1671
+ runRecruiterSearchFromUrl,
1672
+ runRecruiterSearchParameters,
1161
1673
  runRecruiterSearchPeople,
1162
- runRecruiterSync
1674
+ runRecruiterSearchTalentPool,
1675
+ runRecruiterUpdateProject,
1676
+ runRecruiterUpdateProjectJob
1163
1677
  };