Commit Graph
76 Commits
Author SHA1 Message Date
Amruth Pillai 3e14ecaab8 chore: update dependencies 2026-10-01 03:07:07 +02:00
Amruth Pillai 0bdf8066cd fix: make monorepo checks and caching consistent 2026-09-30 22:32:05 +02:00
Amruth Pillai ec0932c5d2 fix(ui): unify fonts and prevent footer text clipping 2026-09-30 15:11:56 +02:00
Amruth Pillai 36ba314e2a chore(deps): update @dotenvx/dotenvx to version 2.32.1 and @babel/core to version 7.29.7 2026-09-30 01:14:44 +02:00
Amruth Pillai 8ded9de46e chore: update versioning and dependencies, remove unused configuration files 2026-09-29 23:34:31 +02:00
Amruth Pillai b399e289d6 feat(web): redesign the landing page as one scroll-driven story
"Everything you've done, on one page." A single resume page is assembled,
written, restyled, checked, tailored and shared as the visitor scrolls,
followed by live community numbers, languages, a support receipt, a
closing call to action and the footer. It replaces the previous homepage
and its playgrounds.

Motion: a small scroll engine (features/homepage/scroll.ts) writes each
section's progress as --p on every animation frame, and the scenes derive
their motion from it with CSS calc(). React only re-renders on coarse
steps held in a zustand store. Reduced motion collapses every pinned
scene to one screen at its end state and stops all ambient motion.

Server-rendered copy: the web build now prerenders the homepage once per
locale (Vite app builder, features/homepage/prerender.tsx) into
apps/web/dist-prerender, which the server sends for "/" by `?locale=`,
then the saved locale cookie. main.tsx waits for the route to load before
React replaces the prerendered page, so it never flashes a loading screen.
dist-prerender is added to turbo outputs, the Docker image and the Vercel
function files.

SEO: localized title and description, a canonical per locale, hreflang
alternates for every locale over `/?locale=` addresses (the app now reads
that parameter), and SoftwareApplication JSON-LD. The FAQ structured data
is dropped because the page shows no FAQ.

Also: self-hosted Anybody and Martian Mono (landing only) and Newsreader
italic, graphite doodles as WebP, new Material Symbols in the icon subset,
the pull-cord theme switch on the app's theme cookie, and new catalog
strings extracted for translation.
2026-09-29 22:34:16 +02:00
Amruth Pillai 8a2fa26451 ci: run the database-backed suites and drop coverage from the unit step
The cover-letter and MCP OAuth flow suites were gated on environment variables
CI never set, so they never ran. Point them at the job's PostgreSQL. The
cover-letter suite works in its own schema; the OAuth suite gets a database of
its own because it writes signing keys under its own secret, which the e2e
server can't decrypt.

Nothing reads the unit step's coverage report, so test:ci no longer collects it.
2026-09-29 22:31:56 +02:00
Amruth Pillai 73a3dfc423 fix(web): keep babel 7 so the react compiler compiles every component
Under @babel/core 8, babel-plugin-react-compiler 1.0 skipped every function with a destructuring default without saying so, which left about 70 components unmemoized, including every packages/ui primitive. A test compiles a component with a default prop through the same preset and fails if that comes back.
2026-09-29 18:13:06 +02:00
Amruth Pillai 31fb576099 feat(web): write custom styles as plain CSS without a version line or checker
Custom styles no longer need @version 1; at the top: the language
version already lives beside the text, so new and converted stylesheets
leave it out, the editor hides it in older ones, and the compiler
ignores it. The validity status and inline diagnostics are gone too:
whatever applies shows in the preview and anything else is left out.
2026-09-29 14:31:59 +02:00
Amruth Pillai 5dc67c3bd4 fix(web): restyle the custom CSS editor in the app's inks and show its toolbar icons 2026-09-29 08:17:12 +02:00
Amruth Pillai c0bf1aebaf feat(pdf): remove react-pdf and move every consumer to forme
The web preview, downloads, template gallery, server export and public
PDF render through Forme. react-pdf, react-pdf-html, the react-pdf
hyphenation package, the Phosphor react-pdf icons and the four patches
are gone. Hyphenation now follows the page language for every language
Forme has patterns for.

