Commit graph

277 commits

Author SHA1 Message Date
7693abf79d fix: guard generateResearch against POST failure, surface partial fetch errors
- Check error from POST /research/generate; only start pollTask on success to prevent unresolvable polling intervals
- Surface contacts and fullJob fetch errors in fetchFor; silently ignore research 404 (expected when no research yet)
- Remove redundant type assertions (as Contact[], as TaskStatus, as FullJobDetail)
- Add @internal JSDoc to pollTask
- Remove redundant vi.runAllTimersAsync() after vi.advanceTimersByTimeAsync(3000) in test
2026-03-20 18:44:11 -07:00
ff0dd8b3cd refactor: use existing useApi composable in prep store, remove duplicate
Delete useApiFetch.ts wrapper (returned T|null) and update prep.ts and
prep.test.ts to import useApiFetch from useApi.ts directly, destructuring
{ data, error } to match the established pattern used by all other stores.
2026-03-20 18:40:33 -07:00
de69140386 feat: add prep store with research polling
Adds usePrepStore (Pinia) for interview prep data: parallel fetch of
research brief, contacts, task status, and full job detail; setInterval-
based polling that stops on completion and re-fetches; clear() cancels
the interval and resets all state. Also adds useApiFetch composable
wrapper (returns T|null directly) used by the store.
2026-03-20 18:36:19 -07:00
71480d630a refactor: use _get_db() pattern in get_research_brief, fix HTTPException style
- Replace lazy import + scripts.db.get_research with inline SQL via _get_db(),
  matching the pattern used by research_task_status and get_job_contacts
- Exclude raw_output from SELECT instead of post-fetch pop
- Change HTTPException in generate_research to positional-arg style
- Update test_get_research_found/not_found to patch dev_api._get_db
2026-03-20 18:32:02 -07:00
a29cc7b7d3 feat: add research and contacts endpoints for interview prep 2026-03-20 18:18:39 -07:00
347c171e26 fix: prefer HTML body in imap_sync, strip head/style/script, remove 4000-char truncation
- _parse_message now prefers text/html over text/plain so digest emails
  retain href attribute values needed for link extraction
- Strip <head>, <style>, <script> blocks before storing to remove CSS/JS
  garbage while keeping anchor tags intact
