yo-moss-ai 0.0.11 → 0.0.12

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 (56) hide show
  1. package/bin/bootstrap-deps.mjs +111 -40
  2. package/bin/runtime-manifest.json +1 -1
  3. package/bin/yo-moss-ai.mjs +2 -1
  4. package/dist/assets/esp-flasher-CLKzE7JE.js +2 -2
  5. package/dist/assets/index-CZ_NROJp.js +8 -8
  6. package/dist/models/mediapipe/blaze_face_full_range.tflite +0 -0
  7. package/dist/models/mediapipe/blaze_face_short_range.tflite +0 -0
  8. package/dist/models/mediapipe/wasm/vision_wasm_internal.js +8841 -0
  9. package/dist/models/mediapipe/wasm/vision_wasm_internal.wasm +0 -0
  10. package/dist/models/mediapipe/wasm/vision_wasm_nosimd_internal.js +8832 -0
  11. package/dist/models/mediapipe/wasm/vision_wasm_nosimd_internal.wasm +0 -0
  12. package/dist/stl/moss.stl +0 -0
  13. package/dist/stl/planetary_engine.stl +0 -0
  14. package/dist/textures/earth-lights.png +0 -0
  15. package/dist/textures/earth-night.jpg +0 -0
  16. package/dist/textures/earth_clouds.jpg +0 -0
  17. package/dist/textures/moon-base.jpg +0 -0
  18. package/dist/textures/moon-bump.jpg +0 -0
  19. package/dist/textures/wandering.png +0 -0
  20. package/dist-server/camera.mjs +1 -1
  21. package/dist-server/ffmpeg.mjs +1 -1
  22. package/dist-server/index.mjs +1 -1
  23. package/dist-server/ir-import-validate.mjs +1 -1
  24. package/dist-server/mcp/backoff.mjs +1 -1
  25. package/dist-server/mcp/bridge-manager.mjs +1 -1
  26. package/dist-server/mcp/builtin-tools.mjs +1 -1
  27. package/dist-server/mcp/dedupe-servers.mjs +1 -1
  28. package/dist-server/mcp/doctor.mjs +1 -1
  29. package/dist-server/mcp/fixtures/echo-mcp.mjs +1 -1
  30. package/dist-server/mcp/fixtures/hotkey-mcp.mjs +1 -1
  31. package/dist-server/mcp/fixtures/onvif-mcp.mjs +1 -1
  32. package/dist-server/mcp/fixtures/shell-mcp.mjs +1 -1
  33. package/dist-server/mcp/hotkey-agent-docs.mjs +1 -1
  34. package/dist-server/mcp/hotkey-driver.mjs +1 -1
  35. package/dist-server/mcp/hotkey-handlers.mjs +1 -1
  36. package/dist-server/mcp/hotkey-import-validate.mjs +1 -1
  37. package/dist-server/mcp/hotkey-store.mjs +1 -1
  38. package/dist-server/mcp/http-client.mjs +1 -1
  39. package/dist-server/mcp/http-pipe.mjs +1 -1
  40. package/dist-server/mcp/local-probe.mjs +1 -1
  41. package/dist-server/mcp/marketplace.mjs +1 -1
  42. package/dist-server/mcp/onvif-handlers.mjs +1 -1
  43. package/dist-server/mcp/parse-server-json.mjs +1 -1
  44. package/dist-server/mcp/paths.mjs +1 -1
  45. package/dist-server/mcp/routes.mjs +1 -1
  46. package/dist-server/mcp/schema.mjs +1 -1
  47. package/dist-server/mcp/settings.mjs +1 -1
  48. package/dist-server/mcp/shell-approval.mjs +1 -1
  49. package/dist-server/mcp/shell-policy.mjs +1 -1
  50. package/dist-server/mcp/shell-trash.mjs +1 -1
  51. package/dist-server/mcp/stdio-pipe.mjs +1 -1
  52. package/dist-server/mcp/store.mjs +1 -1
  53. package/dist-server/mcp/task-notify.mjs +1 -1
  54. package/dist-server/mcp/ws-connect.mjs +1 -1
  55. package/dist-server/media-cache.mjs +1 -1
  56. package/package.json +1 -1
@@ -7,6 +7,7 @@ import { spawn } from 'node:child_process'
7
7
  import { pipeline } from 'node:stream/promises'
8
8
 
9
9
  export const PROGRESS_BAR_WIDTH = 28
10
+ export const MEDIA_PACKAGE_NAME = 'yo-moss-ai-media'
10
11
 
