/** VitePress configuration for the locally projected documentation site. */ import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import type { DefaultTheme, PageData } from 'vitepress' import type { ViteDevServer } from 'vite' import { withMermaid } from 'vitepress-plugin-mermaid' import { landingLink, orderedPages, routeLink, sectionSpec, type DocsLocale, type DocsPage } from '../docs.ts' import { docsSourceFiles, projectDocs } from '../../scripts/project-doc-site.ts' projectDocs() function sidebar(locale: DocsLocale, collection: NonNullable): DefaultTheme.SidebarItem[] { // `orderedPages` already sorts by section placement, so insertion order // carries the group order and each group keeps its pages in sequence. const groups = new Map() for (const page of orderedPages(locale, collection)) { const entries = groups.get(page.section) ?? [] entries.push(page) groups.set(page.section, entries) } return [...groups.entries()].map(([text, entries]) => { const { collapsed } = sectionSpec(locale, text) return { text, // A present `collapsed` is what makes the default theme render the // group as collapsible at all, so an open group must omit the key. ...(collapsed === undefined ? {} : { collapsed }), items: entries.map(page => ({ text: page.label, link: routeLink(page.route) })), } }) } function watchCanonicalDocs(server: ViteDevServer): void { const sources = docsSourceFiles() server.watcher.add(sources) server.watcher.on('change', (changed) => { if (!sources.includes(changed)) return projectDocs() }) } function escapeVueInterpolation(html: string): string { return html.replaceAll('{{', '{{').replaceAll('}}', '}}') } const sharedTheme: Pick = { search: { provider: 'local', options: { locales: { root: { translations: { button: { buttonText: '搜索文档', buttonAriaLabel: '搜索文档', }, modal: { displayDetails: '显示详细列表', resetButtonTitle: '清除搜索', backButtonTitle: '关闭搜索', noResultsText: '未找到相关结果', footer: { selectText: '选择', selectKeyAriaLabel: '回车键', navigateText: '切换', navigateUpKeyAriaLabel: '上方向键', navigateDownKeyAriaLabel: '下方向键', closeText: '关闭', closeKeyAriaLabel: 'Esc 键', }, }, }, }, }, }, }, socialLinks: [ { icon: 'github', link: 'https://github.com/deepseek-ai/deepseek-harness' }, ], editLink: { pattern: ({ frontmatter }: PageData) => { const data: unknown = frontmatter const editSource: unknown = typeof data === 'object' && data !== null ? Reflect.get(data, 'editSource') : undefined if (typeof editSource !== 'string') throw new Error('Projected documentation page has no editSource frontmatter.') return `https://github.com/deepseek-ai/deepseek-harness/edit/master/${editSource}` }, text: '在 GitHub 上编辑此页', }, } /** Site base path, carrying the leading and trailing slashes VitePress requires. */ const base = process.env.DOCS_BASE ?? '/' /** * The DeepSeek wordmark, inlined so its `currentColor` fills follow the active * theme. An `` would freeze the mark at the colors the file declares. */ const wordmark = readFileSync(resolve(import.meta.dirname, '../public/wordmark.svg'), 'utf8') .trim() .replace(' { let idle addEventListener('scroll', (event) => { const target = event.target if (!(target instanceof Element) || !target.classList.contains('VPSidebar')) return target.dataset.scrolling = '' clearTimeout(idle) idle = setTimeout(() => delete target.dataset.scrolling, 800) }, true) })() ` /** * Navigation-bar title: the DeepSeek wordmark and the release-stage tag. * VitePress renders `siteTitle` as HTML. * * @param previewTag - Localized release-stage label. * @returns Markup placed beside the navigation-bar home link. */ function siteTitle(previewTag: string): string { return `${wordmark}${previewTag}` } export default withMermaid({ title: 'DeepSeek Harness', description: '用于构建 Agent Harness 的插件化 SDK', base, head: [ // VitePress leaves head hrefs untouched, so the base belongs here explicitly. ['link', { rel: 'icon', type: 'image/svg+xml', href: `${base}favicon.svg` }], ['style', {}, siteStyle], ['script', {}, scrollbarScript], ], cleanUrls: true, srcDir: '.generated', cacheDir: '.cache', outDir: '.dist', locales: { root: { label: '简体中文', lang: 'zh-CN', themeConfig: { siteTitle: siteTitle('技术预览'), nav: [ { text: '入门', link: landingLink('root', 'zh-guide'), activeMatch: '^/guide/' }, { text: '开发', link: landingLink('root', 'zh-develop'), activeMatch: '^/develop/' }, { text: '参考', link: landingLink('root', 'zh-reference'), activeMatch: '^/reference/' }, ], sidebar: { '/guide/': sidebar('root', 'zh-guide'), '/develop/': sidebar('root', 'zh-develop'), '/reference/': sidebar('root', 'zh-reference'), }, outline: { label: '本页目录' }, docFooter: { prev: '上一篇', next: '下一篇' }, darkModeSwitchLabel: '外观', lightModeSwitchTitle: '切换到浅色主题', darkModeSwitchTitle: '切换到深色主题', sidebarMenuLabel: '菜单', returnToTopLabel: '返回顶部', langMenuLabel: '切换语言', skipToContentLabel: '跳至内容', }, }, en: { label: 'English', lang: 'en-US', link: '/en/', themeConfig: { siteTitle: siteTitle('Preview'), nav: [ { text: 'Guide', link: landingLink('en', 'en-guide'), activeMatch: '^/en/guide/' }, { text: 'Develop', link: landingLink('en', 'en-develop'), activeMatch: '^/en/develop/' }, { text: 'Reference', link: landingLink('en', 'en-reference'), activeMatch: '^/en/reference/' }, ], sidebar: { '/en/guide/': sidebar('en', 'en-guide'), '/en/develop/': sidebar('en', 'en-develop'), '/en/reference/': sidebar('en', 'en-reference'), }, editLink: { pattern: ({ frontmatter }: PageData) => { const data: unknown = frontmatter const editSource: unknown = typeof data === 'object' && data !== null ? Reflect.get(data, 'editSource') : undefined if (typeof editSource !== 'string') throw new Error('Projected documentation page has no editSource frontmatter.') return `https://github.com/deepseek-ai/deepseek-harness/edit/master/${editSource}` }, text: 'Edit this page on GitHub', }, outline: { label: 'On this page' }, docFooter: { prev: 'Previous', next: 'Next' }, }, }, }, vite: { // `srcDir` puts the Vite root inside the disposable generated tree, whose // own `public/` no tracked asset can live in. publicDir: resolve(import.meta.dirname, '../public'), plugins: [ { name: 'deepseek-harness-doc-projector', configureServer: watchCanonicalDocs, }, ], }, markdown: { config(md) { const renderText = md.renderer.rules.text const renderCode = md.renderer.rules.code_inline if (renderText === undefined || renderCode === undefined) { throw new Error('VitePress Markdown renderer is missing its text or inline-code rule.') } md.renderer.rules.text = (...args) => escapeVueInterpolation(renderText(...args)) md.renderer.rules.code_inline = (...args) => escapeVueInterpolation(renderCode(...args)) }, }, mermaid: {}, themeConfig: sharedTheme, })