@dsh-plugins/dsh-museav-assets 0.1.1
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/CHANGELOG.md +48 -0
- package/LICENSE +21 -0
- package/README.en.md +114 -0
- package/README.md +127 -0
- package/cordis.patch.yml +10 -0
- package/lib/client.js +1157 -0
- package/lib/index.js +492 -0
- package/lib/museav.js +320 -0
- package/package.json +68 -0
- package/types/client.d.ts +21 -0
- package/types/index.d.ts +73 -0
package/lib/museav.js
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-museav-assets —— museav CLI 适配层(纯解析 + 进程调用)。
|
|
3
|
+
*
|
|
4
|
+
* 这是**唯一**知道 museav CLI 输出长什么样的文件。路由和 UI 只认这里吐出的结构化
|
|
5
|
+
* 对象;CLI 改文案,改这一个文件 + 它的测试就够,不用动 UI。
|
|
6
|
+
*
|
|
7
|
+
* CLI 的 stdout/stderr 分工是它自己的**契约**(真源 museav-cli/src/commands/projects.ts):
|
|
8
|
+
* - stdout 给脚本:projects → id 换行;projects assets → `id\turl`;jobs → 完整 JSON
|
|
9
|
+
* 数组;projects create → 新建工作区 id
|
|
10
|
+
* - stderr 给人看:名称 / 出图计数 / 素材数 / media_type / tags
|
|
11
|
+
* 所以**真值一律取 stdout**,stderr 只用来补展示字段。stderr 解析不出来就降级成
|
|
12
|
+
* 只显示 id —— 上游改一句中文不能让整个 tab 变空白。
|
|
13
|
+
*
|
|
14
|
+
* 认证:CLI 自己管 ~/.museav.json 的 token,本插件既不读它也不转发它。
|
|
15
|
+
* 没登录时 CLI 报错,这里原样把 stderr 带回去。
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { execFile } from 'node:child_process'
|
|
19
|
+
|
|
20
|
+
/** 上游工作区数量上限(museav projects create 的服务端限制)。 */
|
|
21
|
+
export const PROJECT_LIMIT = 5
|
|
22
|
+
|
|
23
|
+
/** UUID —— 只认标准 8-4-4-4-12,避免把表格里的别的 token 误当 id。 */
|
|
24
|
+
const UUID = '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 跑一条 museav CLI 命令。
|
|
28
|
+
*
|
|
29
|
+
* 不用 shell —— 参数走数组,project 名里的空格/引号不会被解释成别的命令。
|
|
30
|
+
*
|
|
31
|
+
* @param {string[]} args 例如 `['projects', '--project', 'IP 账户运营']`
|
|
32
|
+
* @param {{bin?: string, timeoutMs?: number}} [opts]
|
|
33
|
+
* @returns {Promise<{ok: boolean, code: number|null, stdout: string, stderr: string, error: string|null}>}
|
|
34
|
+
*/
|
|
35
|
+
export function runMuseav (args, opts = {}) {
|
|
36
|
+
const bin = opts.bin || 'museav'
|
|
37
|
+
const timeoutMs = opts.timeoutMs ?? 30000
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
execFile(
|
|
40
|
+
bin,
|
|
41
|
+
args,
|
|
42
|
+
{ timeout: timeoutMs, maxBuffer: 8 * 1024 * 1024, env: process.env },
|
|
43
|
+
(error, stdout, stderr) => {
|
|
44
|
+
if (!error) {
|
|
45
|
+
resolve({ ok: true, code: 0, stdout: stdout ?? '', stderr: stderr ?? '', error: null })
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
// 超时也会走到这里;code 为 null 时不要伪装成 exit 1。
|
|
49
|
+
const timedOut = error.killed === true || error.code === 'ETIMEDOUT'
|
|
50
|
+
resolve({
|
|
51
|
+
ok: false,
|
|
52
|
+
code: typeof error.code === 'number' ? error.code : null,
|
|
53
|
+
stdout: stdout ?? '',
|
|
54
|
+
stderr: stderr ?? '',
|
|
55
|
+
error: timedOut
|
|
56
|
+
? `museav ${args[0] ?? ''} 超时(${timeoutMs}ms)`
|
|
57
|
+
: (stderr || error.message || '').trim(),
|
|
58
|
+
})
|
|
59
|
+
},
|
|
60
|
+
)
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* `museav projects` 的 stdout —— 每行一个 id,这是契约。
|
|
66
|
+
* @param {string} stdout
|
|
67
|
+
* @returns {string[]}
|
|
68
|
+
*/
|
|
69
|
+
export function parseProjectIds (stdout) {
|
|
70
|
+
return String(stdout ?? '')
|
|
71
|
+
.split('\n')
|
|
72
|
+
.map((line) => line.trim())
|
|
73
|
+
.filter((line) => new RegExp(`^${UUID}$`).test(line))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* `museav projects` 的 stderr 表格 —— 人看的补展示字段,解析失败不致命。
|
|
78
|
+
*
|
|
79
|
+
* 表格行长这样(注意 name 是 padEnd(16),名字 ≥16 字时列间只有 1 个空格,
|
|
80
|
+
* 所以分隔一律用「非贪婪 + \s+ 出图」而不是固定宽度):
|
|
81
|
+
* ` <uuid> 默认项目 出图 39/43 素材 0 brand:brandcheck`
|
|
82
|
+
*
|
|
83
|
+
* @param {string} stderr
|
|
84
|
+
* @returns {Map<string, {name: string, genDone: number, genTotal: number, assetCount: number, brand: string|null}>}
|
|
85
|
+
*/
|
|
86
|
+
export function parseProjectTable (stderr) {
|
|
87
|
+
const out = new Map()
|
|
88
|
+
const re = new RegExp(
|
|
89
|
+
`^\\s{2}(${UUID})\\s+(\\S.*?)\\s+出图\\s+(\\d+)\\/(\\d+)\\s+素材\\s+(\\d+)(?:\\s+brand:(\\S+))?\\s*$`,
|
|
90
|
+
)
|
|
91
|
+
for (const line of String(stderr ?? '').split('\n')) {
|
|
92
|
+
const m = re.exec(line)
|
|
93
|
+
if (!m) continue
|
|
94
|
+
out.set(m[1], {
|
|
95
|
+
name: m[2].trim(),
|
|
96
|
+
genDone: Number(m[3]),
|
|
97
|
+
genTotal: Number(m[4]),
|
|
98
|
+
assetCount: Number(m[5]),
|
|
99
|
+
brand: m[6] ?? null,
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
return out
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* stdout 的 id 列表 + stderr 的展示字段合并。
|
|
107
|
+
* stdout 说了算:stderr 里多/少的行都不会改变 id 集合与顺序。
|
|
108
|
+
*
|
|
109
|
+
* @param {string} stdout
|
|
110
|
+
* @param {string} stderr
|
|
111
|
+
* @returns {{id: string, name: string, genDone: number, genTotal: number, assetCount: number, brand: string|null}[]}
|
|
112
|
+
*/
|
|
113
|
+
export function mergeProjects (stdout, stderr) {
|
|
114
|
+
const table = parseProjectTable(stderr)
|
|
115
|
+
return parseProjectIds(stdout).map((id) => {
|
|
116
|
+
const row = table.get(id)
|
|
117
|
+
return {
|
|
118
|
+
id,
|
|
119
|
+
name: row?.name ?? id.slice(0, 8),
|
|
120
|
+
genDone: row?.genDone ?? null,
|
|
121
|
+
genTotal: row?.genTotal ?? null,
|
|
122
|
+
assetCount: row?.assetCount ?? null,
|
|
123
|
+
brand: row?.brand ?? null,
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* `museav projects assets` 的 stdout —— `id\turl` 每行一条(agent 直接拿去当 --ref)。
|
|
130
|
+
* @param {string} stdout
|
|
131
|
+
* @returns {{id: string, url: string}[]}
|
|
132
|
+
*/
|
|
133
|
+
export function parseAssetTsv (stdout) {
|
|
134
|
+
const out = []
|
|
135
|
+
for (const line of String(stdout ?? '').split('\n')) {
|
|
136
|
+
if (!line.includes('\t')) continue
|
|
137
|
+
const idx = line.indexOf('\t')
|
|
138
|
+
const id = line.slice(0, idx).trim()
|
|
139
|
+
const url = line.slice(idx + 1).trim()
|
|
140
|
+
if (!url) continue
|
|
141
|
+
if (!new RegExp(`^${UUID}$`).test(id)) continue
|
|
142
|
+
out.push({ id, url })
|
|
143
|
+
}
|
|
144
|
+
return out
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* stderr 表格:` <uuid> (未命名) image [tag1,tag2]`
|
|
149
|
+
* @param {string} stderr
|
|
150
|
+
* @returns {Map<string, {name: string, mediaType: string, tags: string[]}>}
|
|
151
|
+
*/
|
|
152
|
+
export function parseAssetTable (stderr) {
|
|
153
|
+
const out = new Map()
|
|
154
|
+
const re = new RegExp(`^\\s{2}(${UUID})\\s+(\\S.*?)\\s+([a-zA-Z]+)\\s*(?:\\[([^\\]]*)\\])?\\s*$`)
|
|
155
|
+
for (const line of String(stderr ?? '').split('\n')) {
|
|
156
|
+
const m = re.exec(line)
|
|
157
|
+
if (!m) continue
|
|
158
|
+
out.set(m[1], {
|
|
159
|
+
name: m[2].trim(),
|
|
160
|
+
mediaType: m[3].trim(),
|
|
161
|
+
tags: m[4] ? m[4].split(',').map((t) => t.trim()).filter(Boolean) : [],
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
return out
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @param {string} stdout
|
|
169
|
+
* @param {string} stderr
|
|
170
|
+
* @returns {{id: string, url: string, name: string, mediaType: string, tags: string[]}[]}
|
|
171
|
+
*/
|
|
172
|
+
export function mergeAssets (stdout, stderr) {
|
|
173
|
+
const table = parseAssetTable(stderr)
|
|
174
|
+
return parseAssetTsv(stdout).map(({ id, url }) => {
|
|
175
|
+
const row = table.get(id)
|
|
176
|
+
return {
|
|
177
|
+
id,
|
|
178
|
+
url,
|
|
179
|
+
name: row?.name ?? '(未命名)',
|
|
180
|
+
mediaType: row?.mediaType ?? (/\.(mp4|mov|webm)(\?|$)/i.test(url) ? 'video' : /\.(mp3|wav|m4a)(\?|$)/i.test(url) ? 'audio' : 'image'),
|
|
181
|
+
tags: row?.tags ?? [],
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* `museav templates` 的 stderr 表格。
|
|
188
|
+
*
|
|
189
|
+
* 格式(真机 2026-09-29,`museav templates` 102 条):
|
|
190
|
+
* ` <uuid> 演唱会海报·小红书风 v1.0.0 webkubor@163.com 演唱会 3:4 [图片] 字段:subject,title [平台]`
|
|
191
|
+
*
|
|
192
|
+
* **不能按列位置切**:CLI 用 padEnd 对齐,而 padEnd 按 UTF-16 码元算宽度,CJK 只占
|
|
193
|
+
* 一半 —— 实测 `webkubor@163.com`(15 字符)超出 padEnd(10) 不补空格,于是创建人和
|
|
194
|
+
* 分类粘成了一列 `webkubor@163.com 演唱会`。所以从右侧的括号标签锚定,只取无歧义的
|
|
195
|
+
* 字段:归属 / 类型 / 字段列表 / 版本 / 画幅 / 名称。创建人与分类不显示 —— 猜出来的
|
|
196
|
+
* 分类是错的,比没有更坏。搜索走 CLI 自己的 `--category` 过滤。
|
|
197
|
+
*
|
|
198
|
+
* @param {string} stderr
|
|
199
|
+
* @returns {Map<string, {name: string, version: string|null, ratio: string|null, fieldCount: number, fields: string[], source: string|null, type: string|null}>}
|
|
200
|
+
*/
|
|
201
|
+
export function parseTemplateTable (stderr) {
|
|
202
|
+
const out = new Map()
|
|
203
|
+
const re = new RegExp(`^\\s{2}(${UUID})\\s+(.*)$`)
|
|
204
|
+
for (const line of String(stderr ?? '').split('\n')) {
|
|
205
|
+
const m = re.exec(line)
|
|
206
|
+
if (!m) continue
|
|
207
|
+
const id = m[1]
|
|
208
|
+
let rest = m[2].trim()
|
|
209
|
+
|
|
210
|
+
// 归属:[平台] / [个人] / [租户],永远在最后
|
|
211
|
+
const source = /\[(平台|个人|租户)\]\s*$/.exec(rest)
|
|
212
|
+
if (source) rest = rest.slice(0, source.index).trim()
|
|
213
|
+
|
|
214
|
+
// 字段清单:字段:key1,key2
|
|
215
|
+
const fields = /字段:([^\s[]+)/.exec(rest)
|
|
216
|
+
const fieldList = fields ? fields[1].split(',').map((f) => f.trim()).filter(Boolean) : []
|
|
217
|
+
if (fields) rest = (rest.slice(0, fields.index) + rest.slice(fields.index + fields[0].length)).trim()
|
|
218
|
+
|
|
219
|
+
// 类型:[图片] / [文字]
|
|
220
|
+
const type = /\[(图片|文字)\]/.exec(rest)
|
|
221
|
+
if (type) rest = (rest.slice(0, type.index) + rest.slice(type.index + type[0].length)).trim()
|
|
222
|
+
|
|
223
|
+
// 画幅:形如 3:4 / 16:9
|
|
224
|
+
const ratio = /(\d{1,2}:\d{1,2})\s*$/.exec(rest)
|
|
225
|
+
if (ratio) rest = rest.slice(0, ratio.index).trim()
|
|
226
|
+
|
|
227
|
+
// 版本:v1.0.0 / 1.0 —— 取第一个像版本的 token,它前面就是名称
|
|
228
|
+
const version = /(?:^|\s)(v?\d+\.\d+(?:\.\d+)?)(?=\s|$)/.exec(rest)
|
|
229
|
+
const name = (version ? rest.slice(0, version.index) : rest).trim() || null
|
|
230
|
+
|
|
231
|
+
out.set(id, {
|
|
232
|
+
name: name || id.slice(0, 8),
|
|
233
|
+
version: version ? version[1] : null,
|
|
234
|
+
ratio: ratio ? ratio[1] : null,
|
|
235
|
+
fieldCount: fieldList.length,
|
|
236
|
+
fields: fieldList,
|
|
237
|
+
source: source ? source[1] : null,
|
|
238
|
+
type: type ? type[1] : null,
|
|
239
|
+
})
|
|
240
|
+
}
|
|
241
|
+
return out
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 合并 templates 的 stdout(id 换行)与 stderr 表格。
|
|
246
|
+
* @param {string} stdout
|
|
247
|
+
* @param {string} stderr
|
|
248
|
+
* @returns {{id: string, name: string, version: string|null, ratio: string|null, fieldCount: number, fields: string[], source: string|null, type: string|null}[]}
|
|
249
|
+
*/
|
|
250
|
+
export function mergeTemplates (stdout, stderr) {
|
|
251
|
+
const table = parseTemplateTable(stderr)
|
|
252
|
+
return parseProjectIds(stdout).map((id) => {
|
|
253
|
+
const row = table.get(id)
|
|
254
|
+
return {
|
|
255
|
+
id,
|
|
256
|
+
name: row?.name ?? id.slice(0, 8),
|
|
257
|
+
version: row?.version ?? null,
|
|
258
|
+
ratio: row?.ratio ?? null,
|
|
259
|
+
fieldCount: row?.fieldCount ?? 0,
|
|
260
|
+
// fields 是模板的占位符 key 列表 —— 出图台要按它动态渲染输入框,
|
|
261
|
+
// 再拼成 `museav gen --template <id> --fields '{"key":"值"}'`
|
|
262
|
+
fields: row?.fields ?? [],
|
|
263
|
+
source: row?.source ?? null,
|
|
264
|
+
type: row?.type ?? null,
|
|
265
|
+
}
|
|
266
|
+
})
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* `museav jobs` 的 stdout 是完整 JSON 数组(不是表格),直接 parse。
|
|
271
|
+
* @param {string} stdout
|
|
272
|
+
* @returns {object[]}
|
|
273
|
+
*/
|
|
274
|
+
export function parseJobArray (stdout) {
|
|
275
|
+
const text = String(stdout ?? '').trim()
|
|
276
|
+
if (!text) return []
|
|
277
|
+
try {
|
|
278
|
+
const data = JSON.parse(text)
|
|
279
|
+
return Array.isArray(data) ? data : []
|
|
280
|
+
} catch {
|
|
281
|
+
return []
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* 出图记录只留 tab 要显示的字段 —— prompt 可能几百字,整包塞进 JSON 响应是浪费。
|
|
287
|
+
*
|
|
288
|
+
* 注意 workspace_id 在客户端登录态下常常是 null(见真机输出),所以 --project
|
|
289
|
+
* 的过滤在 CLI 侧本来就可能筛不出东西;这里不过滤,只如实显示返回的记录。
|
|
290
|
+
*
|
|
291
|
+
* @param {object[]} jobs
|
|
292
|
+
* @returns {{id: string, status: string, mediaType: string, model: string, url: string|null, prompt: string, ratio: string|null, createdAt: string|null, workspaceId: string|null, elapsedMs: number|null, error: string|null}[]}
|
|
293
|
+
*/
|
|
294
|
+
export function summarizeJobs (jobs) {
|
|
295
|
+
return jobs.map((job) => ({
|
|
296
|
+
id: job.id,
|
|
297
|
+
status: job.status ?? 'unknown',
|
|
298
|
+
mediaType: job.media_type ?? 'image',
|
|
299
|
+
model: job.model ?? '',
|
|
300
|
+
url: job.cdn_url ?? null,
|
|
301
|
+
prompt: typeof job.prompt === 'string' ? job.prompt : '',
|
|
302
|
+
ratio: job.ratio ?? null,
|
|
303
|
+
createdAt: job.created_at ?? null,
|
|
304
|
+
workspaceId: job.workspace_id ?? null,
|
|
305
|
+
elapsedMs: typeof job.elapsed_ms === 'number' ? job.elapsed_ms : null,
|
|
306
|
+
error: job.error ?? null,
|
|
307
|
+
}))
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* 找「可当 --ref 用的素材 URL」—— 出图记录里的垫图 / 生成结果。
|
|
312
|
+
* @param {{id: string, url: string, mediaType: string}[]} assets
|
|
313
|
+
* @param {string} needle
|
|
314
|
+
* @returns {string[]}
|
|
315
|
+
*/
|
|
316
|
+
export function pickAssetUrls (assets, needle) {
|
|
317
|
+
const key = String(needle ?? '').trim().toLowerCase()
|
|
318
|
+
if (!key) return []
|
|
319
|
+
return assets.filter((a) => a.url.toLowerCase().includes(key)).map((a) => a.url)
|
|
320
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dsh-plugins/dsh-museav-assets",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "MUSE AV 资产台:在 DSH 主区加一个「资产」tab,按项目(工作区)看素材库与最近出图,点素材复制直链当垫图用。基于本机 museav CLI,不碰任何密钥。",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"types": "./types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./types/index.d.ts",
|
|
11
|
+
"default": "./lib/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./client": {
|
|
14
|
+
"types": "./types/client.d.ts",
|
|
15
|
+
"default": "./lib/client.js"
|
|
16
|
+
},
|
|
17
|
+
"./package.json": {
|
|
18
|
+
"default": "./package.json"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"dsh": {
|
|
22
|
+
"bundle": {
|
|
23
|
+
"patch": "./cordis.patch.yml"
|
|
24
|
+
},
|
|
25
|
+
"client": {
|
|
26
|
+
"inject": [
|
|
27
|
+
"@deepseek-ai/dsh-client-locale",
|
|
28
|
+
"@deepseek-ai/dsh-client-ui-slots"
|
|
29
|
+
],
|
|
30
|
+
"platform": "web"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"prepublishOnly": "npm run check && npm test && node scripts/prepublish-gate.mjs && node scripts/readme-gate.mjs",
|
|
35
|
+
"check": "for f in lib/*.js; do node --check \"$f\" || exit 1; done",
|
|
36
|
+
"test": "node --test test/*.test.mjs",
|
|
37
|
+
"deploy": "rsync -av --delete lib/ ~/.dsh/profiles/${DSH_PROFILE:-desktop}/node_modules/@dsh-plugins/dsh-museav-assets/lib/ && rsync -av types package.json cordis.patch.yml README.md README.en.md LICENSE ~/.dsh/profiles/${DSH_PROFILE:-desktop}/node_modules/@dsh-plugins/dsh-museav-assets/"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"dsh",
|
|
41
|
+
"dsh-plugin",
|
|
42
|
+
"deepseek-harness",
|
|
43
|
+
"museav",
|
|
44
|
+
"assets",
|
|
45
|
+
"image-generation"
|
|
46
|
+
],
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/webkubor/dsh-museav-assets.git"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/webkubor/dsh-museav-assets/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/webkubor/dsh-museav-assets#readme",
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"files": [
|
|
60
|
+
"CHANGELOG.md",
|
|
61
|
+
"LICENSE",
|
|
62
|
+
"README.md",
|
|
63
|
+
"README.en.md",
|
|
64
|
+
"cordis.patch.yml",
|
|
65
|
+
"lib",
|
|
66
|
+
"types"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-museav-assets Client Globals
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
declare global {
|
|
6
|
+
interface Window {
|
|
7
|
+
__ModuleLoader__: {
|
|
8
|
+
load(opts: { id: string; factory: (require?: any, exports?: any, module?: any) => any }): void
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare function require(id: string): any
|
|
14
|
+
|
|
15
|
+
declare module 'react' {
|
|
16
|
+
const React: any
|
|
17
|
+
export default React
|
|
18
|
+
export = React
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export {}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-museav-assets TypeScript Definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const name: '@dsh-plugins/dsh-museav-assets'
|
|
6
|
+
export const inject: string[]
|
|
7
|
+
|
|
8
|
+
/** 一个工作区(项目)。id 是真值,name 来自 stderr 表格,解析不到就退回 id 前 8 位。 */
|
|
9
|
+
export interface MuseProject {
|
|
10
|
+
id: string
|
|
11
|
+
name: string
|
|
12
|
+
genDone: number | null
|
|
13
|
+
genTotal: number | null
|
|
14
|
+
assetCount: number | null
|
|
15
|
+
brand: string | null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** 工作区素材库里的一条。url 可直接当 `museav gen --ref` 的垫图直链。 */
|
|
19
|
+
export interface MuseAsset {
|
|
20
|
+
id: string
|
|
21
|
+
url: string
|
|
22
|
+
name: string
|
|
23
|
+
mediaType: string
|
|
24
|
+
tags: string[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** 最近出图记录(已裁剪过 prompt 之外的大字段)。 */
|
|
28
|
+
export interface MuseJob {
|
|
29
|
+
id: string
|
|
30
|
+
status: string
|
|
31
|
+
mediaType: string
|
|
32
|
+
model: string
|
|
33
|
+
url: string | null
|
|
34
|
+
prompt: string
|
|
35
|
+
ratio: string | null
|
|
36
|
+
createdAt: string | null
|
|
37
|
+
workspaceId: string | null
|
|
38
|
+
elapsedMs: number | null
|
|
39
|
+
error: string | null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface ProjectsResponse {
|
|
43
|
+
ok: boolean
|
|
44
|
+
error?: string
|
|
45
|
+
projects: MuseProject[]
|
|
46
|
+
used?: number
|
|
47
|
+
limit?: number
|
|
48
|
+
/** 已达服务端上限(每账户 5 个),此时新建会被拒。 */
|
|
49
|
+
full?: boolean
|
|
50
|
+
id?: string | null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface AssetsResponse {
|
|
54
|
+
ok: boolean
|
|
55
|
+
error?: string
|
|
56
|
+
project?: string
|
|
57
|
+
assets: MuseAsset[]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface JobsResponse {
|
|
61
|
+
ok: boolean
|
|
62
|
+
error?: string
|
|
63
|
+
jobs: MuseJob[]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface HealthResponse {
|
|
67
|
+
ok: boolean
|
|
68
|
+
cli: { bin: string; version: string | null; error: string | null }
|
|
69
|
+
projectLimit: number
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** 服务端工作区数量上限,与 museav projects create 的限制一致。 */
|
|
73
|
+
export const PROJECT_LIMIT: 5
|