11
12
  export function mediaCacheDir() {
12
13
  return process.env.MOSS_MEDIA_ROOT || path.join(os.homedir(), '.moss-desktop', 'media')
@@ -28,11 +29,12 @@ function renderBar(label, ratio) {
28
29
  process.stdout.write(`\r\x1b[2K${formatProgressBar(label, ratio)}`)
29
30
  }
30
31
 
32
+ /** @deprecated 单文件 CDN 对大体积 npm 包不可靠,保留仅供测试/兜底 */
31
33
  export function cdnUrls(version, relativePath) {
32
34
  const encoded = relativePath.split('/').map((part) => encodeURIComponent(part)).join('/')
33
35
  return [
34
- `https://cdn.jsdelivr.net/npm/yo-moss-ai-media@${version}/${encoded}`,
35
- `https://unpkg.com/yo-moss-ai-media@${version}/${encoded}`,
36
+ `https://cdn.jsdelivr.net/npm/${MEDIA_PACKAGE_NAME}@${version}/${encoded}`,
37
+ `https://unpkg.com/${MEDIA_PACKAGE_NAME}@${version}/${encoded}`,
36
38
  ]
37
39
  }
38
40
 
@@ -90,14 +92,41 @@ export function fileReady(filePath, expectedSize) {
90
92
  }
91
93
  }
92
94
 
