careerclaw-js 0.11.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/CHANGELOG.md +362 -0
- package/README.md +348 -0
- package/SECURITY.md +156 -0
- package/SKILL.md +463 -0
- package/dist/adapters/hackernews.d.ts +36 -0
- package/dist/adapters/hackernews.d.ts.map +1 -0
- package/dist/adapters/hackernews.js +164 -0
- package/dist/adapters/hackernews.js.map +1 -0
- package/dist/adapters/index.d.ts +10 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +9 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/remoteok.d.ts +35 -0
- package/dist/adapters/remoteok.d.ts.map +1 -0
- package/dist/adapters/remoteok.js +212 -0
- package/dist/adapters/remoteok.js.map +1 -0
- package/dist/briefing.d.ts +81 -0
- package/dist/briefing.d.ts.map +1 -0
- package/dist/briefing.js +152 -0
- package/dist/briefing.js.map +1 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +235 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +91 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +126 -0
- package/dist/config.js.map +1 -0
- package/dist/core/text-processing.d.ts +62 -0
- package/dist/core/text-processing.d.ts.map +1 -0
- package/dist/core/text-processing.js +187 -0
- package/dist/core/text-processing.js.map +1 -0
- package/dist/drafting.d.ts +28 -0
- package/dist/drafting.d.ts.map +1 -0
- package/dist/drafting.js +116 -0
- package/dist/drafting.js.map +1 -0
- package/dist/gap.d.ts +27 -0
- package/dist/gap.d.ts.map +1 -0
- package/dist/gap.js +90 -0
- package/dist/gap.js.map +1 -0
- package/dist/license.d.ts +40 -0
- package/dist/license.d.ts.map +1 -0
- package/dist/license.js +122 -0
- package/dist/license.js.map +1 -0
- package/dist/llm-enhance.d.ts +69 -0
- package/dist/llm-enhance.d.ts.map +1 -0
- package/dist/llm-enhance.js +376 -0
- package/dist/llm-enhance.js.map +1 -0
- package/dist/matching/engine.d.ts +31 -0
- package/dist/matching/engine.d.ts.map +1 -0
- package/dist/matching/engine.js +51 -0
- package/dist/matching/engine.js.map +1 -0
- package/dist/matching/index.d.ts +8 -0
- package/dist/matching/index.d.ts.map +1 -0
- package/dist/matching/index.js +8 -0
- package/dist/matching/index.js.map +1 -0
- package/dist/matching/scoring.d.ts +84 -0
- package/dist/matching/scoring.d.ts.map +1 -0
- package/dist/matching/scoring.js +184 -0
- package/dist/matching/scoring.js.map +1 -0
- package/dist/models.d.ts +221 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +28 -0
- package/dist/models.js.map +1 -0
- package/dist/requirements.d.ts +22 -0
- package/dist/requirements.d.ts.map +1 -0
- package/dist/requirements.js +30 -0
- package/dist/requirements.js.map +1 -0
- package/dist/resume-intel.d.ts +40 -0
- package/dist/resume-intel.d.ts.map +1 -0
- package/dist/resume-intel.js +111 -0
- package/dist/resume-intel.js.map +1 -0
- package/dist/sources.d.ts +32 -0
- package/dist/sources.d.ts.map +1 -0
- package/dist/sources.js +72 -0
- package/dist/sources.js.map +1 -0
- package/dist/tracking.d.ts +68 -0
- package/dist/tracking.d.ts.map +1 -0
- package/dist/tracking.js +140 -0
- package/dist/tracking.js.map +1 -0
- package/package.json +58 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to careerclaw-js are documented here.
|
|
4
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
|
+
Versioning follows [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## [0.11.0] — 2026-03-05
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `src/license.ts` — `checkLicense(key, options?)` → `Promise<LicenseResult>`:
|
|
18
|
+
Gumroad Pro license validation with 7-day offline cache; raw key never
|
|
19
|
+
written to disk — only `sha256(key)` cached; `{ valid: false, source: "none" }`
|
|
20
|
+
returned immediately when `CAREERCLAW_GUMROAD_PRODUCT_ID` is unset so Free
|
|
21
|
+
tier users are unaffected; `fetchFn` and `cachePath` injectable for offline tests
|
|
22
|
+
- `src/tests/license.test.ts` — 12 offline tests covering the missing product ID
|
|
23
|
+
guard, fresh/stale/missing/wrong-key cache branches, all Gumroad API response
|
|
24
|
+
variants (success, refunded, chargebacked, 404, 500), never-throws invariant,
|
|
25
|
+
and hash safety (raw key must not appear in cache file)
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- `src/briefing.ts` — bare `proKey` presence check replaced with
|
|
30
|
+
`await checkLicense(proKey)`; `isProActive` is now driven by
|
|
31
|
+
`licenseResult.valid`; `BriefingOptions` gains `licenseFetchFn` and
|
|
32
|
+
`licenseCachePath` for test injection
|
|
33
|
+
- `src/config.ts` — added `GUMROAD_PRODUCT_ID`, `GUMROAD_API_BASE`,
|
|
34
|
+
`LICENSE_CACHE_TTL_MS` (7 days in ms); `POLAR_PRODUCT_SLUG` and
|
|
35
|
+
`POLAR_API_BASE` retained and marked `@deprecated` with
|
|
36
|
+
`TODO: Phase 11-Polar` migration comment
|
|
37
|
+
- `.env.example` — Pro purchase URL updated to Gumroad;
|
|
38
|
+
`CAREERCLAW_GUMROAD_PRODUCT_ID=` added with dashboard instructions
|
|
39
|
+
|
|
40
|
+
### Security
|
|
41
|
+
|
|
42
|
+
- Raw license key is never written to disk; only `sha256(key)` is persisted
|
|
43
|
+
- Gumroad validation uses `increment_uses_count=false` — validation calls
|
|
44
|
+
do not consume customer usage quota
|
|
45
|
+
|
|
46
|
+
### Notes
|
|
47
|
+
|
|
48
|
+
270 tests across 16 files, all passing. `tsc --noEmit` clean.
|
|
49
|
+
No new production dependencies. Polar migration path preserved via
|
|
50
|
+
`@deprecated` constants and `TODO: Phase 11-Polar` comment in `config.ts`.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## [0.10.0] — 2026-03-05
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- `src/llm-enhance.ts` — `enhanceDraft(job, profile, resumeIntel, draft, gapKeywords, options)`:
|
|
59
|
+
Pro tier LLM-powered outreach draft generation; parses `LLM_CHAIN` into a left-to-right failover
|
|
60
|
+
list; per-candidate retry loop up to `LLM_MAX_RETRIES`; circuit breaker opens after
|
|
61
|
+
`LLM_CIRCUIT_BREAKER_FAILS` consecutive failures; `_chainOverride` for offline testing
|
|
62
|
+
- `src/tests/llm-enhance.test.ts` — 12 offline tests covering Anthropic path, OpenAI path,
|
|
63
|
+
HTTP error fallback, unparseable response fallback, never-throws invariant, circuit breaker
|
|
64
|
+
call-count bounds, privacy (raw resume text must not appear in outbound request payload),
|
|
65
|
+
and empty-chain no-op
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- `src/briefing.ts` — `BriefingOptions` gains `resumeIntel?: ResumeIntelligence`,
|
|
70
|
+
`proKey?: string`, `enhanceFetchFn?`; draft stage converted to `async`; calls `enhanceDraft()`
|
|
71
|
+
per match when `proKey` is set — falls back to deterministic baseline on any LLM failure
|
|
72
|
+
- `src/cli.ts` — calls `buildResumeIntelligence()` after resume load; passes `resumeIntel` and
|
|
73
|
+
`PRO_KEY` to `runBriefing()`; Pro enhancement path is now live from the CLI
|
|
74
|
+
|
|
75
|
+
### Security
|
|
76
|
+
|
|
77
|
+
- LLM prompt contains only extracted keyword signals (`impact_signals` ≤ 12 tokens,
|
|
78
|
+
`gap_keywords` ≤ 6 tokens) — raw resume text and `resume_summary` are never sent to
|
|
79
|
+
any external API
|
|
80
|
+
|
|
81
|
+
### Notes
|
|
82
|
+
|
|
83
|
+
258 tests across 15 files, all passing. `tsc --noEmit` clean. No new production dependencies.
|
|
84
|
+
License validation (`CAREERCLAW_PRO_KEY` checked against Gumroad) is deferred to Phase 11 (v0.11.0) —
|
|
85
|
+
`proKey` is trusted by presence only in this version.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## [0.8.1] — 2026-03-04
|
|
90
|
+
|
|
91
|
+
### Fixed
|
|
92
|
+
|
|
93
|
+
- **Dentist problem**: replaced additive composite score with a multiplicative model (`total = sqrt(keyword) × qualityBase`);
|
|
94
|
+
zero keyword overlap now always produces a score of 0.0 regardless of metadata alignment — irrelevant jobs can no longer float to the
|
|
95
|
+
top on neutral dimension scores
|
|
96
|
+
- Signal gate added to `rankJobs()`: jobs with keyword score below `minKeywordScore` (default: 0.01) are hard-filtered before ranking
|
|
97
|
+
- `matched_keywords` and `gap_keywords` were hardcoded empty in `engine.ts`; now wired from `compositeScore()` output
|
|
98
|
+
- HTML entity `/` (and all `&#x[hex];` sequences) now decoded in `stripHtml()` — fixes `ML/AI` appearing in HN job titles and
|
|
99
|
+
gap tokens
|
|
100
|
+
- `stripHtml()` now applied to parsed HN job title and company name (previously body text only)
|
|
101
|
+
- Contraction tokens (`i'm`, `i've`, `don't`, etc.) added to `STOPWORDS` — eliminates noise in gap keyword output
|
|
102
|
+
|
|
103
|
+
### Changed
|
|
104
|
+
|
|
105
|
+
- `MatchBreakdown` field names renamed: `keyword_score → keyword`, `experience_score → experience`, `salary_score → salary`,
|
|
106
|
+
`work_mode_score → work_mode`
|
|
107
|
+
- `compositeScore()` return type extended: now includes `matched` and `gaps` string arrays alongside `total` and `breakdown`
|
|
108
|
+
- Default LLM model updated: `claude-sonnet-4-20250514` → `claude-haiku-4-5-20251001`
|
|
109
|
+
- `scripts/smoke_briefing.ts` refactored to multi-profile mode; select profile via `PROFILE=0|1|2` env var
|
|
110
|
+
|
|
111
|
+
### Added
|
|
112
|
+
|
|
113
|
+
- `.env.example` — full credential reference (OpenClaw gateway, agent LLM keys, Pro license, draft enhancement keys, failover chain config)
|
|
114
|
+
- `SECURITY.md` — local-first security architecture, credential handling policy, external network call inventory, LLM data disclosure
|
|
115
|
+
- `src/config.ts`: `LLM_ANTHROPIC_KEY`, `LLM_OPENAI_KEY`, `LLM_CHAIN`, `LLM_MAX_RETRIES`, `LLM_CIRCUIT_BREAKER_FAILS`
|
|
116
|
+
- `scripts/smoke_llm.ts` — LLM connectivity and Pro key smoke test; `npm run smoke:llm`
|
|
117
|
+
|
|
118
|
+
### Notes
|
|
119
|
+
|
|
120
|
+
234 tests across 13 files, all passing. No new production dependencies.
|
|
121
|
+
`MatchBreakdown` rename is a breaking internal change — no public API consumers exist prior to the CLI (Phase 9).
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## [0.8.0] — 2026-03-04
|
|
126
|
+
|
|
127
|
+
### Added
|
|
128
|
+
|
|
129
|
+
- `src/briefing.ts` — `runBriefing(profile, options)`: end-to-end pipeline orchestrator; four timed stages (fetch, rank, draft,
|
|
130
|
+
persist); skill-first design — profile is a parameter, never loaded from disk; `fetchFn` and `repo` are injectable for testing; dry-run
|
|
131
|
+
suppresses all writes while keeping counts accurate; catastrophic fetch failure returns empty result rather than throwing;
|
|
132
|
+
`run_id` generated via `crypto.randomUUID()` (Node built-in); `version` read from package.json at runtime via `createRequire`
|
|
133
|
+
- `BriefingResult` interface added to `src/models.ts` — stable JSON output schema for OpenClaw/ClawHub agent consumption: `run`,
|
|
134
|
+
`matches`, `drafts`, `tracking`, `dry_run`
|
|
135
|
+
- `src/tests/briefing.test.ts` — 17 integration tests; all offline via stubbed `fetchFn` and `tmpdir`-backed `TrackingRepository`
|
|
136
|
+
|
|
137
|
+
### Fixed
|
|
138
|
+
|
|
139
|
+
- `draftOutreach()` and `upsertEntries()` were being passed `ScoredJob` where `NormalizedJob` was required; `ScoredJob` wraps `NormalizedJob`
|
|
140
|
+
as `.job` and does not extend it — both callsites corrected to unwrap `.job`; corresponding test assertion corrected from
|
|
141
|
+
`scored.job_id` to `scored.job.job_id`
|
|
142
|
+
|
|
143
|
+
### Notes
|
|
144
|
+
|
|
145
|
+
243 tests across 13 files, all passing. No new dependencies. The pipeline is now end-to-end complete. Every module from Phase 1 through
|
|
146
|
+
Phase 7 is wired into a single callable function. Phase 9 (CLI entry point) will expose `runBriefing()` as an executable with `--dry-run`,
|
|
147
|
+
`--top-k`, and `--json` flags, matching the Python careerclaw CLI surface.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## [0.7.0] — 2026-03-04
|
|
152
|
+
|
|
153
|
+
### Added
|
|
154
|
+
|
|
155
|
+
- `src/tracking.ts` — `TrackingRepository` class managing two runtime files under `.careerclaw/`:
|
|
156
|
+
- `tracking.json` — keyed object of `TrackingEntry` records; new jobs saved with status `"saved"`; re-encountered jobs have
|
|
157
|
+
`last_seen_at` and `updated_at` refreshed, all other fields (including user-set status) preserved; one disk write per
|
|
158
|
+
`upsertEntries()` call regardless of batch size
|
|
159
|
+
- `runs.jsonl` — append-only newline-delimited JSON log; one `BriefingRun` per line via `appendRun()`
|
|
160
|
+
- Constructor accepts `trackingPath`, `runsPath`, and `dryRun` overrides; defaults from `config.ts`
|
|
161
|
+
- `load()` returns empty store on a missing or corrupt file — no crash
|
|
162
|
+
- `ensureDir()` creates parent directory recursively on first writing
|
|
163
|
+
- `upsertEntries()` returns accurate `{ created, already_present }` counts even in dry-run mode
|
|
164
|
+
- `ScoredJob?` parameter on `upsertEntries()` reserved for Phase 8 score snapshot attachment
|
|
165
|
+
- `src/tests/tracking.test.ts` — 23 unit tests; per-test isolated `tmpdir` directories; covers load, upsert (new + re-encounter),
|
|
166
|
+
disk writes, JSONL append, and dry-run suppression
|
|
167
|
+
|
|
168
|
+
### Notes
|
|
169
|
+
|
|
170
|
+
226 tests across 12 files, all passing. No new dependencies. The `TrackingRepository` is the last infrastructure module before the
|
|
171
|
+
Phase 8 briefing orchestrator wires everything into the full pipeline.
|
|
172
|
+
Dry-run mode is a first-class concern throughout: all writing paths are suppressed, all read and count paths remain fully functional, matching
|
|
173
|
+
the Python careerclaw `--dry-run` behaviour.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## [0.6.0] — 2026-03-04
|
|
178
|
+
|
|
179
|
+
### Added
|
|
180
|
+
|
|
181
|
+
- `src/drafting.ts` — `draftOutreach(job, profile, matchedKeywords)`:
|
|
182
|
+
deterministic outreach email generator; subject line follows `Interest in {title} at {company}` format; body inserts experience
|
|
183
|
+
clause (years or "extensive experience" fallback), up to 3 matched keywords formatted as natural language, and 3 fixed
|
|
184
|
+
reliability/collaboration/instrumentation bullet highlights; word count 161–168 words depending on a keyword path, inside 150–250 word
|
|
185
|
+
spec; `llm_enhanced: false` always; `formatList()` helper for natural-language list formatting
|
|
186
|
+
- `src/tests/drafting.test.ts` — 20 unit tests
|
|
187
|
+
|
|
188
|
+
### Fixed
|
|
189
|
+
|
|
190
|
+
- Deterministic template body was 127 words on the first pass — below the 150-word MVP spec floor; fixed by expanding opening and closing
|
|
191
|
+
paragraphs; both keyword and fallback paths re-verified at 161 and 168 words respectively
|
|
192
|
+
|
|
193
|
+
### Notes
|
|
194
|
+
|
|
195
|
+
203 tests across 11 files, all passing. No new dependencies. `llm_enhanced` is always false in this phase — LLM enhancement
|
|
196
|
+
(Phase 7+) will set this flag to true when the Pro key is configured and the call succeeds. The deterministic template remains the permanent
|
|
197
|
+
fallback for the Free tier and for LLM failure scenarios.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## [0.5.0] — 2026-03-04
|
|
202
|
+
|
|
203
|
+
### Added
|
|
204
|
+
|
|
205
|
+
- `src/requirements.ts` — `extractJobRequirements(job)`: tokenizes job title and description into a deduplicated keyword and phrase corpus for
|
|
206
|
+
use as the job-side input to gap analysis
|
|
207
|
+
- `src/resume-intel.ts` — `buildResumeIntelligence(params)`:
|
|
208
|
+
section-aware keyword/phrase extraction across skills (weight 1.0), summary + target_roles (weight 0.8), and optional resume_text (weight
|
|
209
|
+
0.6); per-keyword weight is the max across sections; `impact_signals` are keywords with weight >= 0.8; `source` flag indicates which inputs
|
|
210
|
+
contributed; PR-E fix (skills injection) baked in from day one
|
|
211
|
+
- `src/gap.ts` — `gapAnalysis(intel, job)`: weighted `fit_score` (sum of matched keyword_weights / job keyword count), `fit_score_unweighted`
|
|
212
|
+
(Jaccard), `signals` (resume ∩ job), `gaps` (job − resume), and top-5 `summary` for display
|
|
213
|
+
- `JobRequirements`, `ResumeIntelligence`, `GapAnalysisResult` interfaces added to `src/models.ts`; `ResumeIntelligence` schema is
|
|
214
|
+
JSON-compatible with Python careerclaw output
|
|
215
|
+
- `src/tests/resume-intel.test.ts` — 19 unit tests
|
|
216
|
+
- `src/tests/gap.test.ts` — 16 unit tests
|
|
217
|
+
|
|
218
|
+
### Fixed
|
|
219
|
+
|
|
220
|
+
- Added `"am"` to `STOPWORDS` in `src/core/text-processing.ts` — missed from an initial set alongside `"is"`, `"are"`, `"was"`, `"were"`, `"be"`;
|
|
221
|
+
caught by resume-intel stopword filter test
|
|
222
|
+
|
|
223
|
+
### Notes
|
|
224
|
+
|
|
225
|
+
183 tests across 10 files, all passing. No new dependencies. The `fit_score` weighted formula is identical to the Python careerclaw
|
|
226
|
+
implementation: skills listed in UserProfile. Skills receive weight 1.0 and will never appear as gaps. The practical fit_score ceiling against
|
|
227
|
+
real job postings is ~50% due to company names and location tokens in the denominator.
|
|
228
|
+
|
|
229
|
+
### Future Work
|
|
230
|
+
|
|
231
|
+
- CorpusCache: Entropy-based token filtering (IDF) to suppress tokens that appear in >80% of fetched jobs. Gated behind corpus_size >= 50.
|
|
232
|
+
Planned for a future release after job tracking accumulates sufficient data.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## [0.4.0] — 2026-03-04
|
|
237
|
+
|
|
238
|
+
### Added
|
|
239
|
+
|
|
240
|
+
- `src/matching/scoring.ts` — four pure scoring functions:
|
|
241
|
+
`scoreKeyword()` (Jaccard token overlap, returns matched and gap keyword lists), `scoreExperience()` (clamped linear user/job years ratio),
|
|
242
|
+
`scoreSalary()` (proportional against a user minimum),
|
|
243
|
+
`scoreWorkMode()` (exact=1.0, hybrid=0.5 partial, mismatch=0.0);
|
|
244
|
+
`compositeScore()` with `WEIGHTS` (keyword=0.50, experience=0.20, salary=0.15, work_mode=0.15)
|
|
245
|
+
- `src/matching/engine.ts` — `rankJobs(jobs, profile, topK)` scores all jobs, sorts descending by composite score, returns top-K `ScoredJob[]`
|
|
246
|
+
with full breakdown and keyword lists; scores rounded to 4 d.p.
|
|
247
|
+
- `src/matching/index.ts` — barrel export for matching public API
|
|
248
|
+
- `src/tests/matching.scoring.test.ts` — 36 unit tests
|
|
249
|
+
- `src/tests/matching.engine.test.ts` — 10 end-to-end tests using real model types
|
|
250
|
+
|
|
251
|
+
### Notes
|
|
252
|
+
|
|
253
|
+
148 tests across 8 files, all passing. No new dependencies. Neutral score (0.5) is used for all null data cases, so missing job fields
|
|
254
|
+
neither reward nor penalize the composite — consistent with Python careerclaw behavior. Gap keywords from `scoreKeyword()` feed directly
|
|
255
|
+
into Phase 5 gap analysis.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## [0.3.0] — 2026-03-04
|
|
260
|
+
|
|
261
|
+
### Added
|
|
262
|
+
|
|
263
|
+
- `src/sources.ts` — source aggregation layer: `fetchAllJobs()` runs both
|
|
264
|
+
adapters concurrently with per-source error isolation; `deduplicate()`
|
|
265
|
+
removes duplicate `job_id` entries (first-seen wins); returns `FetchResult`
|
|
266
|
+
with job list, per-source counts, and error map for run instrumentation
|
|
267
|
+
- `src/core/text-processing.ts` — shared text processing library:
|
|
268
|
+
`STOPWORDS` (English function words and full PR-E recruitment boilerplate set),
|
|
269
|
+
`SECTION_WEIGHTS` (skills=1.0, summary=0.8, experience=0.6, education=0.4),
|
|
270
|
+
`tokenize()`, `tokenizeUnique()`, `extractPhrases()`,
|
|
271
|
+
`extractPhrasesFromText()`, `tokenOverlap()`, `matchedTokens()`,
|
|
272
|
+
`gapTokens()`
|
|
273
|
+
- `src/tests/text-processing.test.ts` — 34 unit tests
|
|
274
|
+
- `src/tests/sources.test.ts` — 10 unit tests (ESM-safe adapter stubs via
|
|
275
|
+
`vi.doMock()` + `vi.resetModules()`; no network)
|
|
276
|
+
|
|
277
|
+
### Notes
|
|
278
|
+
|
|
279
|
+
102 tests across 6 files, all passing. No new production dependencies.
|
|
280
|
+
`SECTION_WEIGHTS` is defined here and will be consumed by resume intelligence
|
|
281
|
+
in Phase 5. The `FetchResult.errors` map feeds into `BriefingRun.sources`
|
|
282
|
+
instrumentation in Phase 8.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## [0.2.0] — 2026-03-03
|
|
287
|
+
|
|
288
|
+
### Added
|
|
289
|
+
|
|
290
|
+
- `src/adapters/remoteok.ts` — RemoteOK RSS adapter; parses RSS XML into
|
|
291
|
+
`NormalizedJob[]`; `parseRss()` exported separately from `fetchRemoteOkJobs()`
|
|
292
|
+
so contract tests call pure parsing functions without network mocking
|
|
293
|
+
- `src/adapters/hackernews.ts` — HN Firebase adapter; fetches "Who is Hiring?"
|
|
294
|
+
thread comments in parallel; `parseComment()` exported for offline testing;
|
|
295
|
+
handles deleted/dead items gracefully
|
|
296
|
+
- `src/adapters/index.ts` — barrel export for all adapter public API
|
|
297
|
+
- `src/tests/fixtures/remoteok.xml` — RSS fixture covering full fields, no-salary,
|
|
298
|
+
and k-suffix salary variants
|
|
299
|
+
- `src/tests/fixtures/hn-thread.json` — HN thread fixture with `kids` array
|
|
300
|
+
- `src/tests/fixtures/hn-comment-job.json` — HN job comment fixture (pipe-separated
|
|
301
|
+
header, HTML body, salary, experience years)
|
|
302
|
+
- `src/tests/fixtures/hn-comment-deleted.json` — deleted comment fixture (adapter
|
|
303
|
+
must skip)
|
|
304
|
+
- `src/tests/adapters.remoteok.test.ts` — 25 offline contract tests (title/company
|
|
305
|
+
splitting, salary parsing, work-mode inference, HTML stripping, `stableId`)
|
|
306
|
+
- `src/tests/adapters.hackernews.test.ts` — 18 offline contract tests (header
|
|
307
|
+
parsing, timestamp conversion, HTML decoding, skip logic for deleted items)
|
|
308
|
+
- `scripts/smoke_sources.ts` — live smoke test hitting real RemoteOK RSS and HN
|
|
309
|
+
Firebase APIs; run manually before releases with `npm run smoke`
|
|
310
|
+
- `fast-xml-parser` added as a production dependency (RSS parsing)
|
|
311
|
+
- `tsx` added as a dev dependency (runs a smoke script without a compiler step)
|
|
312
|
+
|
|
313
|
+
### Changed
|
|
314
|
+
|
|
315
|
+
- `stripHtml()` fixed: opening `<p>` tags now convert to `\n` (was `""`) so HN
|
|
316
|
+
comment header and body lines split correctly after HTML stripping
|
|
317
|
+
- `README.md` — roadmap updated; Phase 2 marked complete; note updated to
|
|
318
|
+
reference v0.2.0
|
|
319
|
+
- **Payment processor:** Pro license switched from Gumroad to **Polar.sh**
|
|
320
|
+
(`https://polar.sh/orestes-garcia-martinez/careerclaw-pro`); `CAREERCLAW_PRO_KEY`
|
|
321
|
+
env var name and SHA-256 cache behavior unchanged
|
|
322
|
+
|
|
323
|
+
### Notes
|
|
324
|
+
|
|
325
|
+
58 tests across 4 test files, all passing. No network calls in CI — all adapter
|
|
326
|
+
tests use offline fixtures. Run `npm run smoke` manually before each release to
|
|
327
|
+
validate live sources.
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
## [0.1.0] — 2026-03-03
|
|
331
|
+
|
|
332
|
+
### Added
|
|
333
|
+
|
|
334
|
+
- Initial repository scaffold: `package.json`, `tsconfig.json`, `vitest.config.ts`
|
|
335
|
+
- `src/models.ts` — canonical data schemas (`NormalizedJob`, `UserProfile`,
|
|
336
|
+
`TrackingEntry`, `BriefingRun`, `ScoredJob`, `OutreachDraft`); identical
|
|
337
|
+
JSON serialization format to Python careerclaw for cross-implementation
|
|
338
|
+
file compatibility
|
|
339
|
+
- `src/config.ts` — centralised environment and source configuration
|
|
340
|
+
(runtime paths, HTTP defaults, RemoteOK RSS URL, HN thread ID, LLM and
|
|
341
|
+
license env vars)
|
|
342
|
+
- `SKILL.md` — OpenClaw skill definition with Node-native self-healing
|
|
343
|
+
install check (`npm install -g careerclaw-js`)
|
|
344
|
+
- `CHANGELOG.md`
|
|
345
|
+
- Unit tests for `models.ts` and `config.ts` (Vitest)
|
|
346
|
+
|
|
347
|
+
### Notes
|
|
348
|
+
|
|
349
|
+
This release establishes the Phase 1 foundation types. No adapters,
|
|
350
|
+
matching, or CLI are included yet — those follow in Phases 2–8 per the
|
|
351
|
+
Node Migration Decision (ADR, March 2026).
|
|
352
|
+
|
|
353
|
+
[Unreleased]: https://github.com/orestes-garcia-martinez/careerclaw-js/compare/v0.8.0...HEAD
|
|
354
|
+
[0.8.1]: https://github.com/orestes-garcia-martinez/careerclaw-js/compare/v0.8.0...v0.8.1
|
|
355
|
+
[0.8.0]: https://github.com/orestes-garcia-martinez/careerclaw-js/compare/v0.7.0...v0.8.0
|
|
356
|
+
[0.7.0]: https://github.com/orestes-garcia-martinez/careerclaw-js/compare/v0.6.0...v0.7.0
|
|
357
|
+
[0.6.0]: https://github.com/orestes-garcia-martinez/careerclaw-js/compare/v0.5.0...v0.6.0
|
|
358
|
+
[0.5.0]: https://github.com/orestes-garcia-martinez/careerclaw-js/compare/v0.4.0...v0.5.0
|
|
359
|
+
[0.4.0]: https://github.com/orestes-garcia-martinez/careerclaw-js/compare/v0.3.0...v0.4.0
|
|
360
|
+
[0.3.0]: https://github.com/orestes-garcia-martinez/careerclaw-js/compare/v0.2.0...v0.3.0
|
|
361
|
+
[0.2.0]: https://github.com/orestes-garcia-martinez/careerclaw-js/compare/v0.1.0...v0.2.0
|
|
362
|
+
[0.1.0]: https://github.com/orestes-garcia-martinez/careerclaw-js/releases/tag/v0.1.0
|