@sewadah/selaras 0.3.1 → 0.4.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.
Files changed (63) hide show
  1. package/README.md +10 -1
  2. package/agent/catalog.mjs +73 -0
  3. package/agent/mcp.mjs +15 -0
  4. package/agent/server.mjs +58 -0
  5. package/dist/agent/catalog.json +1 -0
  6. package/dist/module.json +1 -1
  7. package/dist/module.mjs +7 -5
  8. package/dist/runtime/components/AlertDialog.d.vue.ts +5 -3
  9. package/dist/runtime/components/AlertDialog.vue +17 -9
  10. package/dist/runtime/components/AlertDialog.vue.d.ts +5 -3
  11. package/dist/runtime/components/App.vue +2 -0
  12. package/dist/runtime/components/Autocomplete.d.vue.ts +2 -2
  13. package/dist/runtime/components/Autocomplete.vue +1 -1
  14. package/dist/runtime/components/Autocomplete.vue.d.ts +2 -2
  15. package/dist/runtime/components/Button.d.vue.ts +7 -5
  16. package/dist/runtime/components/Button.vue +14 -3
  17. package/dist/runtime/components/Button.vue.d.ts +7 -5
  18. package/dist/runtime/components/ColorModeSwitch.d.vue.ts +18 -0
  19. package/dist/runtime/components/ColorModeSwitch.vue +59 -0
  20. package/dist/runtime/components/ColorModeSwitch.vue.d.ts +18 -0
  21. package/dist/runtime/components/ConfirmRenderer.d.vue.ts +3 -0
  22. package/dist/runtime/components/ConfirmRenderer.vue +39 -0
  23. package/dist/runtime/components/ConfirmRenderer.vue.d.ts +3 -0
  24. package/dist/runtime/components/ContextMenu.vue +4 -2
  25. package/dist/runtime/components/Drawer.vue +3 -2
  26. package/dist/runtime/components/Dropdown.vue +4 -2
  27. package/dist/runtime/components/Modal.vue +3 -2
  28. package/dist/runtime/components/Popover.vue +4 -2
  29. package/dist/runtime/components/Select.d.vue.ts +8 -4
  30. package/dist/runtime/components/Select.vue +1 -1
  31. package/dist/runtime/components/Select.vue.d.ts +8 -4
  32. package/dist/runtime/components/Slideover.vue +3 -2
  33. package/dist/runtime/components/Tooltip.vue +4 -2
  34. package/dist/runtime/composables/use-confirm.d.ts +14 -0
  35. package/dist/runtime/composables/use-confirm.js +28 -0
  36. package/dist/runtime/internal/ComboboxSelectBase.d.vue.ts +41 -32
  37. package/dist/runtime/internal/ComboboxSelectBase.vue +154 -68
  38. package/dist/runtime/internal/ComboboxSelectBase.vue.d.ts +41 -32
  39. package/dist/runtime/internal/ComboboxSelectBody.d.vue.ts +9 -7
  40. package/dist/runtime/internal/ComboboxSelectBody.vue +6 -6
  41. package/dist/runtime/internal/ComboboxSelectBody.vue.d.ts +9 -7
  42. package/dist/runtime/internal/combobox-select.d.ts +19 -18
  43. package/dist/runtime/internal/combobox-select.js +36 -14
  44. package/dist/runtime/internal/programmatic-services.d.ts +11 -0
  45. package/dist/runtime/internal/programmatic-services.js +1 -0
  46. package/dist/runtime/theme/badge.d.ts +9 -0
  47. package/dist/runtime/theme/badge.js +2 -1
  48. package/dist/runtime/theme/button.d.ts +18 -0
  49. package/dist/runtime/theme/button.js +4 -1
  50. package/dist/runtime/theme/select.js +1 -4
  51. package/dist/runtime/theme/toast.js +1 -1
  52. package/dist/runtime/theme-config.d.ts +1 -1
  53. package/dist/runtime/types/index.d.ts +4 -1
  54. package/dist/runtime/utils/autocomplete-contracts.d.ts +4 -4
  55. package/dist/runtime/utils/file-icons.js +1 -0
  56. package/dist/runtime/utils/messages.d.ts +1 -0
  57. package/dist/runtime/utils/messages.js +1 -0
  58. package/dist/runtime/utils/select-contracts.d.ts +18 -10
  59. package/dist/runtime/utils/ui.d.ts +11 -0
  60. package/dist/runtime/utils/ui.js +54 -1
  61. package/package.json +19 -9
  62. package/skills/selaras/SKILL.md +40 -0
  63. package/skills/selaras/agents/openai.yaml +4 -0