93
- function runNpmInstall(cwd) {
95
+ export function dirByteSize(dir) {
96
+ if (!fs.existsSync(dir)) return 0
97
+ let total = 0
98
+ for (const name of fs.readdirSync(dir)) {
99
+ const full = path.join(dir, name)
100
+ const stat = fs.statSync(full)
101
+ if (stat.isDirectory()) total += dirByteSize(full)
102
+ else total += stat.size
103
+ }
104
+ return total
105
+ }
106
+
107
+ export function copyTree(src, dest) {
108
+ fs.mkdirSync(dest, { recursive: true })
109
+ for (const name of fs.readdirSync(src)) {
110
+ if (name.startsWith('.')) continue
111
+ const from = path.join(src, name)
112
+ const to = path.join(dest, name)
113
+ if (fs.statSync(from).isDirectory()) copyTree(from, to)
114
+ else fs.copyFileSync(from, to)
115
+ }
116
+ }
117
+
118
+ function runNpmInstall(cwd, extraArgs = []) {
94
119
  return new Promise((resolve, reject) => {
95
120
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'
96
- const child = spawn(npmCmd, ['install', '--omit=dev', '--no-audit', '--no-fund', '--loglevel=error'], {
97
- cwd,
98
- stdio: ['ignore', 'ignore', 'pipe'],
99
- shell: process.platform === 'win32',
100
- })
121
+ const child = spawn(
122
+ npmCmd,
123
+ ['install', '--omit=dev', '--no-audit', '--no-fund', '--loglevel=error', ...extraArgs],
124
+ {
125
+ cwd,
126
+ stdio: ['ignore', 'ignore', 'pipe'],
127
+ shell: process.platform === 'win32',
128
+ },
129
+ )
101
130
  let errText = ''
102
131
  child.stderr.on('data', (chunk) => {
103
132
  errText += String(chunk)
@@ -109,6 +138,72 @@ function runNpmInstall(cwd) {
109
138
  })
110
139
  }
111
140
 
141
+ /**
142
+ * 通过 npm registry 安装 yo-moss-ai-media 整包(比 CDN 单文件拉取可靠)。
143
+ */
144
+ export const NPM_REGISTRIES = [
145
+ 'https://registry.npmjs.org',
146
+ 'https://registry.npmmirror.com',
147
+ ]
148
+
149
+ export async function installMediaBundleFromNpm(
150
+ version,
151
+ cacheDir,
152
+ { totalBytes = 0, onProgress, installImpl } = {},
153
+ ) {
154
+ const staging = path.join(cacheDir, '.npm-staging')
155
+ fs.rmSync(staging, { recursive: true, force: true })
156
+ fs.mkdirSync(staging, { recursive: true })
157
+ fs.writeFileSync(
158
+ path.join(staging, 'package.json'),
159
+ `${JSON.stringify({
160
+ name: 'yo-moss-ai-media-staging',
161
+ private: true,
162
+ dependencies: { [MEDIA_PACKAGE_NAME]: version },
163
+ }, null, 2)}\n`,
164
+ )
165
+
166
+ const expected = totalBytes > 0 ? totalBytes : 56_000_000
167
+ const poll = setInterval(() => {
168
+ const size = dirByteSize(path.join(staging, 'node_modules', MEDIA_PACKAGE_NAME))
169
+ onProgress?.(Math.min(0.92, size / expected))
170
+ }, 400)
171
+
172
+ let lastError
173
+ try {
174
+ for (const registry of NPM_REGISTRIES) {
175
+ try {
176
+ const installer = installImpl || ((cwd) => runNpmInstall(cwd, ['--registry', registry]))
177
+ await installer(staging)
178
+ lastError = null
179
+ break
180
+ } catch (err) {
181
+ lastError = err
182
+ fs.rmSync(path.join(staging, 'node_modules'), { recursive: true, force: true })
183
+ }
184
+ }
185
+ if (lastError) {
186
+ throw new Error(`运行资源自动安装失败(${MEDIA_PACKAGE_NAME}@${version}),请检查网络后重试 npx yo-moss-ai`)
187
+ }
188
+ } finally {
189
+ clearInterval(poll)
190
+ }
191
+
192
+ const pkgRoot = path.join(staging, 'node_modules', MEDIA_PACKAGE_NAME)
193
+ if (!fs.existsSync(pkgRoot)) {
194
+ throw new Error(`运行资源自动安装失败(${MEDIA_PACKAGE_NAME}@${version}),请检查网络后重试 npx yo-moss-ai`)
195
+ }
196
+
197
+ onProgress?.(0.95)
198
+ for (const dir of ['models', 'textures', 'stl']) {
199
+ const from = path.join(pkgRoot, dir)
200
+ if (!fs.existsSync(from)) continue
201
+ copyTree(from, path.join(cacheDir, dir))
202
+ }
203
+ fs.rmSync(staging, { recursive: true, force: true })
204
+ onProgress?.(1)
205
+ }
206
+
112
207
  export async function ensureRuntimeNpmDeps(npmDeps, depsRoot = runtimeDepsRoot(), installImpl = runNpmInstall) {
113
208
  fs.mkdirSync(depsRoot, { recursive: true })
114
209
  const pkgPath = path.join(depsRoot, 'package.json')
@@ -164,7 +259,7 @@ export async function bootstrapRuntimeDeps(opts) {
164
259
  version,
165
260
  cacheDir = mediaCacheDir(),
166
261
  depsRoot = runtimeDepsRoot(),
167
- downloadFile = followDownload,
262
+ installMediaBundle = installMediaBundleFromNpm,
168
263
  installNpmDeps = (npmDeps) => ensureRuntimeNpmDeps(npmDeps, depsRoot),
169
264
  } = opts
170
265
 
@@ -201,40 +296,16 @@ export async function bootstrapRuntimeDeps(opts) {
201
296
  }
202
297
 
203
298
  if (needMedia) {
204
- let doneBytes = 0
205
299
  renderBar('下载资源', 0)
300
+ await installMediaBundle(mediaVersion, cacheDir, {
301
+ totalBytes,
302
+ onProgress: (ratio) => renderBar('下载资源', ratio),
303
+ })
304
+ process.stdout.write('\n')
206
305
 
207
- for (const file of mediaFiles) {
208
- const dest = path.join(cacheDir, file.path)
209
- if (fileReady(dest, file.size)) {
210
- doneBytes += file.size || 0
211
- renderBar('下载资源', totalBytes ? doneBytes / totalBytes : 1)
212
- continue
213
- }
214
-
215
- const fileSize = file.size || 0
216
- let fileDone = 0
217
- let lastError
218
- for (const url of cdnUrls(mediaVersion, file.path)) {
219
- try {
220
- await downloadFile(url, dest, (chunkLen) => {
221
- fileDone += chunkLen
222
- const current = doneBytes + Math.min(fileDone, fileSize || fileDone)
223
- renderBar('下载资源', totalBytes ? current / totalBytes : 1)
224
- })
225
- lastError = null
226
- break
227
- } catch (err) {
228
- lastError = err
229
- fileDone = 0
230
- }
231
- }
232
- if (lastError) throw new Error(`无法下载 ${file.path}: ${lastError.message}`)
233
-
234
- doneBytes += fileSize || fs.statSync(dest).size
235
- renderBar('下载资源', totalBytes ? doneBytes / totalBytes : 1)
306
+ if (!mediaCacheReady(mediaFiles, cacheDir)) {
307
+ throw new Error('媒体资源安装完成但校验失败,请删除 ~/.moss-desktop/media 后重试')
236
308
  }
237
- process.stdout.write('\n')
238
309
  }
239
310
 
240
311
  if (needNpm) {
@@ -1,5 +1,5 @@
1
1
  {
2
- "mediaVersion": "0.0.11",
2
+ "mediaVersion": "0.0.12",
3
3
  "mediaFiles": [
4
4
  {
5
5
  "path": "models/mediapipe/blaze_face_full_range.tflite",
@@ -32,7 +32,8 @@ console.log(`yo-moss-ai${pkgVersion ? ` v${pkgVersion}` : ''}`)
32
32
  try {
33
33
  await bootstrapRuntimeDeps({ root, version: pkg.version })
34
34
  } catch (err) {
35
- console.error('\n运行资源准备失败:', err?.message || err)
35
+ console.error('\n启动准备失败:', err?.message || err)
36
+ console.error('请检查网络连接后重新运行:npx yo-moss-ai')
36
37
  process.exit(1)
37
38
  }
38
39