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.
Files changed (81) hide show
  1. package/CHANGELOG.md +362 -0
  2. package/README.md +348 -0
  3. package/SECURITY.md +156 -0
  4. package/SKILL.md +463 -0
  5. package/dist/adapters/hackernews.d.ts +36 -0
  6. package/dist/adapters/hackernews.d.ts.map +1 -0
  7. package/dist/adapters/hackernews.js +164 -0
  8. package/dist/adapters/hackernews.js.map +1 -0
  9. package/dist/adapters/index.d.ts +10 -0
  10. package/dist/adapters/index.d.ts.map +1 -0
  11. package/dist/adapters/index.js +9 -0
  12. package/dist/adapters/index.js.map +1 -0
  13. package/dist/adapters/remoteok.d.ts +35 -0
  14. package/dist/adapters/remoteok.d.ts.map +1 -0
  15. package/dist/adapters/remoteok.js +212 -0
  16. package/dist/adapters/remoteok.js.map +1 -0
  17. package/dist/briefing.d.ts +81 -0
  18. package/dist/briefing.d.ts.map +1 -0
  19. package/dist/briefing.js +152 -0
  20. package/dist/briefing.js.map +1 -0
  21. package/dist/cli.d.ts +22 -0
  22. package/dist/cli.d.ts.map +1 -0
  23. package/dist/cli.js +235 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/config.d.ts +91 -0
  26. package/dist/config.d.ts.map +1 -0
  27. package/dist/config.js +126 -0
  28. package/dist/config.js.map +1 -0
  29. package/dist/core/text-processing.d.ts +62 -0
  30. package/dist/core/text-processing.d.ts.map +1 -0
  31. package/dist/core/text-processing.js +187 -0
  32. package/dist/core/text-processing.js.map +1 -0
  33. package/dist/drafting.d.ts +28 -0
  34. package/dist/drafting.d.ts.map +1 -0
  35. package/dist/drafting.js +116 -0
  36. package/dist/drafting.js.map +1 -0
  37. package/dist/gap.d.ts +27 -0
  38. package/dist/gap.d.ts.map +1 -0
  39. package/dist/gap.js +90 -0
  40. package/dist/gap.js.map +1 -0
  41. package/dist/license.d.ts +40 -0
  42. package/dist/license.d.ts.map +1 -0
  43. package/dist/license.js +122 -0
  44. package/dist/license.js.map +1 -0
  45. package/dist/llm-enhance.d.ts +69 -0
  46. package/dist/llm-enhance.d.ts.map +1 -0
  47. package/dist/llm-enhance.js +376 -0
  48. package/dist/llm-enhance.js.map +1 -0
  49. package/dist/matching/engine.d.ts +31 -0
  50. package/dist/matching/engine.d.ts.map +1 -0
  51. package/dist/matching/engine.js +51 -0
  52. package/dist/matching/engine.js.map +1 -0
  53. package/dist/matching/index.d.ts +8 -0
  54. package/dist/matching/index.d.ts.map +1 -0
  55. package/dist/matching/index.js +8 -0
  56. package/dist/matching/index.js.map +1 -0
  57. package/dist/matching/scoring.d.ts +84 -0
  58. package/dist/matching/scoring.d.ts.map +1 -0
  59. package/dist/matching/scoring.js +184 -0
  60. package/dist/matching/scoring.js.map +1 -0
  61. package/dist/models.d.ts +221 -0
  62. package/dist/models.d.ts.map +1 -0
  63. package/dist/models.js +28 -0
  64. package/dist/models.js.map +1 -0
  65. package/dist/requirements.d.ts +22 -0
  66. package/dist/requirements.d.ts.map +1 -0
  67. package/dist/requirements.js +30 -0
  68. package/dist/requirements.js.map +1 -0
  69. package/dist/resume-intel.d.ts +40 -0
  70. package/dist/resume-intel.d.ts.map +1 -0
  71. package/dist/resume-intel.js +111 -0
  72. package/dist/resume-intel.js.map +1 -0
  73. package/dist/sources.d.ts +32 -0
  74. package/dist/sources.d.ts.map +1 -0
  75. package/dist/sources.js +72 -0
  76. package/dist/sources.js.map +1 -0
  77. package/dist/tracking.d.ts +68 -0
  78. package/dist/tracking.d.ts.map +1 -0
  79. package/dist/tracking.js +140 -0
  80. package/dist/tracking.js.map +1 -0
  81. 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 `&#x2F;` (and all `&#x[hex];` sequences) now decoded in `stripHtml()` — fixes `ML&#x2F;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