yo-moss-ai 0.0.10 → 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.
- package/bin/bootstrap-deps.mjs +326 -0
- package/bin/runtime-manifest.json +67 -0
- package/bin/yo-moss-ai.mjs +11 -1
- package/dist/assets/esp-flasher-CLKzE7JE.js +2 -2
- package/dist/assets/index-CZ_NROJp.js +8 -8
- package/dist/models/mediapipe/blaze_face_full_range.tflite +0 -0
- package/dist/models/mediapipe/blaze_face_short_range.tflite +0 -0
- package/dist/models/mediapipe/wasm/vision_wasm_internal.js +8841 -0
- package/dist/models/mediapipe/wasm/vision_wasm_internal.wasm +0 -0
- package/dist/models/mediapipe/wasm/vision_wasm_nosimd_internal.js +8832 -0
- package/dist/models/mediapipe/wasm/vision_wasm_nosimd_internal.wasm +0 -0
- package/dist/stl/moss.stl +0 -0
- package/dist/stl/planetary_engine.stl +0 -0
- package/dist/textures/earth-lights.png +0 -0
- package/dist/textures/earth-night.jpg +0 -0
- package/dist/textures/earth_clouds.jpg +0 -0
- package/dist/textures/moon-base.jpg +0 -0
- package/dist/textures/moon-bump.jpg +0 -0
- package/dist/textures/wandering.png +0 -0
- package/dist-server/camera.mjs +1 -1
- package/dist-server/ffmpeg.mjs +1 -1
- package/dist-server/index.mjs +1 -1
- package/dist-server/ir-import-validate.mjs +1 -1
- package/dist-server/mcp/backoff.mjs +1 -1
- package/dist-server/mcp/bridge-manager.mjs +1 -1
- package/dist-server/mcp/builtin-tools.mjs +1 -1
- package/dist-server/mcp/dedupe-servers.mjs +1 -1
- package/dist-server/mcp/doctor.mjs +1 -1
- package/dist-server/mcp/fixtures/echo-mcp.mjs +1 -1
- package/dist-server/mcp/fixtures/hotkey-mcp.mjs +1 -1
- package/dist-server/mcp/fixtures/onvif-mcp.mjs +1 -1
- package/dist-server/mcp/fixtures/shell-mcp.mjs +1 -1
- package/dist-server/mcp/hotkey-agent-docs.mjs +1 -1
- package/dist-server/mcp/hotkey-driver.mjs +1 -1
- package/dist-server/mcp/hotkey-handlers.mjs +1 -1
- package/dist-server/mcp/hotkey-import-validate.mjs +1 -1
- package/dist-server/mcp/hotkey-store.mjs +1 -1
- package/dist-server/mcp/http-client.mjs +1 -1
- package/dist-server/mcp/http-pipe.mjs +1 -1
- package/dist-server/mcp/local-probe.mjs +1 -1
- package/dist-server/mcp/marketplace.mjs +1 -1
- package/dist-server/mcp/onvif-handlers.mjs +1 -1
- package/dist-server/mcp/parse-server-json.mjs +1 -1
- package/dist-server/mcp/paths.mjs +1 -1
- package/dist-server/mcp/routes.mjs +1 -1
- package/dist-server/mcp/schema.mjs +1 -1
- package/dist-server/mcp/settings.mjs +1 -1
- package/dist-server/mcp/shell-approval.mjs +1 -1
- package/dist-server/mcp/shell-policy.mjs +1 -1
- package/dist-server/mcp/shell-trash.mjs +1 -1
- package/dist-server/mcp/stdio-pipe.mjs +1 -1
- package/dist-server/mcp/store.mjs +1 -1
- package/dist-server/mcp/task-notify.mjs +1 -1
- package/dist-server/mcp/ws-connect.mjs +1 -1
- package/dist-server/media-cache.mjs +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import os from 'node:os'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import http from 'node:http'
|
|
5
|
+
import https from 'node:https'
|
|
6
|
+
import { spawn } from 'node:child_process'
|
|
7
|
+
import { pipeline } from 'node:stream/promises'
|
|
8
|
+
|
|
9
|
+
export const PROGRESS_BAR_WIDTH = 28
|
|
10
|
+
export const MEDIA_PACKAGE_NAME = 'yo-moss-ai-media'
|
|
11
|
+
|
|
12
|
+
export function mediaCacheDir() {
|
|
13
|
+
return process.env.MOSS_MEDIA_ROOT || path.join(os.homedir(), '.moss-desktop', 'media')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function runtimeDepsRoot() {
|
|
17
|
+
return process.env.MOSS_RUNTIME_DEPS_ROOT || path.join(os.homedir(), '.moss-desktop', 'runtime-deps')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 纯函数:生成终端进度条文本(单行覆盖用) */
|
|
21
|
+
export function formatProgressBar(label, ratio, width = PROGRESS_BAR_WIDTH) {
|
|
22
|
+
const pct = Math.min(100, Math.max(0, Math.round(ratio * 100)))
|
|
23
|
+
const filled = Math.round((pct / 100) * width)
|
|
24
|
+
const bar = '█'.repeat(filled) + '░'.repeat(width - filled)
|
|
25
|
+
return `${label} [${bar}] ${pct}%`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function renderBar(label, ratio) {
|
|
29
|
+
process.stdout.write(`\r\x1b[2K${formatProgressBar(label, ratio)}`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** @deprecated 单文件 CDN 对大体积 npm 包不可靠,保留仅供测试/兜底 */
|
|
33
|
+
export function cdnUrls(version, relativePath) {
|
|
34
|
+
const encoded = relativePath.split('/').map((part) => encodeURIComponent(part)).join('/')
|
|
35
|
+
return [
|
|
36
|
+
`https://cdn.jsdelivr.net/npm/${MEDIA_PACKAGE_NAME}@${version}/${encoded}`,
|
|
37
|
+
`https://unpkg.com/${MEDIA_PACKAGE_NAME}@${version}/${encoded}`,
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function followDownload(url, dest, onChunk, redirects = 0) {
|
|
42
|
+
if (redirects > 5) return Promise.reject(new Error('下载重定向过多'))
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
const client = url.startsWith('http:') ? http : https
|
|
45
|
+
const req = client.get(
|
|
46
|
+
url,
|
|
47
|
+
{ headers: { 'User-Agent': 'yo-moss-ai' }, timeout: 120_000 },
|
|
48
|
+
(res) => {
|
|
49
|
+
const location = res.headers.location
|
|
50
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && location) {
|
|
51
|
+
res.resume()
|
|
52
|
+
followDownload(new URL(location, url).href, dest, onChunk, redirects + 1).then(resolve, reject)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
if (res.statusCode !== 200) {
|
|
56
|
+
res.resume()
|
|
57
|
+
reject(new Error(`HTTP ${res.statusCode}`))
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true })
|
|
61
|
+
const tmp = `${dest}.download`
|
|
62
|
+
const out = fs.createWriteStream(tmp)
|
|
63
|
+
res.on('data', (chunk) => {
|
|
64
|
+
onChunk?.(chunk.length)
|
|
65
|
+
})
|
|
66
|
+
pipeline(res, out)
|
|
67
|
+
.then(() => {
|
|
68
|
+
fs.renameSync(tmp, dest)
|
|
69
|
+
resolve()
|
|
70
|
+
})
|
|
71
|
+
.catch((err) => {
|
|
72
|
+
try {
|
|
73
|
+
fs.unlinkSync(tmp)
|
|
74
|
+
} catch {
|
|
75
|
+
// ignore
|
|
76
|
+
}
|
|
77
|
+
reject(err)
|
|
78
|
+
})
|
|
79
|
+
},
|
|
80
|
+
)
|
|
81
|
+
req.on('timeout', () => req.destroy(new Error('下载超时')))
|
|
82
|
+
req.on('error', reject)
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function fileReady(filePath, expectedSize) {
|
|
87
|
+
try {
|
|
88
|
+
const stat = fs.statSync(filePath)
|
|
89
|
+
return stat.isFile() && (!expectedSize || stat.size === expectedSize)
|
|
90
|
+
} catch {
|
|
91
|
+
return false
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
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 = []) {
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
|
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
|
+
)
|
|
130
|
+
let errText = ''
|
|
131
|
+
child.stderr.on('data', (chunk) => {
|
|
132
|
+
errText += String(chunk)
|
|
133
|
+
})
|
|
134
|
+
child.on('exit', (code) => {
|
|
135
|
+
if (code === 0) resolve()
|
|
136
|
+
else reject(new Error(errText.trim() || `npm install 失败,退出码 ${code}`))
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
}
|
|
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
|
+
|
|
207
|
+
export async function ensureRuntimeNpmDeps(npmDeps, depsRoot = runtimeDepsRoot(), installImpl = runNpmInstall) {
|
|
208
|
+
fs.mkdirSync(depsRoot, { recursive: true })
|
|
209
|
+
const pkgPath = path.join(depsRoot, 'package.json')
|
|
210
|
+
const deps = Object.fromEntries(npmDeps.map((item) => [item.name, item.version]))
|
|
211
|
+
const pkg = {
|
|
212
|
+
name: 'yo-moss-ai-runtime-deps',
|
|
213
|
+
private: true,
|
|
214
|
+
dependencies: deps,
|
|
215
|
+
overrides: { phin: 'npm:phn@^0.2.8' },
|
|
216
|
+
}
|
|
217
|
+
fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`)
|
|
218
|
+
|
|
219
|
+
const marker = path.join(depsRoot, '.installed.json')
|
|
220
|
+
const nextMarker = JSON.stringify(deps)
|
|
221
|
+
if (fs.existsSync(marker) && fs.readFileSync(marker, 'utf8') === nextMarker) {
|
|
222
|
+
const nutEntry = path.join(depsRoot, 'node_modules', '@nut-tree-fork', 'nut-js', 'dist', 'index.js')
|
|
223
|
+
if (fs.existsSync(nutEntry)) return
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
await installImpl(depsRoot)
|
|
227
|
+
fs.writeFileSync(marker, nextMarker)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function loadManifest(root) {
|
|
231
|
+
const manifestPath = path.join(root, 'bin', 'runtime-manifest.json')
|
|
232
|
+
if (!fs.existsSync(manifestPath)) return null
|
|
233
|
+
return JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function hasBundledMedia(distDir) {
|
|
237
|
+
return fs.existsSync(path.join(distDir, 'models'))
|
|
238
|
+
|| fs.existsSync(path.join(distDir, 'textures'))
|
|
239
|
+
|| fs.existsSync(path.join(distDir, 'stl'))
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function runtimeDepsReady(npmDeps, depsRoot = runtimeDepsRoot()) {
|
|
243
|
+
if (!npmDeps.length) return true
|
|
244
|
+
const nutEntry = path.join(depsRoot, 'node_modules', '@nut-tree-fork', 'nut-js', 'dist', 'index.js')
|
|
245
|
+
return fs.existsSync(nutEntry)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function mediaCacheReady(files, cacheDir = mediaCacheDir()) {
|
|
249
|
+
if (!files.length) return true
|
|
250
|
+
return files.every((file) => fileReady(path.join(cacheDir, file.path), file.size))
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* npx 安装精简包后,启动服务前下载媒体资源与扩展 npm 依赖。
|
|
255
|
+
*/
|
|
256
|
+
export async function bootstrapRuntimeDeps(opts) {
|
|
257
|
+
const {
|
|
258
|
+
root,
|
|
259
|
+
version,
|
|
260
|
+
cacheDir = mediaCacheDir(),
|
|
261
|
+
depsRoot = runtimeDepsRoot(),
|
|
262
|
+
installMediaBundle = installMediaBundleFromNpm,
|
|
263
|
+
installNpmDeps = (npmDeps) => ensureRuntimeNpmDeps(npmDeps, depsRoot),
|
|
264
|
+
} = opts
|
|
265
|
+
|
|
266
|
+
const distDir = path.join(root, 'dist')
|
|
267
|
+
if (process.env.MOSS_SKIP_BOOTSTRAP === '1' || hasBundledMedia(distDir)) {
|
|
268
|
+
return { skipped: true }
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const manifest = loadManifest(root)
|
|
272
|
+
if (!manifest) {
|
|
273
|
+
console.warn('缺少 bin/runtime-manifest.json,跳过资源预下载')
|
|
274
|
+
return { skipped: true }
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const mediaVersion = manifest.mediaVersion || version
|
|
278
|
+
const mediaFiles = manifest.mediaFiles || []
|
|
279
|
+
const npmDeps = manifest.npmDeps || []
|
|
280
|
+
const totalBytes = mediaFiles.reduce((sum, file) => sum + (file.size || 0), 0)
|
|
281
|
+
const needMedia = !mediaCacheReady(mediaFiles, cacheDir)
|
|
282
|
+
const needNpm = !runtimeDepsReady(npmDeps, depsRoot)
|
|
283
|
+
|
|
284
|
+
if (!needMedia && !needNpm) {
|
|
285
|
+
process.env.MOSS_MEDIA_ROOT = cacheDir
|
|
286
|
+
process.env.MOSS_RUNTIME_DEPS = path.join(depsRoot, 'node_modules')
|
|
287
|
+
return { skipped: false, cached: true }
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
console.log('')
|
|
291
|
+
if (needMedia) {
|
|
292
|
+
const mb = (totalBytes / 1024 / 1024).toFixed(0)
|
|
293
|
+
console.log(`正在下载运行资源(约 ${mb} MB),完成后自动启动服务…`)
|
|
294
|
+
} else if (needNpm) {
|
|
295
|
+
console.log('正在安装扩展依赖,完成后自动启动服务…')
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (needMedia) {
|
|
299
|
+
renderBar('下载资源', 0)
|
|
300
|
+
await installMediaBundle(mediaVersion, cacheDir, {
|
|
301
|
+
totalBytes,
|
|
302
|
+
onProgress: (ratio) => renderBar('下载资源', ratio),
|
|
303
|
+
})
|
|
304
|
+
process.stdout.write('\n')
|
|
305
|
+
|
|
306
|
+
if (!mediaCacheReady(mediaFiles, cacheDir)) {
|
|
307
|
+
throw new Error('媒体资源安装完成但校验失败,请删除 ~/.moss-desktop/media 后重试')
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (needNpm) {
|
|
312
|
+
renderBar('安装扩展依赖', 0)
|
|
313
|
+
try {
|
|
314
|
+
await installNpmDeps(npmDeps)
|
|
315
|
+
renderBar('安装扩展依赖', 1)
|
|
316
|
+
process.stdout.write('\n')
|
|
317
|
+
} catch (err) {
|
|
318
|
+
process.stdout.write('\n')
|
|
319
|
+
console.warn('扩展依赖安装失败,快捷键/媒体键可能不可用:', err.message)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
process.env.MOSS_MEDIA_ROOT = cacheDir
|
|
324
|
+
process.env.MOSS_RUNTIME_DEPS = path.join(depsRoot, 'node_modules')
|
|
325
|
+
return { skipped: false, cached: false }
|
|
326
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mediaVersion": "0.0.12",
|
|
3
|
+
"mediaFiles": [
|
|
4
|
+
{
|
|
5
|
+
"path": "models/mediapipe/blaze_face_full_range.tflite",
|
|
6
|
+
"size": 1083786
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"path": "models/mediapipe/blaze_face_short_range.tflite",
|
|
10
|
+
"size": 229746
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"path": "models/mediapipe/wasm/vision_wasm_internal.js",
|
|
14
|
+
"size": 323377
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"path": "models/mediapipe/wasm/vision_wasm_internal.wasm",
|
|
18
|
+
"size": 11756954
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"path": "models/mediapipe/wasm/vision_wasm_nosimd_internal.js",
|
|
22
|
+
"size": 323180
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"path": "models/mediapipe/wasm/vision_wasm_nosimd_internal.wasm",
|
|
26
|
+
"size": 10960242
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"path": "textures/earth-lights.png",
|
|
30
|
+
"size": 734910
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"path": "textures/earth-night.jpg",
|
|
34
|
+
"size": 8277759
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"path": "textures/earth_clouds.jpg",
|
|
38
|
+
"size": 12343415
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"path": "textures/moon-base.jpg",
|
|
42
|
+
"size": 1591331
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"path": "textures/moon-bump.jpg",
|
|
46
|
+
"size": 1021019
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"path": "textures/wandering.png",
|
|
50
|
+
"size": 309032
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"path": "stl/moss.stl",
|
|
54
|
+
"size": 1649184
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"path": "stl/planetary_engine.stl",
|
|
58
|
+
"size": 5807034
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"npmDeps": [
|
|
62
|
+
{
|
|
63
|
+
"name": "@nut-tree-fork/nut-js",
|
|
64
|
+
"version": "^4.2.0"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
package/bin/yo-moss-ai.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import fs from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
5
|
+
import { bootstrapRuntimeDeps } from './bootstrap-deps.mjs'
|
|
5
6
|
|
|
6
7
|
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
7
8
|
let pkgVersion = ''
|
|
@@ -10,7 +11,6 @@ try {
|
|
|
10
11
|
} catch {
|
|
11
12
|
// ignore
|
|
12
13
|
}
|
|
13
|
-
console.log(`yo-moss-ai${pkgVersion ? ` v${pkgVersion}` : ''} 正在启动…`)
|
|
14
14
|
|
|
15
15
|
const major = Number(process.versions.node.split('.')[0])
|
|
16
16
|
if (major < 20) {
|
|
@@ -27,6 +27,16 @@ if (!fs.existsSync(server)) {
|
|
|
27
27
|
process.exit(1)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
console.log(`yo-moss-ai${pkgVersion ? ` v${pkgVersion}` : ''}`)
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
await bootstrapRuntimeDeps({ root, version: pkg.version })
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.error('\n启动准备失败:', err?.message || err)
|
|
36
|
+
console.error('请检查网络连接后重新运行:npx yo-moss-ai')
|
|
37
|
+
process.exit(1)
|
|
38
|
+
}
|
|
39
|
+
|
|
30
40
|
process.env.NODE_ENV = 'production'
|
|
31
41
|
process.env.MOSS_OPEN_BROWSER = process.env.MOSS_OPEN_BROWSER || '1'
|
|
32
42
|
process.env.MOSS_VERSION = pkg.version
|