@opentiny/tiny-robot-cli 0.5.2-alpha.16 → 0.5.2-alpha.18

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 (53) hide show
  1. package/README.md +1 -49
  2. package/bin/commands/add.js +270 -561
  3. package/bin/commands/create.js +3 -6
  4. package/bin/utils.js +45 -147
  5. package/package.json +3 -5
  6. package/templates/basic/.env.example +0 -8
  7. package/templates/basic/README.md +22 -53
  8. package/templates/basic/index.html +2 -2
  9. package/templates/basic/package.json +16 -12
  10. package/templates/basic/public/modelcontextprotocol.png +0 -0
  11. package/templates/basic/src/App.vue +119 -112
  12. package/templates/basic/src/components/ChatList.vue +82 -0
  13. package/templates/basic/src/components/ChatSender.vue +125 -0
  14. package/templates/basic/src/components/ConversationHistory.vue +136 -0
  15. package/templates/basic/src/components/HistoryDrawerButton.vue +43 -0
  16. package/templates/basic/src/components/McpServerPickerButton.vue +278 -0
  17. package/templates/basic/src/components/ThemeToggleButton.vue +44 -0
  18. package/templates/basic/src/components/icons/IconDeepThink.vue +29 -0
  19. package/templates/basic/src/components/icons/IconModelAliyunBailian.vue +51 -0
  20. package/templates/basic/src/components/icons/IconModelDeepseek.vue +29 -0
  21. package/templates/basic/src/components/icons/IconMoon.vue +29 -0
  22. package/templates/basic/src/components/icons/IconPlugin.vue +29 -0
  23. package/templates/basic/src/components/icons/IconSun.vue +35 -0
  24. package/templates/basic/src/components/icons/IconWebSearch.vue +36 -0
  25. package/templates/basic/src/components/icons/index.ts +7 -0
  26. package/templates/basic/src/composables/useChat.ts +129 -0
  27. package/templates/basic/src/composables/useMcp.ts +170 -0
  28. package/templates/basic/src/composables/useModel.ts +82 -0
  29. package/templates/basic/src/main.ts +2 -2
  30. package/templates/basic/src/mcpServers.ts +40 -0
  31. package/templates/basic/src/models.ts +81 -0
  32. package/templates/basic/tsconfig.app.json +5 -2
  33. package/templates/basic/tsconfig.node.json +6 -3
  34. package/templates/basic/vite.config.ts +1 -6
  35. package/templates/chat/.env.example +0 -9
  36. package/templates/chat/src/TinyRobotChat.vue +27 -88
  37. package/bin/runtime-version.js +0 -37
  38. package/templates/basic/public/favicon.svg +0 -1
  39. package/templates/basic/public/icons.svg +0 -24
  40. package/templates/chat/README.md +0 -46
  41. package/templates/chat/index.html +0 -12
  42. package/templates/chat/package.json +0 -28
  43. package/templates/chat/src/components/ComposerTools.vue +0 -99
  44. package/templates/chat/src/components/WindowHeader.vue +0 -192
  45. package/templates/chat/src/composables/useWindow.ts +0 -83
  46. package/templates/chat/src/config/chat-runtime.ts +0 -82
  47. package/templates/chat/src/config/chat-ui.ts +0 -290
  48. package/templates/chat/src/index.css +0 -109
  49. package/templates/chat/src/main.ts +0 -7
  50. package/templates/chat/tsconfig.app.json +0 -13
  51. package/templates/chat/tsconfig.json +0 -7
  52. package/templates/chat/tsconfig.node.json +0 -19
  53. package/templates/chat/vite.config.ts +0 -16
@@ -2,7 +2,6 @@ import { input, select } from '@inquirer/prompts'
2
2
  import path from 'node:path'
3
3
  import process from 'node:process'
4
4
 
