Skip to content

Commit 4b8c0db

Browse files
feat(workbench): Knowledge Workbench — new React/TS frontend + supporting backend (#189)
* feat(workbench): scaffold new Tailwind/shadcn/TypeScript frontend * feat(workbench): wire KB list and Home stats to real /api/v1/kbs * feat(api): add /api/v1/graph and /api/v1/page endpoints * feat(workbench): wire KbDetail browse tab to real page/list endpoints * feat(workbench): wire real streaming query/chat with citation page lookup * fix(workbench): prevent session-adopting navigate from clobbering live chat state * refactor(generator): thread optional credential bundle through skill/deck generation * feat(api): add /api/v1/deck and /api/v1/skill generate/list/download endpoints * feat(workbench): wire deck/skill/graph slash commands to real generator endpoints * feat(workbench): wire KbDetail sources and jobs tabs to real add/watch/recompile/lint * feat(api): add GET/PATCH /api/v1/kb/config with merge-patch semantics * feat(workbench): wire Settings page to real kb/config endpoint * feat(workbench): shell-aware TitleBar, 401 handling, final Kimi-adoption pass * fix(api): atomic .env write for credential rotation; lock in path-traversal tests * feat(workbench): Apple token layer + theming infrastructure + motion Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): ambient-ground shell; remove browser title strip Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): glass sidebar, larger nav font, bottom settings/version cluster, theme toggle Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): reflow Home to bottom-pinned input with sessions above and tagline footer Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(api): surface entities in /api/v1/list Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): KbDetail per-type tabs with entities + pagination + materials Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): tokenize chat surfaces + ChatInput; spring-animate artifact preview Migrate ChatInput, ChatSession, and ArtifactCard off hardcoded bg-white/bg-blue-*/border-black/text-neutral-* colors onto the Apple token layer (.glass/.glass-2, border-[hsl(var(--glass-border))], bg-accent-brand, text-foreground/text-muted-foreground). Fixes the shared ChatInput box + slash-command menu rendering white against the dark shell (flagged in Task 4). Source chips gain active:scale-[0.97] + transition duration-fast ease-out-apple press feedback. Wrap the deck preview panel in motion AnimatePresence + a critically- damped spring (bounce:0, 0.24s), degrading to an opacity-only cross-fade under prefers-reduced-motion via useReducedMotion. The sandboxed iframe (sandbox=allow-scripts, src={previewUrl} blob URL) and its blob-URL revocation lifecycle are unchanged; the spring only wraps the panel. Slash-command logic, streaming, citations, and session handling are untouched. Semantic deck/skill/graph accent colors are preserved. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): tokenize Settings and connection dialog Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): materialize KbList; final token sweep + motion review Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(workbench): compile the Apple easing utility; scope KbList transition + press feedback Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(workbench): dark-mode variants for KbDetail status colors KbDetail kept light-only semantic status colors (bg-*-50 / text-*-500 / text-*-600) with no dark: pair, so red error cards and emerald/red status pills rendered as bright light patches in dark mode. Add dark: variants only (no light-mode, layout, or logic changes), matching the app-wide pattern from ChatSession.tsx (red) and ArtifactCard.tsx StatusBadge (emerald): dark:bg-red-500/10 dark:border-red-500/25 dark:text-red-400 and dark:bg-emerald-500/10 dark:text-emerald-400. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(api): graph HTML endpoint + extract graph endpoints to APIRouter * feat(workbench): ArtifactPanel docked component + getGraphBlobUrl client * fix(workbench): clamp artifact-panel width to viewport + clean up resize listeners on unmount * feat(workbench): open deck/graph in a docked artifact panel (compact in-chat cards) * feat(workbench): connector cards → GitHub demand-vote (shared component) * fix(workbench): dedupe artifact-panel switcher by identity (no duplicate React keys) * feat(api): GET /api/v1/meta exposing the real openkb version * feat(workbench): render fenced code blocks + Mermaid diagrams in markdown * feat(workbench): Settings 关于 tab (real version + intro + links) * refactor(workbench): declutter sidebar bottom, icon theme toggle, drop redundant KB badge * feat(workbench): KB Overview stat cards + default to index.md wiki home * refactor(workbench): stop promoting Obsidian in-app (keep the plain-Markdown/no-lock-in message) * refactor(workbench): drop redundant /ask command (default chat already answers from the wiki) * feat(api): give the Workbench chat agent write_file (delegate to build_chat_agent) * feat(api): emit an artifact SSE event when chat write_file produces output/**.html * feat(api): GET /api/v1/output serves path-validated output/**.html (new router) * fix(api): narrow GET /api/v1/output to output/-only (least privilege for the HTML sink) * feat(workbench): file Artifact variant + getOutputBlobUrl + panel wiring * feat(workbench): surface conversationally-written output/**.html as openable cards Fold the artifact SSE event (kind:"file", path, name) into ChatTurnState so a normal chat turn can carry files the agent wrote via write_file. AssistantMessage renders an ArtifactCard per file (kb attached by the caller, since the event itself carries no kb), reusing the existing setPanelArtifact/ArtifactPanel wiring deck/skill/graph already use. viewableArtifacts folds these into the panel switcher too. * fix(workbench): capture kb per file-artifact at fold time (survive mid-session KB switch) * feat(config): add resolve_effective_config three-layer resolver * refactor(runtime): compile/index core resolves config via resolve_effective_config * test(config): make compile-core global-config test exercise convert_document (was vacuous) * refactor(runtime): chat/query/linter resolve config via resolve_effective_config * refactor(runtime): REST query/deck/skill/session resolve config via resolve_effective_config * refactor(runtime): migrate 12 CLI compile/query/chat/lint sites to resolve_effective_config * feat(api): kb/config PATCH null removes key (RFC 7386 revert-to-inherited) * fix(api): kb/config PATCH writes only explicit KB keys (don't materialize defaults, preserve inheritance) Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(api): kb/config GET reports effective values + inheritance metadata * feat(api): add GET/PATCH /api/v1/config global-defaults endpoint Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(api): hold global-config lock across the whole PATCH read-modify-write (protect KB registry) * feat(web): global-config API client + KbConfig inheritance fields * refactor(web): PageTypeTabs -> PageList with fixed type prop Drop PageList's internal Concepts/Entities/Summaries/Reports segmented control; the type is now a required prop set by the caller (Task 13 will drive it from the active Overview card). Pagination (PAGE_SIZE=50), pathFor(), and the onOpen(path)/activePath interface are preserved verbatim. KbDetail.tsx is updated minimally to import PageList and pass a fixed type="concepts" stopgap so the build stays green; full card-nav wiring lands in Task 13. * feat(web): KbOverviewCards become six-card nav with spring layoutId indicator * feat(web): KbSettingsSheet (config inherit/override + moved maintenance) + scroll-edge util * fix(web): threshold override rejects non-integer input (no silent revert); critically-damped sheet spring * feat(web): KbDetail card-nav — cards are the tab bar, settings sheet, spring switch * fix(web): screen-adaptive content widths + clickable wiki-links in the reader * feat(web): global top-right theme chrome cluster + MotionConfig root * fix(web): reserve top-right chrome lane so KbList/KbDetail controls clear the theme pill (+ room for i18n) Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(web): global Settings edits global defaults (KB picker + credentials removed) Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * refactor(web): drop dead `large` prop; Home input is 2 rows Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(web): parse [[target|alias]] wikilinks; test-guard global scalar-key whitelist parity Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(web): i18n infra (react-i18next) + language switcher + common namespace Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(web): i18n home namespace Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(web): i18n kbList namespace * feat(web): i18n kb namespace (KbDetail + overview cards + page list) * feat(web): i18n kbSettings namespace (per-KB gear sheet + maintenance) * feat(web): i18n settings namespace (Settings + About) Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(web): i18n chat namespace (ChatSession + ChatInput) Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(web): i18n artifacts namespace (ArtifactCard + ArtifactPanel) Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * chore(web): i18n full-sweep fixes + leftover-CJK guard Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(web): KB reader fills the window on large screens (generous cap + padding) Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(web): a11y — KbSettingsSheet modal dialog semantics + ArtifactPanel labeled region KbSettingsSheet (modal): compose @radix-ui/react-dialog around the existing motion.aside via asChild + forceMount so AnimatePresence keeps the D-era spring and reduced-motion. Radix supplies focus trap, initial focus, and Escape-close; add aria-modal + aria-labelledby (Dialog.Title on the heading) explicitly, and drive focus return to the opening gear via on{Open,Close}AutoFocus (we open from external state, so Radix's own triggerRef is null and would drop focus to body). Scrim/backdrop-dismiss, config inherit/override, watch/recompile/lint, threshold validation and all i18n preserved. ArtifactPanel (non-modal docked): add role=complementary + aria-label (active artifact label), aria-label on the header controls, and a one-time initial focus to the panel on open. No focus trap and no background inert — Tab still flows out to the chat. iframe/blob/new-tab/download, switcher, motion and i18n preserved. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): wire New knowledge base create flow + de-dup entries The KB list page had two "New knowledge base" controls (top-right button + in-grid dashed card) and NEITHER had an onClick — the frontend never wired KB creation. The sidebar's "+" was a third dead trigger. - add createKb() -> POST /api/v1/init (api/kb.ts) - new CreateKbDialog: Radix modal (Dialog.Trigger asChild for focus-trap/Escape/ focus-return), name-only field (model/creds inherit global defaults), inline backend-error surfacing, success -> navigate to the new KB - KbList: remove the dashed card; wire the single top-right button as the trigger - AppSidebar: wire the "+" to the same dialog Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): interleaved chat trace + drop /compile from palette Previously all streamed delta text (planning narration + the answer) was concatenated into one blob and tool reads showed only as separate chips. - chat.ts: fold SSE events into an ordered TurnStep[] preserving arrival order (text segments interleaved with tool steps); tool_call marks the prior read done; final reconciles the trailing text with the authoritative answer. The flat `answer`/`sources`/`reading` fields are retained for restore/consumers. - ChatSession.tsx: render steps in order — narration via MarkdownView, each read as a status line (spinner -> green check), page reads stay click-through. - drop `/compile` from the slash palette (runTurn never had a compile branch; recompile lives on the KB gear) and remove its now-unused icon import + keys. Chat is for Q&A + generation; KB-lifecycle actions live on the KB surface. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): global default credentials, drop dead footer, UN-language picker Settings global config surface: - backend: GET/PATCH /api/v1/config now also read/write global default credentials (LLM_API_KEY / OPENAI_API_BASE) in ~/.config/openkb/.env, mirroring the per-KB .env write (0o600, atomic, RFC-7386 null-removal, key value never returned/ logged), under the existing global-config lock. GlobalConfigResponse gains openai_api_base + has_api_key; GlobalConfigPatchRequest gains api_key (SecretStr) + openai_api_base. +6 tests. - Settings.tsx: add a Default credentials section (masked key, set/unset hint, deferred clear, API base) folded into the merge-patch save; remove the dead brand/privacy footer card + its i18n key. Wiki output language now offers the six official UN languages as a datalist combobox (still free-text, so e.g. 日本語 works) in both the global Settings and the per-KB gear. Also a one-line LanguageToggle doc-comment fix. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): persist per-turn chat trace so restored sessions keep the trace Revisiting a saved session collapsed the interleaved trace back to one text block, because only the flat answer was persisted. Now the ordered trace (narration text + tool reads) is stored per turn and rebuilt on restore. Backend: - ChatSession gains `assistant_traces` (parallel to assistant_texts, 1:1 by index); to_dict/load_session round-trip it; record_turn accepts a `trace` and back-fills empty traces for older turns so a pre-existing session that gets a new turn stays index-aligned. Old files without the key load as [] (no crash). - iter_chat_turn_events accumulates the trace from delta/tool_call events (same order the frontend folds live) and persists it via record_turn. - ChatSessionLoadResponse returns assistant_traces (new ChatTraceStep model). Frontend: - loadSession exposes assistant_traces; ChatSession restore rebuilds steps via stepsFromTrace (tool steps re-derived through the same read-only whitelist), falling back to a single text step for trace-less (old / CLI) turns. - fix a latent live bug: on `final`, do NOT overwrite the trailing text step with final.answer (which is the full narration+answer concatenation) — that duplicated narration once tool reads split the text; keep the streamed trace and only inject the answer when nothing streamed. Backward compatible: only sessions created after this change carry a trace; older ones render their saved text as before. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(workbench): record only read-tool calls in the persisted chat trace Review follow-up. The trace recorded every tool_call, including write_file, whose `arguments` carries the entire generated file `content`. That bloated the session JSON and was shipped to the browser on restore only to be dropped by the frontend's read-only whitelist. Gate recording to _TRACE_READ_TOOLS (read_file / get_page_content) — the only tools the UI renders — which also fixes a live-vs-restore text-grouping divergence a dropped write_file caused. Plus a tidy-up of the languages.ts doc comment (drop raw CJK). Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(workbench): render LaTeX math (KaTeX) and thematic-break rules in MarkdownView Answers that contain LaTeX (\[ … \] block, \( … \) inline) and `---` rules showed the raw delimiters/dashes as literal text. Add math + horizontal-rule support to the hand-rolled MarkdownView: block/inline math render via KaTeX (bundled + self-contained, no CDN; malformed TeX falls back to a code box), and a `---`/`***`/`___` line renders an <hr>. Adds katex (pinned exact, matching the mermaid/motion convention) + @types/katex. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(workbench): drop the not-yet-live openkb.ai website link from About The About tab linked a "Website openkb.ai" that does not exist yet; remove the link entry and its i18n key (both locales). The Globe icon stays (still used by the Vectify AI company link). Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(workbench): strip wiki frontmatter in the reader (no leading rule / junk) GET /api/v1/page serves pages verbatim, so every concept/entity/summary page's OKF `--- … ---` frontmatter leaked into the reader as junk metadata lines — and, now that MarkdownView renders `---` as an <hr>, as a horizontal rule at the very top. Strip a leading frontmatter block before rendering (reader only; chat answers carry no frontmatter and are untouched). Second-review follow-up. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(config): harden credential .env writes + config resolution (review) - credential .env: consolidate the KB and global read-modify-write into one _merge_patch_env helper that strips a leading `export ` before parsing (so an `export LLM_API_KEY=…` line is actually cleared/rotated, not leaked); reject api_key/openai_api_base values containing newlines (400) so a value can't inject extra KEY=VALUE lines python-dotenv would parse. - resolve_effective_config: coerce a non-dict config.yaml/global.yaml to {} so a malformed (esp. global) YAML degrades to defaults instead of AttributeError-ing KB-wide on every command's hot path. - PATCH /api/v1/config: run the blocking global-config flock via run_in_threadpool so a contended lock no longer stalls the async event loop. +4 tests. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(chat): atomic wiki write + whitespace-answer + tool-call id fallback (review) - write_kb_file now uses atomic_write_text (temp + os.replace) instead of a plain write_text, so a REST /chat-triggered wiki/output write can't be observed torn by a concurrent lint/recompile (and it goes through locks.py per the invariant). - iter_chat_turn_events: inject the final answer into the persisted trace unless a text step with NON-whitespace content exists, so a whitespace-only delta no longer makes a restored turn render empty. - iter_agent_response_events: derive the tool-call correlation id via a shared helper using the SDK's call_id-or-id fallback on BOTH the call and output sides, so LiteLLM/ChatCompletions-routed writes still fire the output artifact card. +8 tests. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(web): chat/input correctness fixes (review) - foldSseEvent final: inject the answer unless a non-whitespace text step exists (whitespace-only delta no longer hides the answer); export markToolStepsDone and run it in runTurn's catch/finally so a stream error settles the tool spinner. - App: wrap the /chat/:id route in a keyed ChatSessionRoute so a route-param change remounts and re-runs restore (no more stale previous session on nav). - ChatInput: guard Enter with !isComposing (CJK/IME users no longer submit mid-composition); use || so an empty kbId shows the placeholder, not blank. - Settings: reject a negative pageindex_threshold, matching the per-KB gear. - KbDetail: stripFrontmatter only strips a real YAML-mapping frontmatter block, so a page whose body legitimately opens with a --- rule keeps its first content. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(web): restore GFM links/italic/strikethrough/ordered-lists in MarkdownView The hand-rolled renderer dropped several GFM features vs the old react-markdown. Add [text](url) links (URL-scheme-guarded), *italic*/_italic_, ~~strikethrough~~, and real <ol> ordered lists — with load-bearing alternation order ([[wikilink]] before link, **bold** before italic) so existing tokens still parse. GFM tables and code syntax highlighting remain out (they need react-markdown re-adoption). Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(backend): atomic write_wiki_file + _setup_llm_key uses effective config - write_wiki_file now uses atomic_write_text (its sibling write_kb_file already did), so a REST /chat-triggered exploration write can't be observed torn. - _setup_llm_key resolves `model` via resolve_effective_config (DEFAULT -> global.yaml -> KB) instead of KB-only load_config, so a global-default model drives provider extraction; drop the now-unused load_config import. +1 test. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(web): restore stop/abort, document delete, upload progress, GFM tables Re-establishes capabilities the plain-CSS app had and closes review gaps: - Stream cancellation: apiStream/streamChat/streamQuery/runRecompile take an optional AbortSignal; ChatSession shows a Stop button while running and aborts the in-flight turn on unmount (no wasted tokens, clean settle — abort ≠ error); KbSettingsSheet aborts a recompile on close. - Documents: per-row delete (POST /api/v1/remove, confirm) + streaming upload with per-file progress (SSE /api/v1/add) replacing the single spinner. - Sidebar KB list refreshes on an `openkb:reload-kbs` event dispatched after a create, so a new KB appears without a full reload. - MarkdownView renders GFM tables (aligned, scrollable, inline-formatted cells). - client.ts warns once when the API base is cross-origin plain-http (token leak). Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(backend): configurable KB root, custom-path init, union KB discovery - kb_root_dir() precedence: env OPENKB_KB_ROOT > global.yaml `kb_root` > default <config>/kbs; GET/PATCH /api/v1/config expose/set `kb_root` (+ `kb_root_env_pinned`). - POST /api/v1/init accepts an optional absolute `path`; a custom-path KB is registered (register_kb_alias) so it still resolves by name (resolve_init_kb_dir; relative path -> 400). - KB discovery (moved to api_kbs.py to keep api.py/api_helpers.py < 800) now unions kb_root children with registered known_kbs/kb_aliases outside the root, deduped by resolved path; each /api/v1/kbs item gains `path`. +15 tests. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * feat(web): surface KB location — create-path preview, custom path, KB-root setting - CreateKbDialog shows a live "Will be created at <root>/<name>" preview (fetched from /api/v1/kbs root) and an optional Custom path field that overrides it. - Settings › General adds a Knowledge base root field (top-level kb_root merge-patch; empty -> null/default) with a note when it's pinned by OPENKB_KB_ROOT. - KbList cards show each KB's path (now that KBs can live outside the root). Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix(backend): allow Unicode KB names + resolve known_kbs KBs by basename Union KB discovery surfaced registered KBs outside kb_root (e.g. a CJK-named `笔记` at ~/Documents/笔记), but they couldn't be opened: validate_kb_name only allowed ASCII so a name-based endpoint 400'd on "笔记", and resolve_kb_alias only checked kb_aliases + the kb_root fallback, never known_kbs. - KB_NAME_RE relaxed to `[\w-]+` (Unicode letters/digits/_/-, still no spaces, dots, or path separators) so a Chinese-named KB is a valid, traversal-safe name. - resolve_kb_alias now matches a known_kbs path by its directory basename (after aliases, before the root fallback), consistent with the KB list — so a registered out-of-root KB is addressable by the name the UI shows. +2 tests. Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG * fix issue in review * fix(web): translate KbDetail comments to English so i18n guard passes The i18n build guard (check-i18n.mjs) flagged raw CJK inside comments in KbDetail.tsx, failing `npm run build`. Its comment-stripper is a naive state machine with no regex-literal handling, so a regex/quote earlier in the file desyncs it into "string" state; from there `{/* ... */}` JSX comments are read as string content and their CJK leaks past the strip. All flagged lines are comments (no real UI string carries CJK in this file), so converting the comments to English resolves the build failure with zero functional risk and matches the codebase norm (English code comments; CJK only in locale JSON). Claude-Session: https://claude.ai/code/session_01XMxbhmAkxxVV8CFWCZDBaG
1 parent 7cde496 commit 4b8c0db

