@curviate/cli 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,49 @@ a new command or flag is a minor; a breaking command/flag/exit-code change is a
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.7.0] - 2026-07-01
12
+
13
+ ### Added
14
+
15
+ - `search` — named filter flags that previously required raw `--filters` JSON:
16
+ - **companies**: `--has-job-offers`, `--headcount <buckets>` (comma-separated
17
+ size buckets `1-10 … 5001-10000`; `10001+` reports a usage error).
18
+ - **jobs**: `--title <ids>`, `--presence`, `--benefits`, `--commitments`,
19
+ `--has-verifications`, `--under-10-applicants`, `--in-your-network`,
20
+ `--fair-chance-employer`, `--location-within-area <miles>`.
21
+ - **people**: `--connections-of`, `--followers-of` (comma-separated → array).
22
+ - **posts**: `--posted-by-member`, `--posted-by-company`, `--posted-by-me`,
23
+ `--mentioning-member`, `--mentioning-company`, `--author-industry`,
24
+ `--author-company`, `--author-keywords`.
25
+
26
+ ### Fixed
27
+
28
+ - `search jobs` slim `company_name` was always `null` — now derived from the
29
+ nested `company.name` (handles postings with no linked company). `--verbose`
30
+ still returns the raw response unchanged.
31
+ - `search parameters --type`, `search jobs --seniority`/`--job-type`, and
32
+ `search posts --content-type` help text now lists the correct/complete
33
+ enumerations (no behavior change).
34
+
35
+ ### Changed
36
+
37
+ - Updated `@curviate/sdk` dependency to `^0.5.0`.
38
+
39
+ ## [0.6.1] - 2026-07-01
40
+
41
+ ### Added
42
+
43
+ - `search people --title` (→ `advanced_keywords.title` keyword, nested-merged),
44
+ `--industry`, `--profile-language`; `--filters` deep-merge (named flags win).
45
+ - `search jobs --location` → `region` (single id) + `--region` alias +
46
+ `--date-posted <days>` (number).
47
+ - `search posts --date-posted` hyphen→underscore normalize.
48
+ - `--all` truncation emits `{"object":"stream_truncated",…}` JSON.
49
+
50
+ ### Changed
51
+
52
+ - Updated `@curviate/sdk` dependency to `^0.4.1`.
53
+
11
54
  ## [0.6.0] - 2026-06-30
12
55
 
13
56
  ### Added
@@ -139,11 +139,12 @@ function slimSearchCompanies(data) {
139
139
  return { ...d, items };
140
140
  }