Semantic CSS keeps its language; declarations Forme can't draw raise an
ENGINE_UNSUPPORTED warning in the editor. The page map rebuilds blocks
Forme leaves out of its layout when they break across pages, and a
render that misplaces a box is repeated with nested rows kept whole.

Tests move to a small shim with the react-pdf calls they were written
against; tests of react-pdf internals are dropped. Forme limits are
recorded as expected failures (RTL line order, characters above
U+FFFF).
2026-09-29 07:11:40 +02:00
Amruth Pillai 9f809890e4 feat(web): settings in three pages that save as you go
Six settings pages become Account, Preferences and AI & developer, with an
in-page nav beside a 680px column (tabs on tablets, a three-row root on
phones, which the Account tab opens).

- Account: photo upload, name, username with the instance host, and email,
  each saving on blur; password, a two-step verification switch, passkeys and
  connected sign-in; Export everything as one zip of documents and
  applications; Delete account with the counts of what goes and typing
  "delete"; Sign out.
- Preferences: Light, Dark and System tiles, the interface language and the
  motion note.
- AI & developer: provider rows with Test ("Connected · 420 ms" or the exact
  error) and an Edit dialog holding the switch and delete; Add provider with
  all sixteen; API keys in a table with a New key dialog (30 days, 90 days,
  Never), the key shown once, and Revoke with Undo; the MCP address with Copy.

The old settings addresses redirect, and links across the app, the command
palette and the user menu point at the new pages.
2026-09-29 00:33:37 +02:00
Amruth Pillai e1d5b9ba9b feat(web): the assistant beside the document, and Improve in every text field
The assistant opens beside the resume or letter it works on: a third column
at 1280px and wider, in place of the left panel from 1024px, a drawer below
that, and full screen on phones. The bar's button and Mod+J toggle it.

The panel sets up a provider in place, suggests what to ask, streams replies
with Stop and Continue, asks clarifying questions, and shows proposed edits as
change sets with page marks, the outline's "n proposed" pill and the page
caption. Context chips decide whether the next message shares the document and
the posting. Errors keep the message with Retry and Switch model, past
conversations are grouped by document with their outcomes, and the
conversation can be copied as a transcript.

Improve in the rich-text toolbar suggests a stronger verb, a result, a shorter
line or the user's own request for the line holding the caret, and replaces it
only on Replace.

The Agents pages, the builder's assistant sheet and the application copilot
panel are removed; /agent links redirect to the document with the assistant
open. Command palette Ask, Job match's missing terms, Applications' Prepare for
next step and Copy for a job all open the assistant on the right document.
Removes the unused react-resizable-panels and @shadcn/helpers dependencies.
2026-09-29 00:11:16 +02:00
Amruth Pillai f2a76b2f69 feat(web): replace the builder with the Desk & Paper editor shell
One editor at /builder/$resumeId: a bar with the document menu and save
status, the Write, Design and Check modes (in ?mode=), undo, history,
assistant, Share and the Download PDF split button, over the panel and the
page canvas. Tablets get a drawer that can be pinned in landscape; phones
get Write, Page, Design and Check tabs.

The canvas renders pages at the zoom level (60-150%, Fit), outlines the
selected entry, links page clicks to the panel and panel focus to the page,
and offers Edit entry on phones. Share & export hosts sharing, statistics and
every download format. Offline, the panel explains the state and Share and
Download wait for a connection.

Until their milestones land, the modes host today's section editors, design
sections and ATS check. The resizable-panel shells, rails, dock, header,
mobile shell and react-zoom-pan-pinch are removed.
2026-09-28 17:18:04 +02:00
Amruth Pillai d0d20ce0fd chore(deps): upgrade dependencies
Bump workspace dependencies to their latest versions and dedupe the lockfile.

The upgrade left stale duplicates in pnpm-lock.yaml that broke the build and tests:

- @deepseek-ai/schemastery resolved to both 3.18.2 and 3.18.4. Both copies declare
  the global Schemastery namespace, so dsh-plugin's declaration emit failed with
  TS2883 on `Config`. `pnpm dedupe` collapses it to 3.18.4.