- Remove [:4000] truncation — digest emails need full body for URL regex
- Update test: large body should NOT be truncated (assert len == 10_000)
2026-03-20 13:35:30 -07:00
51f5b3f0a0 fix: bootstrap digest store on app mount for correct badge count on load 2026-03-20 10:27:13 -07:00
5621140a72 fix: add error feedback and keyboard accessibility to DigestView 2026-03-20 10:16:24 -07:00
8302b58b20 feat: add DigestView with expand/extract/queue UI 2026-03-20 10:12:45 -07:00
247f807e02 fix: bind aria-label on nav badge span (was static string, not template expression) 2026-03-20 10:10:10 -07:00
165811c420 feat: add Digest tab to nav and router 2026-03-20 10:07:12 -07:00
154f691334 style: use void instead of .catch on fire-and-forget digest-queue call 2026-03-20 10:06:04 -07:00
4246e71061 feat: fire digest-queue add call from digest chip handler 2026-03-20 09:58:16 -07:00
9bf14fbc75 fix: add error rollback and error state hygiene in digest store 2026-03-20 09:56:22 -07:00
4c2a08057c feat: add digest Pinia store 2026-03-20 09:52:52 -07:00
f3e7f89e2e style: pass Path(DB_PATH) to insert_job for type consistency 2026-03-20 09:51:35 -07:00
1b2643675d feat: add queue-jobs and delete digest endpoints 2026-03-20 07:44:19 -07:00
5bb3674fea fix: guard extract_digest_links db.close(), remove domain-in-path false positive, add hint assertion 2026-03-20 07:04:24 -07:00
182ab789df feat: add /extract-links endpoint with URL scoring 2026-03-20 06:59:26 -07:00
7993984af9 fix: guard db.close() in add_to_digest_queue with try/finally 2026-03-20 06:54:50 -07:00
a503ecde3b feat: add GET/POST /api/digest-queue endpoints 2026-03-20 02:51:17 -07:00
0590a3a12e fix: fix indentation and add try/finally in digest startup 2026-03-20 02:36:23 -07:00
6a1ee3ed28 feat: add digest_queue table to schema and dev-api startup 2026-03-20 02:34:41 -07:00
c6f810fb30 feat(signals): add Unrelated and Digest reclassify chips to InterviewsView 2026-03-19 20:01:08 -07:00
87aae6eefc feat(signals): add Unrelated and Digest reclassify chips to InterviewCard 2026-03-19 20:00:27 -07:00
34494db8d8 feat(signals): strip HTML and normalize whitespace from email bodies 2026-03-19 19:59:59 -07:00
909fe60908 feat(interviews): paginate applied list (10 per page) 2026-03-19 19:45:59 -07:00
e487942eeb fix(signals): add .stop modifiers and aria-labels to pre-list signal banner buttons 2026-03-19 19:35:15 -07:00
9de51d6b4a feat(signals): expandable body + reclassify chips in InterviewsView pre-list 2026-03-19 19:31:23 -07:00
804c2a8064 fix(signals): per-signal expand state, error rollback, type safety in InterviewCard 2026-03-19 19:26:36 -07:00
2796d0d911 feat(signals): expandable body + reclassify chips in InterviewCard 2026-03-19 19:22:10 -07:00
3b2df5e89e feat(signals): add body and from_addr to StageSignal interface 2026-03-19 19:19:27 -07:00
218f4ff9c8 fix(signals): capture rowcount after commit in reclassify_signal (consistency) 2026-03-19 19:18:43 -07:00
1d943ed8a3 feat(signals): add body/from_addr to signal query; add reclassify endpoint 2026-03-19 19:14:11 -07:00
e24e0b7233 feat(interviews): collapsible Applied section, email sync pill, pre-list signal banners 2026-03-19 16:38:05 -07:00
5ca25e160c feat(interviews): add stage signal banners and extend move emit in InterviewCard 2026-03-19 16:31:33 -07:00
52c7dfcfe3 feat(interviews): add preSelectedStage prop to MoveToSheet 2026-03-19 16:25:48 -07:00
6e2ddaf6da feat(interviews): export StageSignal interface; add stage_signals to PipelineJob 2026-03-19 16:22:59 -07:00
bc8174271e feat(interviews): add stage signals, email sync, and dismiss endpoints to dev-api 2026-03-19 16:17:22 -07:00
4abdf21981 fix(apply): check saveCoverLetter error; document cover-letter-generated in wrapper 2026-03-19 08:36:19 -07:00
1006e88e5b fix(apply): ensure loading resets on fetchJobs error and clear toast timer on unmount 2026-03-19 08:24:52 -07:00
b94828855b feat(apply): desktop split-pane layout with narrow list, expand animation, speed demon + marathon easter eggs 2026-03-19 08:21:08 -07:00
d8aca3ec52 feat(apply): extract ApplyWorkspace component with job-removed emit and perfect match easter egg 2026-03-19 08:14:15 -07:00
5ac742d892 refactor(apply): add score-badge--mid-high token for 4-tier scoring 2026-03-19 08:09:39 -07:00
73c2557c31 feat(interviews): complete InterviewsView with kanban, keyboard nav, confetti
Replaces stub with full kanban implementation: three-column pipeline
(Phone Screen / Interviewing / Offer+Hired), pre-list for applied/survey
jobs, rejected accordion, keyboard navigation (arrow keys + vim keys),
confetti easter egg on hired move (respects prefers-reduced-motion),
and /prep/:id route added to router.
2026-03-19 00:38:11 -07:00
c5b3d31cb9 feat(interviews): add MoveToSheet bottom sheet / dialog component 2026-03-18 18:15:02 -07:00
b523707d17 feat(interviews): add InterviewCard component (medium density) 2026-03-18 18:15:01 -07:00
4dcab5ff29 feat(interviews): add interviews Pinia store with optimistic moves
Setup-form Pinia store with per-stage computed lanes, optimistic status
mutation on move, and API-error rollback. Shallow-copies API response
objects on fetch to prevent shared-reference mutation across tests.
2026-03-18 15:26:44 -07:00
6fb366e499 feat(interviews): add /api/interviews and /api/jobs/:id/move endpoints
Adds GET /api/interviews to fetch all pipeline-stage jobs in one call,
and POST /api/jobs/:id/move to transition a job between kanban statuses
with automatic timestamp stamping (or rejection_stage capture).
2026-03-18 15:22:51 -07:00
cce0f8195a feat(vue-spa): Apply view — job picker list + cover letter workspace
- router: add /apply/:id → ApplyWorkspaceView (lazy-loaded)
- ApplyView.vue: approved job list sorted by match score; badges for
  match %, remote, and cover-letter draft status; links to workspace
- ApplyWorkspaceView.vue: two-panel desktop layout (sticky job details
  left, editor right); cover letter state machine (none/queued/running/
  ready/failed); auto-resize textarea; word count toolbar; Save button
  with dirty tracking; Download PDF (programmatic <a> click, named file);
  Generate with AI + Retry; Mark as Applied + Reject Listing actions;
  polling loop for in-flight generation tasks; toast on action
- HomeView.vue: split combined "Archive Pending + Rejected" into three
  separate per-status archive buttons (only shown when count > 0)
- dev-api.py: add GET /api/jobs/:id, POST /api/jobs/:id/applied,
  PATCH /api/jobs/:id/cover_letter, POST .../cover_letter/generate
  (wires submit_task), GET .../cover_letter/task (poll), GET .../pdf
  (reportlab); has_cover_letter field on list + detail responses
2026-03-18 09:05:40 -07:00