141
141
  function slimSearchJobsItem(item) {
142
+ const company = item["company"];
142
143
  return {
143
144
  job_urn: item["job_urn"] ?? null,
144
145
  title: item["title"] ?? null,
145
146
  location: item["location"] ?? null,
146
- company_name: item["company_name"] ?? null,
147
+ company_name: company?.["name"] ?? null,
147
148
  posted_at: item["posted_at"] ?? null,
148
149
  easy_apply: item["easy_apply"] ?? null
149
150
  };
package/dist/cli.js CHANGED
@@ -143,10 +143,10 @@ var main = defineCommand({
143
143
  // ---------------------------------------------------------------------------
144
144
  // Noun groups — lazy-loaded on first invocation.
145
145
  // ---------------------------------------------------------------------------
146
- profile: () => import("./profile-4IPEB7MN.js").then((m) => m.profileCommand),
147
- company: () => import("./company-WH2ZETTP.js").then((m) => m.companyCommand),
148
- connect: () => import("./connect-YUJ2T5CN.js").then((m) => m.connectCommand),
149
- search: () => import("./search-ONCNS43D.js").then((m) => m.searchCommand),
146
+ profile: () => import("./profile-GGUBDI3P.js").then((m) => m.profileCommand),
147
+ company: () => import("./company-HPHLJCKB.js").then((m) => m.companyCommand),
148
+ connect: () => import("./connect-EUJBSLNM.js").then((m) => m.connectCommand),
149
+ search: () => import("./search-RZYVGGMN.js").then((m) => m.searchCommand),
150
150
  inbox: () => import("./inbox-YV6GPRG6.js").then((m) => m.inboxCommand),
151
151
  message: () => import("./message-YRMLMHK7.js").then((m) => m.messageCommand),
152
152
  post: () => import("./post-KBSR3ADF.js").then((m) => m.postCommand),
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-SZB3CFRZ.js";
5
5
  import {
6
6
  slimCompany
7
- } from "./chunk-FX6VBI43.js";
7
+ } from "./chunk-J5KGG2EE.js";
8
8
  import {
9
9
  createClient,
10
10
  renderError,
@@ -13,7 +13,7 @@ import {
13
13
  slimInviteReceivedItem,
14
14
  slimInviteSent,
15
15
  slimInviteSentItem
16
- } from "./chunk-FX6VBI43.js";
16
+ } from "./chunk-J5KGG2EE.js";
17
17
  import {
18
18
  createClient,
19
19
  renderError,
@@ -11,7 +11,7 @@ import {
11
11
  import {
12
12
  slimProfile,
13
13
  slimProfileMe
14
- } from "./chunk-FX6VBI43.js";
14
+ } from "./chunk-J5KGG2EE.js";
15
15
  import {
16
16
  createClient,
17
17
  renderError,
@@ -17,7 +17,7 @@ import {
17
17
  slimSearchPeopleItem,
18
18
  slimSearchPosts,
19
19
  slimSearchPostsItem
20
- } from "./chunk-FX6VBI43.js";
20
+ } from "./chunk-J5KGG2EE.js";
21
21
  import {
22
22
  createClient,
23
23
  renderError,
@@ -31,6 +31,15 @@ import {
31
31
 
32
32
  // src/commands/search.ts
33
33
  import { defineCommand } from "citty";
34
+ var HEADCOUNT_BUCKETS = {
35
+ "1-10": { min: 1, max: 10 },
36
+ "11-50": { min: 11, max: 50 },
37
+ "51-200": { min: 51, max: 200 },
38
+ "201-500": { min: 201, max: 500 },
39
+ "501-1000": { min: 501, max: 1e3 },
40
+ "1001-5000": { min: 1001, max: 5e3 },
41
+ "5001-10000": { min: 5001, max: 1e4 }
42
+ };
34
43
  var PEOPLE_INVALID_FLAGS = ["seniority", "function", "employment-type", "sort-by"];
35
44
  var FILTER_FLAGS = {
36
45
  filters: {
@@ -81,6 +90,10 @@ function applyCommonSearchFlags(body, flags) {
81
90
  if (flags.cursor) body["cursor"] = flags.cursor;
82
91
  if (flags.limit) body["limit"] = parseInt(flags.limit, 10);
83
92
  }
93
+ function mergeNested(body, key, patch) {
94
+ const existing = body[key] !== null && body[key] !== void 0 && typeof body[key] === "object" && !Array.isArray(body[key]) ? body[key] : {};
95
+ body[key] = { ...existing, ...patch };
96
+ }
84
97
  var NAMED_FLAG_MAPPERS = {
85
98
  people(body, flags) {
86
99
  if (flags.industry) body["industry"] = splitCsv(flags.industry);
@@ -89,8 +102,8 @@ var NAMED_FLAG_MAPPERS = {
89
102
  if (flags["past-company"]) body["past_company"] = splitCsv(flags["past-company"]);
90
103
  if (flags.school) body["school"] = splitCsv(flags.school);
91
104
  if (flags["network-distance"]) body["network_distance"] = splitCsvNumbers(flags["network-distance"]);
92
- if (flags["connections-of"]) body["connections_of"] = flags["connections-of"];
93
- if (flags["followers-of"]) body["followers_of"] = flags["followers-of"];
105
+ if (flags["connections-of"]) body["connections_of"] = splitCsv(flags["connections-of"]);
106
+ if (flags["followers-of"]) body["followers_of"] = splitCsv(flags["followers-of"]);
94
107
  if (flags.title) {
95
108
  const existingAK = body["advanced_keywords"] !== null && body["advanced_keywords"] !== void 0 && typeof body["advanced_keywords"] === "object" && !Array.isArray(body["advanced_keywords"]) ? body["advanced_keywords"] : {};
96
109
  body["advanced_keywords"] = { ...existingAK, title: flags.title };
@@ -101,11 +114,30 @@ var NAMED_FLAG_MAPPERS = {
101
114
  if (flags.industry) body["industry"] = splitCsv(flags.industry);
102
115
  if (flags.location) body["location"] = splitCsv(flags.location);
103
116
  if (flags["network-distance"]) body["network_distance"] = splitCsvNumbers(flags["network-distance"]);
117
+ if (flags["has-job-offers"]) body["has_job_offers"] = true;
118
+ if (flags.headcount) {
119
+ const buckets = splitCsv(flags.headcount);
120
+ const mapped = [];
121
+ for (const bucket of buckets) {
122
+ const range = HEADCOUNT_BUCKETS[bucket];
123
+ if (!range) return `--headcount: unrecognized bucket "${bucket}"`;
124
+ mapped.push(range);
125
+ }
126
+ body["headcount"] = mapped;
127
+ }
104
128
  },
105
129
  posts(body, flags) {
106
130
  if (flags["sort-by"]) body["sort_by"] = flags["sort-by"];
107
131
  if (flags["date-posted"]) body["date_posted"] = flags["date-posted"].replace(/-/g, "_");
108
132
  if (flags["content-type"]) body["content_type"] = flags["content-type"];
133
+ if (flags["posted-by-member"]) mergeNested(body, "posted_by", { member: splitCsv(flags["posted-by-member"]) });
134
+ if (flags["posted-by-company"]) mergeNested(body, "posted_by", { company: splitCsv(flags["posted-by-company"]) });
135
+ if (flags["posted-by-me"]) mergeNested(body, "posted_by", { me: true });
136
+ if (flags["mentioning-member"]) mergeNested(body, "mentioning", { member: splitCsv(flags["mentioning-member"]) });
137
+ if (flags["mentioning-company"]) mergeNested(body, "mentioning", { company: splitCsv(flags["mentioning-company"]) });
138
+ if (flags["author-industry"]) mergeNested(body, "author", { industry: splitCsv(flags["author-industry"]) });
139
+ if (flags["author-company"]) mergeNested(body, "author", { company: splitCsv(flags["author-company"]) });
140
+ if (flags["author-keywords"]) mergeNested(body, "author", { keywords: flags["author-keywords"] });
109
141
  },
110
142
  jobs(body, flags) {
111
143
  if (flags.location) body["region"] = flags.location;
@@ -119,6 +151,22 @@ var NAMED_FLAG_MAPPERS = {
119
151
  body["date_posted"] = Number(flags["date-posted"]);
120
152
  }
121
153
  if (flags.region) body["region"] = flags.region;
154
+ if (flags.title) body["role"] = splitCsv(flags.title);
155
+ if (flags.presence) body["presence"] = splitCsv(flags.presence);
156
+ if (flags.benefits) body["benefits"] = splitCsv(flags.benefits);
157
+ if (flags.commitments) body["commitments"] = splitCsv(flags.commitments);
158
+ if (flags["has-verifications"]) body["has_verifications"] = true;
159
+ if (flags["under-10-applicants"]) body["under_10_applicants"] = true;
160
+ if (flags["in-your-network"]) body["in_your_network"] = true;
161
+ if (flags["fair-chance-employer"]) body["fair_chance_employer"] = true;
162
+ if (flags["location-within-area"] !== void 0) {
163
+ const raw = flags["location-within-area"];
164
+ const n = Number(raw);
165
+ if (raw.trim() === "" || !Number.isFinite(n)) {
166
+ return `--location-within-area: must be a number (miles)`;
167
+ }
168
+ body["location_within_area"] = n;
169
+ }
122
170
  }
123
171
  };
124
172
  async function buildSearchBody(kind, flags, readers) {
@@ -126,7 +174,8 @@ async function buildSearchBody(kind, flags, readers) {
126
174
  if ("error" in assembled) return assembled;
127
175
  const body = assembled.body;
128
176
  applyCommonSearchFlags(body, flags);
129
- NAMED_FLAG_MAPPERS[kind](body, flags);
177
+ const mapperError = NAMED_FLAG_MAPPERS[kind](body, flags);
178
+ if (mapperError) return { error: mapperError };
130
179
  return { body };
131
180
  }
132
181
  async function runSearchPeople(client, flags, out, readers = DEFAULT_FILTER_READERS) {
@@ -332,7 +381,7 @@ async function runSearchParameters(client, flags, out) {
332
381
  }
333
382
  }
334
383
  var searchPeopleCommand = defineCommand({
335
- meta: { name: "people", description: "Search LinkedIn members with structured filters." },
384
+ meta: { name: "people", description: "Search members with structured filters." },
336
385
  args: {
337
386
  ...GLOBAL_FLAGS,
338
387
  keywords: { type: "string", description: "Full-text keyword search." },
@@ -344,8 +393,8 @@ var searchPeopleCommand = defineCommand({
344
393
  "past-company": { type: "string", description: "Past company ids (comma-separated)." },
345
394
  school: { type: "string", description: "School ids (comma-separated)." },
346
395
  "network-distance": { type: "string", description: "Network distance, 1-3 (comma-separated)." },
347
- "connections-of": { type: "string", description: "Member id whose connections to search." },
348
- "followers-of": { type: "string", description: "Member id whose followers to search." },
396
+ "connections-of": { type: "string", description: 'member id(s), comma-separated (resolve: search parameters --type CONNECTIONS --keywords "<name>")' },
397
+ "followers-of": { type: "string", description: 'member id(s), comma-separated (resolve: search parameters --type PEOPLE --keywords "<name>")' },
349
398
  // People-specific filter flags
350
399
  title: { type: "string", description: "Job title keyword filter (maps to advanced_keywords.title)." },
351
400
  "profile-language": { type: "string", description: "Profile language codes (comma-separated, e.g. en,de)." }
@@ -369,7 +418,7 @@ var searchPeopleCommand = defineCommand({
369
418
  }
370
419
  });
371
420
  var searchCompaniesCommand = defineCommand({
372
- meta: { name: "companies", description: "Search LinkedIn companies." },
421
+ meta: { name: "companies", description: "Search companies." },
373
422
  args: {
374
423
  ...GLOBAL_FLAGS,
375
424
  keywords: { type: "string", description: "Full-text keyword search." },
@@ -377,7 +426,12 @@ var searchCompaniesCommand = defineCommand({
377
426
  ...FILTER_FLAGS,
378
427
  industry: { type: "string", description: "Industry ids (comma-separated)." },
379
428
  location: { type: "string", description: "Location ids (comma-separated)." },
380
- "network-distance": { type: "string", description: "Network distance, 1-3 (comma-separated)." }
429
+ "network-distance": { type: "string", description: "Network distance, 1-3 (comma-separated)." },
430
+ "has-job-offers": { type: "boolean", description: "only companies with active job listings" },
431
+ headcount: {
432
+ type: "string",
433
+ description: "company size, comma-separated: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+ (10001+ not yet supported)"
434
+ }
381
435
  },
382
436
  async run({ args }) {
383
437
  const flags = args;
@@ -398,7 +452,7 @@ var searchCompaniesCommand = defineCommand({
398
452
  }
399
453
  });
400
454
  var searchPostsCommand = defineCommand({
401
- meta: { name: "posts", description: "Search LinkedIn posts." },
455
+ meta: { name: "posts", description: "Search posts." },
402
456
  args: {
403
457
  ...GLOBAL_FLAGS,
404
458
  keywords: { type: "string", description: "Full-text keyword search." },
@@ -406,7 +460,15 @@ var searchPostsCommand = defineCommand({
406
460
  ...FILTER_FLAGS,
407
461
  "sort-by": { type: "string", description: "Sort order (e.g. relevance, date)." },
408
462
  "date-posted": { type: "string", description: "time window: past_day, past_week, or past_month (hyphens also accepted: past-day, past-week, past-month)" },
409
- "content-type": { type: "string", description: "Content type (e.g. videos, images, jobs)." }
463
+ "content-type": { type: "string", description: "content type: videos, images, live_videos, collaborative_articles, documents" },
464
+ "posted-by-member": { type: "string", description: "member id(s), comma-separated (resolve: search parameters --type PEOPLE); merges into posted_by" },
465
+ "posted-by-company": { type: "string", description: "company id(s), comma-separated (resolve: search parameters --type COMPANY); merges into posted_by" },
466
+ "posted-by-me": { type: "boolean", description: "only posts authored by you; merges into posted_by" },
467
+ "mentioning-member": { type: "string", description: "member id(s) mentioned in the post, comma-separated (resolve: search parameters --type PEOPLE); merges into mentioning" },
468
+ "mentioning-company": { type: "string", description: "company id(s) mentioned in the post, comma-separated (resolve: search parameters --type COMPANY); merges into mentioning" },
469
+ "author-industry": { type: "string", description: "author's industry id(s), comma-separated (resolve: search parameters --type INDUSTRY); merges into author" },
470
+ "author-company": { type: "string", description: "author's company id(s), comma-separated (resolve: search parameters --type COMPANY); merges into author" },
471
+ "author-keywords": { type: "string", description: "author keyword filter (free text); merges into author" }
410
472
  },
411
473
  async run({ args }) {
412
474
  const flags = args;
@@ -427,7 +489,7 @@ var searchPostsCommand = defineCommand({
427
489
  }
428
490
  });
429
491
  var searchJobsCommand = defineCommand({
430
- meta: { name: "jobs", description: "Search LinkedIn jobs." },
492
+ meta: { name: "jobs", description: "Search jobs." },
431
493
  args: {
432
494
  ...GLOBAL_FLAGS,
433
495
  keywords: { type: "string", description: "Full-text keyword search." },
@@ -436,13 +498,28 @@ var searchJobsCommand = defineCommand({
436
498
  // On jobs, --location maps to the geo region filter (not a location array — different API shape for jobs vs people)
437
499
  location: { type: "string", description: "geo region id (single id; resolve via search parameters --type LOCATION); maps to region filter" },
438
500
  industry: { type: "string", description: "Industry ids (comma-separated)." },
439
- seniority: { type: "string", description: "Seniority ids (comma-separated)." },
501
+ seniority: { type: "string", description: "seniority level, closed enum: executive|director|mid_senior|associate|entry|intern (comma-separated)" },
440
502
  function: { type: "string", description: "Job function ids (comma-separated)." },
441
- "job-type": { type: "string", description: "Job type ids, e.g. F,P (comma-separated)." },
503
+ "job-type": { type: "string", description: "job type, independent 7-value enum: full_time|part_time|contract|temporary|volunteer|internship|other (comma-separated)" },
442
504
  company: { type: "string", description: "Company ids (comma-separated)." },
443
505
  "sort-by": { type: "string", description: "Sort order (e.g. relevance, recent)." },
444
506
  "date-posted": { type: "string", description: "maximum job age in days (a number \u2014 e.g. 7, 14, 30; not an enum string)" },
445
- region: { type: "string", description: "alias for --location (same body field: region)" }
507
+ region: { type: "string", description: "alias for --location (same body field: region)" },
508
+ title: {
509
+ type: "string",
510
+ description: "job title id(s), comma-separated (resolve: search parameters --type JOB_TITLE); ID-based targeting \u2014 unlike search people --title, which is free-text"
511
+ },
512
+ presence: { type: "string", description: "work presence, comma-separated: on_site, hybrid, remote" },
513
+ benefits: { type: "string", description: "benefit ids, comma-separated" },
514
+ commitments: { type: "string", description: "commitment/employment types, comma-separated" },
515
+ "has-verifications": { type: "boolean", description: "only jobs with verified details" },
516
+ "under-10-applicants": { type: "boolean", description: "only jobs with fewer than 10 applicants" },
517
+ "in-your-network": { type: "boolean", description: "only jobs where you have a connection at the company" },
518
+ "fair-chance-employer": { type: "boolean", description: "only fair-chance employer jobs" },
519
+ "location-within-area": {
520
+ type: "string",
521
+ description: "radius in miles from --location (requires --location; numeric only)"
522
+ }
446
523
  },
447
524
  async run({ args }) {
448
525
  const flags = args;
@@ -466,7 +543,11 @@ var searchParametersCommand = defineCommand({
466
543
  meta: { name: "parameters", description: "Resolve human-readable terms to opaque filter IDs." },
467
544
  args: {
468
545
  ...GLOBAL_FLAGS,
469
- type: { type: "string", description: "Parameter type (e.g. LOCATION, COMPANY, INDUSTRY).", required: true },
546
+ type: {
547
+ type: "string",
548
+ description: "Parameter type: LOCATION, PEOPLE, CONNECTIONS, COMPANY, SCHOOL, INDUSTRY, SERVICE, JOB_FUNCTION, JOB_TITLE, EMPLOYMENT_TYPE, SKILL.",
549
+ required: true
550
+ },
470
551
  keywords: { type: "string", description: "Human term to resolve (not required for EMPLOYMENT_TYPE)." }
471
552
  },
472
553
  async run({ args }) {
@@ -488,7 +569,7 @@ var searchParametersCommand = defineCommand({
488
569
  }
489
570
  });
490
571
  var searchCommand = defineCommand({
491
- meta: { name: "search", description: "Search LinkedIn members, companies, posts, and jobs." },
572
+ meta: { name: "search", description: "Search people, companies, posts, and jobs." },
492
573
  subCommands: {
493
574
  people: searchPeopleCommand,
494
575
  companies: searchCompaniesCommand,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curviate/cli",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "private": false,
5
5
  "description": "Official command-line interface for the Curviate API.",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "clean": "rm -rf dist *.tsbuildinfo"
41
41
  },
42
42
  "dependencies": {
43
- "@curviate/sdk": "^0.4.1",
43
+ "@curviate/sdk": "^0.5.0",
44
44
  "citty": "^0.1.6"
45
45
  },
46
46
  "devDependencies": {