- vite's optional tsx peer resolved to 4.23.13 for importers without a direct tsx
  dependency and 4.23.15 elsewhere, producing two vitest 5.0.2 instances. Loading
  both in one run broke `expect(...).rejects`. Re-resolving tsx unifies the graph.
2026-09-28 00:23:21 +02:00
Amruth Pillai 4fde62df6d chore: update dependencies 2026-09-19 22:05:55 +02:00
Amruth Pillai b953435f2c fix: audit code for reduction 2026-09-17 22:16:44 +02:00
Amruth Pillai 96c7142fbc chore: update dependencies 2026-09-16 18:36:50 +02:00
Amruth Pillai dc8f9787a4 chore: update dependencies 2026-09-09 23:57:37 +02:00
Amruth Pillai 607eafd3e8 chore(deps): bump ai-sdk, aws-sdk, react-email and tooling dependencies
Patch and minor bumps across the AI provider SDKs (@ai-sdk/*, ai),
@aws-sdk/client-s3, react-email/@react-email/ui, knip and jszip, with
pnpm-lock.yaml regenerated to match.

Also records the audit overrides and patched dependencies in the root
package.json alongside the existing pnpm-workspace.yaml entries.
2026-09-09 12:16:20 +02:00
Amruth Pillai 6416da28a4 feat(homepage): rebuild landing page and fix untranslated homepage strings in 16 locales (#3496) 2026-09-08 18:01:59 +02:00
Amruth Pillai 4f60856706 refactor: remove unused UI and runtime scaffolding 2026-09-07 22:40:50 +02:00
Amruth Pillai e272037bec chore: update dependencies 2026-09-06 16:42:58 +02:00
Amruth Pillai 7fef84078d chore: update dependencies 2026-09-06 08:46:54 +02:00
Amruth Pillai ea97de5ec4 fix(editor): preserve literal rich-text whitespace (#3472)
* fix(web): preserve imported rich-text tables

* fix(web): harden imported table preservation

* fix(web): fail closed on lossy table markup

* chore: remove plan 16 evidence reports

* fix(web): close imported table preservation gaps

* fix(editor): preserve literal rich-text whitespace

* chore: remove plan 19 evidence report

* fix: preserve literal whitespace through layout and editor transforms

* fix: preserve whitespace in bare table cells

* chore: keep orchestration evidence untracked
2026-09-05 19:57:50 -07:00
Amruth Pillai 999cd618cb feat(web): preserve editable imported tables (#3464)
* fix(web): preserve imported rich-text tables

* fix(web): harden imported table preservation

* fix(web): fail closed on lossy table markup

* chore: remove plan 16 evidence reports

* fix(web): close imported table preservation gaps
2026-09-05 18:41:38 -07:00
Amruth Pillai 84645f122b chore: update dependencies 2026-09-04 11:05:22 +02:00
Amruth Pillai c288675b16 Release v5.2.9 (#3382)
* feat(ats): add ATS checker and replace resume analysis

Adds a public, browser-only ATS checker at /ats-checker and an ATS Check
section in the builder's right sidebar. PDFs are parsed locally: text
extraction, reading order, contact and date recovery, section detection,
and file-level readability are scored deterministically, with evidence
cited per finding and skipped checks reported rather than counted as
passes.

Removes the AI-scored resume analysis it supersedes: the resume_analysis
table (dropped via migration), the get_resume_analysis MCP tool, and
POST /ai/analyze-resume. The replacement, POST /ai/ats-review, reviews
extracted resume text and returns qualitative feedback with no score.

Also bumps the version to 5.2.9 and adds the changelog entry.

* chore(deps): bump workspace dependencies

* fix(ats-checker): keep negation inside each 'what this does not do' bullet

The three bullets were bare fragments whose negation came from the
section heading, which translators never see. A dozen locales rendered
them as affirmative assertions or imperatives, so the page claimed the
checker enforces a one-page rule and predicts rejection -- the opposite
of the source, and directly contradicted by the sentence beside it.

Each bullet now carries its own negation, so the polarity cannot be
lost in translation. Re-extracted and refilled across all 53 target
locales.
2026-08-27 03:37:01 +02:00
Amruth Pillai 3c195dc3f8 Release v5.2.8 (#3375)
Upgrades to Better Auth 1.7, expands Custom Styles coverage of item headers, and adds a human-approval step to the AI agent's resume edits.

Breaking for self-hosters using a custom OAuth provider: the callback path changes from /api/auth/oauth2/callback/custom to /api/auth/callback/custom, and installs using OAUTH_DISCOVERY_URL need one additional UPDATE after upgrading. Both are documented in docs/self-hosting/sso.mdx.

- Better Auth 1.7, with the account issuer migration and the jwks alg/crv columns the 1.7 jwt plugin requires
- Agent edits gated behind an approval step, with crash-safe runs and context pruning
- item-header now covers every section header row on every template; adds the item-header-row part
- Fixes provider unlinking, auth error messages, and version conflicts on freshly created resumes
- New /auth/error page, translated across all 53 target locales
- DeepSeek Harness plugin moved into packages/dsh-plugin
- Dependency bumps across the workspace
2026-08-24 21:44:16 +02:00
Amruth Pillai c8081ac2fe feat(agent): adopt AI SDK v7 — crash safety, context pruning, HITL approvals (#3362)
* docs(adr): propose agent AI SDK v7 adoption plan

* fix(ai): bind analyzeResume through aiService in service test

The test destructured analyzeResume as a named export that does not exist; main was red.

* test(agent): keep pure ai helpers real via spread-actual mock factory

* feat(agent): add run guards, patch version guard, run wall-clock timeout

* feat(agent): validate UI messages at the send boundary

* feat(agent): crash-safe draft-row persistence and server-side cancellation

* feat(agent): reap stale run claims at boot, on send, and on thread open

* feat(agent): fresh-document patch output and tiered context pruning

* feat(ai): shared agent tool contracts and message metadata schema

* feat(agent): add per-thread review-patches setting with update endpoint

* feat(agent): gate resume patches behind hmac-signed tool approval

* feat(agent): merge question answers and approval decisions before run claim

* feat(agent): approval ui with composed auto-send and fixture-driven tests

* feat(agent): usage metadata, tool activity cards, smoother streaming

* feat(agent): tool-call repair, input examples, structured step logging

* chore(i18n): translate new agent workspace strings across all locales

* fix(agent): gate stale-run draft cancellation on winning the claim clear

Snapshot streaming drafts before the conditional clear and skip the flip entirely when another reaper or a replacement run already cleared the claim. Also address review nits in eleven locale catalogs.

* fix(agent): flip reaped drafts only when their snapshotted state is unchanged

* fix(agent): address review findings across run lifecycle, context budget, and approval flow

- bind patches to the revision the model read via signed baseUpdatedAt
- claim the run before consuming a continuation; recorded-but-unexecuted approvals retry as pending continuations
- keep run ownership on stop() until cancellation persists; preserve the claim for the reaper when final persistence fails
- estimate tokens without serializing binary attachments (tokenx) and enforce the budget by dropping oldest whole turns
- mark crash-recovered patch results as snapshot boundaries; strip /data prefixes at execution time
- retry failed continuations without regenerate; mount a single AgentChat; disable response controls on read-only threads; freeze review toggle during runs (client+server)
- accumulate usage across continuations and match the SDK's nested usage shape; label-form token strings; reorderable source label; accessible note field; state-neutral web-search label

* chore(i18n): translate revised agent strings across all locales

* fix(agent): harden baseUpdatedAt validation and address review follow-ups

- bundle tokenx in the server runtime dependencies (e2e boot failure)
- strict ISO schema for baseUpdatedAt plus loud executor rejection of unparseable values
- it-IT source label consistency (Fonte)
- prove penultimate-turn retention in the context pruning test

* chore(deps): exempt tokenx from knip for the externalized server bundle
2026-08-20 08:06:53 +02:00
Amruth Pillai 9dc2aade46 chore(deps): update dependencies
Routine version bumps across the workspace. The @react-pdf/textkit patch is
renamed to drop the pinned version so it survives the next bump.
2026-08-17 22:32:33 +02:00
Amruth Pillai 035d94183b fix(web): show static template previews in gallery (#3302) 2026-08-10 12:18:47 +02:00
Amruth Pillai 88a19619da chore: update dependencies 2026-08-09 12:17:09 +02:00
Amruth Pillai 131c1492cd chore: update dependencies 2026-07-31 17:24:32 +02:00
Amruth Pillai 164a279306 chore: update dependencies 2026-07-30 12:45:49 +02:00
Amruth PillaiandCursor Agent d2ffbf9618 feat: add semantic CSS stylesheets (#3274)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-07-30 12:39:15 +02:00
Amruth Pillai b303b89758 fix(web): restore Tiptap Enter and list editing 2026-07-28 15:10:24 +02:00
Amruth Pillai 994093b981 chore: update translations 2026-07-27 20:57:54 +02:00
Amruth Pillai 3266066826 chore: update dependencies 2026-07-27 13:19:54 +02:00
Amruth Pillai 90105cb148 chore: integrate improve-integration 2026-07-08 19:08:31 +02:00
Amruth Pillai b404dbd42a Add application tracker (#3220)
* feat(applications): job application tracker with AI copilot

Add an Applications module at /dashboard/applications: pipeline board
(dnd-kit), table view with bulk actions, Insights (fit tiles, funnel,
sources, shareable funnel-flow SVG), campaigns, tags, CSV import, and
Add/Edit/Detail slide-overs. Each application links a live Reactive
Resume.

AI "Application Copilot" (applications.ai.*): job-posting autofill,
resume↔job match score (fit ring), resume tailoring, and cover-letter /
follow-up drafting — via the user's configured provider.

Board cards + table rows get context menus (edit / move / archive /
delete). Charts are CSS/SVG (no new chart dep); adds a UI Checkbox.

Also includes local TanStack devtools setup and toolchain bumps.

Claude-Session: https://claude.ai/code/session_01TEeRHnEayw2MFCShFRyL5f

* feat(applications): close follow-up gaps + squash migrations

Finish the deferred/open items on the applications tracker:

- Cover-letter upload re-enabled. Fix the storage blocker by deriving the
  key extension from content type (buildFileKey/EXTENSION_BY_CONTENT_TYPE)
  instead of hardcoding .jpeg, so PDFs serve correctly and non-JPEG image
  avatars keep working under FLAG_DISABLE_IMAGE_PROCESSING. Add
  coverLetterUrl/coverLetterName columns + Documents-section upload/remove.
- Contacts editor in the detail sheet (add/edit/remove, keyed per app).
- Board caps rendered cards per column (COLUMN_PAGE_SIZE=50 + "Show more").
- Extract new Lingui messages across locales.
- Guard coverLetterUrl to http(s)/relative at the API boundary.

Squash the five branch-only application-table migrations (create -> +tags
-> +cover-letter -> drop -> re-add) into a single clean CREATE TABLE via
drizzle-kit generate.

Claude-Session: https://claude.ai/code/session_01TEeRHnEayw2MFCShFRyL5f

* chore: update dependencies

* fix(web): address React Doctor findings — compiler, purity, query, component structure

prefer-module-scope-pure-function: hoist buildSubtitle, getDecimalPlaces,
handleLocaleChange, onLocaleChange, stop, listContent/groupedListContent to
module scope so they aren't rebuilt on every render.

react-compiler-todo (??=): rewrite draft.metadata.styleRules ??= [] to the
non-assignment form to unblock auto-memoization.

set-state-in-effect: derive updatedAtLabel at render time instead of syncing
it through useState + useEffect.

query-destructure-result: destructure useQuery results at call site in
resume-analysis and resume-thumbnail to follow TanStack Query v5 convention.

only-export-components: extract non-component exports to sibling .ts files so
Fast Refresh can preserve component state:
  - getNextWeights → typography/get-next-weights.ts
  - detectJsonImportType + ImportType → dialogs/resume/import.utils.ts
  - getLocaleOptions → features/locale/locale-options.tsx
  - preview helpers + DEFAULT_PDF_PAGE_SIZE → preview.shared.utils.ts
  - resolveHighlightToolbarState + defaultHighlightColor → rich-input.utils.ts
  - computeDelta + getSparklinePoints → statistics.utils.ts

no-multi-comp: split multi-component files into focused companions:
  - ResumePane + ToolbarButton → routes/agent/-components/resume-pane.tsx
  - DesktopBuilderShell → builder/$resumeId/-components/desktop-builder-shell.tsx
  - MobileBuilderShell + helpers → builder/$resumeId/-components/mobile-builder-shell.tsx
  - setBuilderLayout/getBuilderLayout moved to -store/sidebar.ts

fix(tests): add Resume type import to section-builder mocks and cast partial
mock data as unknown as Resume to satisfy stricter type checking; fix
noExplicitAny Biome errors in the same mocks.

* feat(applications): improve performance

* chore: fix knip issues

* perf(builder): halve per-keystroke render cost

Section-form fields called `form.handleSubmit()` on every keystroke, which
re-validated the whole form and toggled submit state — firing the render
cascade twice per character (~6809 renders/keystroke, FPS dropping to 9).

Persist via a form-level `listeners.onChange` instead and drop the per-field
`handleSubmit()` (basics, custom-fields, design). Narrow header/dock resume
subscriptions to metadata slices so they no longer re-render on content edits.

Cuts renders 6809 -> 3403 per keystroke (50%), 0 frame drops. Save, preview,
and design controls verified working; 449/449 web tests pass.

* perf(home): eliminate hero CLS from unreserved video box

The hero <section> is `flex items-center` (shrink-to-fit), so the video
wrapper's width depended on the video's intrinsic size, which only resolves
after the media loads. aspect-ratio couldn't reserve height without a definite
width, so the video grew from ~190px to ~563px after first paint and shoved the
centered hero text down ~373px (CLS ~0.095).

Give the wrapper a definite width (w-full + mx-auto on the CometCard) and set an
explicit aspect ratio + width/height on the video so its box is reserved before
load. CLS 0.095 -> 0; hero stays visually centered at max-w-4xl.

* docs: add application tracker guides

* chore(db): squash application migrations

* fix(email): import React in auth template for server-side rendering compatibility

* chore(release): v5.2.1

* Refactor resume rendering and builder workflows

* fix: address application tracker review findings
2026-07-05 23:44:04 +02:00
Amruth Pillai 20c803e934 feat(export): separate resume/cover-letter downloads, redesign dialog, add Markdown export (#3217)
* feat(export): separate resume/cover-letter downloads, redesign dialog, add Markdown

Let people export the resume and cover letter as distinct documents, and add a
Markdown format alongside PDF / DOCX / JSON (handy for AI agents).

- Server/API: scope PDF generation and download URLs to a resume/cover-letter target.
- Export domain: getResumeExportData + resumeHasCoverLetter in @reactive-resume/resume.
- Redesign the download dialog: one global "What to export" scope toggle (Tabs) plus
  flattened per-format rows, reusing existing UI components and design language.
- Add Markdown export (@reactive-resume/resume/markdown) with a small tiptap-HTML converter.
- Fix blank section headings in DOCX and Markdown by injecting the locale-aware
  section-title resolver (titles are stored empty and resolved at render time).
- Locale catalogs updated for the new strings.

* test(e2e): open the download dialog before exporting JSON

The JSON export moved into the redesigned download dialog, so the spec now opens
the dialog from the Export sidebar section before clicking "Download JSON".
2026-07-05 14:40:49 +02:00
Amruth Pillai 82d961241e fix: polish ai agent and command palette 2026-07-04 20:24:39 +02:00
Amruth Pillai d87c6758ab chore: update dependencies 2026-07-04 19:06:31 +02:00
Amruth Pillai 57e9c8c487 v5.2.0: undo/redo, version history, embedded AI assistant, mobile builder & more (#3205) 2026-07-04 14:57:25 +02:00
Amruth Pillai 2a80e6a1df chore: update dependencies 2026-07-03 20:04:36 +02:00
Amruth Pillai d3735ebe27 chore: update dependencies 2026-06-29 09:09:00 +02:00
Amruth Pillai ef5ff30b13 chore: update linter configuration and add rimraf dependency 2026-06-17 10:51:10 +02:00
Amruth Pillai 37faf592b7 chore: update dependencies 2026-06-17 10:40:23 +02:00
Amruth Pillai 042d076efa chore: update dependencies 2026-06-05 23:35:23 +02:00