5
- import { resolveRuntimeVersion } from '../runtime-version.js'
6
5
  import {
7
6
  DEFAULT_PROJECT_NAME,
8
7
  DEFAULT_TEMPLATE,
@@ -120,13 +119,12 @@ function printCreateSuccess(projectName) {
120
119
  console.log()
121
120
  }
122
121
 
123
- async function createProject(initialProjectName, initialTemplateName, runtimeVersion, skipPrompt) {
124
- const runtime = resolveRuntimeVersion(runtimeVersion)
122
+ async function createProject(initialProjectName, initialTemplateName, skipPrompt) {
125
123
  const options = await resolveCreateOptions(initialProjectName, initialTemplateName, skipPrompt)
126
124
 
127
125
  const { templateDir, targetDir } = validateCreateOptions(options)
128
126
 
129
- scaffoldProject(templateDir, targetDir, options.projectName, runtime.specifier)
127
+ scaffoldProject(templateDir, targetDir, options.projectName)
130
128
 
131
129
  printCreateSuccess(options.projectName)
132
130
  }
@@ -136,11 +134,10 @@ export function registerCreateCommand(program) {
136
134
  .command('create [project-name]')
137
135
  .description('Create a TinyRobot project from template')
138
136
  .option('-t, --template <name>', 'template name')
139
- .option('--runtime-version <version>', 'override the TinyRobot runtime version')
140
137
  .action((projectName, options) => {
141
138
  const skipPrompt = !process.stdout.isTTY
142
139
 
143
- createProject(projectName ?? '', options.template ?? '', options.runtimeVersion, skipPrompt).catch((error) => {
140
+ createProject(projectName ?? '', options.template ?? '', skipPrompt).catch((error) => {
144
141
  if (error instanceof Error && error.name === 'ExitPromptError') {
145
142
  console.error('\nOperation cancelled.')
146
143
  process.exit(1)
package/bin/utils.js CHANGED
@@ -5,7 +5,6 @@ import pc from 'picocolors'
5
5
  import yaml from 'yaml'
6
6
 
7
7
  const TEMPLATE_PLACEHOLDER = '__PROJECT_NAME__'
8
- const RUNTIME_VERSION_PLACEHOLDER = '__TINY_ROBOT_VERSION__'
9
8
 
10
9
  export const BUILTIN_TEMPLATES = ['basic']
11
10
  export const DEFAULT_TEMPLATE = 'basic'
@@ -37,7 +36,10 @@ export function logError(message) {
37
36
  }
38
37
 
39
38
  export function invariant(condition, message) {
40
- if (!condition) throw new Error(message)
39
+ if (!condition) {
40
+ console.error(`Error: ${message}`)
41
+ process.exit(1)
42
+ }
41
43
  }
42
44
 
43
45
  export function exists(file) {
@@ -86,10 +88,6 @@ export function validateProjectName(name) {
86
88
  }
87
89
 
88
90
  export function copyTemplate(sourceDir, targetDir) {
89
- copyDirectory(sourceDir, targetDir)
90
- }
91
-
92
- export function copyDirectory(sourceDir, targetDir) {
93
91
  fs.cpSync(sourceDir, targetDir, {
94
92
  recursive: true,
95
93
  filter: (source) => {
@@ -112,7 +110,7 @@ function renameSpecialFiles(targetDir) {
112
110
  }
113
111
 
114
112
  function replaceTemplateVariables(targetDir, variables) {
115
- const replaceFiles = ['package.json', 'README.md', 'index.html']
113
+ const replaceFiles = ['package.json', 'README.md']
116
114
 
117
115
  for (const relativePath of replaceFiles) {
118
116
  const file = path.join(targetDir, relativePath)
@@ -131,14 +129,13 @@ function replaceTemplateVariables(targetDir, variables) {
131
129
  }
132
130
  }
133
131
 
134
- export function scaffoldProject(templateDir, targetDir, projectName, runtimeVersion) {
132
+ export function scaffoldProject(templateDir, targetDir, projectName) {
135
133
  copyTemplate(templateDir, targetDir)
136
134
 
137
135
  renameSpecialFiles(targetDir)
138
136
 
139
137
  replaceTemplateVariables(targetDir, {
140
138
  [TEMPLATE_PLACEHOLDER]: projectName,
141
- [RUNTIME_VERSION_PLACEHOLDER]: runtimeVersion,
142
139
  })
143
140
  }
144
141
 
@@ -169,24 +166,20 @@ export function findProjectRoot(cwd) {
169
166
  }
170
167
 
171
168
  export function findSubPackageRoot(cwd, workspaceRoot) {
172
- let dir = path.resolve(cwd)
173
- const root = path.resolve(workspaceRoot)
174
-
175
- for (;;) {
176
- if (dir === root) return null
177
- if (isPackageDir(dir)) return dir
169
+ return findUp(cwd, (dir) => {
170
+ if (dir === workspaceRoot) {
171
+ return false
172
+ }
178
173
 
179
- const parent = path.dirname(dir)
180
- if (parent === dir) return null
181
- dir = parent
182
- }
174
+ return isPackageDir(dir)
175
+ })
183
176
  }
184
177
 
185
178
  export function findWorkspacePackages(workspaceRoot) {
186
179
  const workspaceFile = resolveWorkspaceFile(workspaceRoot)
187
180
 
188
181
  if (!workspaceFile) {
189
- return undefined
182
+ return []
190
183
  }
191
184
 
192
185
  try {
@@ -194,139 +187,56 @@ export function findWorkspacePackages(workspaceRoot) {
194
187
 
195
188
  const config = yaml.parse(content)
196
189
 
197
- if (config === null || typeof config !== 'object' || Array.isArray(config)) {
198
- throw new Error('workspace configuration must be a YAML mapping')
199
- }
200
-
201
- if (!Object.prototype.hasOwnProperty.call(config, 'packages')) {
202
- return undefined
203
- }
204
-
205
- if (!Array.isArray(config.packages)) {
206
- throw new Error('packages must be an array')
207
- }
208
-
209
- if (config.packages.some((pattern) => typeof pattern !== 'string' || pattern.trim().length === 0)) {
210
- throw new Error('packages entries must be non-empty strings')
211
- }
212
-
213
- return config.packages.map((pattern) => pattern.trim())
214
- } catch (error) {
215
- const detail = error instanceof Error ? `: ${error.message}` : ''
216
- throw new Error(`Failed to read ${path.basename(workspaceFile)}${detail}`)
190
+ return Array.isArray(config?.packages)
191
+ ? config.packages.filter(
192
+ (pattern) => typeof pattern === 'string' && pattern.length > 0 && !pattern.startsWith('!'),
193
+ )
194
+ : []
195
+ } catch {
196
+ return []
217
197
  }
218
198
  }
219
199
 
220
- const WORKSPACE_SCAN_IGNORES = new Set(['.git', 'node_modules'])
221
-
222
200
  function normalizeWorkspacePattern(pattern) {
223
- let normalized = pattern.replaceAll('\\', '/').trim()
224
- if (normalized.startsWith('./')) normalized = normalized.slice(2)
225
- return normalized.replace(/\/$/, '')
201
+ return pattern.replace(/\*\*?/g, '').replace(/\/$/, '')
226
202
  }
227
203
 
228
- function globSource(pattern) {
229
- let source = ''
230
-
231
- for (let index = 0; index < pattern.length; index += 1) {
232
- const char = pattern[index]
233
-
234
- if (char === '*') {
235
- if (pattern[index + 1] === '*') {
236
- while (pattern[index + 1] === '*') index += 1
237
- if (pattern[index + 1] === '/') {
238
- source += '(?:.*/)?'
239
- index += 1
240
- } else {
241
- source += '.*'
242
- }
243
- } else {
244
- source += '[^/]*'
245
- }
246
- continue
247
- }
248
-
249
- if (char === '?') {
250
- source += '[^/]'
251
- continue
252
- }
253
-
254
- if (char === '{') {
255
- const close = pattern.indexOf('}', index + 1)
256
- if (close !== -1) {
257
- const alternatives = pattern
258
- .slice(index + 1, close)
259
- .split(',')
260
- .map((item) => globSource(item))
261
- source += `(?:${alternatives.join('|')})`
262
- index = close
263
- continue
264
- }
265
- }
204
+ export function listPackages(workspaceRoot, patterns) {
205
+ const packageDirs = []
266
206
 
267
- if (char === '[') {
268
- const close = pattern.indexOf(']', index + 1)
269
- if (close !== -1) {
270
- source += pattern.slice(index, close + 1)
271
- index = close
272
- continue
273
- }
207
+ const addPackage = (dir) => {
208
+ if (isPackageDir(dir)) {
209
+ packageDirs.push(dir)
274
210
  }
275
-
276
- source += char.replace(/[\\.^$+()|]/g, '\\$&')
277
211
  }
278
212
 
279
- return source
280
- }
213
+ for (const pattern of patterns) {
214
+ const base = normalizeWorkspacePattern(pattern)
281
215
 
282
- function matchesWorkspacePattern(relativePath, pattern) {
283
- const normalized = normalizeWorkspacePattern(pattern)
284
- if (normalized === '.') return relativePath === ''
285
- return new RegExp(`^${globSource(normalized)}$`).test(relativePath)
286
- }
216
+ const fullPath = path.join(workspaceRoot, base)
287
217
 
288
- function collectPackageDirs(workspaceRoot) {
289
- const packageDirs = []
218
+ if (!exists(fullPath)) {
219
+ continue
220
+ }
290
221
 
291
- const visit = (dir) => {
292
- if (isPackageDir(dir)) packageDirs.push(dir)
222
+ if (pattern.includes('*')) {
223
+ const entries = fs.readdirSync(fullPath, {
224
+ withFileTypes: true,
225
+ })
293
226
 
294
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
295
- if (!entry.isDirectory() || WORKSPACE_SCAN_IGNORES.has(entry.name)) continue
296
- visit(path.join(dir, entry.name))
227
+ for (const entry of entries) {
228
+ if (entry.isDirectory()) {
229
+ addPackage(path.join(fullPath, entry.name))
230
+ }
231
+ }
232
+ } else {
233
+ addPackage(fullPath)
297
234
  }
298
235
  }
299
236
 
300
- visit(workspaceRoot)
301
237
  return packageDirs
302
238
  }
303
239
 
304
- export function listPackages(workspaceRoot, patterns = undefined) {
305
- const configuredPatterns = patterns ?? ['**']
306
- const includePatterns = configuredPatterns.filter((pattern) => !pattern.startsWith('!'))
307
- const excludePatterns = configuredPatterns
308
- .filter((pattern) => pattern.startsWith('!'))
309
- .map((pattern) => pattern.slice(1))
310
-
311
- if (includePatterns.length === 0) return []
312
-
313
- const root = path.resolve(workspaceRoot)
314
- const packageDirs = collectPackageDirs(root)
315
- const matched = packageDirs.filter((dir) => {
316
- const relativePath = path.relative(root, dir).replaceAll('\\', '/')
317
- return (
318
- includePatterns.some((pattern) => matchesWorkspacePattern(relativePath, pattern)) &&
319
- !excludePatterns.some((pattern) => matchesWorkspacePattern(relativePath, pattern))
320
- )
321
- })
322
-
323
- return [...new Set(matched)].sort((left, right) => {
324
- const leftRelative = path.relative(root, left)
325
- const rightRelative = path.relative(root, right)
326
- return leftRelative.localeCompare(rightRelative)
327
- })
328
- }
329
-
330
240
  function ensureDir(file) {
331
241
  fs.mkdirSync(path.dirname(file), {
332
242
  recursive: true,
@@ -376,19 +286,6 @@ export function mergeEnvFile(templateFile, targetFile) {
376
286
 
377
287
  const targetContent = fs.readFileSync(targetFile, 'utf-8')
378
288
 
379
- const result = mergeEnvContent(templateContent, targetContent)
380
-
381
- if (result.type === 'merged') {
382
- fs.writeFileSync(targetFile, result.content)
383
- }
384
-
385
- return {
386
- type: result.type,
387
- ...(result.added === undefined ? {} : { added: result.added }),
388
- }
389
- }
390
-
391
- export function mergeEnvContent(templateContent, targetContent) {
392
289
  const templateEnv = parseEnv(templateContent)
393
290
 
394
291
  const targetEnv = parseEnv(targetContent)
@@ -411,9 +308,10 @@ export function mergeEnvContent(templateContent, targetContent) {
411
308
 
412
309
  const nextContent = targetTrimmed ? `${targetTrimmed}\n${appendLines.join('\n')}\n` : `${appendLines.join('\n')}\n`
413
310
 
311
+ fs.writeFileSync(targetFile, nextContent)
312
+
414
313
  return {
415
314
  type: 'merged',
416
315
  added: appendLines.length,
417
- content: nextContent,
418
316
  }
419
317
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentiny/tiny-robot-cli",
3
- "version": "0.5.2-alpha.16",
3
+ "version": "0.5.2-alpha.18",
4
4
  "description": "CLI to scaffold TinyRobot product projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,8 +19,7 @@
19
19
  "README.md"
20
20
  ],
21
21
  "scripts": {
22
- "start": "node ./bin/cli.js",
23
- "test": "node --test test/*.test.js"
22
+ "start": "node ./bin/cli.js"
24
23
  },
25
24
  "license": "MIT",
26
25
  "engines": {
@@ -28,11 +27,10 @@
28
27
  },
29
28
  "dependencies": {
30
29
  "@inquirer/prompts": "^8.3.2",
31
- "@vue/compiler-sfc": "^3.5.40",
32
30
  "commander": "^14.0.3",
33
31
  "picocolors": "^1.1.1",
34
32
  "semver": "^7.8.1",
35
33
  "yaml": "^2.9.0"
36
34
  },
37
- "gitHead": "1bad8116c3bf83194a44bcde3dbd970cb8aacdd2"
35
+ "gitHead": "5c71743e5b961694e8121d714f7126fb76eee35a"
38
36
  }
@@ -1,10 +1,2 @@
1
- # Optional custom model endpoints. Leave blank to use official Provider defaults.
2
- VITE_QWEN_API_URL=
3
- VITE_DEEPSEEK_API_URL=
4
-
5
- # Optional custom MCP endpoint. Leave blank to use the official endpoint.
6
- VITE_AMAP_MCP_URL=
7
-
8
- # Optional local direct-connection credentials.
9
1
  VITE_ALIYUN_DASHSCOPE_KEY=
10
2
  VITE_DEEPSEEK_API_KEY=
@@ -1,71 +1,39 @@
1
- # **PROJECT_NAME**
1
+ # __PROJECT_NAME__
2
2
 
3
- This project is generated from the TinyRobot Chat Basic template. It covers conversations, streaming responses, cancellation, Markdown rendering, responsive history, themes, model capabilities, and MCP Server/Tool management.
3
+ TinyRobot AI chat starter built with Vue 3 + Vite.
4
4
 
5
- ## MCP support
5
+ ## Features
6
6
 
7
- The demo declares MCP Servers through `mcpServers`:
7
+ - Vue 3 + Vite + TypeScript project scaffold
8
+ - TinyRobot chat UI with `TrBubbleList`, `TrSender`, and markdown rendering
9
+ - Conversation management via `useConversation`
10
+ - Model switch with thinking/search capability toggles
11
+ - MCP server picker for add/toggle/delete server usage
12
+ - MCP transport support for both `sse` and `streamableHttp`
13
+ - Tool calling pipeline through `toolPlugin` + MCP `listTools` / `callTool`
14
+ - Theme toggle and responsive layout for desktop/mobile
8
15
 
9
- ```ts
10
- const mcpServers = [
11
- { id: 'amap-maps', name: '高德地图', baseUrl: 'https://...' },
12
- {
13
- id: 'model-context-protocol-mcp',
14
- name: 'Model Context Protocol MCP',
15
- baseUrl: '/modelcontextprotocol-mcp',
16
- installed: true,
17
- },
18
- ]
19
- ```
20
-
21
- `installed: true` means initially installed only. The Server remains disabled and does not connect or discover Tools until enabled.
22
-
23
- | Server | Transport | Authentication |
24
- | -------------------------- | --------------- | ---------------- |
25
- | 高德地图 | Streamable HTTP | Optional API Key |
26
- | Model Context Protocol MCP | Streamable HTTP | None |
27
-
28
- Tools are discovered dynamically with `client.listTools()`. Tool choices are stored in the next user message's `runConfig` metadata snapshot, so changing a Tool affects subsequent turns without modifying a request already in progress.
29
-
30
- Server installation, enabling, Tool loading, retry, de-duplication, and Tool calls are handled by the default adapter in `@opentiny/tiny-robot-chat`. If a Server cannot load its Tools, it remains installed but is automatically disabled. Other enabled Servers and normal chat remain available.
31
-
32
- ## Model connection modes
33
-
34
- - API Key only: connects directly to the official Qwen or DeepSeek endpoint.
35
- - `apiUrl` + API Key: connects to a custom service with frontend authentication.
36
- - `apiUrl` only: connects to a backend proxy without frontend authentication.
37
-
38
- The Chat package does not prompt for or validate missing API Keys. The upstream service or backend proxy decides whether authentication is required.
16
+ ## Setup
39
17
 
40
- MCP follows the same three modes: the official endpoint with an optional API Key, a custom `baseUrl` with optional headers, or a proxy `baseUrl` without headers.
18
+ 1. Copy environment variables:
41
19
 
42
- The basic template already includes the Model Context MCP proxy in `vite.config.ts`. If you use `add chat` in an existing project, the CLI does not modify that project's Vite configuration; add the same `/modelcontextprotocol-mcp` proxy under `server.proxy` manually and restart Vite.
43
-
44
- ## Model capabilities
45
-
46
- Qwen models support deep thinking and web search. DeepSeek models support deep thinking. Unsupported capabilities remain visible as disabled buttons so the available model capabilities are clear.
47
-
48
- DeepSeek models inherit the provider's thinking effort options: `low`, `high`, and `max`, with `high` as the default. The effort selector appears only after `深度思考` is enabled. To customize a model, set `efforts` and `defaultEffort` on that model in `src/App.vue`; use `thinkingRequired: true` only for models that cannot disable thinking.
49
-
50
- ## Environment variables
20
+ ```bash
21
+ cp .env.example .env
22
+ ```
51
23
 
52
- Copy `.env.example` to `.env.local`. Leave endpoint variables blank for official Provider/MCP defaults, or set them for custom services and backend proxies:
24
+ 2. Fill your provider keys in `.env`:
53
25
 
54
26
  ```env
55
- VITE_QWEN_API_URL=
56
- VITE_DEEPSEEK_API_URL=
57
- VITE_AMAP_MCP_URL=
58
- VITE_ALIYUN_DASHSCOPE_KEY=
59
- VITE_DEEPSEEK_API_KEY=
27
+ VITE_ALIYUN_DASHSCOPE_KEY=your_dashscope_key
28
+ VITE_DEEPSEEK_API_KEY=your_deepseek_key
60
29
  ```
61
30
 
62
- For a proxy setup, set for example `VITE_QWEN_API_URL=/api/chat/qwen`, `VITE_DEEPSEEK_API_URL=/api/chat/deepseek`, and `VITE_AMAP_MCP_URL=/api/mcp/amap-maps`, then leave the API Key variables blank.
63
-
64
- Variables prefixed with `VITE_` are exposed to browser code. Direct browser connections are intended only for servers without secrets and with CORS enabled. Production applications should keep credentials behind a backend or BFF proxy.
31
+ `VITE_ALIYUN_DASHSCOPE_KEY` is also used by configured MCP servers that require DashScope authorization.
65
32
 
66
33
  ## Development
67
34
 
68
35
  ```bash
36
+ pnpm install
69
37
  pnpm dev
70
38
  ```
71
39
 
@@ -73,4 +41,5 @@ pnpm dev
73
41
 
74
42
  ```bash
75
43
  pnpm build
44
+ pnpm preview
76
45
  ```
@@ -2,9 +2,9 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
5
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>__PROJECT_NAME__</title>
7
+ <title>TinyRobot AI Chat</title>
8
8
  </head>
9
9
  <body>
10
10
  <div id="app"></div>
@@ -1,25 +1,29 @@
1
1
  {
2
2
  "name": "__PROJECT_NAME__",
3
3
  "private": true,
4
- "version": "0.0.0",
4
+ "version": "0.1.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "vue-tsc -b && vite build",
9
- "preview": "vite preview"
9
+ "preview": "vite preview",
10
+ "type-check": "vue-tsc --noEmit"
10
11
  },
11
12
  "dependencies": {
12
- "@opentiny/tiny-robot-chat": "__TINY_ROBOT_VERSION__",
13
- "@opentiny/tiny-robot": "__TINY_ROBOT_VERSION__",
14
- "@opentiny/tiny-robot-svgs": "__TINY_ROBOT_VERSION__",
15
- "vue": "^3.5.40"
13
+ "@modelcontextprotocol/sdk": "^1.18.1",
14
+ "@opentiny/tiny-robot": "^0.5.0",
15
+ "@opentiny/tiny-robot-kit": "^0.5.0",
16
+ "@opentiny/tiny-robot-svgs": "^0.5.0",
17
+ "dompurify": "^3.3.1",
18
+ "markdown-it": "^14.1.0",
19
+ "vue": "^3.5.30"
16
20
  },
17
21
  "devDependencies": {
18
- "@types/node": "^24.13.3",
19
- "@vitejs/plugin-vue": "^6.0.8",
20
- "@vue/tsconfig": "^0.9.1",
21
- "typescript": "~6.0.2",
22
- "vite": "^8.2.0",
23
- "vue-tsc": "^3.3.8"
22
+ "@types/node": "^24.12.0",
23
+ "@vitejs/plugin-vue": "^6.0.5",
24
+ "@vue/tsconfig": "^0.9.0",
25
+ "typescript": "~5.9.3",
26
+ "vite": "^8.0.1",
27
+ "vue-tsc": "^3.2.5"
24
28
  }
25
29
  }