172 files changed

Lines changed: 23443 additions & 4078 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

frontend/.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
110
node_modules
211
dist
12+
dist-ssr
313
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

frontend/components.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": false,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "postcss.config.js",
8+
"css": "src/index.css",
9+
"baseColor": "slate",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"iconLibrary": "lucide",
14+
"aliases": {
15+
"components": "@/components",
16+
"utils": "@/lib/utils",
17+
"ui": "@/components/ui",
18+
"lib": "@/lib",
19+
"hooks": "@/hooks"
20+
},
21+
"registries": {}
22+
}

frontend/eslint.config.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals'
3+
import reactHooks from 'eslint-plugin-react-hooks'
4+
import reactRefresh from 'eslint-plugin-react-refresh'
5+
import tseslint from 'typescript-eslint'
6+
import { defineConfig, globalIgnores } from 'eslint/config'
7+
8+
export default defineConfig([
9+
globalIgnores(['dist']),
10+
{
11+
files: ['**/*.{ts,tsx}'],
12+
extends: [
13+
js.configs.recommended,
14+
tseslint.configs.recommended,
15+
reactHooks.configs.flat.recommended,
16+
reactRefresh.configs.vite,
17+
],
18+
languageOptions: {
19+
ecmaVersion: 2020,
20+
globals: globals.browser,
21+
},
22+
},
23+
])

frontend/index.html

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<!doctype html>
2-
<html lang="en">
2+
<html lang="zh-CN">
33
<head>
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6-
<title>OpenKB · Knowledge Workbench</title>
7-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11/styles/github-dark.min.css" />
6+
<title>OpenKB Studio</title>
7+
<link rel="preconnect" href="https://fonts.googleapis.com" />
8+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
810
</head>
911
<body>
1012
<div id="root"></div>
11-
<script type="module" src="/src/main.jsx"></script>
13+
<script type="module" src="/src/main.tsx"></script>
1214
</body>
1315
</html>

0 commit comments

Comments
 (0)