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,394 @@
|
|
|
1
|
+
# LinkedIn CLI - Open Source Publishing Design
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-03-03
|
|
4
|
+
**Status:** Approved
|
|
5
|
+
**Author:** Thaddeus Liu
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
This design document outlines the preparations needed to publish the LinkedIn CLI tool as an open source project for the community. The goal is comprehensive quality without over-engineering.
|
|
10
|
+
|
|
11
|
+
## Goals
|
|
12
|
+
|
|
13
|
+
1. **Code Quality** - Ensure the codebase is well-tested and maintainable
|
|
14
|
+
2. **Open Source Ready** - Include all standard OSS metadata and contribution guidelines
|
|
15
|
+
3. **CI/CD Pipeline** - Automated testing and builds for community confidence
|
|
16
|
+
4. **Developer Experience** - Clear documentation for users and contributors
|
|
17
|
+
5. **YAGNI** - Avoid over-engineering; add complexity only when needed
|
|
18
|
+
|
|
19
|
+
## Non-Goals
|
|
20
|
+
|
|
21
|
+
- Release automation (manual releases for now)
|
|
22
|
+
- Docker containerization
|
|
23
|
+
- Homebrew distribution
|
|
24
|
+
- Web UI or GUI
|
|
25
|
+
- Database support
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Architecture
|
|
30
|
+
|
|
31
|
+
### Current Structure (No Changes)
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
linkedin-cli/
|
|
35
|
+
├── cmd/linkedin/ # Entry point
|
|
36
|
+
├── internal/
|
|
37
|
+
│ ├── cmd/ # Cobra commands
|
|
38
|
+
│ ├── config/ # Profile & rate limit persistence
|
|
39
|
+
│ ├── linkedin/ # LinkedIn page interactions
|
|
40
|
+
│ ├── pinchtab/ # PinchTab HTTP client
|
|
41
|
+
│ └── ratelimit/ # Rate limiting logic
|
|
42
|
+
├── docs/
|
|
43
|
+
│ └── plans/ # Design and implementation docs
|
|
44
|
+
├── go.mod
|
|
45
|
+
└── README.md
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Decision:** Keep existing package structure - it follows Go best practices.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Components
|
|
53
|
+
|
|
54
|
+
### 1. Testing Coverage
|
|
55
|
+
|
|
56
|
+
**Current State:**
|
|
57
|
+
- `config/` - 4 tests ✅
|
|
58
|
+
- `pinchtab/` - 3 tests ✅
|
|
59
|
+
- `linkedin/` - 0 tests ❌
|
|
60
|
+
- `ratelimit/` - 0 tests ❌
|
|
61
|
+
|
|
62
|
+
**Required:**
|
|
63
|
+
|
|
64
|
+
| Package | Tests to Add | Priority |
|
|
65
|
+
|---------|-------------|----------|
|
|
66
|
+
| `linkedin/validator.go` | URL validation (valid, invalid, edge cases) | High |
|
|
67
|
+
| `linkedin/navigator.go` | Mock client tests for button finding, modal handling | High |
|
|
68
|
+
| `ratelimit/limiter.go` | Rate limit logic, daily/weekly reset | High |
|
|
69
|
+
| `ratelimit/limits.go` | Default/conservative limits verification | Medium |
|
|
70
|
+
|
|
71
|
+
**Approach:**
|
|
72
|
+
- Use table-driven tests for validators
|
|
73
|
+
- Create mock PinchTab client for navigator tests
|
|
74
|
+
- Test rate limit boundary conditions
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### 2. Open Source Metadata
|
|
79
|
+
|
|
80
|
+
**Files to Create:**
|
|
81
|
+
|
|
82
|
+
| File | Purpose | Priority |
|
|
83
|
+
|------|---------|----------|
|
|
84
|
+
| `LICENSE` | MIT License | Critical |
|
|
85
|
+
| `CONTRIBUTING.md` | How to contribute | High |
|
|
86
|
+
| `.github/ISSUE_TEMPLATE/bug_report.md` | Bug reports | Medium |
|
|
87
|
+
| `.github/ISSUE_TEMPLATE/feature_request.md` | Feature requests | Medium |
|
|
88
|
+
| `.github/PULL_REQUEST_TEMPLATE.md` | PR guidelines | Medium |
|
|
89
|
+
| `.github/CODEOWNERS` | Default reviewers | Low |
|
|
90
|
+
|
|
91
|
+
**LICENSE Content:**
|
|
92
|
+
```
|
|
93
|
+
MIT License - matches PinchTab's license
|
|
94
|
+
Copyright (c) 2026 Thaddeus Liu
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**CONTRIBUTING.md Sections:**
|
|
98
|
+
- Development setup (Go version, dependencies)
|
|
99
|
+
- Running tests
|
|
100
|
+
- Code style guidelines
|
|
101
|
+
- Pull request process
|
|
102
|
+
- Issue reporting guidelines
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### 3. CI/CD Pipeline
|
|
107
|
+
|
|
108
|
+
**GitHub Actions Workflow:**
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
name: CI
|
|
112
|
+
|
|
113
|
+
on:
|
|
114
|
+
push:
|
|
115
|
+
branches: [main]
|
|
116
|
+
pull_request:
|
|
117
|
+
branches: [main]
|
|
118
|
+
|
|
119
|
+
jobs:
|
|
120
|
+
test:
|
|
121
|
+
runs-on: ubuntu-latest
|
|
122
|
+
steps:
|
|
123
|
+
- uses: actions/checkout@v4
|
|
124
|
+
- uses: actions/setup-go@v5
|
|
125
|
+
with:
|
|
126
|
+
go-version: '1.21'
|
|
127
|
+
- run: go test -v ./...
|
|
128
|
+
- run: go test -coverprofile=coverage.out ./...
|
|
129
|
+
- uses: codecov/codecov-action@v4
|
|
130
|
+
|
|
131
|
+
build:
|
|
132
|
+
runs-on: ${{ matrix.os }}
|
|
133
|
+
strategy:
|
|
134
|
+
matrix:
|
|
135
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
136
|
+
steps:
|
|
137
|
+
- uses: actions/checkout@v4
|
|
138
|
+
- uses: actions/setup-go@v5
|
|
139
|
+
with:
|
|
140
|
+
go-version: '1.21'
|
|
141
|
+
- run: go build -o linkedin-cli ./cmd/linkedin
|
|
142
|
+
|
|
143
|
+
lint:
|
|
144
|
+
runs-on: ubuntu-latest
|
|
145
|
+
steps:
|
|
146
|
+
- uses: actions/checkout@v4
|
|
147
|
+
- uses: actions/setup-go@v5
|
|
148
|
+
- uses: golangci/golangci-lint-action@v4
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**What's NOT included:**
|
|
152
|
+
- No release automation
|
|
153
|
+
- No Docker builds
|
|
154
|
+
- No deployment steps
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### 4. Version Management
|
|
159
|
+
|
|
160
|
+
**Implementation:**
|
|
161
|
+
|
|
162
|
+
```go
|
|
163
|
+
// cmd/linkedin/main.go
|
|
164
|
+
var Version = "dev"
|
|
165
|
+
|
|
166
|
+
func main() {
|
|
167
|
+
cmd.Version = Version
|
|
168
|
+
cmd.Execute()
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Build with version:**
|
|
173
|
+
```bash
|
|
174
|
+
go build -ldflags "-X main.Version=$(git describe --tags)" ./cmd/linkedin
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Usage:**
|
|
178
|
+
```bash
|
|
179
|
+
linkedin --version
|
|
180
|
+
# Output: linkedin version 0.1.0
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
### 5. Structured Logging
|
|
186
|
+
|
|
187
|
+
**Replace `fmt.Printf` with `log/slog`:**
|
|
188
|
+
|
|
189
|
+
```go
|
|
190
|
+
import "log/slog"
|
|
191
|
+
|
|
192
|
+
var logger = slog.New(slog.NewTextHandler(os.Stdout, nil))
|
|
193
|
+
|
|
194
|
+
// Before
|
|
195
|
+
fmt.Printf("Sending connection request to %s...\n", profileURL)
|
|
196
|
+
|
|
197
|
+
// After
|
|
198
|
+
logger.Info("sending connection request", "url", profileURL)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Benefits:**
|
|
202
|
+
- JSON output option for CI/CD
|
|
203
|
+
- Log levels (Debug, Info, Warn, Error)
|
|
204
|
+
- Consistent formatting
|
|
205
|
+
- Built into Go 1.21+ (no external dependency)
|
|
206
|
+
|
|
207
|
+
**Migration:**
|
|
208
|
+
- Replace user-facing output with `fmt` (keep CLI UX)
|
|
209
|
+
- Use `slog` for debug/verbose logging only
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
### 6. Testable Time Handling
|
|
214
|
+
|
|
215
|
+
**Problem:** Hard-coded `time.Sleep()` in navigator
|
|
216
|
+
|
|
217
|
+
**Solution:**
|
|
218
|
+
|
|
219
|
+
```go
|
|
220
|
+
// internal/linkedin/navigator.go
|
|
221
|
+
type Sleeper interface {
|
|
222
|
+
Sleep(time.Duration)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
type RealSleeper struct{}
|
|
226
|
+
func (RealSleeper) Sleep(d time.Duration) { time.Sleep(d) }
|
|
227
|
+
|
|
228
|
+
type NoOpSleeper struct{}
|
|
229
|
+
func (NoOpSleeper) Sleep(time.Duration) {}
|
|
230
|
+
|
|
231
|
+
type Navigator struct {
|
|
232
|
+
client *pinchtab.Client
|
|
233
|
+
sleeper Sleeper
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
func NewNavigator(client *pinchtab.Client) *Navigator {
|
|
237
|
+
return &Navigator{
|
|
238
|
+
client: client,
|
|
239
|
+
sleeper: RealSleeper{},
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// In tests
|
|
244
|
+
navigator := NewNavigator(mockClient)
|
|
245
|
+
navigator.sleeper = NoOpSleeper{}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Not over-engineering:**
|
|
249
|
+
- Simple interface, no DI framework
|
|
250
|
+
- Default injection in constructor
|
|
251
|
+
- Tests override as needed
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
### 7. Documentation
|
|
256
|
+
|
|
257
|
+
**README.md Additions:**
|
|
258
|
+
|
|
259
|
+
1. **Badges** (top of README)
|
|
260
|
+
- Build status
|
|
261
|
+
- Test coverage
|
|
262
|
+
- License
|
|
263
|
+
- Go version
|
|
264
|
+
|
|
265
|
+
2. **"Why This Tool"** section
|
|
266
|
+
- Problem statement
|
|
267
|
+
- How it differs from alternatives
|
|
268
|
+
|
|
269
|
+
3. **"How It Works"** diagram
|
|
270
|
+
- Architecture overview
|
|
271
|
+
|
|
272
|
+
4. **Troubleshooting** section
|
|
273
|
+
- Common issues and solutions
|
|
274
|
+
|
|
275
|
+
5. **Development** section
|
|
276
|
+
- Setup instructions
|
|
277
|
+
- Running tests
|
|
278
|
+
- Contributing guidelines
|
|
279
|
+
|
|
280
|
+
**New Documentation:**
|
|
281
|
+
|
|
282
|
+
| File | Purpose |
|
|
283
|
+
|------|---------|
|
|
284
|
+
| `docs/ARCHITECTURE.md` | Package organization, data flow |
|
|
285
|
+
| `docs/RATE_LIMITS.md` | LinkedIn safety guidelines |
|
|
286
|
+
| `docs/SECURITY.md` | Security considerations |
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
### 8. Code Quality
|
|
291
|
+
|
|
292
|
+
**Refactors:**
|
|
293
|
+
|
|
294
|
+
| Change | Impact | Effort |
|
|
295
|
+
|--------|--------|--------|
|
|
296
|
+
| Extract magic numbers to constants | Low | Low |
|
|
297
|
+
| Add context to error messages | Medium | Low |
|
|
298
|
+
| Improve user-facing errors | Medium | Low |
|
|
299
|
+
| Consistent naming conventions | Low | Low |
|
|
300
|
+
|
|
301
|
+
**Not Changing:**
|
|
302
|
+
- Package structure (already good)
|
|
303
|
+
- Command structure (clean)
|
|
304
|
+
- Overall architecture (solid)
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Error Handling
|
|
309
|
+
|
|
310
|
+
**Current State:**
|
|
311
|
+
```go
|
|
312
|
+
return fmt.Errorf("failed to navigate: %w", err)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Improvements:**
|
|
316
|
+
```go
|
|
317
|
+
// Add context
|
|
318
|
+
return fmt.Errorf("navigating to profile %s: %w", profileURL, err)
|
|
319
|
+
|
|
320
|
+
// User-friendly errors
|
|
321
|
+
if strings.Contains(err.Error(), "connect button not found") {
|
|
322
|
+
return fmt.Errorf("could not send request: profile may already be connected")
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Testing Strategy
|
|
329
|
+
|
|
330
|
+
### Unit Tests
|
|
331
|
+
|
|
332
|
+
**Coverage Target:** 70%+ for core logic
|
|
333
|
+
|
|
334
|
+
**Test Files to Add:**
|
|
335
|
+
- `internal/linkedin/validator_test.go`
|
|
336
|
+
- `internal/linkedin/navigator_test.go`
|
|
337
|
+
- `internal/ratelimit/limiter_test.go`
|
|
338
|
+
- `internal/ratelimit/limits_test.go`
|
|
339
|
+
|
|
340
|
+
### Integration Tests
|
|
341
|
+
|
|
342
|
+
**Manual test script** (already exists: `test_auth.sh`)
|
|
343
|
+
|
|
344
|
+
**Future:** Add automated integration tests with mock LinkedIn (not in scope)
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Trade-offs
|
|
349
|
+
|
|
350
|
+
### Approach Considered
|
|
351
|
+
|
|
352
|
+
| Option | Pros | Cons | Decision |
|
|
353
|
+
|--------|------|------|----------|
|
|
354
|
+
| Minimal (just LICENSE) | Fast | Not community-ready | ❌ Rejected |
|
|
355
|
+
| Comprehensive (this design) | Professional, maintainable | More work upfront | ✅ Selected |
|
|
356
|
+
| Full enterprise (CI/CD, releases, benchmarks) | Production-ready | Over-engineered for v1 | ❌ Rejected |
|
|
357
|
+
|
|
358
|
+
### Why Not Over-Engineer?
|
|
359
|
+
|
|
360
|
+
- No users yet (validate demand first)
|
|
361
|
+
- Can add features based on community feedback
|
|
362
|
+
- Keep maintenance burden low
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Implementation Plan
|
|
367
|
+
|
|
368
|
+
See: `docs/plans/YYYY-MM-DD-linkedin-cli-oss-publishing-plan.md`
|
|
369
|
+
|
|
370
|
+
**Phases:**
|
|
371
|
+
|
|
372
|
+
1. **Phase 1 (Critical):** LICENSE, tests, version
|
|
373
|
+
2. **Phase 2 (Important):** CI/CD, logging, OSS metadata
|
|
374
|
+
3. **Phase 3 (Nice to have):** Docs, refactors
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Success Criteria
|
|
379
|
+
|
|
380
|
+
- [ ] All packages have tests (70%+ coverage)
|
|
381
|
+
- [ ] MIT LICENSE file present
|
|
382
|
+
- [ ] CI runs tests on every PR
|
|
383
|
+
- [ ] `linkedin --version` works
|
|
384
|
+
- [ ] CONTRIBUTING.md exists
|
|
385
|
+
- [ ] README has badges and examples
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## References
|
|
390
|
+
|
|
391
|
+
- [Go Project Layout](https://github.com/golang-standards/project-layout)
|
|
392
|
+
- [Go Testing Best Practices](https://github.com/golang/go/wiki/TestComments)
|
|
393
|
+
- [GitHub Actions for Go](https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go)
|
|
394
|
+
- [MIT License](https://opensource.org/licenses/MIT)
|