commitlint had no config anywhere (no config file, no husky commit-msg
hook), so its rules were never loaded; the "commit" script also pointed
at an uninstalled binary. Remove @commitlint/cli and
@commitlint/config-conventional, the dead "commit"/"commitlint" scripts,
and the stale commitlint entry in README Development Requirements.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Confirmed unused via depcheck + manual verification:
- anser, js-cookie, @types/js-cookie — no imports anywhere
- rehype-raw — only referenced in a vite manualChunks regex, never
imported as a markdown plugin (markdown.tsx uses rehype-highlight/slug
and remark-gfm); also dropped from that regex
- @graphql-codegen/{client-preset,near-operation-file-preset,typescript}
— codegen config uses explicit plugins (typescript-operations,
typed-document-node), not these presets/base plugin
Also drop the dead package.json "eslintConfig" block — it is ignored by
the flat config (eslint.config.mjs) and referenced an uninstalled
storybook plugin.
Verified: graphql:generate reproduces src/graphql/types.ts unchanged,
plus build, lint, 604 tests, and --frozen-lockfile all pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The plugin was a direct devDependency but never enabled in
eslint.config.mjs (0 active jsx-a11y rules via --print-config). Dropping
it removes dead weight and one stale eslint-9 peer constraint. Lint still
passes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- add frontend/.nvmrc (24.17.0) as the single source of truth for Node;
GitHub CI reads it via node-version-file, Dockerfile uses node:24.17.0-slim
- bump packageManager to pnpm@11.8.0; drop "corepack prepare pnpm@latest"
so the pnpm version derives from packageManager everywhere
- migrate pnpm onlyBuiltDependencies -> allowBuilds in pnpm-workspace.yaml
(the package.json "pnpm" field is no longer read by pnpm 11)
- add a CI step that fails if the Dockerfile Node tag drifts from .nvmrc
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
vite build strips types and never type-checks, and the old build`s bare tsc (solution config, files:[]) checked nothing — so type errors reached main unnoticed (which is how 76 had accumulated). Now they fail fast everywhere.
- build: `tsc -b && vite build` — `pnpm build` (and the Docker image build, which runs `pnpm run build`) fails on any type error before bundling.
- add `typescript` script (`tsc -b`, checks both app + node project configs).
- ci.yml: blocking "Frontend - Type check" step in lint-and-test (runs on every branch push; docker-build only runs on main/tags).
Verified: a type error makes both `pnpm run typescript` and `pnpm build` exit non-zero (vite never runs); removing it restores a clean build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the deprecated typescript-react-apollo codegen plugin (unmaintained for Apollo Client v4) with typed-document-node. All ~105 useXxxQuery/Mutation/Subscription call sites are rewritten to the generic useQuery/useMutation/useSubscription(XxxDocument, ...) form, with skipToken replacing skip + conditional-variables.
graphql-codegen.ts: plugins typescript-operations + typed-document-node; add scalars { Time: string } (was unknown); drop withHooks/apolloReact* options. tsconfig.app/node.json: ignoreDeprecations "6.0" for the baseUrl TS5101 deprecation. Regenerate src/graphql/types.ts.
Behavior-preserving: variables, fetchPolicy, error handling, and subscription onData/refetchQueries are unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
monaco-terminal.tsx had no importers; drop it together with the now-unused
monaco-editor and @monaco-editor/react dependencies (~3 MB). The component is
preserved on branch feature/frontend-monaco-terminal for later work.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds an opt-in `isVirtualized` prop on DataTable, wired through
@tanstack/react-virtual's useWindowVirtualizer. Threshold gates short
tables (preserves Find-in-page, screen-reader enumeration). Padding <tr>
sentinels keep native HTML table semantics. Skipped when
`renderSubComponent` is set — expanded rows would need per-row
remeasurement we don't wire here.
Enabled on /flows. Measured with pageSize=All (1116 rows):
DOM elements: 41,657 → 1,121 (37x less)
tbody <tr>: 1,116 → 22
a11y tree size: ~485 KB → ~80 KB
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After landing the imperative-timer fix and extracting `useDebouncedCallback`
into our own hook, the use-site count climbed past three and the case for
a single, battle-tested contract beat the case for in-tree code. Drops
both our `useDebouncedValue` and `useDebouncedCallback` and routes every
caller through `use-debounce@10.1.1` (1M+ weekly, ~3KB gzip).
API mapping at each use-site:
- value debounce: `useDebouncedValue(v, ms)` → `const [v] = useDebounce(v, ms)`
- callback debounce: `useDebouncedCallback(fn, ms)` → identical signature,
same `.cancel()`/`.isPending()` semantics we relied on, plus `.flush()`
and leading/trailing/maxWait options we now get for free.
Files touched (7 use-sites): data-table.tsx, input-search.tsx,
use-table-state.ts, use-table-query-filter.ts, knowledges-provider.tsx,
use-flow-files-search.ts, use-detail-navigation.ts.
pnpm + Vite gotcha: pnpm hoists into `.pnpm/<name>@<ver>/`, so any
transitive `import React from 'react'` from a third-party package can
resolve to its own physical copy. With one path through our code and
another through use-debounce, the runtime crashed at `useRef` with
"Cannot read properties of null (reading 'useRef')". Added
`resolve.dedupe: ['react', 'react-dom']` in vite.config.ts so the
bundle ships exactly one React.
Tests:
- new input-search.test.tsx (10 tests) covers collapsed/expanded
presentation, expand-on-click + rAF focus, burst-typing coalesce,
Esc-clear mid-debounce, two-stage Esc semantics, external-source-wins
race, Ctrl+F / Cmd+F global hotkey expansion.
- data-table.test.tsx +5 tests: deep-link initial filterValue,
6-keystroke burst coalesce, unmount-mid-debounce cleanup, two
independent DataTables on one page (settings/prompts shape),
back-button-style external clear, three-round type/clear stress.
- full suite: 541/541 passing, lint 0 errors.
Manual smoke via Chrome DevTools MCP on every page that mounts a
filter input — /flows, /templates, /settings/api-tokens,
/settings/prompts (both tables independent), /knowledges (filter
+ semantic search hitting the server through ?qs=). All scenarios
collapse to a single `[{v="", u=""}]` transition; no URL re-emit
after X, no leftover timer after Esc, no cross-table leakage.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New `components/ui/input-search.tsx`: a controlled, collapsible search
control that idles as just a `<Search>` icon button and expands into a
text input with a motion-driven width animation. Adapted from the
sofy-front version with:
- Trigger is a real `<button>` (via `InputGroupButton`) instead of a
`<div onClick>` — keyboard reachable, screen-reader announced, and
avoids the invalid-HTML nesting that putting an `<input>` inside a
`<button>` would create.
- Configurable Mod+`hotkey` (default `'f'`, `null` to disable). The
knowledges page uses `'k'` so it doesn't fight the browser's own
Ctrl+F find-in-page.
- Escape clears the value on the first press, blurs + collapses on the
second — matches native search-input muscle memory.
- Single collapse effect on `searchQuery` change instead of the
duplicate blur+effect pair.
- `aria-label` prop wired to both the trigger button and the input.
The knowledges header now mounts this control bound to `?qs=` via
`useSearchParams`. The provider already debounces the URL value before
hitting `searchKnowledge`, so the input commits keystrokes immediately
(instant UI feedback) while the server roundtrip waits for the 400 ms
debounce. URL writes use `replace` to avoid history-stack churn.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Runs pnpm update + bumps prettier-plugin-tailwindcss 0.7.4 → 0.8.0
(the 0.8 release is the one that pairs with Tailwind v4).
After this commit, pnpm outdated only reports three deliberately
pinned packages: eslint / @eslint/js (held on 9.x while
eslint-plugin-react still targets eslint ^9) and @types/node (held on
24.x to match the Node 24.12 runtime; npm latest is 25.x for Node 25).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps @types/node 22.19.19 → 24.12.4 to match the actual Node 24.12
runtime the project is built and run on. The latest published tag is
25.x (for the not-yet-released Node 25 line); we deliberately stay on
24.x.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps @commitlint/cli and @commitlint/config-conventional from 20.5.3
to 21.0.1. Dev-only — affects the commit-message hook, not the app.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps typescript 5.9.3 → 6.0.3.
Adds compilerOptions.ignoreDeprecations = "6.0" to tsconfig.json so the
existing baseUrl/paths setup keeps working — TS 6 has flagged baseUrl
as deprecated (it will be removed in 7.0). The vite-tsconfig-paths
plugin still consumes the paths mapping; nothing else in the codebase
needed changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps eslint-plugin-perfectionist 4.15.1 → 5.9.0.
eslint and @eslint/js are intentionally kept on 9.39.4 (the latest
9.x): eslint 10 changes the rule context API
(contextOrFilename.getFilename is gone) and eslint-plugin-react still
ships only versions targeting eslint ^9 — the v10 upgrade currently
crashes the lint run with "Error while loading rule
'react/display-name'". Once eslint-plugin-react publishes a v10-aware
release we can finish this bump.
perfectionist v5 already supports the eslint ^8.45 || ^9 || ^10 peer
range, so it ships cleanly today and gives us its v5 rule changes
without dragging eslint along.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps vite 7.3.3 → 8.0.13 and vite-tsconfig-paths 5.1.4 → 6.1.1.
Vite 8 ships rolldown (the Rust bundler that replaced rollup) and that
required two fixes:
1. build.rollupOptions.output.manualChunks: rolldown no longer accepts
the { chunkName: [packages] } static object form, so it is now an
(id) => string callback that matches paths under node_modules.
2. src/components/ui/resizable.tsx: switched from the namespace import
`import * as ResizablePrimitive` to named `{ Group, Panel, Separator }`
from react-resizable-panels. The v4 release of that library renamed
PanelGroup → Group and PanelResizeHandle → Separator; rollup's
loose tree-shaking happened to keep the old names working at
build-time, but rolldown enforces the export list and the page
failed at runtime with "Element type is invalid". Public wrapper
exports (ResizableHandle, ResizablePanel, ResizablePanelGroup) are
unchanged so the rest of the app keeps working.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps the codegen stack: cli 6→7, client-preset 5→6, typescript 5→6,
typescript-operations 5→6 (typescript-react-apollo and
near-operation-file-preset only moved within their minor range).
Configures typescript-react-apollo to emit Apollo v4-compatible imports
via apolloReactCommonImportFrom / apolloReactHooksImportFrom set to
@apollo/client/react, so re-running pnpm run graphql:generate now
produces ApolloReactCommon / ApolloReactHooks namespaces from the v4
subpath instead of the v3 single-entry import.
src/graphql/types.ts is fully regenerated under the new config.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps @apollo/client from 3.14.1 to 4.1.9.
Apollo v4 moved React-only exports to the @apollo/client/react
subpath. Updated the three import sites that consume them:
- ApolloProvider in app.tsx
- useApolloClient in providers/resources-provider.tsx
- the Apollo namespace import in graphql/types.ts (covers useQuery,
useMutation, useSubscription, useLazyQuery, useSuspenseQuery,
skipToken, *HookOptions, *QueryResult)
Everything else (gql, ApolloClient, ApolloLink, createHttpLink,
InMemoryCache, Observable, split, NetworkStatus, getMainDefinition,
onError, GraphQLWsLink) keeps its existing import path in v4.
Build output shrunk from 223 kB to 191 kB for the apollo-client chunk.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps zod 3.25.76 → 4.4.3 and @hookform/resolvers 3.10.0 → 5.2.2
(the resolvers v5 requires zod v4).
zod is used in 25 source files (schemas, form validators, table state
parsers). Build passes without changes — the project relies on the
shared subset of the v3/v4 API (z.object/z.string/z.number/z.enum,
z.infer, .min/.max/.optional, refinements). Runtime form validation
keeps disabling submit until required fields are filled.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps react-resizable-panels from 3.0.6 to 4.11.1. The wrapper in
src/components/ui/resizable.tsx only re-exports PanelGroup, Panel and
PanelResizeHandle; their props remain compatible across the major.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps react-day-picker from 9.14.0 to 10.0.1. The Calendar wrapper in
src/components/ui/calendar.tsx uses the v9 classNames keys
(button_next/previous, day_button, range_*, week, weekday, weekdays)
and the components.Chevron API; all of these are preserved in v10.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps marked from 17.0.6 to 18.0.3. Used only in
src/lib/report/report-pdf.tsx for PDF generation via marked.lexer();
that API is compatible across the major.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps lucide-react from 0.553.0 to 1.16.0. The 0.x → 1.x jump is a
versioning policy change, not a breaking API change — all icon imports
keep working as before.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pin React/React-DOM to 19.2.6 and @types/react* to 19.2.0 in
package.json — lockfile already resolved the latest 19.x; this just
makes the minimum explicit so future installs don't regress.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- @react-pdf/renderer (~1.5 MB) moved to an async chunk. lib/report.ts
used to statically re-export PDF helpers from ./report-pdf, which
pulled the entire PDF library into every page that imports
lib/report (flow.tsx, flow-report.tsx). The re-exports are now
async wrappers using `await import('./report-pdf')`, so the
library loads only when the user actually triggers a PDF export.
Initial JS for /flows/:id/report drops from ~2.0 MB to ~500 KB.
- Drop html2pdf.js: zero imports anywhere in the source, but it was
declared as a dependency and reserved a (now-empty) manual chunk in
vite.config.ts. Removing it also drops 22 transitive packages from
the lockfile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- src/lib/сlipboard.ts → clipboard.ts: the filename used a Cyrillic 'с'
(U+0441) instead of Latin 'c', which made the path silently
unmatchable by anyone typing the import with a Latin letter. Update
the 4 importers in features/flows.
- Delete unreachable settings-mcp-server(s).tsx (~1.3k lines): no
routes registered in app.tsx and nothing imports them. Remove the
matching dead branches and commented menu entry from
settings-layout.tsx.
- Drop unused dev deps simple-git-hooks and lint-staged: no config in
the repo, not used by CI or Docker, hooks were never wired up. Also
remove simple-git-hooks from pnpm.onlyBuiltDependencies.
- Drop unused tsconfig path aliases: @/ui/*, @env (env.ts doesn't even
exist), and @pkg. Only @/* remains.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- replace plain textarea with a tiptap-based markdown editor (StarterKit, tiptap-markdown, placeholder) and a basic formatting toolbar so authors can edit knowledge content with rich formatting while keeping markdown as the storage format for embeddings
- introduce a reusable MarkdownEditor shared component and a tiptap Storage type augmentation
- move the save action from the input addon into the page header on the right
- give each desktop resizable panel its own internal scroll so long meta or content no longer makes the whole page scroll
Co-authored-by: Cursor <cursoragent@cursor.com>
- introduce src/components/file-manager with tree rendering, search highlighting, multi-select (single / toggle / shift-range), keyboard navigation (arrows, Home/End, Space, Cmd+A, Esc) and bulk delete
- expose unified actions[] API with downloadAction / copyPathAction / deleteAction factory helpers instead of separate built-in props
- split orchestration into useFileManagerExpansion and useFileManagerSelection hooks; derive expanded/selected state during render without useEffect, preserving Set identity for memo-friendly downstream
- add ARIA tree semantics (role=tree on the container, treeitem rows, roving tabindex via activeRowPath, aria-expanded/aria-selected)
- pure tree utils: O(1) folder lookup via Map, normalizeRootGroups, dedupeOverlappingPaths, findNodeByPath, plus 37 vitest unit tests
- ship shadcn checkbox primitive (depends on @radix-ui/react-checkbox) which the file manager uses for row and select-all controls
Made-with: Cursor