linkedin-automation-cli 1.0.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/.env.example +12 -0
- package/.github/workflows/ci.yml +66 -0
- package/.github/workflows/publish.yml +48 -0
- package/.husky/pre-commit +6 -0
- package/.prettierignore +4 -0
- package/.prettierrc +10 -0
- package/AGENTS.md +294 -0
- package/CHANGELOG.md +40 -0
- package/GIT_RELEASE.md +167 -0
- package/LICENSE +21 -0
- package/Makefile +30 -0
- package/NPM_PUBLISHING.md +230 -0
- package/PYEOF +0 -0
- package/README.md +295 -0
- package/TESTING-GUIDE.md +151 -0
- package/cmd/linkedin/main.go +9 -0
- package/dist/agent/action-executor.d.ts +81 -0
- package/dist/agent/action-executor.d.ts.map +1 -0
- package/dist/agent/action-executor.js +170 -0
- package/dist/agent/action-executor.js.map +1 -0
- package/dist/agent/action-executor.test.d.ts +2 -0
- package/dist/agent/action-executor.test.d.ts.map +1 -0
- package/dist/agent/action-executor.test.js +366 -0
- package/dist/agent/action-executor.test.js.map +1 -0
- package/dist/agent/claude-client.d.ts +74 -0
- package/dist/agent/claude-client.d.ts.map +1 -0
- package/dist/agent/claude-client.js +314 -0
- package/dist/agent/claude-client.js.map +1 -0
- package/dist/agent/claude-client.test.d.ts +2 -0
- package/dist/agent/claude-client.test.d.ts.map +1 -0
- package/dist/agent/claude-client.test.js +590 -0
- package/dist/agent/claude-client.test.js.map +1 -0
- package/dist/agent/dom-extractor.d.ts +50 -0
- package/dist/agent/dom-extractor.d.ts.map +1 -0
- package/dist/agent/dom-extractor.js +374 -0
- package/dist/agent/dom-extractor.js.map +1 -0
- package/dist/agent/dom-extractor.test.d.ts +7 -0
- package/dist/agent/dom-extractor.test.d.ts.map +1 -0
- package/dist/agent/dom-extractor.test.js +504 -0
- package/dist/agent/dom-extractor.test.js.map +1 -0
- package/dist/agent/extension-client.d.ts +75 -0
- package/dist/agent/extension-client.d.ts.map +1 -0
- package/dist/agent/extension-client.js +245 -0
- package/dist/agent/extension-client.js.map +1 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +16 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/page-agent.d.ts +76 -0
- package/dist/agent/page-agent.d.ts.map +1 -0
- package/dist/agent/page-agent.js +236 -0
- package/dist/agent/page-agent.js.map +1 -0
- package/dist/agent/types.d.ts +236 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +37 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli/agent-commands.d.ts +3 -0
- package/dist/cli/agent-commands.d.ts.map +1 -0
- package/dist/cli/agent-commands.js +250 -0
- package/dist/cli/agent-commands.js.map +1 -0
- package/dist/cli/auth.d.ts +3 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +288 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/company.d.ts +3 -0
- package/dist/cli/company.d.ts.map +1 -0
- package/dist/cli/company.js +55 -0
- package/dist/cli/company.js.map +1 -0
- package/dist/cli/connection.d.ts +3 -0
- package/dist/cli/connection.d.ts.map +1 -0
- package/dist/cli/connection.js +79 -0
- package/dist/cli/connection.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +17 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/messages.d.ts +3 -0
- package/dist/cli/messages.d.ts.map +1 -0
- package/dist/cli/messages.js +268 -0
- package/dist/cli/messages.js.map +1 -0
- package/dist/cli/profile.d.ts +3 -0
- package/dist/cli/profile.d.ts.map +1 -0
- package/dist/cli/profile.js +81 -0
- package/dist/cli/profile.js.map +1 -0
- package/dist/cli/profile.test.d.ts +2 -0
- package/dist/cli/profile.test.d.ts.map +1 -0
- package/dist/cli/profile.test.js +15 -0
- package/dist/cli/profile.test.js.map +1 -0
- package/dist/cli/reply.d.ts +3 -0
- package/dist/cli/reply.d.ts.map +1 -0
- package/dist/cli/reply.js +129 -0
- package/dist/cli/reply.js.map +1 -0
- package/dist/core/audit.d.ts +17 -0
- package/dist/core/audit.d.ts.map +1 -0
- package/dist/core/audit.js +121 -0
- package/dist/core/audit.js.map +1 -0
- package/dist/core/audit.test.d.ts +2 -0
- package/dist/core/audit.test.d.ts.map +1 -0
- package/dist/core/audit.test.js +142 -0
- package/dist/core/audit.test.js.map +1 -0
- package/dist/core/browser-cookies.d.ts +19 -0
- package/dist/core/browser-cookies.d.ts.map +1 -0
- package/dist/core/browser-cookies.js +181 -0
- package/dist/core/browser-cookies.js.map +1 -0
- package/dist/core/browser.d.ts +50 -0
- package/dist/core/browser.d.ts.map +1 -0
- package/dist/core/browser.js +318 -0
- package/dist/core/browser.js.map +1 -0
- package/dist/core/config.d.ts +20 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +103 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/config.test.d.ts +2 -0
- package/dist/core/config.test.d.ts.map +1 -0
- package/dist/core/config.test.js +111 -0
- package/dist/core/config.test.js.map +1 -0
- package/dist/core/storage.d.ts +19 -0
- package/dist/core/storage.d.ts.map +1 -0
- package/dist/core/storage.js +124 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/storage.test.d.ts +2 -0
- package/dist/core/storage.test.d.ts.map +1 -0
- package/dist/core/storage.test.js +142 -0
- package/dist/core/storage.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/linkedin/auth.d.ts +22 -0
- package/dist/linkedin/auth.d.ts.map +1 -0
- package/dist/linkedin/auth.js +167 -0
- package/dist/linkedin/auth.js.map +1 -0
- package/dist/linkedin/company-extractor.d.ts +36 -0
- package/dist/linkedin/company-extractor.d.ts.map +1 -0
- package/dist/linkedin/company-extractor.js +211 -0
- package/dist/linkedin/company-extractor.js.map +1 -0
- package/dist/linkedin/company-extractor.test.d.ts +2 -0
- package/dist/linkedin/company-extractor.test.d.ts.map +1 -0
- package/dist/linkedin/company-extractor.test.js +52 -0
- package/dist/linkedin/company-extractor.test.js.map +1 -0
- package/dist/linkedin/connector.d.ts +45 -0
- package/dist/linkedin/connector.d.ts.map +1 -0
- package/dist/linkedin/connector.js +245 -0
- package/dist/linkedin/connector.js.map +1 -0
- package/dist/linkedin/message-sender.d.ts +32 -0
- package/dist/linkedin/message-sender.d.ts.map +1 -0
- package/dist/linkedin/message-sender.js +112 -0
- package/dist/linkedin/message-sender.js.map +1 -0
- package/dist/linkedin/messages.d.ts +78 -0
- package/dist/linkedin/messages.d.ts.map +1 -0
- package/dist/linkedin/messages.js +745 -0
- package/dist/linkedin/messages.js.map +1 -0
- package/dist/linkedin/profile.d.ts +37 -0
- package/dist/linkedin/profile.d.ts.map +1 -0
- package/dist/linkedin/profile.js +268 -0
- package/dist/linkedin/profile.js.map +1 -0
- package/dist/linkedin/profile.test.d.ts +2 -0
- package/dist/linkedin/profile.test.d.ts.map +1 -0
- package/dist/linkedin/profile.test.js +68 -0
- package/dist/linkedin/profile.test.js.map +1 -0
- package/dist/linkedin/reply.d.ts +21 -0
- package/dist/linkedin/reply.d.ts.map +1 -0
- package/dist/linkedin/reply.js +76 -0
- package/dist/linkedin/reply.js.map +1 -0
- package/dist/linkedin/selector-engine.d.ts +69 -0
- package/dist/linkedin/selector-engine.d.ts.map +1 -0
- package/dist/linkedin/selector-engine.js +339 -0
- package/dist/linkedin/selector-engine.js.map +1 -0
- package/dist/linkedin/selector-engine.test.d.ts +2 -0
- package/dist/linkedin/selector-engine.test.d.ts.map +1 -0
- package/dist/linkedin/selector-engine.test.js +135 -0
- package/dist/linkedin/selector-engine.test.js.map +1 -0
- package/dist/linkedin/selectors.d.ts +65 -0
- package/dist/linkedin/selectors.d.ts.map +1 -0
- package/dist/linkedin/selectors.js +261 -0
- package/dist/linkedin/selectors.js.map +1 -0
- package/dist/templates/engine.d.ts +37 -0
- package/dist/templates/engine.d.ts.map +1 -0
- package/dist/templates/engine.js +215 -0
- package/dist/templates/engine.js.map +1 -0
- package/dist/templates/engine.test.d.ts +2 -0
- package/dist/templates/engine.test.d.ts.map +1 -0
- package/dist/templates/engine.test.js +212 -0
- package/dist/templates/engine.test.js.map +1 -0
- package/dist/templates/index.d.ts +2 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +7 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/types/index.d.ts +113 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/index.test.d.ts +2 -0
- package/dist/types/index.test.d.ts.map +1 -0
- package/dist/types/index.test.js +90 -0
- package/dist/types/index.test.js.map +1 -0
- package/dist/utils/paths.d.ts +8 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +68 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +22 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +57 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/retry.d.ts +18 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +49 -0
- package/dist/utils/retry.js.map +1 -0
- package/docs/connection-command.md +52 -0
- package/docs/plans/2025-03-03-linkedin-cli-design.md +280 -0
- package/docs/plans/2025-03-03-linkedin-cli-implementation-plan.md +2087 -0
- package/docs/plans/2025-03-03-linkedin-cli-implementation.md +2420 -0
- package/docs/plans/2026-02-19-linkedin-connection-feature.md +596 -0
- package/docs/plans/2026-02-28-messages-send-feature.md +480 -0
- package/docs/plans/2026-02-28-messages-show-design.md +243 -0
- package/docs/plans/2026-03-03-linkedin-cli-oss-publishing-design.md +394 -0
- package/docs/plans/2026-03-03-linkedin-cli-oss-publishing-plan.md +1592 -0
- package/docs/superpowers/plans/2026-03-13-linkedin-automation-resilience-migration.md +425 -0
- package/docs/superpowers/plans/2026-03-13-playwright-fara-migration.md +1112 -0
- package/docs/superpowers/plans/2026-03-14-page-agent-plan.md +1598 -0
- package/docs/superpowers/plans/2026-03-15-company-profile-extraction.md +591 -0
- package/docs/superpowers/plans/2026-03-15-profile-extraction-plan.md +943 -0
- package/docs/superpowers/specs/2026-03-14-company-profile-extraction-design.md +371 -0
- package/docs/superpowers/specs/2026-03-14-page-agent-design.md +385 -0
- package/docs/superpowers/specs/2026-03-15-profile-extraction-design.md +409 -0
- package/eslint.config.mjs +58 -0
- package/go.mod +9 -0
- package/go.sum +10 -0
- package/import-cookies.js +376 -0
- package/internal/cmd/actions.go +123 -0
- package/internal/cmd/auth.go +108 -0
- package/internal/cmd/connect.go +42 -0
- package/internal/cmd/message.go +44 -0
- package/internal/cmd/people.go +454 -0
- package/internal/cmd/profiles.go +121 -0
- package/internal/cmd/root.go +89 -0
- package/internal/cmd/sequence.go +192 -0
- package/internal/config/config.go +187 -0
- package/internal/config/config_test.go +121 -0
- package/internal/config/profile.go +65 -0
- package/internal/linkedin/navigator.go +195 -0
- package/internal/linkedin/selectors.go +39 -0
- package/internal/linkedin/validator.go +69 -0
- package/internal/pinchtab/client.go +183 -0
- package/internal/pinchtab/client_test.go +67 -0
- package/internal/pinchtab/types.go +50 -0
- package/internal/ratelimit/limiter.go +115 -0
- package/internal/ratelimit/limits.go +32 -0
- package/package.json +67 -0
- package/release.sh +66 -0
- package/scripts/debug-linkedin.js +156 -0
- package/scripts/debug-login.js +193 -0
- package/scripts/extract-from-edge.js +96 -0
- package/scripts/import-cookies.js +101 -0
- package/scripts/poc-show-data.js +205 -0
- package/scripts/proof-of-access.js +87 -0
- package/scripts/prove-connection.js +110 -0
- package/scripts/show-linkedin-data.js +173 -0
- package/src/agent/action-executor.test.ts +464 -0
- package/src/agent/action-executor.ts +203 -0
- package/src/agent/claude-client.test.ts +707 -0
- package/src/agent/claude-client.ts +422 -0
- package/src/agent/dom-extractor.test.ts +574 -0
- package/src/agent/dom-extractor.ts +437 -0
- package/src/agent/extension-client.ts +306 -0
- package/src/agent/index.ts +28 -0
- package/src/agent/page-agent.ts +292 -0
- package/src/agent/types.ts +288 -0
- package/src/cli/agent-commands.ts +274 -0
- package/src/cli/auth.ts +343 -0
- package/src/cli/company.ts +66 -0
- package/src/cli/connection.ts +89 -0
- package/src/cli/index.ts +7 -0
- package/src/cli/messages.ts +338 -0
- package/src/cli/profile.test.ts +14 -0
- package/src/cli/profile.ts +95 -0
- package/src/cli/reply.ts +110 -0
- package/src/core/audit.test.ts +134 -0
- package/src/core/audit.ts +98 -0
- package/src/core/browser-cookies.ts +203 -0
- package/src/core/browser.ts +304 -0
- package/src/core/config.test.ts +90 -0
- package/src/core/config.ts +81 -0
- package/src/core/storage.test.ts +129 -0
- package/src/core/storage.ts +100 -0
- package/src/index.ts +70 -0
- package/src/linkedin/auth.ts +218 -0
- package/src/linkedin/company-extractor.test.ts +58 -0
- package/src/linkedin/company-extractor.ts +222 -0
- package/src/linkedin/connector.ts +336 -0
- package/src/linkedin/message-sender.ts +141 -0
- package/src/linkedin/messages.ts +894 -0
- package/src/linkedin/profile.test.ts +79 -0
- package/src/linkedin/profile.ts +314 -0
- package/src/linkedin/reply.ts +96 -0
- package/src/linkedin/selector-engine.test.ts +167 -0
- package/src/linkedin/selector-engine.ts +393 -0
- package/src/linkedin/selectors.ts +268 -0
- package/src/templates/defaults/followup.txt +14 -0
- package/src/templates/defaults/meeting.txt +16 -0
- package/src/templates/defaults/welcome.txt +14 -0
- package/src/templates/engine.test.ts +228 -0
- package/src/templates/engine.ts +208 -0
- package/src/templates/index.ts +1 -0
- package/src/types/index.test.ts +94 -0
- package/src/types/index.ts +143 -0
- package/src/types/sql.js.d.ts +23 -0
- package/src/utils/paths.ts +33 -0
- package/src/utils/rate-limiter.ts +75 -0
- package/src/utils/retry.ts +78 -0
- package/test-cli.sh +85 -0
- package/test-real-data.sh +97 -0
- package/tsconfig.json +23 -0
- package/vitest.config.ts +35 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SELECTORS = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Multi-layer selector system for LinkedIn's unstable UI
|
|
6
|
+
* Each selector key has multiple fallback strategies
|
|
7
|
+
*/
|
|
8
|
+
exports.SELECTORS = {
|
|
9
|
+
// Login page
|
|
10
|
+
login: {
|
|
11
|
+
emailInput: ['input#username', 'input[name="session_key"]', 'input[type="email"]'],
|
|
12
|
+
passwordInput: ['input#password', 'input[name="session_password"]', 'input[type="password"]'],
|
|
13
|
+
submitButton: [
|
|
14
|
+
'button[type="submit"]',
|
|
15
|
+
'button.sign-in-form__submit-btn',
|
|
16
|
+
'button:has-text("Sign in")',
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
// 2FA
|
|
20
|
+
twoFA: {
|
|
21
|
+
pinInput: [
|
|
22
|
+
'input#input__phone_verification_pin',
|
|
23
|
+
'input[name="pin"]',
|
|
24
|
+
'input[type="text"][*="pin" i]',
|
|
25
|
+
],
|
|
26
|
+
submitButton: [
|
|
27
|
+
'button[type="submit"]',
|
|
28
|
+
'button:has-text("Submit")',
|
|
29
|
+
'button:has-text("Verify")',
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
// Navigation / logged in indicators
|
|
33
|
+
nav: {
|
|
34
|
+
globalNav: ['nav.global-nav', 'header.global-nav', '[data-testid="global-nav"]'],
|
|
35
|
+
profileDropdown: [
|
|
36
|
+
'button[aria-label*="Settings"]',
|
|
37
|
+
'.global-nav__me-menu button',
|
|
38
|
+
'[data-testid="settings-menu-trigger"]',
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
// Messaging
|
|
42
|
+
messages: {
|
|
43
|
+
conversationList: [
|
|
44
|
+
'div.msg-conversations-container__conversations-list',
|
|
45
|
+
'[data-testid="conversations-list"]',
|
|
46
|
+
'div[class*="conversations-list"]',
|
|
47
|
+
],
|
|
48
|
+
conversationItem: [
|
|
49
|
+
'div.msg-conversation-card',
|
|
50
|
+
'[data-testid="conversation-card"]',
|
|
51
|
+
'div[class*="conversation-card"]',
|
|
52
|
+
],
|
|
53
|
+
messageBubble: [
|
|
54
|
+
'div.msg-s-message-group__message',
|
|
55
|
+
'[data-testid="message-bubble"]',
|
|
56
|
+
'div[class*="message-bubble"]',
|
|
57
|
+
],
|
|
58
|
+
messageInput: [
|
|
59
|
+
'div.msg-form__contenteditable',
|
|
60
|
+
'div[contenteditable="true"][role="textbox"]',
|
|
61
|
+
'[data-testid="message-input"]',
|
|
62
|
+
],
|
|
63
|
+
sendButton: ['button.msg-form__send-btn', 'button[type="submit"]', 'button:has-text("Send")'],
|
|
64
|
+
},
|
|
65
|
+
// Connection requests
|
|
66
|
+
connection: {
|
|
67
|
+
// Primary connect button (various states)
|
|
68
|
+
// LinkedIn has many variants - we need comprehensive fallbacks
|
|
69
|
+
connectButton: [
|
|
70
|
+
// Aria-label variants
|
|
71
|
+
'button[aria-label*="Connect"]',
|
|
72
|
+
'button[aria-label*="Invite"]',
|
|
73
|
+
'button[aria-label*="to connect"]',
|
|
74
|
+
// Text content variants
|
|
75
|
+
'button:has-text("Connect")',
|
|
76
|
+
'button:has-text("Invite")',
|
|
77
|
+
'button:has-text("Connect ")',
|
|
78
|
+
// Class-based variants (LinkedIn uses artdeco classes)
|
|
79
|
+
'button.artdeco-button--primary:has-text("Connect")',
|
|
80
|
+
'button.artdeco-button--secondary:has-text("Connect")',
|
|
81
|
+
'button.artdeco-button--primary',
|
|
82
|
+
'button.artdeco-button--secondary',
|
|
83
|
+
// Specific profile page selectors
|
|
84
|
+
'.pv-top-card-v2-ctas button:has-text("Connect")',
|
|
85
|
+
'.profile-topcard-actions button:has-text("Connect")',
|
|
86
|
+
'div.pv-top-card-v2-ctas button',
|
|
87
|
+
// Data test IDs
|
|
88
|
+
'[data-testid="connect-button"]',
|
|
89
|
+
'[data-testid="invite-button"]',
|
|
90
|
+
// Generic fallback - any button with connect-related text
|
|
91
|
+
'button[id*="connect"]',
|
|
92
|
+
'button[id*="invite"]',
|
|
93
|
+
],
|
|
94
|
+
// More actions menu (three dots)
|
|
95
|
+
moreActionsButton: [
|
|
96
|
+
'button[aria-label*="More actions"]',
|
|
97
|
+
'button[aria-label*="More"]',
|
|
98
|
+
'button:has-text("More")',
|
|
99
|
+
'.artdeco-dropdown__trigger',
|
|
100
|
+
'button[data-testid="more-actions"]',
|
|
101
|
+
],
|
|
102
|
+
// Connect option in dropdown menu
|
|
103
|
+
connectOptionInMenu: [
|
|
104
|
+
'div[role="menuitem"]:has-text("Connect")',
|
|
105
|
+
'button:has-text("Connect")',
|
|
106
|
+
'[role="menuitem"][aria-label*="Connect"]',
|
|
107
|
+
],
|
|
108
|
+
// Add a note modal
|
|
109
|
+
addNoteButton: ['button[aria-label*="Add a note"]', 'button:has-text("Add a note")'],
|
|
110
|
+
noteTextarea: ['textarea[name="message"]', 'textarea[placeholder*="note"]', 'textarea'],
|
|
111
|
+
sendButton: [
|
|
112
|
+
// Aria-label variants
|
|
113
|
+
'button[aria-label*="Send invitation"]',
|
|
114
|
+
'button[aria-label*="Send invite"]',
|
|
115
|
+
'button[aria-label="Send"]',
|
|
116
|
+
// Text content variants
|
|
117
|
+
'button:has-text("Send")',
|
|
118
|
+
'button:has-text("Send invitation")',
|
|
119
|
+
'button:has-text("Send invite")',
|
|
120
|
+
// Modal-specific primary buttons
|
|
121
|
+
'.artdeco-modal button.artdeco-button--primary',
|
|
122
|
+
'.artdeco-modal button:has-text("Send")',
|
|
123
|
+
'.artdeco-modal button[type="submit"]',
|
|
124
|
+
// Generic modal submit
|
|
125
|
+
'[role="dialog"] button.artdeco-button--primary',
|
|
126
|
+
'[role="dialog"] button:has-text("Send")',
|
|
127
|
+
// Form submit in modal
|
|
128
|
+
'form button[type="submit"]',
|
|
129
|
+
'.artdeco-modal form button.artdeco-button--primary',
|
|
130
|
+
// Generic fallback
|
|
131
|
+
'button[type="submit"]',
|
|
132
|
+
'.artdeco-button--primary',
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
// Company profile extraction
|
|
136
|
+
company: {
|
|
137
|
+
name: [
|
|
138
|
+
'h1.text-heading-xlarge',
|
|
139
|
+
'.org-top-card-primary-content h1',
|
|
140
|
+
'h1.org-top-card-summary__title',
|
|
141
|
+
],
|
|
142
|
+
website: [
|
|
143
|
+
'a[data-testid="website-link"]',
|
|
144
|
+
'.org-about-us-module__website a',
|
|
145
|
+
'dd a[href^="http"]:not([href*="linkedin"])',
|
|
146
|
+
],
|
|
147
|
+
industry: [
|
|
148
|
+
'dt:has-text("Industry") + dd',
|
|
149
|
+
'.org-about-company-module__dl dt:has-text("Industry") + dd',
|
|
150
|
+
],
|
|
151
|
+
company_size: [
|
|
152
|
+
'dt:has-text("Company size") + dd',
|
|
153
|
+
'dt:has-text("Employees") + dd',
|
|
154
|
+
'.org-about-company-module__dl dt:has-text("Company size") + dd',
|
|
155
|
+
],
|
|
156
|
+
headquarters: [
|
|
157
|
+
'dt:has-text("Headquarters") + dd',
|
|
158
|
+
'.org-about-company-module__dl dt:has-text("Headquarters") + dd',
|
|
159
|
+
],
|
|
160
|
+
founded: [
|
|
161
|
+
'dt:has-text("Founded") + dd',
|
|
162
|
+
'.org-about-company-module__dl dt:has-text("Founded") + dd',
|
|
163
|
+
],
|
|
164
|
+
specialties: [
|
|
165
|
+
'dt:has-text("Specialties") + dd',
|
|
166
|
+
'.org-about-company-module__dl dt:has-text("Specialties") + dd',
|
|
167
|
+
],
|
|
168
|
+
type: [
|
|
169
|
+
'dt:has-text("Company type") + dd',
|
|
170
|
+
'dt:has-text("Type") + dd',
|
|
171
|
+
'.org-about-company-module__dl dt:has-text("Company type") + dd',
|
|
172
|
+
],
|
|
173
|
+
follower_count: [
|
|
174
|
+
'.org-top-card-primary-content__followers-count',
|
|
175
|
+
'.org-top-card-module__followers-count',
|
|
176
|
+
'span:has-text("followers")',
|
|
177
|
+
'.org-top-card-summary__followers',
|
|
178
|
+
],
|
|
179
|
+
// Authwall dismiss button
|
|
180
|
+
dismissAuthwall: [
|
|
181
|
+
'button[aria-label="Dismiss"]',
|
|
182
|
+
'button[aria-label="Close"]',
|
|
183
|
+
'.artdeco-modal__dismiss',
|
|
184
|
+
'button.artdeco-modal__dismiss',
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
// Profile extraction
|
|
188
|
+
profile: {
|
|
189
|
+
// Top card
|
|
190
|
+
name: [
|
|
191
|
+
'h1.text-heading-xlarge',
|
|
192
|
+
'[data-testid="top-card-profile-name"]',
|
|
193
|
+
'.pv-top-card .text-heading-xlarge',
|
|
194
|
+
'section.artdeco-card h1',
|
|
195
|
+
],
|
|
196
|
+
headline: [
|
|
197
|
+
'.text-body-medium',
|
|
198
|
+
'[data-testid="top-card-profile-headline"]',
|
|
199
|
+
'.pv-top-card .text-body-medium',
|
|
200
|
+
],
|
|
201
|
+
location: [
|
|
202
|
+
'.text-body-small.inline.t-black--light',
|
|
203
|
+
'[data-testid="top-card-profile-location"]',
|
|
204
|
+
'.pv-top-card .text-body-small',
|
|
205
|
+
],
|
|
206
|
+
// Experience section - find by heading text pattern
|
|
207
|
+
experienceSection: [
|
|
208
|
+
'section:has(h2:has-text("Experience"))',
|
|
209
|
+
'section[data-view-name="profile-card-experience"]',
|
|
210
|
+
'section[id*="experience"]',
|
|
211
|
+
],
|
|
212
|
+
experienceList: [
|
|
213
|
+
'li[data-view-name="profile-component-entity"]',
|
|
214
|
+
'section:has(h2:has-text("Experience")) li',
|
|
215
|
+
'.pvs-list__item',
|
|
216
|
+
],
|
|
217
|
+
// Title: First .t-bold span in each experience item
|
|
218
|
+
experienceTitle: [
|
|
219
|
+
'.t-bold span[aria-hidden="true"]',
|
|
220
|
+
'.hoverable-link-text span[aria-hidden="true"]',
|
|
221
|
+
'.display-flex.align-items-center.t-bold span',
|
|
222
|
+
],
|
|
223
|
+
// Company: First .t-14.t-normal span (after title)
|
|
224
|
+
experienceCompany: ['.t-14.t-normal span[aria-hidden="true"]', 'span[class*="t-14"]'],
|
|
225
|
+
// Duration: caption wrapper contains "X yrs Y mos"
|
|
226
|
+
experienceDuration: [
|
|
227
|
+
'.pvs-entity__caption-wrapper',
|
|
228
|
+
'.t-14.t-black--light span[aria-hidden="true"]',
|
|
229
|
+
'span[class*="caption"]',
|
|
230
|
+
],
|
|
231
|
+
companyLink: ['a[data-field="experience_company_logo"]', 'a[href*="/company/"]'],
|
|
232
|
+
// Contact info
|
|
233
|
+
contactInfoButton: [
|
|
234
|
+
'a[href*="contact-info"]',
|
|
235
|
+
'button[aria-label*="contact info" i]',
|
|
236
|
+
'[data-control-name="contact_see_more"]',
|
|
237
|
+
],
|
|
238
|
+
contactInfoPanel: [
|
|
239
|
+
'.pv-contact-info',
|
|
240
|
+
'[data-testid="contact-info-panel"]',
|
|
241
|
+
'.artdeco-modal__content',
|
|
242
|
+
],
|
|
243
|
+
contactInfoCloseButton: [
|
|
244
|
+
'.artdeco-modal__dismiss',
|
|
245
|
+
'button[aria-label*="Dismiss"]',
|
|
246
|
+
'button[aria-label*="Close"]',
|
|
247
|
+
'[data-testid="modal-close"]',
|
|
248
|
+
],
|
|
249
|
+
email: [
|
|
250
|
+
'a[href^="mailto:"]',
|
|
251
|
+
'[data-testid="contact-email"]',
|
|
252
|
+
'.pv-contact-info__contact-type[href*="mailto"]',
|
|
253
|
+
],
|
|
254
|
+
phone: [
|
|
255
|
+
'a[href^="tel:"]',
|
|
256
|
+
'[data-testid="contact-phone"]',
|
|
257
|
+
'.pv-contact-info__contact-type[href*="tel"]',
|
|
258
|
+
],
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
//# sourceMappingURL=selectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectors.js","sourceRoot":"","sources":["../../src/linkedin/selectors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Template } from '../types';
|
|
2
|
+
export interface RenderOptions {
|
|
3
|
+
variables: Record<string, string>;
|
|
4
|
+
fallback?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class TemplateEngine {
|
|
7
|
+
private defaultsDir;
|
|
8
|
+
private customDir;
|
|
9
|
+
constructor();
|
|
10
|
+
private ensureDirectories;
|
|
11
|
+
/**
|
|
12
|
+
* Load a template by ID
|
|
13
|
+
*/
|
|
14
|
+
load(templateId: string): Template | null;
|
|
15
|
+
/**
|
|
16
|
+
* Parse a template file into a Template object
|
|
17
|
+
*/
|
|
18
|
+
private parseTemplate;
|
|
19
|
+
/**
|
|
20
|
+
* Save a custom template
|
|
21
|
+
*/
|
|
22
|
+
save(template: Template): void;
|
|
23
|
+
/**
|
|
24
|
+
* Delete a custom template
|
|
25
|
+
*/
|
|
26
|
+
delete(templateId: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* List all available templates
|
|
29
|
+
*/
|
|
30
|
+
list(): Template[];
|
|
31
|
+
/**
|
|
32
|
+
* Render a template with variables
|
|
33
|
+
*/
|
|
34
|
+
render(templateId: string, options: RenderOptions): string;
|
|
35
|
+
}
|
|
36
|
+
export declare function getTemplateEngine(): TemplateEngine;
|
|
37
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/templates/engine.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;;IAQ1B,OAAO,CAAC,iBAAiB;IASzB;;OAEG;IACH,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAgBzC;;OAEG;IACH,OAAO,CAAC,aAAa;IAwDrB;;OAEG;IACH,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAe9B;;OAEG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IASnC;;OAEG;IACH,IAAI,IAAI,QAAQ,EAAE;IAiClB;;OAEG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM;CAqB3D;AAKD,wBAAgB,iBAAiB,IAAI,cAAc,CAKlD"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.TemplateEngine = void 0;
|
|
37
|
+
exports.getTemplateEngine = getTemplateEngine;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const paths_1 = require("../utils/paths");
|
|
41
|
+
class TemplateEngine {
|
|
42
|
+
defaultsDir;
|
|
43
|
+
customDir;
|
|
44
|
+
constructor() {
|
|
45
|
+
this.defaultsDir = (0, paths_1.getDefaultsDir)();
|
|
46
|
+
this.customDir = (0, paths_1.getCustomDir)();
|
|
47
|
+
this.ensureDirectories();
|
|
48
|
+
}
|
|
49
|
+
ensureDirectories() {
|
|
50
|
+
if (!fs.existsSync(this.defaultsDir)) {
|
|
51
|
+
fs.mkdirSync(this.defaultsDir, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
if (!fs.existsSync(this.customDir)) {
|
|
54
|
+
fs.mkdirSync(this.customDir, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Load a template by ID
|
|
59
|
+
*/
|
|
60
|
+
load(templateId) {
|
|
61
|
+
// Try custom templates first (user overrides)
|
|
62
|
+
const customPath = path.join(this.customDir, `${templateId}.txt`);
|
|
63
|
+
if (fs.existsSync(customPath)) {
|
|
64
|
+
return this.parseTemplate(templateId, customPath);
|
|
65
|
+
}
|
|
66
|
+
// Fall back to defaults
|
|
67
|
+
const defaultPath = path.join(this.defaultsDir, `${templateId}.txt`);
|
|
68
|
+
if (fs.existsSync(defaultPath)) {
|
|
69
|
+
return this.parseTemplate(templateId, defaultPath);
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parse a template file into a Template object
|
|
75
|
+
*/
|
|
76
|
+
parseTemplate(id, filePath) {
|
|
77
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
78
|
+
const lines = content.split('\n');
|
|
79
|
+
// Parse frontmatter if present
|
|
80
|
+
let name = id;
|
|
81
|
+
let description = '';
|
|
82
|
+
let category = 'custom';
|
|
83
|
+
let variables = [];
|
|
84
|
+
let templateContent = content;
|
|
85
|
+
if (lines[0] === '---') {
|
|
86
|
+
const endIndex = lines.indexOf('---', 1);
|
|
87
|
+
if (endIndex !== -1) {
|
|
88
|
+
const frontmatter = lines.slice(1, endIndex).join('\n');
|
|
89
|
+
templateContent = lines.slice(endIndex + 1).join('\n');
|
|
90
|
+
// Parse YAML-like frontmatter
|
|
91
|
+
for (const line of frontmatter.split('\n')) {
|
|
92
|
+
const match = line.match(/^(\w+):\s*(.+)$/);
|
|
93
|
+
if (match) {
|
|
94
|
+
const [, key, value] = match;
|
|
95
|
+
switch (key) {
|
|
96
|
+
case 'name':
|
|
97
|
+
name = value;
|
|
98
|
+
break;
|
|
99
|
+
case 'description':
|
|
100
|
+
description = value;
|
|
101
|
+
break;
|
|
102
|
+
case 'category':
|
|
103
|
+
if (['welcome', 'followup', 'meeting', 'custom'].includes(value)) {
|
|
104
|
+
category = value;
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Extract variables from template content
|
|
113
|
+
const variableMatches = templateContent.match(/\{\{(\w+)\}\}/g);
|
|
114
|
+
if (variableMatches) {
|
|
115
|
+
variables = [...new Set(variableMatches.map((m) => m.replace(/[\{\}]/g, '')))];
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
id,
|
|
119
|
+
name,
|
|
120
|
+
description,
|
|
121
|
+
content: templateContent.trim(),
|
|
122
|
+
variables,
|
|
123
|
+
category,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Save a custom template
|
|
128
|
+
*/
|
|
129
|
+
save(template) {
|
|
130
|
+
const filePath = path.join(this.customDir, `${template.id}.txt`);
|
|
131
|
+
const frontmatter = [
|
|
132
|
+
'---',
|
|
133
|
+
`name: ${template.name}`,
|
|
134
|
+
`description: ${template.description}`,
|
|
135
|
+
`category: ${template.category}`,
|
|
136
|
+
'---',
|
|
137
|
+
].join('\n');
|
|
138
|
+
const content = `${frontmatter}\n\n${template.content}`;
|
|
139
|
+
fs.writeFileSync(filePath, content);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Delete a custom template
|
|
143
|
+
*/
|
|
144
|
+
delete(templateId) {
|
|
145
|
+
const customPath = path.join(this.customDir, `${templateId}.txt`);
|
|
146
|
+
if (fs.existsSync(customPath)) {
|
|
147
|
+
fs.unlinkSync(customPath);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* List all available templates
|
|
154
|
+
*/
|
|
155
|
+
list() {
|
|
156
|
+
const templates = [];
|
|
157
|
+
// Load defaults
|
|
158
|
+
if (fs.existsSync(this.defaultsDir)) {
|
|
159
|
+
const defaultFiles = fs.readdirSync(this.defaultsDir).filter((f) => f.endsWith('.txt'));
|
|
160
|
+
for (const file of defaultFiles) {
|
|
161
|
+
const id = path.basename(file, '.txt');
|
|
162
|
+
const template = this.load(id);
|
|
163
|
+
if (template)
|
|
164
|
+
templates.push(template);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Load customs (may override defaults)
|
|
168
|
+
if (fs.existsSync(this.customDir)) {
|
|
169
|
+
const customFiles = fs.readdirSync(this.customDir).filter((f) => f.endsWith('.txt'));
|
|
170
|
+
for (const file of customFiles) {
|
|
171
|
+
const id = path.basename(file, '.txt');
|
|
172
|
+
const template = this.load(id);
|
|
173
|
+
if (template) {
|
|
174
|
+
// Remove default if exists
|
|
175
|
+
const existingIndex = templates.findIndex((t) => t.id === id);
|
|
176
|
+
if (existingIndex !== -1) {
|
|
177
|
+
templates.splice(existingIndex, 1);
|
|
178
|
+
}
|
|
179
|
+
templates.push(template);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return templates;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Render a template with variables
|
|
187
|
+
*/
|
|
188
|
+
render(templateId, options) {
|
|
189
|
+
const template = this.load(templateId);
|
|
190
|
+
if (!template) {
|
|
191
|
+
throw new Error(`Template "${templateId}" not found`);
|
|
192
|
+
}
|
|
193
|
+
let content = template.content;
|
|
194
|
+
// Replace variables
|
|
195
|
+
for (const [key, value] of Object.entries(options.variables)) {
|
|
196
|
+
const regex = new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, 'g');
|
|
197
|
+
content = content.replace(regex, value);
|
|
198
|
+
}
|
|
199
|
+
// Handle missing variables
|
|
200
|
+
if (options.fallback !== undefined) {
|
|
201
|
+
content = content.replace(/\{\{\s*\w+\s*\}\}/g, options.fallback);
|
|
202
|
+
}
|
|
203
|
+
return content;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
exports.TemplateEngine = TemplateEngine;
|
|
207
|
+
// Singleton instance
|
|
208
|
+
let templateEngine = null;
|
|
209
|
+
function getTemplateEngine() {
|
|
210
|
+
if (!templateEngine) {
|
|
211
|
+
templateEngine = new TemplateEngine();
|
|
212
|
+
}
|
|
213
|
+
return templateEngine;
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/templates/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.test.d.ts","sourceRoot":"","sources":["../../src/templates/engine.test.ts"],"names":[],"mappings":""}
|