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.
Files changed (314) hide show
  1. package/.env.example +12 -0
  2. package/.github/workflows/ci.yml +66 -0
  3. package/.github/workflows/publish.yml +48 -0
  4. package/.husky/pre-commit +6 -0
  5. package/.prettierignore +4 -0
  6. package/.prettierrc +10 -0
  7. package/AGENTS.md +294 -0
  8. package/CHANGELOG.md +40 -0
  9. package/GIT_RELEASE.md +167 -0
  10. package/LICENSE +21 -0
  11. package/Makefile +30 -0
  12. package/NPM_PUBLISHING.md +230 -0
  13. package/PYEOF +0 -0
  14. package/README.md +295 -0
  15. package/TESTING-GUIDE.md +151 -0
  16. package/cmd/linkedin/main.go +9 -0
  17. package/dist/agent/action-executor.d.ts +81 -0
  18. package/dist/agent/action-executor.d.ts.map +1 -0
  19. package/dist/agent/action-executor.js +170 -0
  20. package/dist/agent/action-executor.js.map +1 -0
  21. package/dist/agent/action-executor.test.d.ts +2 -0
  22. package/dist/agent/action-executor.test.d.ts.map +1 -0
  23. package/dist/agent/action-executor.test.js +366 -0
  24. package/dist/agent/action-executor.test.js.map +1 -0
  25. package/dist/agent/claude-client.d.ts +74 -0
  26. package/dist/agent/claude-client.d.ts.map +1 -0
  27. package/dist/agent/claude-client.js +314 -0
  28. package/dist/agent/claude-client.js.map +1 -0
  29. package/dist/agent/claude-client.test.d.ts +2 -0
  30. package/dist/agent/claude-client.test.d.ts.map +1 -0
  31. package/dist/agent/claude-client.test.js +590 -0
  32. package/dist/agent/claude-client.test.js.map +1 -0
  33. package/dist/agent/dom-extractor.d.ts +50 -0
  34. package/dist/agent/dom-extractor.d.ts.map +1 -0
  35. package/dist/agent/dom-extractor.js +374 -0
  36. package/dist/agent/dom-extractor.js.map +1 -0
  37. package/dist/agent/dom-extractor.test.d.ts +7 -0
  38. package/dist/agent/dom-extractor.test.d.ts.map +1 -0
  39. package/dist/agent/dom-extractor.test.js +504 -0
  40. package/dist/agent/dom-extractor.test.js.map +1 -0
  41. package/dist/agent/extension-client.d.ts +75 -0
  42. package/dist/agent/extension-client.d.ts.map +1 -0
  43. package/dist/agent/extension-client.js +245 -0
  44. package/dist/agent/extension-client.js.map +1 -0
  45. package/dist/agent/index.d.ts +8 -0
  46. package/dist/agent/index.d.ts.map +1 -0
  47. package/dist/agent/index.js +16 -0
  48. package/dist/agent/index.js.map +1 -0
  49. package/dist/agent/page-agent.d.ts +76 -0
  50. package/dist/agent/page-agent.d.ts.map +1 -0
  51. package/dist/agent/page-agent.js +236 -0
  52. package/dist/agent/page-agent.js.map +1 -0
  53. package/dist/agent/types.d.ts +236 -0
  54. package/dist/agent/types.d.ts.map +1 -0
  55. package/dist/agent/types.js +37 -0
  56. package/dist/agent/types.js.map +1 -0
  57. package/dist/cli/agent-commands.d.ts +3 -0
  58. package/dist/cli/agent-commands.d.ts.map +1 -0
  59. package/dist/cli/agent-commands.js +250 -0
  60. package/dist/cli/agent-commands.js.map +1 -0
  61. package/dist/cli/auth.d.ts +3 -0
  62. package/dist/cli/auth.d.ts.map +1 -0
  63. package/dist/cli/auth.js +288 -0
  64. package/dist/cli/auth.js.map +1 -0
  65. package/dist/cli/company.d.ts +3 -0
  66. package/dist/cli/company.d.ts.map +1 -0
  67. package/dist/cli/company.js +55 -0
  68. package/dist/cli/company.js.map +1 -0
  69. package/dist/cli/connection.d.ts +3 -0
  70. package/dist/cli/connection.d.ts.map +1 -0
  71. package/dist/cli/connection.js +79 -0
  72. package/dist/cli/connection.js.map +1 -0
  73. package/dist/cli/index.d.ts +7 -0
  74. package/dist/cli/index.d.ts.map +1 -0
  75. package/dist/cli/index.js +17 -0
  76. package/dist/cli/index.js.map +1 -0
  77. package/dist/cli/messages.d.ts +3 -0
  78. package/dist/cli/messages.d.ts.map +1 -0
  79. package/dist/cli/messages.js +268 -0
  80. package/dist/cli/messages.js.map +1 -0
  81. package/dist/cli/profile.d.ts +3 -0
  82. package/dist/cli/profile.d.ts.map +1 -0
  83. package/dist/cli/profile.js +81 -0
  84. package/dist/cli/profile.js.map +1 -0
  85. package/dist/cli/profile.test.d.ts +2 -0
  86. package/dist/cli/profile.test.d.ts.map +1 -0
  87. package/dist/cli/profile.test.js +15 -0
  88. package/dist/cli/profile.test.js.map +1 -0
  89. package/dist/cli/reply.d.ts +3 -0
  90. package/dist/cli/reply.d.ts.map +1 -0
  91. package/dist/cli/reply.js +129 -0
  92. package/dist/cli/reply.js.map +1 -0
  93. package/dist/core/audit.d.ts +17 -0
  94. package/dist/core/audit.d.ts.map +1 -0
  95. package/dist/core/audit.js +121 -0
  96. package/dist/core/audit.js.map +1 -0
  97. package/dist/core/audit.test.d.ts +2 -0
  98. package/dist/core/audit.test.d.ts.map +1 -0
  99. package/dist/core/audit.test.js +142 -0
  100. package/dist/core/audit.test.js.map +1 -0
  101. package/dist/core/browser-cookies.d.ts +19 -0
  102. package/dist/core/browser-cookies.d.ts.map +1 -0
  103. package/dist/core/browser-cookies.js +181 -0
  104. package/dist/core/browser-cookies.js.map +1 -0
  105. package/dist/core/browser.d.ts +50 -0
  106. package/dist/core/browser.d.ts.map +1 -0
  107. package/dist/core/browser.js +318 -0
  108. package/dist/core/browser.js.map +1 -0
  109. package/dist/core/config.d.ts +20 -0
  110. package/dist/core/config.d.ts.map +1 -0
  111. package/dist/core/config.js +103 -0
  112. package/dist/core/config.js.map +1 -0
  113. package/dist/core/config.test.d.ts +2 -0
  114. package/dist/core/config.test.d.ts.map +1 -0
  115. package/dist/core/config.test.js +111 -0
  116. package/dist/core/config.test.js.map +1 -0
  117. package/dist/core/storage.d.ts +19 -0
  118. package/dist/core/storage.d.ts.map +1 -0
  119. package/dist/core/storage.js +124 -0
  120. package/dist/core/storage.js.map +1 -0
  121. package/dist/core/storage.test.d.ts +2 -0
  122. package/dist/core/storage.test.d.ts.map +1 -0
  123. package/dist/core/storage.test.js +142 -0
  124. package/dist/core/storage.test.js.map +1 -0
  125. package/dist/index.d.ts +3 -0
  126. package/dist/index.d.ts.map +1 -0
  127. package/dist/index.js +63 -0
  128. package/dist/index.js.map +1 -0
  129. package/dist/linkedin/auth.d.ts +22 -0
  130. package/dist/linkedin/auth.d.ts.map +1 -0
  131. package/dist/linkedin/auth.js +167 -0
  132. package/dist/linkedin/auth.js.map +1 -0
  133. package/dist/linkedin/company-extractor.d.ts +36 -0
  134. package/dist/linkedin/company-extractor.d.ts.map +1 -0
  135. package/dist/linkedin/company-extractor.js +211 -0
  136. package/dist/linkedin/company-extractor.js.map +1 -0
  137. package/dist/linkedin/company-extractor.test.d.ts +2 -0
  138. package/dist/linkedin/company-extractor.test.d.ts.map +1 -0
  139. package/dist/linkedin/company-extractor.test.js +52 -0
  140. package/dist/linkedin/company-extractor.test.js.map +1 -0
  141. package/dist/linkedin/connector.d.ts +45 -0
  142. package/dist/linkedin/connector.d.ts.map +1 -0
  143. package/dist/linkedin/connector.js +245 -0
  144. package/dist/linkedin/connector.js.map +1 -0
  145. package/dist/linkedin/message-sender.d.ts +32 -0
  146. package/dist/linkedin/message-sender.d.ts.map +1 -0
  147. package/dist/linkedin/message-sender.js +112 -0
  148. package/dist/linkedin/message-sender.js.map +1 -0
  149. package/dist/linkedin/messages.d.ts +78 -0
  150. package/dist/linkedin/messages.d.ts.map +1 -0
  151. package/dist/linkedin/messages.js +745 -0
  152. package/dist/linkedin/messages.js.map +1 -0
  153. package/dist/linkedin/profile.d.ts +37 -0
  154. package/dist/linkedin/profile.d.ts.map +1 -0
  155. package/dist/linkedin/profile.js +268 -0
  156. package/dist/linkedin/profile.js.map +1 -0
  157. package/dist/linkedin/profile.test.d.ts +2 -0
  158. package/dist/linkedin/profile.test.d.ts.map +1 -0
  159. package/dist/linkedin/profile.test.js +68 -0
  160. package/dist/linkedin/profile.test.js.map +1 -0
  161. package/dist/linkedin/reply.d.ts +21 -0
  162. package/dist/linkedin/reply.d.ts.map +1 -0
  163. package/dist/linkedin/reply.js +76 -0
  164. package/dist/linkedin/reply.js.map +1 -0
  165. package/dist/linkedin/selector-engine.d.ts +69 -0
  166. package/dist/linkedin/selector-engine.d.ts.map +1 -0
  167. package/dist/linkedin/selector-engine.js +339 -0
  168. package/dist/linkedin/selector-engine.js.map +1 -0
  169. package/dist/linkedin/selector-engine.test.d.ts +2 -0
  170. package/dist/linkedin/selector-engine.test.d.ts.map +1 -0
  171. package/dist/linkedin/selector-engine.test.js +135 -0
  172. package/dist/linkedin/selector-engine.test.js.map +1 -0
  173. package/dist/linkedin/selectors.d.ts +65 -0
  174. package/dist/linkedin/selectors.d.ts.map +1 -0
  175. package/dist/linkedin/selectors.js +261 -0
  176. package/dist/linkedin/selectors.js.map +1 -0
  177. package/dist/templates/engine.d.ts +37 -0
  178. package/dist/templates/engine.d.ts.map +1 -0
  179. package/dist/templates/engine.js +215 -0
  180. package/dist/templates/engine.js.map +1 -0
  181. package/dist/templates/engine.test.d.ts +2 -0
  182. package/dist/templates/engine.test.d.ts.map +1 -0
  183. package/dist/templates/engine.test.js +212 -0
  184. package/dist/templates/engine.test.js.map +1 -0
  185. package/dist/templates/index.d.ts +2 -0
  186. package/dist/templates/index.d.ts.map +1 -0
  187. package/dist/templates/index.js +7 -0
  188. package/dist/templates/index.js.map +1 -0
  189. package/dist/types/index.d.ts +113 -0
  190. package/dist/types/index.d.ts.map +1 -0
  191. package/dist/types/index.js +3 -0
  192. package/dist/types/index.js.map +1 -0
  193. package/dist/types/index.test.d.ts +2 -0
  194. package/dist/types/index.test.d.ts.map +1 -0
  195. package/dist/types/index.test.js +90 -0
  196. package/dist/types/index.test.js.map +1 -0
  197. package/dist/utils/paths.d.ts +8 -0
  198. package/dist/utils/paths.d.ts.map +1 -0
  199. package/dist/utils/paths.js +68 -0
  200. package/dist/utils/paths.js.map +1 -0
  201. package/dist/utils/rate-limiter.d.ts +22 -0
  202. package/dist/utils/rate-limiter.d.ts.map +1 -0
  203. package/dist/utils/rate-limiter.js +57 -0
  204. package/dist/utils/rate-limiter.js.map +1 -0
  205. package/dist/utils/retry.d.ts +18 -0
  206. package/dist/utils/retry.d.ts.map +1 -0
  207. package/dist/utils/retry.js +49 -0
  208. package/dist/utils/retry.js.map +1 -0
  209. package/docs/connection-command.md +52 -0
  210. package/docs/plans/2025-03-03-linkedin-cli-design.md +280 -0
  211. package/docs/plans/2025-03-03-linkedin-cli-implementation-plan.md +2087 -0
  212. package/docs/plans/2025-03-03-linkedin-cli-implementation.md +2420 -0
  213. package/docs/plans/2026-02-19-linkedin-connection-feature.md +596 -0
  214. package/docs/plans/2026-02-28-messages-send-feature.md +480 -0
  215. package/docs/plans/2026-02-28-messages-show-design.md +243 -0
  216. package/docs/plans/2026-03-03-linkedin-cli-oss-publishing-design.md +394 -0
  217. package/docs/plans/2026-03-03-linkedin-cli-oss-publishing-plan.md +1592 -0
  218. package/docs/superpowers/plans/2026-03-13-linkedin-automation-resilience-migration.md +425 -0
  219. package/docs/superpowers/plans/2026-03-13-playwright-fara-migration.md +1112 -0
  220. package/docs/superpowers/plans/2026-03-14-page-agent-plan.md +1598 -0
  221. package/docs/superpowers/plans/2026-03-15-company-profile-extraction.md +591 -0
  222. package/docs/superpowers/plans/2026-03-15-profile-extraction-plan.md +943 -0
  223. package/docs/superpowers/specs/2026-03-14-company-profile-extraction-design.md +371 -0
  224. package/docs/superpowers/specs/2026-03-14-page-agent-design.md +385 -0
  225. package/docs/superpowers/specs/2026-03-15-profile-extraction-design.md +409 -0
  226. package/eslint.config.mjs +58 -0
  227. package/go.mod +9 -0
  228. package/go.sum +10 -0
  229. package/import-cookies.js +376 -0
  230. package/internal/cmd/actions.go +123 -0
  231. package/internal/cmd/auth.go +108 -0
  232. package/internal/cmd/connect.go +42 -0
  233. package/internal/cmd/message.go +44 -0
  234. package/internal/cmd/people.go +454 -0
  235. package/internal/cmd/profiles.go +121 -0
  236. package/internal/cmd/root.go +89 -0
  237. package/internal/cmd/sequence.go +192 -0
  238. package/internal/config/config.go +187 -0
  239. package/internal/config/config_test.go +121 -0
  240. package/internal/config/profile.go +65 -0
  241. package/internal/linkedin/navigator.go +195 -0
  242. package/internal/linkedin/selectors.go +39 -0
  243. package/internal/linkedin/validator.go +69 -0
  244. package/internal/pinchtab/client.go +183 -0
  245. package/internal/pinchtab/client_test.go +67 -0
  246. package/internal/pinchtab/types.go +50 -0
  247. package/internal/ratelimit/limiter.go +115 -0
  248. package/internal/ratelimit/limits.go +32 -0
  249. package/package.json +67 -0
  250. package/release.sh +66 -0
  251. package/scripts/debug-linkedin.js +156 -0
  252. package/scripts/debug-login.js +193 -0
  253. package/scripts/extract-from-edge.js +96 -0
  254. package/scripts/import-cookies.js +101 -0
  255. package/scripts/poc-show-data.js +205 -0
  256. package/scripts/proof-of-access.js +87 -0
  257. package/scripts/prove-connection.js +110 -0
  258. package/scripts/show-linkedin-data.js +173 -0
  259. package/src/agent/action-executor.test.ts +464 -0
  260. package/src/agent/action-executor.ts +203 -0
  261. package/src/agent/claude-client.test.ts +707 -0
  262. package/src/agent/claude-client.ts +422 -0
  263. package/src/agent/dom-extractor.test.ts +574 -0
  264. package/src/agent/dom-extractor.ts +437 -0
  265. package/src/agent/extension-client.ts +306 -0
  266. package/src/agent/index.ts +28 -0
  267. package/src/agent/page-agent.ts +292 -0
  268. package/src/agent/types.ts +288 -0
  269. package/src/cli/agent-commands.ts +274 -0
  270. package/src/cli/auth.ts +343 -0
  271. package/src/cli/company.ts +66 -0
  272. package/src/cli/connection.ts +89 -0
  273. package/src/cli/index.ts +7 -0
  274. package/src/cli/messages.ts +338 -0
  275. package/src/cli/profile.test.ts +14 -0
  276. package/src/cli/profile.ts +95 -0
  277. package/src/cli/reply.ts +110 -0
  278. package/src/core/audit.test.ts +134 -0
  279. package/src/core/audit.ts +98 -0
  280. package/src/core/browser-cookies.ts +203 -0
  281. package/src/core/browser.ts +304 -0
  282. package/src/core/config.test.ts +90 -0
  283. package/src/core/config.ts +81 -0
  284. package/src/core/storage.test.ts +129 -0
  285. package/src/core/storage.ts +100 -0
  286. package/src/index.ts +70 -0
  287. package/src/linkedin/auth.ts +218 -0
  288. package/src/linkedin/company-extractor.test.ts +58 -0
  289. package/src/linkedin/company-extractor.ts +222 -0
  290. package/src/linkedin/connector.ts +336 -0
  291. package/src/linkedin/message-sender.ts +141 -0
  292. package/src/linkedin/messages.ts +894 -0
  293. package/src/linkedin/profile.test.ts +79 -0
  294. package/src/linkedin/profile.ts +314 -0
  295. package/src/linkedin/reply.ts +96 -0
  296. package/src/linkedin/selector-engine.test.ts +167 -0
  297. package/src/linkedin/selector-engine.ts +393 -0
  298. package/src/linkedin/selectors.ts +268 -0
  299. package/src/templates/defaults/followup.txt +14 -0
  300. package/src/templates/defaults/meeting.txt +16 -0
  301. package/src/templates/defaults/welcome.txt +14 -0
  302. package/src/templates/engine.test.ts +228 -0
  303. package/src/templates/engine.ts +208 -0
  304. package/src/templates/index.ts +1 -0
  305. package/src/types/index.test.ts +94 -0
  306. package/src/types/index.ts +143 -0
  307. package/src/types/sql.js.d.ts +23 -0
  308. package/src/utils/paths.ts +33 -0
  309. package/src/utils/rate-limiter.ts +75 -0
  310. package/src/utils/retry.ts +78 -0
  311. package/test-cli.sh +85 -0
  312. package/test-real-data.sh +97 -0
  313. package/tsconfig.json +23 -0
  314. 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)