package/README.md CHANGED
@@ -37,6 +37,12 @@ matter of overriding variables, not rebuilding the library.
37
37
  wrappers for `@nuxt/content`.
38
38
  - Components auto-import with an `S` prefix (`SButton`, `SSelect`, ...).
39
39
 
40
+ ## Agent support
41
+
42
+ Use the [Selaras skill](skills/selaras/SKILL.md) to guide component selection and customization. The package also includes `selaras-mcp`, a local stdio MCP server with versioned documentation search, component discovery, and Vue examples. It needs no hosted service or API key.
43
+
44
+ See the [agent support guides](https://sewadahapp.github.io/selaras/overview/agent-support/overview) for skill installation, MCP client configuration, and the public `llms.txt` exports.
45
+
40
46
  ## Quick Setup
41
47
 
42
48
  Install the module to your Nuxt application with one command:
@@ -128,7 +134,10 @@ See the full [Theming guide](./docs/content/overview/theming.md).
128
134
  # Generate type stubs and prepare the docs site
129
135
  npm run docs:prepare
130
136
 
131
- # Develop with the docs site (documentation + component showcase)
137
+ # Develop with the Selaras documentation site in /docs
138
+ npm run dev
139
+
140
+ # Develop the standalone documentation template preview
132
141
  npm run docs:dev
133
142
 
134
143
  # Generate the static docs site
@@ -0,0 +1,73 @@
1
+ import { readFile } from 'node:fs/promises'
2
+
3
+ export async function loadCatalog(url = new URL('../dist/agent/catalog.json', import.meta.url)) {
4
+ const catalog = JSON.parse(await readFile(url, 'utf8'))
5
+ if (typeof catalog.version !== 'string' || !Array.isArray(catalog.documents) || !Array.isArray(catalog.examples))
6
+ throw new Error('Invalid Selaras documentation catalog. Reinstall the package or run agent:build in the repository.')
7
+ return catalog
8
+ }
9
+
10
+ export function documentSummary(document) {
11
+ return {
12
+ path: document.path,
13
+ title: document.title,
14
+ description: document.description,
15
+ category: document.category,
16
+ component: document.component,
17
+ examples: document.examples,
18
+ uri: `selaras://docs${document.path}`,
19
+ }
20
+ }
21
+
22
+ export function findDocument(catalog, path) {
23
+ const normalized = `/${path.replace(/^\/+/, '').replace(/\.md$/, '')}`
24
+ return catalog.documents.find(document => document.path === normalized
25
+ || document.component?.toLowerCase() === path.toLowerCase())
26
+ }
27
+
28
+ export function searchDocuments(catalog, query, limit = 10) {
29
+ const words = query.toLowerCase().match(/[\p{L}\p{N}_-]+/gu) ?? []
30
+ if (!words.length)
31
+ return []
32
+ return catalog.documents.map((document) => {
33
+ const title = `${document.title} ${document.component ?? ''}`.toLowerCase()
34
+ const description = document.description.toLowerCase()
35
+ const content = document.content.toLowerCase()
36
+ const score = words.reduce((total, word) => total
37
+ + (title.includes(word) ? 10 : 0)
38
+ + (description.includes(word) ? 4 : 0)
39
+ + (document.path.includes(word) ? 2 : 0)
40
+ + (content.includes(word) ? 1 : 0), 0)
41
+ return { document, score }
42
+ }).filter(result => result.score > 0).sort((a, b) => b.score - a.score || a.document.path.localeCompare(b.document.path)).slice(0, limit).map(({ document }) => documentSummary(document))
43
+ }
44
+
45
+ export function readSection(content, section) {
46
+ if (!section)
47
+ return content
48
+ const headings = []
49
+ let fence
50
+ let offset = 0
51
+ for (const line of content.split('\n')) {
52
+ const marker = line.match(/^ {0,3}(`{3,}|~{3,})/)
53
+ if (fence) {
54
+ if (marker && marker[1][0] === fence[0] && marker[1].length >= fence.length && !line.slice(marker[0].length).trim())
55
+ fence = undefined
56
+ }
57
+ else if (marker) {
58
+ fence = marker[1]
59
+ }
60
+ else {
61
+ const heading = line.match(/^(#{1,6})[ \t]+(\S.*)$/)
62
+ if (heading)
63
+ headings.push({ level: heading[1].length, title: heading[2], offset })
64
+ }
65
+ offset += line.length + 1
66
+ }
67
+ const index = headings.findIndex(heading => heading.title.replace(/`/g, '').toLowerCase() === section.toLowerCase())
68
+ if (index < 0)
69
+ return undefined
70
+ const start = headings[index]
71
+ const end = headings.slice(index + 1).find(heading => heading.level <= start.level)
72
+ return content.slice(start.offset, end?.offset ?? content.length).trim()
73
+ }
package/agent/mcp.mjs ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import process from 'node:process'
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
4
+ import { loadCatalog } from './catalog.mjs'
5
+ import { createServer } from './server.mjs'
6
+
7
+ async function main() {
8
+ const server = createServer(await loadCatalog())
9
+ await server.connect(new StdioServerTransport())
10
+ }
11
+
12
+ main().catch((error) => {
13
+ console.error(`[selaras-mcp] ${error instanceof Error ? error.message : error}`)
14
+ process.exitCode = 1
15
+ })
@@ -0,0 +1,58 @@
1
+ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
2
+ import { z } from 'zod'
3
+ import { documentSummary, findDocument, readSection, searchDocuments } from './catalog.mjs'
4
+
5
+ const annotations = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
6
+ const text = value => ({ content: [{ type: 'text', text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) }] })
7
+ const failure = message => ({ ...text(message), isError: true })
8
+
9
+ export function createServer(catalog) {
10
+ const server = new McpServer({ name: 'selaras', version: catalog.version }, {
11
+ instructions: 'Use the component catalog before implementing UI. Read matching API guides and Vue examples; customize existing Selaras components with props, slots, ui, and shared configuration. This offline catalog matches the installed package version.',
12
+ })
13
+ server.registerTool('list_components', {
14
+ description: 'Discover Selaras components and composites, their documentation paths, and available examples. Filter by category such as forms, overlays, data, or dashboard.',
15
+ inputSchema: { category: z.string().max(100).optional() },
16
+ annotations,
17
+ }, async ({ category }) => text(catalog.documents.filter(document => document.component
18
+ && (!category || document.category.toLowerCase().includes(category.toLowerCase()))).map(documentSummary)))
19
+ server.registerTool('search_documentation', {
20
+ description: 'Search component APIs, setup, theming, icons, messages, adaptive controls, and composables. Returns matching guide paths to read next.',
21
+ inputSchema: { query: z.string().trim().min(1).max(200), limit: z.number().int().min(1).max(20).default(10) },
22
+ annotations,
23
+ }, async ({ query, limit }) => text(searchDocuments(catalog, query, limit)))
24
+ server.registerTool('get_documentation', {
25
+ description: 'Read a guide by its catalog path or component name (for example SSelect). Contains API tables and complete Vue source for embedded examples. Optionally read one heading section.',
26
+ inputSchema: { path: z.string().min(1).max(200), section: z.string().max(200).optional() },
27
+ annotations,
28
+ }, async ({ path, section }) => {
29
+ const document = findDocument(catalog, path)
30
+ if (!document)
31
+ return failure('Unknown documentation path. Use search_documentation or list_components to find a guide.')
32
+ const content = readSection(document.content, section)
33
+ return content === undefined
34
+ ? failure(`Unknown section in ${document.path}. Read the full guide to see available headings.`)
35
+ : text(`# ${document.title}\n\nPackage version: ${catalog.version}\nDocumentation: ${document.path}\n\n${content}`)
36
+ })
37
+ server.registerTool('get_example', {
38
+ description: 'Read the exact Vue source of a named example from a component guide or list_components result.',
39
+ inputSchema: { name: z.string().min(1).max(200) },
40
+ annotations,
41
+ }, async ({ name }) => {
42
+ const example = catalog.examples.find(example => example.name === name)
43
+ return example ? text(example.source) : failure('Unknown example name. Read the examples field in list_components or a component guide.')
44
+ })
45
+ server.registerResource('catalog', 'selaras://catalog', {
46
+ description: 'Guide and component index for this Selaras package version.',
47
+ mimeType: 'application/json',
48
+ }, async uri => ({ contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify({ version: catalog.version, documents: catalog.documents.map(documentSummary) }) }] }))
49
+ server.registerResource('documentation', new ResourceTemplate('selaras://docs/{+path}', {
50
+ list: async () => ({ resources: catalog.documents.map(document => ({ uri: documentSummary(document).uri, name: document.title, description: document.description, mimeType: 'text/markdown' })) }),
51
+ }), { mimeType: 'text/markdown', description: 'Versioned Selaras documentation with Vue examples.' }, async (uri, { path }) => {
52
+ const document = typeof path === 'string' ? findDocument(catalog, path) : undefined
53
+ if (!document)
54
+ throw new Error('Unknown Selaras documentation resource')
55
+ return { contents: [{ uri: uri.href, mimeType: 'text/markdown', text: document.content }] }
56
+ })
57
+ return server
58
+ }