@lhremote/cli 0.5.0 → 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/README.md +5 -4
- package/dist/handlers/add-people-to-collection.d.ts +10 -0
- package/dist/handlers/add-people-to-collection.d.ts.map +1 -0
- package/dist/handlers/add-people-to-collection.js +79 -0
- package/dist/handlers/add-people-to-collection.js.map +1 -0
- package/dist/handlers/add-people-to-collection.test.d.ts +2 -0
- package/dist/handlers/add-people-to-collection.test.d.ts.map +1 -0
- package/dist/handlers/add-people-to-collection.test.js +107 -0
- package/dist/handlers/add-people-to-collection.test.js.map +1 -0
- package/dist/handlers/build-url.d.ts +17 -0
- package/dist/handlers/build-url.d.ts.map +1 -0
- package/dist/handlers/build-url.js +90 -0
- package/dist/handlers/build-url.js.map +1 -0
- package/dist/handlers/collect-people.d.ts +12 -0
- package/dist/handlers/collect-people.d.ts.map +1 -0
- package/dist/handlers/collect-people.js +39 -0
- package/dist/handlers/collect-people.js.map +1 -0
- package/dist/handlers/collect-people.test.d.ts +2 -0
- package/dist/handlers/collect-people.test.d.ts.map +1 -0
- package/dist/handlers/collect-people.test.js +92 -0
- package/dist/handlers/collect-people.test.js.map +1 -0
- package/dist/handlers/create-collection.d.ts +8 -0
- package/dist/handlers/create-collection.d.ts.map +1 -0
- package/dist/handlers/create-collection.js +26 -0
- package/dist/handlers/create-collection.js.map +1 -0
- package/dist/handlers/create-collection.test.d.ts +2 -0
- package/dist/handlers/create-collection.test.d.ts.map +1 -0
- package/dist/handlers/create-collection.test.js +55 -0
- package/dist/handlers/create-collection.test.js.map +1 -0
- package/dist/handlers/delete-collection.d.ts +8 -0
- package/dist/handlers/delete-collection.d.ts.map +1 -0
- package/dist/handlers/delete-collection.js +31 -0
- package/dist/handlers/delete-collection.js.map +1 -0
- package/dist/handlers/delete-collection.test.d.ts +2 -0
- package/dist/handlers/delete-collection.test.d.ts.map +1 -0
- package/dist/handlers/delete-collection.test.js +74 -0
- package/dist/handlers/delete-collection.test.js.map +1 -0
- package/dist/handlers/import-people-from-collection.d.ts +8 -0
- package/dist/handlers/import-people-from-collection.d.ts.map +1 -0
- package/dist/handlers/import-people-from-collection.js +55 -0
- package/dist/handlers/import-people-from-collection.js.map +1 -0
- package/dist/handlers/import-people-from-collection.test.d.ts +2 -0
- package/dist/handlers/import-people-from-collection.test.d.ts.map +1 -0
- package/dist/handlers/import-people-from-collection.test.js +121 -0
- package/dist/handlers/import-people-from-collection.test.js.map +1 -0
- package/dist/handlers/index.d.ts +10 -0
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/index.js +10 -0
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/list-collections.d.ts +5 -0
- package/dist/handlers/list-collections.d.ts.map +1 -0
- package/dist/handlers/list-collections.js +48 -0
- package/dist/handlers/list-collections.js.map +1 -0
- package/dist/handlers/list-collections.test.d.ts +2 -0
- package/dist/handlers/list-collections.test.d.ts.map +1 -0
- package/dist/handlers/list-collections.test.js +111 -0
- package/dist/handlers/list-collections.test.js.map +1 -0
- package/dist/handlers/list-reference-data.d.ts +5 -0
- package/dist/handlers/list-reference-data.d.ts.map +1 -0
- package/dist/handlers/list-reference-data.js +33 -0
- package/dist/handlers/list-reference-data.js.map +1 -0
- package/dist/handlers/remove-people-from-collection.d.ts +10 -0
- package/dist/handlers/remove-people-from-collection.d.ts.map +1 -0
- package/dist/handlers/remove-people-from-collection.js +75 -0
- package/dist/handlers/remove-people-from-collection.js.map +1 -0
- package/dist/handlers/remove-people-from-collection.test.d.ts +2 -0
- package/dist/handlers/remove-people-from-collection.test.d.ts.map +1 -0
- package/dist/handlers/remove-people-from-collection.test.js +100 -0
- package/dist/handlers/remove-people-from-collection.test.js.map +1 -0
- package/dist/handlers/resolve-entity.d.ts +9 -0
- package/dist/handlers/resolve-entity.d.ts.map +1 -0
- package/dist/handlers/resolve-entity.js +48 -0
- package/dist/handlers/resolve-entity.js.map +1 -0
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +105 -1
- package/dist/program.js.map +1 -1
- package/dist/program.test.js +11 -1
- package/dist/program.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
vi.mock("@lhremote/core", async (importOriginal) => {
|
|
5
|
+
const actual = await importOriginal();
|
|
6
|
+
return {
|
|
7
|
+
...actual,
|
|
8
|
+
DatabaseClient: vi.fn(),
|
|
9
|
+
CollectionListRepository: vi.fn(),
|
|
10
|
+
discoverAllDatabases: vi.fn(),
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
import { CollectionListRepository } from "@lhremote/core";
|
|
14
|
+
import { handleListCollections } from "./list-collections.js";
|
|
15
|
+
import { getStdout, mockDb, mockDiscovery } from "./testing/mock-helpers.js";
|
|
16
|
+
const MOCK_COLLECTIONS = [
|
|
17
|
+
{
|
|
18
|
+
id: 1,
|
|
19
|
+
name: "Prospects Q1",
|
|
20
|
+
peopleCount: 42,
|
|
21
|
+
createdAt: "2025-01-01T00:00:00Z",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 2,
|
|
25
|
+
name: "Follow-Up List",
|
|
26
|
+
peopleCount: 7,
|
|
27
|
+
createdAt: "2025-01-02T00:00:00Z",
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
function mockRepo(collections = MOCK_COLLECTIONS) {
|
|
31
|
+
vi.mocked(CollectionListRepository).mockImplementation(function () {
|
|
32
|
+
return {
|
|
33
|
+
listCollections: vi.fn().mockReturnValue(collections),
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function setupSuccessPath() {
|
|
38
|
+
mockDiscovery();
|
|
39
|
+
mockDb();
|
|
40
|
+
mockRepo();
|
|
41
|
+
}
|
|
42
|
+
describe("handleListCollections", () => {
|
|
43
|
+
const originalExitCode = process.exitCode;
|
|
44
|
+
let stdoutSpy;
|
|
45
|
+
let stderrSpy;
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
process.exitCode = undefined;
|
|
48
|
+
vi.clearAllMocks();
|
|
49
|
+
stdoutSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
|
|
50
|
+
stderrSpy = vi.spyOn(process.stderr, "write").mockReturnValue(true);
|
|
51
|
+
});
|
|
52
|
+
afterEach(() => {
|
|
53
|
+
process.exitCode = originalExitCode;
|
|
54
|
+
vi.restoreAllMocks();
|
|
55
|
+
});
|
|
56
|
+
it("prints JSON with --json", async () => {
|
|
57
|
+
setupSuccessPath();
|
|
58
|
+
await handleListCollections({ json: true });
|
|
59
|
+
expect(process.exitCode).toBeUndefined();
|
|
60
|
+
const parsed = JSON.parse(getStdout(stdoutSpy));
|
|
61
|
+
expect(parsed.collections).toHaveLength(2);
|
|
62
|
+
expect(parsed.total).toBe(2);
|
|
63
|
+
});
|
|
64
|
+
it("prints human-readable output", async () => {
|
|
65
|
+
setupSuccessPath();
|
|
66
|
+
await handleListCollections({});
|
|
67
|
+
expect(process.exitCode).toBeUndefined();
|
|
68
|
+
const output = getStdout(stdoutSpy);
|
|
69
|
+
expect(output).toContain("Collections (2 total):");
|
|
70
|
+
expect(output).toContain("#1 Prospects Q1");
|
|
71
|
+
expect(output).toContain("42 people");
|
|
72
|
+
expect(output).toContain("#2 Follow-Up List");
|
|
73
|
+
expect(output).toContain("7 people");
|
|
74
|
+
});
|
|
75
|
+
it("prints 'No collections found' when empty", async () => {
|
|
76
|
+
mockDiscovery();
|
|
77
|
+
mockDb();
|
|
78
|
+
mockRepo([]);
|
|
79
|
+
await handleListCollections({});
|
|
80
|
+
expect(process.exitCode).toBeUndefined();
|
|
81
|
+
expect(getStdout(stdoutSpy)).toContain("No collections found.");
|
|
82
|
+
});
|
|
83
|
+
it("sets exitCode 1 when no databases found", async () => {
|
|
84
|
+
mockDiscovery(new Map());
|
|
85
|
+
await handleListCollections({});
|
|
86
|
+
expect(process.exitCode).toBe(1);
|
|
87
|
+
expect(stderrSpy).toHaveBeenCalledWith("No LinkedHelper databases found.\n");
|
|
88
|
+
});
|
|
89
|
+
it("closes database after listing", async () => {
|
|
90
|
+
mockDiscovery();
|
|
91
|
+
const { close } = mockDb();
|
|
92
|
+
mockRepo();
|
|
93
|
+
await handleListCollections({});
|
|
94
|
+
expect(close).toHaveBeenCalledOnce();
|
|
95
|
+
});
|
|
96
|
+
it("sets exitCode 1 on database error", async () => {
|
|
97
|
+
mockDiscovery();
|
|
98
|
+
mockDb();
|
|
99
|
+
vi.mocked(CollectionListRepository).mockImplementation(function () {
|
|
100
|
+
return {
|
|
101
|
+
listCollections: vi.fn().mockImplementation(() => {
|
|
102
|
+
throw new Error("database locked");
|
|
103
|
+
}),
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
await handleListCollections({});
|
|
107
|
+
expect(process.exitCode).toBe(1);
|
|
108
|
+
expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining("database locked"));
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
//# sourceMappingURL=list-collections.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-collections.test.js","sourceRoot":"","sources":["../../src/handlers/list-collections.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#list-reference-data | list-reference-data} CLI command. */
|
|
2
|
+
export declare function handleListReferenceData(dataType: string, options: {
|
|
3
|
+
json?: boolean;
|
|
4
|
+
}): void;
|
|
5
|
+
//# sourceMappingURL=list-reference-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-reference-data.d.ts","sourceRoot":"","sources":["../../src/handlers/list-reference-data.ts"],"names":[],"mappings":"AAkBA,0HAA0H;AAC1H,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;IACP,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GACA,IAAI,CA6BN"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { getLinkedInReferenceData, isReferenceDataType, } from "@lhremote/core";
|
|
4
|
+
const VALID_DATA_TYPES = [
|
|
5
|
+
"INDUSTRY",
|
|
6
|
+
"SENIORITY",
|
|
7
|
+
"FUNCTION",
|
|
8
|
+
"COMPANY_SIZE",
|
|
9
|
+
"CONNECTION_DEGREE",
|
|
10
|
+
"PROFILE_LANGUAGE",
|
|
11
|
+
];
|
|
12
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#list-reference-data | list-reference-data} CLI command. */
|
|
13
|
+
export function handleListReferenceData(dataType, options) {
|
|
14
|
+
if (!isReferenceDataType(dataType)) {
|
|
15
|
+
process.stderr.write(`Unknown reference data type: ${dataType}\n` +
|
|
16
|
+
`Valid types: ${VALID_DATA_TYPES.join(", ")}\n`);
|
|
17
|
+
process.exitCode = 1;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const items = getLinkedInReferenceData(dataType);
|
|
21
|
+
if (options.json) {
|
|
22
|
+
process.stdout.write(JSON.stringify({ dataType, items }, null, 2) + "\n");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
process.stdout.write(`${dataType} (${String(items.length)} entries):\n\n`);
|
|
26
|
+
for (const item of items) {
|
|
27
|
+
// Each entry type has different key names; normalise for display
|
|
28
|
+
const entries = Object.entries(item);
|
|
29
|
+
const parts = entries.map(([key, value]) => `${key}: ${String(value)}`);
|
|
30
|
+
process.stdout.write(` ${parts.join(", ")}\n`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=list-reference-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-reference-data.js","sourceRoot":"","sources":["../../src/handlers/list-reference-data.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAEL,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,MAAM,gBAAgB,GAAiC;IACrD,UAAU;IACV,WAAW;IACX,UAAU;IACV,cAAc;IACd,mBAAmB;IACnB,kBAAkB;CACnB,CAAC;AAEF,0HAA0H;AAC1H,MAAM,UAAU,uBAAuB,CACrC,QAAgB,EAChB,OAEC;IAED,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gCAAgC,QAAQ,IAAI;YAC1C,gBAAgB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAClD,CAAC;QACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAEjD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CACpD,CAAC;QACF,OAAO;IACT,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,KAAK,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAE3E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,iEAAiE;QACjE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAA0C,CAAC,CAAC;QAC3E,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CACvB,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAC7C,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#remove-people-from-collection | remove-people-from-collection} CLI command. */
|
|
2
|
+
export declare function handleRemovePeopleFromCollection(collectionId: number, options: {
|
|
3
|
+
personIds?: string;
|
|
4
|
+
personIdsFile?: string;
|
|
5
|
+
cdpPort?: number;
|
|
6
|
+
cdpHost?: string;
|
|
7
|
+
allowRemote?: boolean;
|
|
8
|
+
json?: boolean;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=remove-people-from-collection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-people-from-collection.d.ts","sourceRoot":"","sources":["../../src/handlers/remove-people-from-collection.ts"],"names":[],"mappings":"AA8BA,8IAA8I;AAC9I,wBAAsB,gCAAgC,CACpD,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE;IACP,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GACA,OAAO,CAAC,IAAI,CAAC,CAoDf"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { DEFAULT_CDP_PORT, removePeopleFromCollection, errorMessage, } from "@lhremote/core";
|
|
5
|
+
function parsePersonIds(raw) {
|
|
6
|
+
return raw
|
|
7
|
+
.split(",")
|
|
8
|
+
.map((s) => s.trim())
|
|
9
|
+
.filter((s) => s.length > 0)
|
|
10
|
+
.map(Number)
|
|
11
|
+
.filter((n) => Number.isInteger(n) && n > 0);
|
|
12
|
+
}
|
|
13
|
+
function readPersonIdsFile(filePath) {
|
|
14
|
+
const content = readFileSync(filePath, "utf-8");
|
|
15
|
+
return content
|
|
16
|
+
.split(/[\n,]/)
|
|
17
|
+
.map((s) => s.trim())
|
|
18
|
+
.filter((s) => s.length > 0)
|
|
19
|
+
.map(Number)
|
|
20
|
+
.filter((n) => Number.isInteger(n) && n > 0);
|
|
21
|
+
}
|
|
22
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#remove-people-from-collection | remove-people-from-collection} CLI command. */
|
|
23
|
+
export async function handleRemovePeopleFromCollection(collectionId, options) {
|
|
24
|
+
if (options.personIds && options.personIdsFile) {
|
|
25
|
+
process.stderr.write("Use only one of --person-ids or --person-ids-file.\n");
|
|
26
|
+
process.exitCode = 1;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let personIds;
|
|
30
|
+
if (options.personIds) {
|
|
31
|
+
personIds = parsePersonIds(options.personIds);
|
|
32
|
+
}
|
|
33
|
+
else if (options.personIdsFile) {
|
|
34
|
+
try {
|
|
35
|
+
personIds = readPersonIdsFile(options.personIdsFile);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
const message = errorMessage(error);
|
|
39
|
+
process.stderr.write(`${message}\n`);
|
|
40
|
+
process.exitCode = 1;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
process.stderr.write("Either --person-ids or --person-ids-file is required.\n");
|
|
46
|
+
process.exitCode = 1;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (personIds.length === 0) {
|
|
50
|
+
process.stderr.write("No valid person IDs provided.\n");
|
|
51
|
+
process.exitCode = 1;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const result = await removePeopleFromCollection({
|
|
56
|
+
collectionId,
|
|
57
|
+
personIds,
|
|
58
|
+
cdpPort: options.cdpPort ?? DEFAULT_CDP_PORT,
|
|
59
|
+
cdpHost: options.cdpHost,
|
|
60
|
+
allowRemote: options.allowRemote,
|
|
61
|
+
});
|
|
62
|
+
if (options.json) {
|
|
63
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
process.stdout.write(`Removed ${String(result.removed)} people from collection #${String(collectionId)}.\n`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
const message = errorMessage(error);
|
|
71
|
+
process.stderr.write(`${message}\n`);
|
|
72
|
+
process.exitCode = 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=remove-people-from-collection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-people-from-collection.js","sourceRoot":"","sources":["../../src/handlers/remove-people-from-collection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-people-from-collection.test.d.ts","sourceRoot":"","sources":["../../src/handlers/remove-people-from-collection.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
vi.mock("@lhremote/core", async (importOriginal) => {
|
|
5
|
+
const actual = await importOriginal();
|
|
6
|
+
return {
|
|
7
|
+
...actual,
|
|
8
|
+
removePeopleFromCollection: vi.fn(),
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
vi.mock("node:fs", async (importOriginal) => {
|
|
12
|
+
const actual = await importOriginal();
|
|
13
|
+
return {
|
|
14
|
+
...actual,
|
|
15
|
+
readFileSync: vi.fn(),
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
import { removePeopleFromCollection, } from "@lhremote/core";
|
|
19
|
+
import { readFileSync } from "node:fs";
|
|
20
|
+
import { handleRemovePeopleFromCollection } from "./remove-people-from-collection.js";
|
|
21
|
+
import { getStdout } from "./testing/mock-helpers.js";
|
|
22
|
+
const MOCK_RESULT = {
|
|
23
|
+
success: true,
|
|
24
|
+
collectionId: 1,
|
|
25
|
+
removed: 2,
|
|
26
|
+
};
|
|
27
|
+
describe("handleRemovePeopleFromCollection", () => {
|
|
28
|
+
const originalExitCode = process.exitCode;
|
|
29
|
+
let stdoutSpy;
|
|
30
|
+
let stderrSpy;
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
process.exitCode = undefined;
|
|
33
|
+
vi.clearAllMocks();
|
|
34
|
+
stdoutSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
|
|
35
|
+
stderrSpy = vi.spyOn(process.stderr, "write").mockReturnValue(true);
|
|
36
|
+
});
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
process.exitCode = originalExitCode;
|
|
39
|
+
vi.restoreAllMocks();
|
|
40
|
+
});
|
|
41
|
+
it("removes people with --person-ids and prints result", async () => {
|
|
42
|
+
vi.mocked(removePeopleFromCollection).mockResolvedValue(MOCK_RESULT);
|
|
43
|
+
await handleRemovePeopleFromCollection(1, { personIds: "100,200" });
|
|
44
|
+
expect(process.exitCode).toBeUndefined();
|
|
45
|
+
expect(getStdout(stdoutSpy)).toContain("Removed 2 people from collection #1.");
|
|
46
|
+
});
|
|
47
|
+
it("reads from --person-ids-file", async () => {
|
|
48
|
+
vi.mocked(readFileSync).mockReturnValue("100\n200\n300");
|
|
49
|
+
vi.mocked(removePeopleFromCollection).mockResolvedValue({
|
|
50
|
+
...MOCK_RESULT,
|
|
51
|
+
removed: 3,
|
|
52
|
+
});
|
|
53
|
+
await handleRemovePeopleFromCollection(1, { personIdsFile: "ids.txt" });
|
|
54
|
+
expect(process.exitCode).toBeUndefined();
|
|
55
|
+
expect(getStdout(stdoutSpy)).toContain("Removed 3 people");
|
|
56
|
+
});
|
|
57
|
+
it("prints JSON with --json", async () => {
|
|
58
|
+
vi.mocked(removePeopleFromCollection).mockResolvedValue(MOCK_RESULT);
|
|
59
|
+
await handleRemovePeopleFromCollection(1, { personIds: "100,200", json: true });
|
|
60
|
+
expect(process.exitCode).toBeUndefined();
|
|
61
|
+
const parsed = JSON.parse(getStdout(stdoutSpy));
|
|
62
|
+
expect(parsed.success).toBe(true);
|
|
63
|
+
expect(parsed.collectionId).toBe(1);
|
|
64
|
+
expect(parsed.removed).toBe(2);
|
|
65
|
+
});
|
|
66
|
+
it("sets exitCode 1 when both person-ids options provided", async () => {
|
|
67
|
+
await handleRemovePeopleFromCollection(1, {
|
|
68
|
+
personIds: "100",
|
|
69
|
+
personIdsFile: "ids.txt",
|
|
70
|
+
});
|
|
71
|
+
expect(process.exitCode).toBe(1);
|
|
72
|
+
expect(stderrSpy).toHaveBeenCalledWith("Use only one of --person-ids or --person-ids-file.\n");
|
|
73
|
+
});
|
|
74
|
+
it("sets exitCode 1 when no person-ids option provided", async () => {
|
|
75
|
+
await handleRemovePeopleFromCollection(1, {});
|
|
76
|
+
expect(process.exitCode).toBe(1);
|
|
77
|
+
expect(stderrSpy).toHaveBeenCalledWith("Either --person-ids or --person-ids-file is required.\n");
|
|
78
|
+
});
|
|
79
|
+
it("sets exitCode 1 when person IDs are empty", async () => {
|
|
80
|
+
vi.mocked(readFileSync).mockReturnValue("");
|
|
81
|
+
await handleRemovePeopleFromCollection(1, { personIdsFile: "empty.txt" });
|
|
82
|
+
expect(process.exitCode).toBe(1);
|
|
83
|
+
expect(stderrSpy).toHaveBeenCalledWith("No valid person IDs provided.\n");
|
|
84
|
+
});
|
|
85
|
+
it("sets exitCode 1 on error", async () => {
|
|
86
|
+
vi.mocked(removePeopleFromCollection).mockRejectedValue(new Error("timeout"));
|
|
87
|
+
await handleRemovePeopleFromCollection(1, { personIds: "100" });
|
|
88
|
+
expect(process.exitCode).toBe(1);
|
|
89
|
+
expect(stderrSpy).toHaveBeenCalledWith("timeout\n");
|
|
90
|
+
});
|
|
91
|
+
it("sets exitCode 1 when person-ids-file read fails", async () => {
|
|
92
|
+
vi.mocked(readFileSync).mockImplementation(() => {
|
|
93
|
+
throw new Error("ENOENT: no such file");
|
|
94
|
+
});
|
|
95
|
+
await handleRemovePeopleFromCollection(1, { personIdsFile: "missing.txt" });
|
|
96
|
+
expect(process.exitCode).toBe(1);
|
|
97
|
+
expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining("ENOENT"));
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=remove-people-from-collection.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-people-from-collection.test.js","sourceRoot":"","sources":["../../src/handlers/remove-people-from-collection.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#resolve-entity | resolve-entity} CLI command. */
|
|
2
|
+
export declare function handleResolveEntity(entityType: string, query: string, options: {
|
|
3
|
+
cdpPort?: number;
|
|
4
|
+
cdpHost?: string;
|
|
5
|
+
allowRemote?: boolean;
|
|
6
|
+
json?: boolean;
|
|
7
|
+
limit?: number;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=resolve-entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-entity.d.ts","sourceRoot":"","sources":["../../src/handlers/resolve-entity.ts"],"names":[],"mappings":"AAgBA,gHAAgH;AAChH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,IAAI,CAAC,CA+Cf"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { DEFAULT_CDP_PORT, resolveLinkedInEntity, errorMessage, } from "@lhremote/core";
|
|
4
|
+
const VALID_ENTITY_TYPES = [
|
|
5
|
+
"COMPANY",
|
|
6
|
+
"GEO",
|
|
7
|
+
"SCHOOL",
|
|
8
|
+
];
|
|
9
|
+
/** Handle the {@link https://github.com/alexey-pelykh/lhremote#resolve-entity | resolve-entity} CLI command. */
|
|
10
|
+
export async function handleResolveEntity(entityType, query, options) {
|
|
11
|
+
if (!VALID_ENTITY_TYPES.includes(entityType)) {
|
|
12
|
+
process.stderr.write(`Unknown entity type: ${entityType}\n` +
|
|
13
|
+
`Valid types: ${VALID_ENTITY_TYPES.join(", ")}\n`);
|
|
14
|
+
process.exitCode = 1;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const result = await resolveLinkedInEntity({
|
|
19
|
+
query,
|
|
20
|
+
entityType: entityType,
|
|
21
|
+
cdpPort: options.cdpPort ?? DEFAULT_CDP_PORT,
|
|
22
|
+
...(options.cdpHost !== undefined && { cdpHost: options.cdpHost }),
|
|
23
|
+
...(options.allowRemote !== undefined && { allowRemote: options.allowRemote }),
|
|
24
|
+
});
|
|
25
|
+
let matches = result.matches;
|
|
26
|
+
if (options.limit !== undefined) {
|
|
27
|
+
matches = matches.slice(0, options.limit);
|
|
28
|
+
}
|
|
29
|
+
if (options.json) {
|
|
30
|
+
process.stdout.write(JSON.stringify({ matches, strategy: result.strategy }, null, 2) + "\n");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (matches.length === 0) {
|
|
34
|
+
process.stdout.write(`No matches found for "${query}"\n`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
process.stdout.write(`Matches for "${query}" (${entityType}, via ${result.strategy}):\n\n`);
|
|
38
|
+
for (const match of matches) {
|
|
39
|
+
process.stdout.write(` ${match.id} ${match.name} [${match.type}]\n`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const message = errorMessage(error);
|
|
44
|
+
process.stderr.write(`${message}\n`);
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=resolve-entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-entity.js","sourceRoot":"","sources":["../../src/handlers/resolve-entity.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EACL,gBAAgB,EAEhB,qBAAqB,EACrB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,MAAM,kBAAkB,GAA0B;IAChD,SAAS;IACT,KAAK;IACL,QAAQ;CACT,CAAC;AAEF,gHAAgH;AAChH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,UAAkB,EAClB,KAAa,EACb,OAMC;IAED,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,UAAwB,CAAC,EAAE,CAAC;QAC3D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,wBAAwB,UAAU,IAAI;YACpC,gBAAgB,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CACpD,CAAC;QACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC;YACzC,KAAK;YACL,UAAU,EAAE,UAAwB;YACpC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,gBAAgB;YAC5C,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;YAClE,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;SAC/E,CAAC,CAAC;QAEH,IAAI,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC7B,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CACvE,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,KAAK,KAAK,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,gBAAgB,KAAK,MAAM,UAAU,SAAS,MAAM,CAAC,QAAQ,QAAQ,CACtE,CAAC;QACF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
package/dist/program.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAgC,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAgC,MAAM,WAAW,CAAC;AAgGlE;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CA0iBvC"}
|
package/dist/program.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { Command, InvalidArgumentError, Option } from "commander";
|
|
5
|
-
import { handleCampaignAddAction, handleCampaignCreate, handleCampaignDelete, handleCampaignExcludeAdd, handleCampaignExcludeList, handleCampaignExcludeRemove, handleCampaignExport, handleCampaignGet, handleCampaignList, handleCampaignListPeople, handleCampaignMoveNext, handleCampaignRemoveAction, handleCampaignRemovePeople, handleCampaignReorderActions, handleCampaignRetry, handleCampaignStart, handleCampaignStatistics, handleCampaignStatus, handleCampaignStop, handleCampaignUpdate, handleCampaignUpdateAction, handleImportPeopleFromUrls, handleCheckReplies, handleCheckStatus, handleDescribeActions, handleFindApp, handleGetErrors, handleLaunchApp, handleListAccounts, handleQueryMessages, handleQueryProfile, handleQueryProfiles, handleQueryProfilesBulk, handleScrapeMessagingHistory, handleQuitApp, handleStartInstance, handleStopInstance, } from "./handlers/index.js";
|
|
5
|
+
import { handleAddPeopleToCollection, handleBuildUrl, handleCampaignAddAction, handleCampaignCreate, handleCampaignDelete, handleCampaignExcludeAdd, handleCampaignExcludeList, handleCampaignExcludeRemove, handleCampaignExport, handleCampaignGet, handleCampaignList, handleCampaignListPeople, handleCampaignMoveNext, handleCampaignRemoveAction, handleCampaignRemovePeople, handleCampaignReorderActions, handleCampaignRetry, handleCampaignStart, handleCampaignStatistics, handleCampaignStatus, handleCampaignStop, handleCampaignUpdate, handleCampaignUpdateAction, handleCreateCollection, handleDeleteCollection, handleImportPeopleFromCollection, handleImportPeopleFromUrls, handleListCollections, handleCheckReplies, handleCheckStatus, handleCollectPeople, handleDescribeActions, handleFindApp, handleGetErrors, handleLaunchApp, handleListAccounts, handleListReferenceData, handleQueryMessages, handleQueryProfile, handleQueryProfiles, handleQueryProfilesBulk, handleRemovePeopleFromCollection, handleResolveEntity, handleScrapeMessagingHistory, handleQuitApp, handleStartInstance, handleStopInstance, } from "./handlers/index.js";
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
7
7
|
const { version } = require("../package.json");
|
|
8
8
|
/** Parse a string as a positive integer, throwing on invalid input. */
|
|
@@ -315,6 +315,20 @@ export function createProgram() {
|
|
|
315
315
|
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
316
316
|
.option("--json", "Output as JSON")
|
|
317
317
|
.action(handleImportPeopleFromUrls);
|
|
318
|
+
program
|
|
319
|
+
.command("collect-people")
|
|
320
|
+
.description("Collect people from a LinkedIn page into a campaign")
|
|
321
|
+
.argument("<campaignId>", "Campaign ID to collect into", parsePositiveInt)
|
|
322
|
+
.argument("<sourceUrl>", "LinkedIn page URL to collect from")
|
|
323
|
+
.option("--limit <n>", "Max profiles to collect", parsePositiveInt)
|
|
324
|
+
.option("--max-pages <n>", "Max pages to process", parsePositiveInt)
|
|
325
|
+
.option("--page-size <n>", "Results per page", parsePositiveInt)
|
|
326
|
+
.option("--source-type <type>", "Explicit source type (bypasses URL detection)")
|
|
327
|
+
.option("--cdp-port <port>", "CDP debugging port", parsePositiveInt)
|
|
328
|
+
.option("--cdp-host <host>", "CDP host (default: 127.0.0.1)")
|
|
329
|
+
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
330
|
+
.option("--json", "Output as JSON")
|
|
331
|
+
.action(handleCollectPeople);
|
|
318
332
|
program
|
|
319
333
|
.command("campaign-remove-people")
|
|
320
334
|
.description("Remove people from a campaign's target list entirely")
|
|
@@ -326,6 +340,61 @@ export function createProgram() {
|
|
|
326
340
|
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
327
341
|
.option("--json", "Output as JSON")
|
|
328
342
|
.action(handleCampaignRemovePeople);
|
|
343
|
+
program
|
|
344
|
+
.command("list-collections")
|
|
345
|
+
.description("List LinkedHelper collections (Lists)")
|
|
346
|
+
.option("--json", "Output as JSON")
|
|
347
|
+
.action(handleListCollections);
|
|
348
|
+
program
|
|
349
|
+
.command("create-collection")
|
|
350
|
+
.description("Create a new LinkedHelper collection (List)")
|
|
351
|
+
.argument("<name>", "Name for the new collection")
|
|
352
|
+
.option("--cdp-port <port>", "CDP debugging port", parsePositiveInt)
|
|
353
|
+
.option("--cdp-host <host>", "CDP host (default: 127.0.0.1)")
|
|
354
|
+
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
355
|
+
.option("--json", "Output as JSON")
|
|
356
|
+
.action(handleCreateCollection);
|
|
357
|
+
program
|
|
358
|
+
.command("delete-collection")
|
|
359
|
+
.description("Delete a LinkedHelper collection (List) and its people associations")
|
|
360
|
+
.argument("<collectionId>", "Collection ID to delete", parsePositiveInt)
|
|
361
|
+
.option("--cdp-port <port>", "CDP debugging port", parsePositiveInt)
|
|
362
|
+
.option("--cdp-host <host>", "CDP host (default: 127.0.0.1)")
|
|
363
|
+
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
364
|
+
.option("--json", "Output as JSON")
|
|
365
|
+
.action(handleDeleteCollection);
|
|
366
|
+
program
|
|
367
|
+
.command("add-people-to-collection")
|
|
368
|
+
.description("Add people to a LinkedHelper collection (List)")
|
|
369
|
+
.argument("<collectionId>", "Collection ID", parsePositiveInt)
|
|
370
|
+
.option("--person-ids <ids>", "Comma-separated person IDs")
|
|
371
|
+
.option("--person-ids-file <path>", "File containing person IDs")
|
|
372
|
+
.option("--cdp-port <port>", "CDP debugging port", parsePositiveInt)
|
|
373
|
+
.option("--cdp-host <host>", "CDP host (default: 127.0.0.1)")
|
|
374
|
+
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
375
|
+
.option("--json", "Output as JSON")
|
|
376
|
+
.action(handleAddPeopleToCollection);
|
|
377
|
+
program
|
|
378
|
+
.command("remove-people-from-collection")
|
|
379
|
+
.description("Remove people from a LinkedHelper collection (List)")
|
|
380
|
+
.argument("<collectionId>", "Collection ID", parsePositiveInt)
|
|
381
|
+
.option("--person-ids <ids>", "Comma-separated person IDs")
|
|
382
|
+
.option("--person-ids-file <path>", "File containing person IDs")
|
|
383
|
+
.option("--cdp-port <port>", "CDP debugging port", parsePositiveInt)
|
|
384
|
+
.option("--cdp-host <host>", "CDP host (default: 127.0.0.1)")
|
|
385
|
+
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
386
|
+
.option("--json", "Output as JSON")
|
|
387
|
+
.action(handleRemovePeopleFromCollection);
|
|
388
|
+
program
|
|
389
|
+
.command("import-people-from-collection")
|
|
390
|
+
.description("Import people from a LinkedHelper collection (List) into a campaign")
|
|
391
|
+
.argument("<collectionId>", "Collection ID to import from", parsePositiveInt)
|
|
392
|
+
.argument("<campaignId>", "Campaign ID to import into", parsePositiveInt)
|
|
393
|
+
.option("--cdp-port <port>", "CDP debugging port", parsePositiveInt)
|
|
394
|
+
.option("--cdp-host <host>", "CDP host (default: 127.0.0.1)")
|
|
395
|
+
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
396
|
+
.option("--json", "Output as JSON")
|
|
397
|
+
.action(handleImportPeopleFromCollection);
|
|
329
398
|
program
|
|
330
399
|
.command("describe-actions")
|
|
331
400
|
.description("List available LinkedHelper action types")
|
|
@@ -403,6 +472,41 @@ export function createProgram() {
|
|
|
403
472
|
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
404
473
|
.option("--json", "Output as JSON")
|
|
405
474
|
.action(handleGetErrors);
|
|
475
|
+
program
|
|
476
|
+
.command("build-url")
|
|
477
|
+
.description("Build a LinkedIn URL for a given source type")
|
|
478
|
+
.argument("<sourceType>", "Source type (e.g., SearchPage, SNSearchPage, OrganizationPeople)")
|
|
479
|
+
.option("--keywords <keywords>", "Search keywords (SearchPage, SNSearchPage)")
|
|
480
|
+
.option("--current-company <id>", "Current company ID (SearchPage, repeatable)", collectString, [])
|
|
481
|
+
.option("--past-company <id>", "Past company ID (SearchPage, repeatable)", collectString, [])
|
|
482
|
+
.option("--geo <id>", "Geographic URN ID (SearchPage, repeatable)", collectString, [])
|
|
483
|
+
.option("--industry <id>", "Industry ID (SearchPage, repeatable)", collectString, [])
|
|
484
|
+
.option("--school <id>", "School ID (SearchPage, repeatable)", collectString, [])
|
|
485
|
+
.option("--network <code>", "Connection degree: F, S, O (SearchPage, repeatable)", collectString, [])
|
|
486
|
+
.option("--profile-language <code>", "Profile language code (SearchPage, repeatable)", collectString, [])
|
|
487
|
+
.option("--service-category <id>", "Service category ID (SearchPage, repeatable)", collectString, [])
|
|
488
|
+
.option("--filter <spec>", "SN filter TYPE|ID|TEXT|INCLUDED (SNSearchPage, repeatable)", collectString, [])
|
|
489
|
+
.option("--slug <slug>", "Company or school slug (OrganizationPeople, Alumni)")
|
|
490
|
+
.option("--id <id>", "Entity ID (Group, Event, SNListPage, etc.)")
|
|
491
|
+
.option("--json", "Output as JSON")
|
|
492
|
+
.action(handleBuildUrl);
|
|
493
|
+
program
|
|
494
|
+
.command("resolve-entity")
|
|
495
|
+
.description("Resolve a LinkedIn entity (company, geo, school) by name")
|
|
496
|
+
.argument("<entityType>", "Entity type: COMPANY, GEO, or SCHOOL")
|
|
497
|
+
.argument("<query>", "Search query")
|
|
498
|
+
.option("--limit <n>", "Max results to show", parsePositiveInt)
|
|
499
|
+
.option("--cdp-port <port>", "CDP debugging port", parsePositiveInt)
|
|
500
|
+
.option("--cdp-host <host>", "CDP host (default: 127.0.0.1)")
|
|
501
|
+
.option("--allow-remote", "SECURITY: allow non-loopback CDP connections (enables remote code execution on target)")
|
|
502
|
+
.option("--json", "Output as JSON")
|
|
503
|
+
.action(handleResolveEntity);
|
|
504
|
+
program
|
|
505
|
+
.command("list-reference-data")
|
|
506
|
+
.description("List LinkedIn reference data (industries, seniorities, functions, etc.)")
|
|
507
|
+
.argument("<dataType>", "Data type: INDUSTRY, SENIORITY, FUNCTION, COMPANY_SIZE, CONNECTION_DEGREE, PROFILE_LANGUAGE")
|
|
508
|
+
.option("--json", "Output as JSON")
|
|
509
|
+
.action(handleListReferenceData);
|
|
406
510
|
return program;
|
|
407
511
|
}
|
|
408
512
|
//# sourceMappingURL=program.js.map
|