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
package/.env.example
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Dashscope Claude API Configuration
|
|
2
|
+
# Get your API key from: https://dashscope.aliyun.com/
|
|
3
|
+
DASHSCOPE_API_KEY=your_key_here
|
|
4
|
+
DASHSCOPE_BASE_URL=https://coding.dashscope.aliyuncs.com/apps/anthropic/v1
|
|
5
|
+
DASHSCOPE_MODEL=qwen3.5-plus
|
|
6
|
+
|
|
7
|
+
# Page Agent Extension Configuration (for fast mode)
|
|
8
|
+
# Get auth token from extension side panel
|
|
9
|
+
PAGE_AGENT_AUTH_TOKEN=your_extension_auth_token
|
|
10
|
+
|
|
11
|
+
# Page Agent CDP Port (default: 9222)
|
|
12
|
+
PAGE_AGENT_CDP_PORT=9222
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
node-version: [18.x, 20.x, 22.x]
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
22
|
+
uses: actions/setup-node@v4
|
|
23
|
+
with:
|
|
24
|
+
node-version: ${{ matrix.node-version }}
|
|
25
|
+
cache: 'npm'
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: npm ci
|
|
29
|
+
|
|
30
|
+
- name: Type check
|
|
31
|
+
run: npm run typecheck
|
|
32
|
+
|
|
33
|
+
- name: Lint
|
|
34
|
+
run: npm run lint
|
|
35
|
+
continue-on-error: true
|
|
36
|
+
|
|
37
|
+
- name: Format check
|
|
38
|
+
run: npm run format:check
|
|
39
|
+
|
|
40
|
+
- name: Run tests with coverage
|
|
41
|
+
run: npm run test:coverage
|
|
42
|
+
|
|
43
|
+
build:
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
needs: test
|
|
46
|
+
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v4
|
|
49
|
+
|
|
50
|
+
- name: Use Node.js 20.x
|
|
51
|
+
uses: actions/setup-node@v4
|
|
52
|
+
with:
|
|
53
|
+
node-version: 20.x
|
|
54
|
+
cache: 'npm'
|
|
55
|
+
|
|
56
|
+
- name: Install dependencies
|
|
57
|
+
run: npm ci
|
|
58
|
+
|
|
59
|
+
- name: Build
|
|
60
|
+
run: npm run build
|
|
61
|
+
|
|
62
|
+
- name: Verify dist output
|
|
63
|
+
run: |
|
|
64
|
+
test -d dist/
|
|
65
|
+
test -f dist/index.js
|
|
66
|
+
echo "Build verified successfully"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*' # Trigger on version tags like v1.0.0
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Use Node.js 20.x
|
|
16
|
+
uses: actions/setup-node@v4
|
|
17
|
+
with:
|
|
18
|
+
node-version: 20.x
|
|
19
|
+
cache: 'npm'
|
|
20
|
+
cache-dependency-path: package-lock.json
|
|
21
|
+
registry-url: 'https://registry.npmjs.org'
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: npm ci
|
|
25
|
+
|
|
26
|
+
- name: Type check
|
|
27
|
+
run: npm run typecheck
|
|
28
|
+
|
|
29
|
+
- name: Lint
|
|
30
|
+
run: npm run lint
|
|
31
|
+
|
|
32
|
+
- name: Run tests with coverage
|
|
33
|
+
run: npm run test:coverage
|
|
34
|
+
|
|
35
|
+
- name: Build
|
|
36
|
+
run: npm run build
|
|
37
|
+
|
|
38
|
+
- name: Publish to npm
|
|
39
|
+
run: npm publish --access public
|
|
40
|
+
env:
|
|
41
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
42
|
+
|
|
43
|
+
- name: Create GitHub Release
|
|
44
|
+
uses: softprops/action-gh-release@v1
|
|
45
|
+
with:
|
|
46
|
+
generate_release_notes: true
|
|
47
|
+
env:
|
|
48
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package/.prettierignore
ADDED
package/.prettierrc
ADDED
package/AGENTS.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# AGENTS.md - LinkedIn CLI Development Guide
|
|
2
|
+
|
|
3
|
+
This document provides essential information for AI coding agents working on the LinkedIn CLI codebase.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
LinkedIn CLI is a Go-based command-line tool for LinkedIn automation using PinchTab (browser automation HTTP server). It sends connection requests and direct messages with built-in rate limiting for safety.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Go 1.21+, Cobra CLI, PinchTab HTTP client
|
|
10
|
+
|
|
11
|
+
## Build, Test, and Lint Commands
|
|
12
|
+
|
|
13
|
+
### Build
|
|
14
|
+
```bash
|
|
15
|
+
make build # Build binary → linkedin-cli
|
|
16
|
+
go build -o linkedin-cli ./cmd/linkedin
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Test
|
|
20
|
+
```bash
|
|
21
|
+
make test # Run all tests
|
|
22
|
+
go test -v ./... # Run all tests with verbose output
|
|
23
|
+
|
|
24
|
+
# Run single test
|
|
25
|
+
go test -v -run TestFunctionName ./path/to/package
|
|
26
|
+
go test -v -run TestProfileCRUD ./internal/config
|
|
27
|
+
|
|
28
|
+
# Run tests in specific package
|
|
29
|
+
go test -v ./internal/config
|
|
30
|
+
go test -v ./internal/pinchtab
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Lint and Format
|
|
34
|
+
```bash
|
|
35
|
+
make lint # Run golangci-lint
|
|
36
|
+
make fmt # Format code with go fmt
|
|
37
|
+
golangci-lint run # Run linter directly
|
|
38
|
+
go fmt ./... # Format all files
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Clean
|
|
42
|
+
```bash
|
|
43
|
+
make clean # Remove binary and clean build cache
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Project Structure
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
linkedin-cli/
|
|
50
|
+
├── cmd/linkedin/main.go # Entry point
|
|
51
|
+
├── internal/ # Private packages
|
|
52
|
+
│ ├── cmd/ # CLI commands (Cobra)
|
|
53
|
+
│ │ ├── root.go # Base command, flags, helpers
|
|
54
|
+
│ │ ├── auth.go # Authentication flow
|
|
55
|
+
│ │ ├── connect.go # Send connection requests
|
|
56
|
+
│ │ ├── message.go # Send direct messages
|
|
57
|
+
│ │ └── profiles.go # Profile management
|
|
58
|
+
│ ├── config/ # Configuration persistence
|
|
59
|
+
│ │ ├── config.go # Manager for profile/rate limits
|
|
60
|
+
│ │ └── profile.go # Profile and RateLimits types
|
|
61
|
+
│ ├── linkedin/ # LinkedIn page interactions
|
|
62
|
+
│ │ ├── navigator.go # Page interaction logic
|
|
63
|
+
│ │ ├── selectors.go # CSS selectors (fragile!)
|
|
64
|
+
│ │ └── validator.go # URL validation
|
|
65
|
+
│ ├── pinchtab/ # PinchTab HTTP client
|
|
66
|
+
│ │ ├── client.go # API wrapper
|
|
67
|
+
│ │ └── types.go # Instance, Tab, Snapshot types
|
|
68
|
+
│ └── ratelimit/ # Rate limiting logic
|
|
69
|
+
│ ├── limiter.go # Check/Record methods
|
|
70
|
+
│ └── limits.go # Default/Conservative limits
|
|
71
|
+
├── go.mod
|
|
72
|
+
├── Makefile
|
|
73
|
+
└── README.md
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Code Style Guidelines
|
|
77
|
+
|
|
78
|
+
### Imports
|
|
79
|
+
Organize imports in three groups, separated by blank lines:
|
|
80
|
+
1. Standard library
|
|
81
|
+
2. External packages
|
|
82
|
+
3. Internal packages
|
|
83
|
+
|
|
84
|
+
```go
|
|
85
|
+
import (
|
|
86
|
+
"fmt"
|
|
87
|
+
"os"
|
|
88
|
+
"time"
|
|
89
|
+
|
|
90
|
+
"github.com/spf13/cobra"
|
|
91
|
+
|
|
92
|
+
"github.com/thaddeus-git/linkedin-cli/internal/config"
|
|
93
|
+
"github.com/thaddeus-git/linkedin-cli/internal/pinchtab"
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Naming Conventions
|
|
98
|
+
- **Packages:** lowercase, single word if possible (e.g., `config`, `cmd`, `pinchtab`)
|
|
99
|
+
- **Types:** PascalCase for exported, camelCase for private
|
|
100
|
+
- **Functions/Methods:** PascalCase for exported, camelCase for private
|
|
101
|
+
- **Variables:** camelCase, descriptive but concise
|
|
102
|
+
- **Constants:** PascalCase or UPPER_SNAKE_CASE
|
|
103
|
+
- **Interfaces:** typically end with `-er` (e.g., `Navigator`, `Sleeper`)
|
|
104
|
+
|
|
105
|
+
### Comments
|
|
106
|
+
- Start with the name of the thing being commented
|
|
107
|
+
- Use complete sentences
|
|
108
|
+
- No inline comments explaining obvious code
|
|
109
|
+
|
|
110
|
+
```go
|
|
111
|
+
// Manager handles configuration and state
|
|
112
|
+
type Manager struct {
|
|
113
|
+
configDir string
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// NewManager creates a new config manager
|
|
117
|
+
func NewManager() (*Manager, error) {
|
|
118
|
+
// Implementation
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Error Handling
|
|
123
|
+
- Wrap errors with context using `fmt.Errorf` and `%w`
|
|
124
|
+
- Provide actionable error messages
|
|
125
|
+
- Use `exitWithError()` in CLI commands for user-facing errors
|
|
126
|
+
|
|
127
|
+
```go
|
|
128
|
+
// Good: wrap with context
|
|
129
|
+
if err := client.Navigate(url); err != nil {
|
|
130
|
+
return fmt.Errorf("failed to navigate: %w", err)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Good: user-facing error in CLI
|
|
134
|
+
if profileName == "" {
|
|
135
|
+
exitWithError("Profile name is required (--profile or LINKEDIN_PROFILE)")
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Avoid: bare error returns without context
|
|
139
|
+
return err
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Types and Structures
|
|
143
|
+
- Use structs for data, interfaces for behavior
|
|
144
|
+
- Prefer composition over inheritance
|
|
145
|
+
- Keep structs small and focused
|
|
146
|
+
|
|
147
|
+
```go
|
|
148
|
+
// Good: focused struct with clear purpose
|
|
149
|
+
type Profile struct {
|
|
150
|
+
Name string `json:"name"`
|
|
151
|
+
CreatedAt time.Time `json:"created_at"`
|
|
152
|
+
LastUsed time.Time `json:"last_used"`
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Testing Guidelines
|
|
157
|
+
|
|
158
|
+
### Test Structure
|
|
159
|
+
- Place tests in `*_test.go` files alongside source code
|
|
160
|
+
- Use `t.TempDir()` for test isolation (auto-cleanup)
|
|
161
|
+
- Follow AAA pattern: Arrange, Act, Assert
|
|
162
|
+
|
|
163
|
+
```go
|
|
164
|
+
func TestProfileCRUD(t *testing.T) {
|
|
165
|
+
// Arrange
|
|
166
|
+
tempDir := t.TempDir()
|
|
167
|
+
mgr := &Manager{configDir: tempDir}
|
|
168
|
+
profile := &Profile{Name: "test"}
|
|
169
|
+
|
|
170
|
+
// Act
|
|
171
|
+
err := mgr.SaveProfile(profile)
|
|
172
|
+
|
|
173
|
+
// Assert
|
|
174
|
+
if err != nil {
|
|
175
|
+
t.Fatalf("failed to save: %v", err)
|
|
176
|
+
}
|
|
177
|
+
if !mgr.ProfileExists("test") {
|
|
178
|
+
t.Error("profile should exist")
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Table-Driven Tests
|
|
184
|
+
Use for testing multiple scenarios:
|
|
185
|
+
|
|
186
|
+
```go
|
|
187
|
+
func TestValidateProfileURL(t *testing.T) {
|
|
188
|
+
tests := []struct {
|
|
189
|
+
name string
|
|
190
|
+
input string
|
|
191
|
+
want string
|
|
192
|
+
wantErr bool
|
|
193
|
+
}{
|
|
194
|
+
{"full URL", "https://linkedin.com/in/john", "https://linkedin.com/in/john", false},
|
|
195
|
+
{"username only", "john", "https://linkedin.com/in/john", false},
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
for _, tt := range tests {
|
|
199
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
200
|
+
got, err := ValidateProfileURL(tt.input)
|
|
201
|
+
if (err != nil) != tt.wantErr {
|
|
202
|
+
t.Errorf("ValidateProfileURL() error = %v", err)
|
|
203
|
+
}
|
|
204
|
+
if got != tt.want {
|
|
205
|
+
t.Errorf("ValidateProfileURL() = %v, want %v", got, tt.want)
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Architecture Patterns
|
|
213
|
+
|
|
214
|
+
### CLI Commands
|
|
215
|
+
- Use Cobra framework for all commands
|
|
216
|
+
- Define commands in `init()` function
|
|
217
|
+
- Extract logic to separate `run*` functions
|
|
218
|
+
- Use `exitWithError()` for errors, not `log.Fatal()`
|
|
219
|
+
|
|
220
|
+
```go
|
|
221
|
+
func init() {
|
|
222
|
+
rootCmd.AddCommand(connectCmd)
|
|
223
|
+
connectCmd.Flags().StringVarP(&connectURL, "url", "u", "", "LinkedIn profile URL")
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
var connectCmd = &cobra.Command{
|
|
227
|
+
Use: "connect",
|
|
228
|
+
Short: "Send a connection request",
|
|
229
|
+
Run: runConnect,
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
func runConnect(cmd *cobra.Command, args []string) {
|
|
233
|
+
// Validate, execute, handle errors
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### HTTP Client Pattern
|
|
238
|
+
- Wrap external APIs in dedicated client packages
|
|
239
|
+
- Use struct with methods for API calls
|
|
240
|
+
- Return errors with context
|
|
241
|
+
|
|
242
|
+
```go
|
|
243
|
+
type Client struct {
|
|
244
|
+
baseURL string
|
|
245
|
+
client *http.Client
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
func (c *Client) Navigate(url string) error {
|
|
249
|
+
return c.post("/navigate", map[string]string{"url": url}, nil)
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Configuration Management
|
|
254
|
+
- Store in `~/.linkedin-cli/` directory
|
|
255
|
+
- JSON format for persistence
|
|
256
|
+
- Separate files for profiles and rate limits
|
|
257
|
+
|
|
258
|
+
## Important Notes
|
|
259
|
+
|
|
260
|
+
### LinkedIn Selectors
|
|
261
|
+
- Selectors in `internal/linkedin/selectors.go` are **fragile**
|
|
262
|
+
- LinkedIn changes their UI frequently
|
|
263
|
+
- These may need updates when LinkedIn updates
|
|
264
|
+
|
|
265
|
+
### Rate Limiting
|
|
266
|
+
- Default: 20 connections/day, 100/week, 50 messages/day
|
|
267
|
+
- Delays: 3-8 seconds between actions
|
|
268
|
+
- Stored per profile in `~/.linkedin-cli/ratelimit.json`
|
|
269
|
+
|
|
270
|
+
### PinchTab Integration
|
|
271
|
+
- Requires PinchTab running on `http://localhost:9867`
|
|
272
|
+
- Install: `curl -fsSL https://pinchtab.com/install.sh | bash`
|
|
273
|
+
- No built-in session persistence - user must re-login manually
|
|
274
|
+
|
|
275
|
+
### No External Dependencies
|
|
276
|
+
- Only use `github.com/spf13/cobra` for CLI
|
|
277
|
+
- Use standard library for everything else
|
|
278
|
+
- Avoid adding unnecessary dependencies
|
|
279
|
+
|
|
280
|
+
## Development Workflow
|
|
281
|
+
|
|
282
|
+
1. **Make changes** → Edit relevant files in `internal/`
|
|
283
|
+
2. **Format code** → `make fmt` or `go fmt ./...`
|
|
284
|
+
3. **Run tests** → `make test` or `go test -v ./...`
|
|
285
|
+
4. **Lint check** → `make lint`
|
|
286
|
+
5. **Build** → `make build`
|
|
287
|
+
6. **Test manually** → `./linkedin-cli --help`
|
|
288
|
+
|
|
289
|
+
## Debugging
|
|
290
|
+
|
|
291
|
+
- Use `--verbose` flag for detailed output
|
|
292
|
+
- Use `--dry-run` flag to preview actions without executing
|
|
293
|
+
- Check PinchTab logs if browser automation fails
|
|
294
|
+
- Use `curl http://localhost:9867/health` to verify PinchTab is running
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.0.0] - 2025-03-14
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- **`agent ext:connect` removed** - Merged into `agent connect`
|
|
10
|
+
- Old: `linkedin agent ext:connect <url>`
|
|
11
|
+
- New: `linkedin agent connect <url>` (auto-detects extension)
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **`agent connect` now auto-detects extension** - Uses fast extension mode when CDP browser available
|
|
16
|
+
- Falls back to Playwright when no CDP browser found
|
|
17
|
+
- Add `--playwright` flag to force Playwright mode
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **`agent playwright` command** - Explicit Playwright mode (old `connect` behavior)
|
|
22
|
+
- **`PAGE_AGENT_AUTH_TOKEN` env var** - Configure extension auth token
|
|
23
|
+
- **CDP auto-detection** - Automatically uses fastest available method
|
|
24
|
+
|
|
25
|
+
### Migration Guide
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Before (v0.3.0)
|
|
29
|
+
linkedin agent ext:connect https://linkedin.com/in/user/
|
|
30
|
+
|
|
31
|
+
# After (v1.0.0)
|
|
32
|
+
linkedin agent connect https://linkedin.com/in/user/
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Prerequisites for Extension Mode
|
|
36
|
+
|
|
37
|
+
1. Install [Page Agent Extension](https://chromewebstore.google.com/detail/page-agent-ext/akldabonmimlicnjlflnapfeklbfemhj)
|
|
38
|
+
2. Start Chrome with CDP: `chrome --remote-debugging-port=9222`
|
|
39
|
+
3. Log into LinkedIn in that browser
|
|
40
|
+
4. Set `DASHSCOPE_API_KEY` env var
|
package/GIT_RELEASE.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Git Release Guide
|
|
2
|
+
|
|
3
|
+
This guide walks you through committing and pushing all changes to GitHub.
|
|
4
|
+
|
|
5
|
+
## Quick Release
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# 1. Navigate to worktree
|
|
9
|
+
cd /Users/thaddeus/projects/linkedin-automation/.worktrees/linkedin-automation-cli
|
|
10
|
+
|
|
11
|
+
# 2. Install new dependencies
|
|
12
|
+
npm install
|
|
13
|
+
|
|
14
|
+
# 3. Run all quality checks
|
|
15
|
+
npm run typecheck
|
|
16
|
+
npm run lint
|
|
17
|
+
npm run format
|
|
18
|
+
npm run test:coverage
|
|
19
|
+
|
|
20
|
+
# 4. Build the project
|
|
21
|
+
npm run build
|
|
22
|
+
|
|
23
|
+
# 5. Stage all changes
|
|
24
|
+
git add -A
|
|
25
|
+
|
|
26
|
+
# 6. Commit
|
|
27
|
+
git commit -m "feat: add startup best practices (tests, CI/CD, linting)
|
|
28
|
+
|
|
29
|
+
- Added Vitest for unit testing with 80% coverage threshold
|
|
30
|
+
- Added ESLint + Prettier for code quality
|
|
31
|
+
- Added GitHub Actions CI/CD workflows
|
|
32
|
+
- Added Husky pre-commit hooks
|
|
33
|
+
- Created test files for core modules:
|
|
34
|
+
- storage.test.ts (encryption, secure storage)
|
|
35
|
+
- config.test.ts (configuration management)
|
|
36
|
+
- audit.test.ts (audit logging)
|
|
37
|
+
- selector-engine.test.ts (multi-layer selectors)
|
|
38
|
+
- engine.test.ts (template rendering)
|
|
39
|
+
- Fixed duplicate code in browser.ts and cli/auth.ts
|
|
40
|
+
- Updated package.json with new scripts and dependencies
|
|
41
|
+
- Added npm publishing guide
|
|
42
|
+
|
|
43
|
+
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
|
|
44
|
+
|
|
45
|
+
# 7. Push to main branch
|
|
46
|
+
git push origin main
|
|
47
|
+
|
|
48
|
+
# 8. Create and push version tag (triggers auto-publish)
|
|
49
|
+
npm version minor # or patch/major as needed
|
|
50
|
+
git push origin --tags
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Step-by-Step Verification
|
|
54
|
+
|
|
55
|
+
### 1. Check Git Status
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git status
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
You should see all the new files staged for commit.
|
|
62
|
+
|
|
63
|
+
### 2. Verify Tests Pass
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm run test:coverage
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Expected output:
|
|
70
|
+
- All tests pass
|
|
71
|
+
- Coverage meets 80% threshold
|
|
72
|
+
|
|
73
|
+
### 3. Verify Build
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm run build
|
|
77
|
+
node dist/index.js --help
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Should display CLI help text.
|
|
81
|
+
|
|
82
|
+
### 4. Verify CI Configuration
|
|
83
|
+
|
|
84
|
+
Check that `.github/workflows/ci.yml` exists and contains:
|
|
85
|
+
- Test job (runs on push/PR)
|
|
86
|
+
- Build job (runs after tests pass)
|
|
87
|
+
|
|
88
|
+
### 5. Commit and Push
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
git add -A
|
|
92
|
+
git commit -m "feat: add startup best practices"
|
|
93
|
+
git push origin main
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 6. Create Release Tag
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# This bumps version, creates commit, and creates tag
|
|
100
|
+
npm version minor
|
|
101
|
+
|
|
102
|
+
# Push the tag (triggers GitHub Actions publish workflow)
|
|
103
|
+
git push && git push --tags
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Verify on GitHub
|
|
107
|
+
|
|
108
|
+
1. Go to: https://github.com/thaddeus-git/linkedin-cli
|
|
109
|
+
2. Check that all files are visible
|
|
110
|
+
3. Check Actions tab for CI run
|
|
111
|
+
4. After tag push, check Releases for auto-created release
|
|
112
|
+
|
|
113
|
+
## Manual npm Publish (if needed)
|
|
114
|
+
|
|
115
|
+
If GitHub Actions doesn't auto-publish:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Login (one-time)
|
|
119
|
+
npm login
|
|
120
|
+
|
|
121
|
+
# Dry run
|
|
122
|
+
npm publish --dry-run
|
|
123
|
+
|
|
124
|
+
# Publish
|
|
125
|
+
npm publish --access public
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Files Added Summary
|
|
129
|
+
|
|
130
|
+
### Configuration Files
|
|
131
|
+
- `vitest.config.ts` - Vitest test configuration
|
|
132
|
+
- `eslint.config.mjs` - ESLint configuration
|
|
133
|
+
- `.prettierrc` - Prettier formatting rules
|
|
134
|
+
- `.prettierignore` - Files to ignore for formatting
|
|
135
|
+
- `.husky/pre-commit` - Pre-commit hook script
|
|
136
|
+
|
|
137
|
+
### GitHub Actions
|
|
138
|
+
- `.github/workflows/ci.yml` - CI pipeline
|
|
139
|
+
- `.github/workflows/publish.yml` - npm publish pipeline
|
|
140
|
+
|
|
141
|
+
### Test Files
|
|
142
|
+
- `src/core/storage.test.ts`
|
|
143
|
+
- `src/core/config.test.ts`
|
|
144
|
+
- `src/core/audit.test.ts`
|
|
145
|
+
- `src/linkedin/selector-engine.test.ts`
|
|
146
|
+
- `src/templates/engine.test.ts`
|
|
147
|
+
|
|
148
|
+
### Documentation
|
|
149
|
+
- `NPM_PUBLISHING.md` - npm publishing guide
|
|
150
|
+
- `GIT_RELEASE.md` - This file
|
|
151
|
+
- Updated `README.md` with development workflow
|
|
152
|
+
|
|
153
|
+
### Code Fixes
|
|
154
|
+
- Fixed duplicate code in `src/core/browser.ts`
|
|
155
|
+
- Fixed duplicate code in `src/cli/auth.ts`
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
**Troubleshooting:**
|
|
160
|
+
|
|
161
|
+
| Issue | Solution |
|
|
162
|
+
|-------|----------|
|
|
163
|
+
| Tests fail | Run `npm run test:watch` to debug |
|
|
164
|
+
| Lint errors | Run `npm run lint:fix` to auto-fix |
|
|
165
|
+
| Format errors | Run `npm run format` |
|
|
166
|
+
| Coverage too low | Add more tests for uncovered code |
|
|
167
|
+
| Git push rejected | Run `git pull --rebase` first |
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thaddeus Liu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Makefile
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.PHONY: build test clean install lint
|
|
2
|
+
|
|
3
|
+
BINARY_NAME=linkedin-cli
|
|
4
|
+
MAIN_PACKAGE=./cmd/linkedin
|
|
5
|
+
|
|
6
|
+
build:
|
|
7
|
+
go build -o $(BINARY_NAME) $(MAIN_PACKAGE)
|
|
8
|
+
|
|
9
|
+
test:
|
|
10
|
+
go test -v ./...
|
|
11
|
+
|
|
12
|
+
clean:
|
|
13
|
+
rm -f $(BINARY_NAME)
|
|
14
|
+
go clean
|
|
15
|
+
|
|
16
|
+
install: build
|
|
17
|
+
mv $(BINARY_NAME) $(GOPATH)/bin/linkedin
|
|
18
|
+
|
|
19
|
+
dev:
|
|
20
|
+
go run $(MAIN_PACKAGE)
|
|
21
|
+
|
|
22
|
+
lint:
|
|
23
|
+
golangci-lint run
|
|
24
|
+
|
|
25
|
+
fmt:
|
|
26
|
+
go fmt ./...
|
|
27
|
+
|
|
28
|
+
deps:
|
|
29
|
+
go mod download
|
|
30
|
+
go mod tidy
|