docus 5.10.1 → 5.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/app.config.ts +1 -1
- package/app/components/docs/DocsPageHeaderLinks.vue +9 -4
- package/app/pages/[[lang]]/[...slug].vue +1 -0
- package/app/plugins/i18n.ts +1 -1
- package/modules/assistant/index.ts +4 -2
- package/modules/config.ts +12 -1
- package/modules/css.ts +27 -6
- package/modules/markdown-rewrite.ts +1 -1
- package/modules/skills/index.ts +4 -2
- package/package.json +2 -1
- package/server/mcp/tools/get-page.ts +7 -4
- package/server/mcp/tools/list-pages.ts +6 -3
package/app/app.config.ts
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useClipboard } from '@vueuse/core'
|
|
3
|
+
import { joinURL, withTrailingSlash } from 'ufo'
|
|
3
4
|
import { useRuntimeConfig } from '#imports'
|
|
4
5
|
|
|
5
6
|
const route = useRoute()
|
|
6
7
|
const toast = useToast()
|
|
7
|
-
const
|
|
8
|
+
const runtimeConfig = useRuntimeConfig()
|
|
9
|
+
const appBaseURL = runtimeConfig.app?.baseURL || '/'
|
|
10
|
+
const mcpRoute = (runtimeConfig.public.mcp as { route?: string } | undefined)?.route || '/mcp'
|
|
8
11
|
|
|
9
12
|
const { copy, copied } = useClipboard()
|
|
10
13
|
const { t } = useDocusI18n()
|
|
11
14
|
|
|
12
|
-
const markdownLink = computed(() => `${window?.location?.origin}${appBaseURL}raw${route.path}.md`)
|
|
15
|
+
const markdownLink = computed(() => `${window?.location?.origin}${withTrailingSlash(appBaseURL)}raw${route.path}.md`)
|
|
16
|
+
const mcpServerUrl = computed(() => `${window?.location?.origin}${joinURL(appBaseURL, mcpRoute)}`)
|
|
17
|
+
const mcpDeeplink = joinURL(mcpRoute, 'deeplink')
|
|
13
18
|
const items = [
|
|
14
19
|
[{
|
|
15
20
|
label: t('docs.copy.link'),
|
|
@@ -41,7 +46,7 @@ const items = [
|
|
|
41
46
|
label: 'Copy MCP Server URL',
|
|
42
47
|
icon: 'i-lucide-link',
|
|
43
48
|
onSelect() {
|
|
44
|
-
copy(
|
|
49
|
+
copy(mcpServerUrl.value)
|
|
45
50
|
toast.add({
|
|
46
51
|
title: 'Copied to clipboard',
|
|
47
52
|
icon: 'i-lucide-check-circle',
|
|
@@ -52,7 +57,7 @@ const items = [
|
|
|
52
57
|
label: 'Add MCP Server',
|
|
53
58
|
icon: 'i-simple-icons:cursor',
|
|
54
59
|
target: '_blank',
|
|
55
|
-
to:
|
|
60
|
+
to: mcpDeeplink,
|
|
56
61
|
},
|
|
57
62
|
],
|
|
58
63
|
]
|
package/app/plugins/i18n.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RouteLocationNormalized } from 'vue-router'
|
|
2
2
|
import { consola } from 'consola'
|
|
3
3
|
|
|
4
|
-
const log = consola.withTag('
|
|
4
|
+
const log = consola.withTag('docus')
|
|
5
5
|
|
|
6
6
|
// Lazy import functions for locale files (bundled but not eagerly loaded)
|
|
7
7
|
const localeFiles = import.meta.glob<{ default: Record<string, unknown> }>('../../i18n/locales/*.json')
|
|
@@ -21,7 +21,7 @@ export interface AssistantModuleOptions {
|
|
|
21
21
|
model?: string
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const log = logger.withTag('
|
|
24
|
+
const log = logger.withTag('docus')
|
|
25
25
|
|
|
26
26
|
const defaults: Required<AssistantModuleOptions> = {
|
|
27
27
|
apiPath: '/__docus__/assistant',
|
|
@@ -77,7 +77,9 @@ export default defineNuxtModule<AssistantModuleOptions>({
|
|
|
77
77
|
)
|
|
78
78
|
|
|
79
79
|
if (!hasAiGatewayAuth) {
|
|
80
|
-
|
|
80
|
+
nuxt.hook('modules:done', () => {
|
|
81
|
+
log.warn('AI assistant disabled: neither `AI_GATEWAY_API_KEY` nor `VERCEL_OIDC_TOKEN` found')
|
|
82
|
+
})
|
|
81
83
|
return
|
|
82
84
|
}
|
|
83
85
|
|
package/modules/config.ts
CHANGED
|
@@ -5,10 +5,11 @@ import { join } from 'node:path'
|
|
|
5
5
|
import { inferSiteURL, getPackageJsonMetadata } from '../utils/meta'
|
|
6
6
|
import { getGitBranch, getGitEnv, getLocalGitInfo } from '../utils/git'
|
|
7
7
|
|
|
8
|
-
const log = logger.withTag('
|
|
8
|
+
const log = logger.withTag('docus')
|
|
9
9
|
|
|
10
10
|
type I18nLocale = string | { code: string, name?: string }
|
|
11
11
|
type DocusI18nOptions = { locales?: I18nLocale[], strategy?: string }
|
|
12
|
+
type DocusMcpOptions = { route?: string, enabled?: boolean }
|
|
12
13
|
type RegisterModuleOptions = {
|
|
13
14
|
langDir: string
|
|
14
15
|
locales: Array<{ code: string, name: string, file: string }>
|
|
@@ -58,6 +59,16 @@ export default defineNuxtModule({
|
|
|
58
59
|
branch: getGitBranch(),
|
|
59
60
|
})
|
|
60
61
|
|
|
62
|
+
/*
|
|
63
|
+
** MCP route (expose to client so the page header dropdown stays in sync
|
|
64
|
+
** with the user-configured `mcp.route` from @nuxtjs/mcp-toolkit)
|
|
65
|
+
*/
|
|
66
|
+
const mcpOptions = (nuxt.options as typeof nuxt.options & { mcp?: DocusMcpOptions }).mcp
|
|
67
|
+
nuxt.options.runtimeConfig.public.mcp = defu(
|
|
68
|
+
nuxt.options.runtimeConfig.public.mcp as DocusMcpOptions | undefined,
|
|
69
|
+
{ route: mcpOptions?.route || '/mcp' },
|
|
70
|
+
)
|
|
71
|
+
|
|
61
72
|
const forcedColorMode = (nuxt.options.appConfig.docus as Record<string, unknown>)?.colorMode as string | undefined
|
|
62
73
|
if (forcedColorMode === 'light' || forcedColorMode === 'dark') {
|
|
63
74
|
nuxt.options.colorMode = defu({ preference: forcedColorMode, fallback: forcedColorMode }, nuxt.options.colorMode || {}) as typeof nuxt.options.colorMode
|
package/modules/css.ts
CHANGED
|
@@ -1,21 +1,37 @@
|
|
|
1
|
-
import { defineNuxtModule, addTemplate, createResolver } from '@nuxt/kit'
|
|
2
|
-
import {
|
|
1
|
+
import { defineNuxtModule, addTemplate, createResolver, logger } from '@nuxt/kit'
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { readFile } from 'node:fs/promises'
|
|
4
|
+
import { resolve } from 'pathe'
|
|
3
5
|
import { resolveModulePath } from 'exsolve'
|
|
4
6
|
|
|
7
|
+
const log = logger.withTag('docus')
|
|
8
|
+
|
|
5
9
|
export default defineNuxtModule({
|
|
6
10
|
meta: {
|
|
7
|
-
name: 'css',
|
|
11
|
+
name: 'docus-css',
|
|
8
12
|
},
|
|
9
13
|
async setup(_options, nuxt) {
|
|
10
|
-
const dir = nuxt.options.rootDir
|
|
11
14
|
const resolver = createResolver(import.meta.url)
|
|
12
15
|
|
|
13
|
-
const contentDir =
|
|
16
|
+
const contentDir = resolve(nuxt.options.rootDir, 'content')
|
|
14
17
|
const uiPath = resolveModulePath('@nuxt/ui', { from: import.meta.url, conditions: ['style'] })
|
|
15
18
|
const tailwindPath = resolveModulePath('tailwindcss', { from: import.meta.url, conditions: ['style'] })
|
|
16
19
|
const layerDir = resolver.resolve('../app')
|
|
17
20
|
const assistantDir = resolver.resolve('../modules/assistant')
|
|
18
21
|
|
|
22
|
+
let userDocusPath: string | null = resolve(nuxt.options.srcDir, 'app.css')
|
|
23
|
+
if (existsSync(userDocusPath)) {
|
|
24
|
+
const userDocusCss = await readFile(userDocusPath, 'utf-8')
|
|
25
|
+
if (userDocusCss.includes('@import "tailwindcss"')) {
|
|
26
|
+
nuxt.hook('modules:done', () => {
|
|
27
|
+
log.warn('`app.css` contains `@import "tailwindcss";` consider removing it to avoid duplicate css.')
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
userDocusPath = null
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
const cssTemplate = addTemplate({
|
|
20
36
|
filename: 'docus.css',
|
|
21
37
|
getContents: () => {
|
|
@@ -25,7 +41,12 @@ export default defineNuxtModule({
|
|
|
25
41
|
@source "${contentDir.replace(/\\/g, '/')}/**/*";
|
|
26
42
|
@source "${layerDir.replace(/\\/g, '/')}/**/*";
|
|
27
43
|
@source "../../app.config.ts";
|
|
28
|
-
@source "${assistantDir.replace(/\\/g, '/')}/**/*"
|
|
44
|
+
@source "${assistantDir.replace(/\\/g, '/')}/**/*";
|
|
45
|
+
|
|
46
|
+
:root {
|
|
47
|
+
--ui-container: 90rem;
|
|
48
|
+
}
|
|
49
|
+
` + (userDocusPath ? `\n@import ${JSON.stringify(userDocusPath)};` : '')
|
|
29
50
|
},
|
|
30
51
|
})
|
|
31
52
|
|
|
@@ -2,7 +2,7 @@ import { defineNuxtModule, logger } from '@nuxt/kit'
|
|
|
2
2
|
import { resolve } from 'node:path'
|
|
3
3
|
import { readFile, writeFile } from 'node:fs/promises'
|
|
4
4
|
|
|
5
|
-
const log = logger.withTag('
|
|
5
|
+
const log = logger.withTag('docus')
|
|
6
6
|
|
|
7
7
|
type I18nLocale = string | { code: string }
|
|
8
8
|
type DocusI18nOptions = { locales?: I18nLocale[] }
|
package/modules/skills/index.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface SkillsModuleOptions {
|
|
|
19
19
|
const SKILL_NAME_REGEX = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/
|
|
20
20
|
const MAX_NAME_LENGTH = 64
|
|
21
21
|
|
|
22
|
-
const log = logger.withTag('
|
|
22
|
+
const log = logger.withTag('docus')
|
|
23
23
|
|
|
24
24
|
const defaults: Required<SkillsModuleOptions> = {
|
|
25
25
|
dir: 'skills',
|
|
@@ -38,7 +38,9 @@ export default defineNuxtModule<SkillsModuleOptions>({
|
|
|
38
38
|
const catalog = await scanSkills(skillsDir)
|
|
39
39
|
if (!catalog.length) return
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
nuxt.hook('modules:done', () => {
|
|
42
|
+
log.info(`Found ${catalog.length} agent skill${catalog.length > 1 ? 's' : ''}: ${catalog.map(s => s.name).join(', ')}`)
|
|
43
|
+
})
|
|
42
44
|
|
|
43
45
|
nuxt.options.runtimeConfig.skills = { catalog }
|
|
44
46
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docus",
|
|
3
3
|
"description": "Nuxt layer for Docus documentation theme",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.11.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
7
7
|
"repository": {
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"motion-v": "^2.2.1",
|
|
51
51
|
"nuxt-llms": "^0.2.0",
|
|
52
52
|
"nuxt-og-image": "^6.4.5",
|
|
53
|
+
"pathe": "^2.0.3",
|
|
53
54
|
"pkg-types": "^2.3.0",
|
|
54
55
|
"scule": "^1.3.0",
|
|
55
56
|
"shiki-stream": "^0.1.4",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
+
import { joinURL } from 'ufo'
|
|
2
3
|
import { queryCollection } from '@nuxt/content/server'
|
|
3
4
|
import type { Collections } from '@nuxt/content'
|
|
4
5
|
import { getAvailableLocales, getCollectionFromPath } from '../../utils/content'
|
|
@@ -33,11 +34,13 @@ WORKFLOW: This tool returns the complete page content including title, descripti
|
|
|
33
34
|
cache: '1h',
|
|
34
35
|
handler: async ({ path }) => {
|
|
35
36
|
const event = useEvent()
|
|
36
|
-
const config = useRuntimeConfig(event)
|
|
37
|
+
const config = useRuntimeConfig(event)
|
|
38
|
+
const publicConfig = config.public
|
|
37
39
|
const siteUrl = getRequestURL(event).origin || inferSiteURL()
|
|
40
|
+
const baseURL = config.app?.baseURL || '/'
|
|
38
41
|
|
|
39
|
-
const availableLocales = getAvailableLocales(
|
|
40
|
-
const collectionName =
|
|
42
|
+
const availableLocales = getAvailableLocales(publicConfig)
|
|
43
|
+
const collectionName = publicConfig.i18n?.locales
|
|
41
44
|
? getCollectionFromPath(path, availableLocales)
|
|
42
45
|
: 'docs'
|
|
43
46
|
|
|
@@ -58,7 +61,7 @@ WORKFLOW: This tool returns the complete page content including title, descripti
|
|
|
58
61
|
path: page.path,
|
|
59
62
|
description: page.description,
|
|
60
63
|
content,
|
|
61
|
-
url:
|
|
64
|
+
url: siteUrl ? joinURL(siteUrl, baseURL, page.path) : joinURL(baseURL, page.path),
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
67
|
catch (error) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
+
import { joinURL } from 'ufo'
|
|
2
3
|
import { queryCollection } from '@nuxt/content/server'
|
|
3
4
|
import type { Collections } from '@nuxt/content'
|
|
4
5
|
import { getCollectionsToQuery, getAvailableLocales } from '../../utils/content'
|
|
@@ -39,10 +40,12 @@ OUTPUT: Returns a structured list with:
|
|
|
39
40
|
cache: '1h',
|
|
40
41
|
handler: async ({ locale }) => {
|
|
41
42
|
const event = useEvent()
|
|
42
|
-
const config = useRuntimeConfig(event)
|
|
43
|
+
const config = useRuntimeConfig(event)
|
|
44
|
+
const publicConfig = config.public
|
|
43
45
|
|
|
44
46
|
const siteUrl = getRequestURL(event).origin || inferSiteURL()
|
|
45
|
-
const
|
|
47
|
+
const baseURL = config.app?.baseURL || '/'
|
|
48
|
+
const availableLocales = getAvailableLocales(publicConfig)
|
|
46
49
|
const collections = getCollectionsToQuery(locale, availableLocales)
|
|
47
50
|
|
|
48
51
|
try {
|
|
@@ -57,7 +60,7 @@ OUTPUT: Returns a structured list with:
|
|
|
57
60
|
path: page.path,
|
|
58
61
|
description: page.description,
|
|
59
62
|
locale: collectionName.replace('docs_', ''),
|
|
60
|
-
url:
|
|
63
|
+
url: siteUrl ? joinURL(siteUrl, baseURL, page.path) : joinURL(baseURL, page.path),
|
|
61
64
|
}))
|
|
62
65
|
}),
|
|
63
66
|
)
|