@uzooai/anime-ai-cli 0.5.0 → 0.6.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/.agents/skills/uzoo-anime-cli/SKILL.md +10 -4
- package/.agents/skills/uzoo-anime-cli/references/agreement-workflow.md +0 -10
- package/.agents/skills/uzoo-anime-cli/references/commands.md +8 -16
- package/.agents/skills/uzoo-anime-cli/references/generation-workflow.md +3 -13
- package/.agents/skills/uzoo-anime-cli/references/image-tools-workflow.md +5 -27
- package/.agents/skills/uzoo-anime-cli/references/interaction-workflow.md +1 -1
- package/.agents/skills/uzoo-anime-cli/references/material-graph-workflow.md +7 -17
- package/.agents/skills/uzoo-anime-cli/references/node-capabilities.md +19 -50
- package/.agents/skills/uzoo-anime-cli/references/node-workflow.md +3 -7
- package/.agents/skills/uzoo-anime-cli/references/remake-workflow.md +1 -1
- package/.agents/skills/uzoo-anime-cli/references/repaint-workflow.md +7 -294
- package/.agents/skills/uzoo-anime-cli/references/seedance-review-workflow.md +1 -5
- package/.agents/skills/uzoo-anime-cli/references/video-tools-workflow.md +3 -7
- package/CHANGELOG.md +9 -85
- package/README.md +27 -219
- package/docs/Agent/346/216/245/345/205/245/344/270/216/347/211/210/346/234/254/346/233/264/346/226/260.md +41 -0
- package/package.json +11 -13
- package/src/cli.js +5 -0
- package/src/group-membership.js +0 -1
- package/src/install.js +237 -0
- package/assets/README.md +0 -4
- package/docs/CLI/345/275/223/345/211/215/350/214/203/345/233/264/344/270/216/346/234/254/345/234/260/346/211/223/345/214/205-20261103.md +0 -134
- package/docs/CLI/346/216/210/346/235/203/346/216/245/345/217/243/344/270/216/344/273/244/347/211/214/350/207/252/345/212/250/345/210/267/346/226/260/350/256/276/350/256/241.md +0 -540
- package/docs/CLI/347/274/272/345/217/243/346/240/270/345/257/271/344/270/216/346/224/266/345/260/276-20261105.md +0 -65
- package/docs/CLI/347/275/221/351/241/265/344/277/235/345/255/230/350/212/202/347/202/271/347/274/272/345/244/261/344/272/244/346/216/245.md +0 -52
- package/docs/M0-M5/345/256/236/346/226/275/344/270/216/351/252/214/346/224/266.md +0 -89
- package/docs/npm/347/272/277/344/270/212/345/217/221/345/270/203/344/270/216/345/256/211/350/243/205/344/275/277/347/224/250.md +0 -151
- package/docs//344/270/213/350/275/275/346/216/245/345/217/243/351/200/202/351/205/215/344/270/216/351/252/214/346/224/266.md +0 -107
- package/docs//344/270/232/345/212/241/350/203/275/345/212/233/350/241/245/345/205/250/344/270/216Skill/347/273/223/346/236/204/350/247/204/345/210/222.md +0 -311
- package/docs//345/205/250/345/261/200/351/231/204/344/273/266/350/265/204/346/272/220/345/234/260/345/235/200/344/270/216/346/250/241/345/236/213/350/257/273/345/217/226/345/267/256/345/274/202.md +0 -47
- package/docs//345/206/205/351/203/250Windows/345/256/211/350/243/205/344/270/216/345/215/207/347/272/247/351/252/214/346/224/266/346/270/205/345/215/225.md +0 -34
- package/docs//345/233/276/347/211/207/346/212/240/345/233/276/346/216/245/345/205/245/344/270/216/351/252/214/346/224/266-20261104.md +0 -110
- package/docs//345/274/200/345/217/221/350/256/241/345/210/222.md +0 -127
- package/docs//345/274/202/346/255/245/346/212/240/345/233/276CLI/346/235/203/351/231/220/344/272/244/346/216/245-20261105.md +0 -50
- package/docs//345/274/202/346/255/245/346/212/240/345/233/276/347/234/237/345/256/236/351/252/214/346/224/266-20261105.md +0 -44
- package/docs//346/226/260/344/274/232/350/257/235/344/273/273/345/212/241/344/272/244/344/273/243-/351/230/266/346/256/2652A.md +0 -79
- package/docs//346/226/260/351/203/250/347/275/262/347/224/273/345/270/203/345/206/262/347/252/201/351/252/214/346/224/266-20261102.md +0 -61
- package/docs//346/231/256/351/200/232/346/265/217/350/247/210/345/231/250/347/231/273/345/275/225.md +0 -53
- package/docs//346/255/243/345/274/217/347/253/231/345/210/207/346/215/242/344/270/216/351/252/214/346/224/266-20261104.md +0 -90
- package/docs//347/224/273/345/270/203CLI/344/270/213/344/270/200/351/230/266/346/256/265/345/274/200/345/217/221/350/256/241/345/210/222.md +0 -136
- package/docs//347/224/273/345/270/203CLI/351/235/236/350/275/254/347/273/230/345/256/214/345/226/204/350/256/241/345/210/222.md +0 -183
- package/docs//347/224/273/345/270/203/350/203/275/345/212/233/345/245/221/347/272/246/346/240/270/345/257/271.md +0 -59
- package/docs//347/234/237/345/256/236/344/270/232/345/212/241/346/216/245/345/205/245/344/270/216/346/265/213/350/257/225.md +0 -1004
- package/docs//347/264/240/346/235/220/345/205/245/345/272/223/344/270/216/347/224/273/345/270/203/344/277/235/345/255/230/351/227/256/351/242/230/345/256/232/344/275/215.md +0 -52
- package/docs//351/230/266/346/256/2653B/351/252/214/346/224/266/344/272/244/346/216/245.md +0 -44
- package/docs//351/230/266/346/256/265/344/270/200/351/252/214/346/224/266.md +0 -60
- package/docs//351/235/236/350/275/254/347/273/230/346/214/201/347/273/255/345/256/214/345/226/204/344/270/216/351/252/214/346/224/266-20261103.md +0 -76
- package/docs//351/235/236/350/275/254/347/273/230/347/254/254/344/272/214/346/211/271/345/256/236/346/226/275/344/270/216/351/252/214/346/224/266.md +0 -39
- package/docs//351/235/236/350/275/254/347/273/230/350/241/245/345/205/205/346/235/241/344/273/266/351/252/214/346/224/266-20261103.md +0 -113
- package/docs//351/235/236/350/275/254/347/273/230/351/246/226/346/211/271/345/256/236/346/226/275/344/270/216/351/252/214/346/224/266.md +0 -71
- package/examples/real-business/image-request.template.json +0 -7
- package/examples/real-business/node-patch.template.json +0 -11
- package/scripts/check-package-resources.mjs +0 -56
- package/scripts/check-release.mjs +0 -19
- package/scripts/pack-local.mjs +0 -33
- package/scripts/release-policy.mjs +0 -22
package/src/install.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import { createHash } from 'node:crypto'
|
|
5
|
+
import { execFile } from 'node:child_process'
|
|
6
|
+
import { promisify } from 'node:util'
|
|
7
|
+
import { createInterface } from 'node:readline/promises'
|
|
8
|
+
import { setTimeout as delay } from 'node:timers/promises'
|
|
9
|
+
import { packageInfo } from './package-info.js'
|
|
10
|
+
|
|
11
|
+
const exec = promisify(execFile)
|
|
12
|
+
const skillName = 'uzoo-anime-cli'
|
|
13
|
+
const receipt = '.uzoo-install.json'
|
|
14
|
+
const bundle = path.join('.agents', 'skills', skillName)
|
|
15
|
+
const registry = 'https://registry.npmjs.org/'
|
|
16
|
+
const agents = {
|
|
17
|
+
codex: { label: 'Codex', config: '.agents', detect: '.codex' },
|
|
18
|
+
workbuddy: { label: 'WorkBuddy', config: '.workbuddy' },
|
|
19
|
+
'claude-code': { label: 'Claude Code', config: '.claude' },
|
|
20
|
+
}
|
|
21
|
+
const help = `安装或更新同版本的 CLI 和 Skill(用户级)
|
|
22
|
+
install 检测并选择一个或多个 Agent
|
|
23
|
+
install --agent codex --agent workbuddy
|
|
24
|
+
install --agent codex --yes 非交互,须明确指定 Agent
|
|
25
|
+
install --agent workbuddy --dry-run 仅预览,不安装
|
|
26
|
+
Agent:codex、workbuddy、claude-code
|
|
27
|
+
原 npm install -g 仍只安装 CLI 和随包文件,不写 Agent 技能目录。`
|
|
28
|
+
|
|
29
|
+
export function parseInstall(args) {
|
|
30
|
+
const selected = [], flags = new Set()
|
|
31
|
+
for (let i = 0; i < args.length; i++) {
|
|
32
|
+
const arg = args[i]
|
|
33
|
+
if (arg === '--agent') {
|
|
34
|
+
const id = args[++i]?.toLowerCase()
|
|
35
|
+
if (!Object.hasOwn(agents, id)) throw new Error('未知或缺少 --agent;可选 codex、workbuddy、claude-code')
|
|
36
|
+
if (!selected.includes(id)) selected.push(id)
|
|
37
|
+
} else if (['--yes', '--dry-run', '--help', '-h'].includes(arg) && !flags.has(arg)) {
|
|
38
|
+
flags.add(arg)
|
|
39
|
+
} else throw new Error(`未知或重复的安装参数:${arg}`)
|
|
40
|
+
}
|
|
41
|
+
if (flags.has('--yes') && !selected.length) throw new Error('--yes 需要明确指定至少一个 --agent')
|
|
42
|
+
return { selected, yes: flags.has('--yes'), dryRun: flags.has('--dry-run'), help: flags.has('--help') || flags.has('-h') }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function stat(file) {
|
|
46
|
+
try { return await fs.lstat(file) } catch (error) { if (error.code !== 'ENOENT') throw error }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function safeDirectories(...directories) {
|
|
50
|
+
for (const dir of directories) {
|
|
51
|
+
const s = await stat(dir)
|
|
52
|
+
if (s && (!s.isDirectory() || s.isSymbolicLink())) throw new Error(`不是普通目录,未修改:${dir}`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function agentTargets(home) {
|
|
57
|
+
return Promise.all(Object.entries(agents).map(async ([id, agent]) => {
|
|
58
|
+
const config = path.join(home, agent.config)
|
|
59
|
+
const root = path.join(config, 'skills')
|
|
60
|
+
const detected = Boolean((await stat(path.join(home, agent.detect || agent.config)))?.isDirectory())
|
|
61
|
+
return { id, label: agent.label, config, root, target: path.join(root, skillName), detected }
|
|
62
|
+
}))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function fingerprint(directory) {
|
|
66
|
+
const hash = createHash('sha256')
|
|
67
|
+
async function walk(dir, prefix = '') {
|
|
68
|
+
for (const entry of (await fs.readdir(dir, { withFileTypes: true })).sort((a, b) => a.name < b.name ? -1 : a.name === b.name ? 0 : 1)) {
|
|
69
|
+
if (!prefix && entry.name === receipt) continue
|
|
70
|
+
const file = path.join(dir, entry.name), name = prefix + entry.name
|
|
71
|
+
if (entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
72
|
+
hash.update(JSON.stringify(['directory', name]))
|
|
73
|
+
await walk(file, name + '/')
|
|
74
|
+
} else if (entry.isFile() && !entry.isSymbolicLink()) {
|
|
75
|
+
hash.update(JSON.stringify(['file', name, createHash('sha256').update(await fs.readFile(file)).digest('hex')]))
|
|
76
|
+
} else throw new Error(`技能中存在链接或特殊文件:${file}`)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
await safeDirectories(directory)
|
|
80
|
+
await walk(directory)
|
|
81
|
+
return hash.digest('hex')
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function inspect(target) {
|
|
85
|
+
await safeDirectories(target.config, target.root, target.target)
|
|
86
|
+
if (!await stat(target.target)) return { kind: 'new' }
|
|
87
|
+
const marker = path.join(target.target, receipt)
|
|
88
|
+
if (!(await stat(marker))?.isFile()) return { kind: 'protected' }
|
|
89
|
+
let meta
|
|
90
|
+
try { meta = JSON.parse(await fs.readFile(marker, 'utf8')) } catch (error) {
|
|
91
|
+
if (!(error instanceof SyntaxError)) throw error
|
|
92
|
+
return { kind: 'protected' }
|
|
93
|
+
}
|
|
94
|
+
if (meta?.package !== packageInfo.name || meta?.schema !== 1) return { kind: 'protected' }
|
|
95
|
+
const digest = await fingerprint(target.target)
|
|
96
|
+
if (meta.digest !== digest) return { kind: 'protected' }
|
|
97
|
+
return { kind: 'managed', digest, version: meta.version }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function verifyBundle(directory) {
|
|
101
|
+
if (!(await stat(path.join(directory, 'SKILL.md')))?.isFile() ||
|
|
102
|
+
!(await stat(path.join(directory, 'references')))?.isDirectory() ||
|
|
103
|
+
await stat(path.join(directory, receipt))) throw new Error('npm 包内 Skill 不完整或含安装记录')
|
|
104
|
+
return fingerprint(directory)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function renameSkill(from, to) {
|
|
108
|
+
// Windows indexers can briefly hold a handle to freshly copied files.
|
|
109
|
+
for (const wait of [25, 50, 100, 200, 400, 0]) {
|
|
110
|
+
if (await stat(to)) throw new Error(`目标目录已存在,未覆盖:${to}`)
|
|
111
|
+
try { await fs.rename(from, to); return } catch (error) {
|
|
112
|
+
if (process.platform !== 'win32' || !wait || !['EPERM', 'EACCES', 'EBUSY'].includes(error.code)) throw error
|
|
113
|
+
await delay(wait)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function installSkill(target, directory, digest, version, expected) {
|
|
119
|
+
const current = await inspect(target)
|
|
120
|
+
if (JSON.stringify(current) !== JSON.stringify(expected)) throw new Error(`${target.label} 的 Skill 在确认后有变化,请重新预览`)
|
|
121
|
+
if (current.digest === digest && current.version === version) return 'unchanged'
|
|
122
|
+
await fs.mkdir(target.root, { recursive: true })
|
|
123
|
+
const stage = await fs.mkdtemp(path.join(target.config, '.uzoo-install-'))
|
|
124
|
+
const next = path.join(stage, 'next'), previous = path.join(stage, 'previous')
|
|
125
|
+
let moved = false
|
|
126
|
+
try {
|
|
127
|
+
await fs.cp(directory, next, { recursive: true, errorOnExist: true, force: false })
|
|
128
|
+
if (await fingerprint(next) !== digest) throw new Error('Skill 暂存校验失败')
|
|
129
|
+
await fs.writeFile(path.join(next, receipt), JSON.stringify({ schema: 1, package: packageInfo.name, version, digest }) + '\n', { flag: 'wx' })
|
|
130
|
+
if (JSON.stringify(await inspect(target)) !== JSON.stringify(current)) throw new Error(`${target.label} 的 Skill 已变化,请重新预览`)
|
|
131
|
+
if (current.kind === 'managed') {
|
|
132
|
+
await renameSkill(target.target, previous); moved = true
|
|
133
|
+
// Preserve an edit made between the final check and the directory move.
|
|
134
|
+
if (await fingerprint(previous) !== current.digest) throw new Error(`${target.label} 的 Skill 在替换前有变化`)
|
|
135
|
+
}
|
|
136
|
+
await renameSkill(next, target.target)
|
|
137
|
+
moved = false
|
|
138
|
+
return current.kind === 'new' ? 'installed' : 'updated'
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (moved) {
|
|
141
|
+
try { await renameSkill(previous, target.target); moved = false } catch {
|
|
142
|
+
throw new Error(`${error.message};原 Skill 保留于 ${previous}`)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
throw error
|
|
146
|
+
} finally {
|
|
147
|
+
if (!moved) await fs.rm(stage, { recursive: true, force: true }).catch(() => {})
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function runNpm(args, signal) {
|
|
152
|
+
const npmCli = process.env.npm_execpath
|
|
153
|
+
const options = { timeout: 120_000, windowsHide: true, signal }
|
|
154
|
+
if (npmCli && path.isAbsolute(npmCli) && path.basename(npmCli) === 'npm-cli.js') {
|
|
155
|
+
return (await exec(process.execPath, [npmCli, ...args], options)).stdout.trim()
|
|
156
|
+
}
|
|
157
|
+
if (process.platform !== 'win32') return (await exec('npm', args, options)).stdout.trim()
|
|
158
|
+
// cmd is needed for npm.cmd. Only the fixed command and validated tokens may reach it.
|
|
159
|
+
if (args.some(arg => !/^[\w.@:/-]+$/.test(arg))) throw new Error('不支持的 npm 参数')
|
|
160
|
+
return (await exec('cmd.exe', ['/d', '/c', 'npm', ...args], options)).stdout.trim()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export async function runInstall(args, {
|
|
164
|
+
home = homedir(), npm = runNpm, input = process.stdin, output = process.stdout,
|
|
165
|
+
log = console.log, version = packageInfo.version, signal,
|
|
166
|
+
} = {}) {
|
|
167
|
+
const opts = parseInstall(args)
|
|
168
|
+
if (opts.help) { log(help); return }
|
|
169
|
+
if (!/^\d+\.\d+\.\d+(?:-rc\.\d+)?$/.test(version)) throw new Error('安装入口要求明确的包版本')
|
|
170
|
+
const pkg = `${packageInfo.name}@${version}`
|
|
171
|
+
const all = await agentTargets(home)
|
|
172
|
+
let selected = all.filter(agent => opts.selected.includes(agent.id))
|
|
173
|
+
const detected = all.filter(agent => agent.detected)
|
|
174
|
+
const interactive = input.isTTY && output.isTTY
|
|
175
|
+
let rl
|
|
176
|
+
const ask = async prompt => {
|
|
177
|
+
rl ??= createInterface({ input, output })
|
|
178
|
+
return (await rl.question(prompt, { signal })).trim()
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
if (!selected.length && opts.dryRun) {
|
|
182
|
+
log(JSON.stringify({ package: pkg, dry_run: true, detected: detected.map(({ id, target }) => ({ id, target })) }, null, 2))
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
if (!interactive && !opts.dryRun && !opts.yes) throw new Error('非交互安装需指定 --agent NAME --yes;可先运行 install --dry-run')
|
|
186
|
+
if (!selected.length) {
|
|
187
|
+
const choices = detected.length ? detected : all
|
|
188
|
+
log(detected.length ? '检测到以下 Agent:' : '未检测到 Agent,可手动选择已安装的宿主:')
|
|
189
|
+
choices.forEach(({ label, target }, i) => log(` ${i + 1}. ${label} ${target}`))
|
|
190
|
+
if (detected.length && detected.length < all.length) log('其他宿主可通过 --agent 明确指定。')
|
|
191
|
+
const answer = await ask('输入一个或多个序号(空格或逗号分隔,回车取消):')
|
|
192
|
+
if (!answer) { log('已取消,未安装。'); return }
|
|
193
|
+
const indexes = [...new Set(answer.split(/[\s,,]+/))]
|
|
194
|
+
if (indexes.some(i => !/^[1-9]\d*$/.test(i) || Number(i) > choices.length)) throw new Error('Agent 序号无效')
|
|
195
|
+
selected = indexes.map(i => choices[Number(i) - 1])
|
|
196
|
+
}
|
|
197
|
+
const states = await Promise.all(selected.map(inspect))
|
|
198
|
+
const blocked = selected.filter((_, i) => states[i].kind === 'protected')
|
|
199
|
+
log(JSON.stringify({ package: pkg, dry_run: opts.dryRun, skills: selected.map(({ id, target }, i) => ({ id, target, state: states[i].kind })) }, null, 2))
|
|
200
|
+
if (opts.dryRun) return
|
|
201
|
+
if (blocked.length) throw new Error(`已有手动安装或改动过的 Skill:${blocked.map(x => x.target).join(';')}。未安装;请先备份至扫描目录之外,或只选择其它 Agent。`)
|
|
202
|
+
if (!opts.yes && !/^(?:y|yes)$/i.test(await ask('安装或更新以上 CLI 和 Skill?[y/N] '))) { log('已取消,未安装。'); return }
|
|
203
|
+
|
|
204
|
+
signal?.throwIfAborted()
|
|
205
|
+
const root = await npm(['root', '--global'], signal)
|
|
206
|
+
if (!path.isAbsolute(root)) throw new Error('无法定位 npm 全局目录')
|
|
207
|
+
const directory = path.join(root, ...packageInfo.name.split('/'))
|
|
208
|
+
const metadata = async () => {
|
|
209
|
+
try { return JSON.parse(await fs.readFile(path.join(directory, 'package.json'), 'utf8')) } catch (error) {
|
|
210
|
+
if (error.code !== 'ENOENT' && !(error instanceof SyntaxError)) throw error
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
let installed = await metadata()
|
|
214
|
+
if (installed?.name !== packageInfo.name || installed?.version !== version) {
|
|
215
|
+
await npm(['install', '--global', pkg, '--registry=' + registry, '--ignore-scripts', '--no-audit', '--no-fund'], signal)
|
|
216
|
+
installed = await metadata()
|
|
217
|
+
}
|
|
218
|
+
if (installed?.name !== packageInfo.name || installed?.version !== version || installed?.bin?.['uzoo-anime'] !== 'src/cli.js') {
|
|
219
|
+
throw new Error('全局 CLI 包身份、版本或入口验证失败,未写入 Skill')
|
|
220
|
+
}
|
|
221
|
+
const entry = path.join(directory, 'src', 'cli.js')
|
|
222
|
+
const prefix = await npm(['prefix', '--global'], signal)
|
|
223
|
+
if (!path.isAbsolute(prefix)) throw new Error('无法定位 npm 全局命令目录,未写入 Skill')
|
|
224
|
+
const bin = process.platform === 'win32' ? path.join(prefix, 'uzoo-anime.cmd') : path.join(prefix, 'bin', 'uzoo-anime')
|
|
225
|
+
const result = await exec(process.execPath, [entry, '--version'], { timeout: 15_000, windowsHide: true, signal })
|
|
226
|
+
if (!await stat(bin) || result.stdout.trim() !== version) throw new Error('全局 CLI 命令或版本验证失败,未写入 Skill')
|
|
227
|
+
const source = path.join(directory, bundle)
|
|
228
|
+
const digest = await verifyBundle(source)
|
|
229
|
+
for (let i = 0; i < selected.length; i++) {
|
|
230
|
+
signal?.throwIfAborted()
|
|
231
|
+
const status = await installSkill(selected[i], source, digest, version, states[i])
|
|
232
|
+
log(`${selected[i].label}: ${status} — ${selected[i].target}`)
|
|
233
|
+
}
|
|
234
|
+
log(`CLI ${version}: ${bin}`)
|
|
235
|
+
log('请在目标 Agent 的新会话验证 uzoo-anime --version;若命令不可见,请检查 npm 全局命令目录是否在其 PATH。')
|
|
236
|
+
} finally { rl?.close() }
|
|
237
|
+
}
|
package/assets/README.md
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# CLI当前范围与本地打包(2026-11-03)
|
|
2
|
-
|
|
3
|
-
## 可交付范围
|
|
4
|
-
|
|
5
|
-
当前可制作内测用npm压缩包,不把本地打包成功等同正式发布或所有真实业务验收完成。正式名称更新为@uzooai/anime-ai-cli、MIT许可证、待发布版本0.5.0,已准备private=false/public/官方registry/latest,保留Node.js >=22要求;原生ESM JavaScript无需转译,没有新增构建依赖。禁止自动npm发布、Git提交或推送。
|
|
6
|
-
|
|
7
|
-
已收紧的普通路线包括媒体复制的任务来源/历史/引用归属,画布CAS和读回,同节点再次生成的提交前快照与最新任务保护,未知提交原operation恢复,独立费用确认和本人协议签署。图片prepare之外的直接estimate/submit也只接受数值image_count=1;多张、零张、字符串数量在估价前拒绝,不能通过手写JSON扩展前端未支持的参数。
|
|
8
|
-
|
|
9
|
-
当前抠图已接同步/本地后台及服务端异步job;正式站202、CLI退出后按原job查询/取回PNG、实际0 OO、一次CAS及用户网页重开通过。image matting-check仍为只读预检;未取得job_id或原结果引用的未知提交无法可靠查回,不重POST。此前开发部署无服务/正式站授权关闭为历史状态。
|
|
10
|
-
|
|
11
|
-
## 构建与打包
|
|
12
|
-
|
|
13
|
-
```powershell
|
|
14
|
-
npm run build
|
|
15
|
-
npm test
|
|
16
|
-
npm run pack:local
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
build做语法和离线包资源检查,不生成编译目录。pack:local先build,再离线npm pack,输出outputs/npm/独立时间目录/*.tgz及manifest.json,校验实际归档长度、SHA-1及SHA-512 integrity。目录每次独立,保留全部旧产物。标准npm pack也有prepack构建检查;资源dry-run显式ignore-scripts以免递归。
|
|
20
|
-
|
|
21
|
-
files白名单包含src、assets、完整skill入口及13份参考、历史登录扩展兼容资源、示例、文档及两个打包检查脚本;README/package.json由npm包含。排除test、本机outputs/.local/node_modules、宿主AGENTS、安装专项脚本、内部远端联调记录、凭据及旧tgz。维护者文档中的兄弟前后端仓库源码链接只作为历史证据,不属于运行依赖;CLI、README和skill所需包内相对依赖另行检查。
|
|
22
|
-
|
|
23
|
-
可以将该tgz交付给内测用户,通过npm安装;本轮没有执行安装、全局配置修改或干净Windows/跨版本验收,不属于N5专项。npm安装不会自动注册Agent skill,仍按README复制完整skill目录到宿主支持的位置。
|
|
24
|
-
|
|
25
|
-
## 尚未宣称完成的路线
|
|
26
|
-
|
|
27
|
-
| 路线 | 具体条件/边界 |
|
|
28
|
-
|---|---|
|
|
29
|
-
| 图片历史网页保存重开 | 采用1986/离开重开/恢复2071再次重开及独立服务端读回已通过 |
|
|
30
|
-
| 样片转正片 | 2072→2073真实CLI闭环、父子关联、回填、下载/解码及52+260 OO核验通过;正片网页重开、1440×1440/4.064秒完整播放已通过 |
|
|
31
|
-
| 协议阻断后原生成续接 | 2026-11-04猫猫队新协议v3真实前检阻断→本人签署→原operation任务2078完成,16 OO;回填/下载/解码及无重复提交通过 |
|
|
32
|
-
| 抠图 | 单次免费执行、透明PNG、已知结果GET/缓存恢复、CAS落图与正式站网页重开通过;无引用的未知提交仍缺服务端查询契约,不重发 |
|
|
33
|
-
| 真实过期/不可续期、私有/下架下载组合 | 非成员拒绝已过,其余需受控真实条件,不篡改凭证或删除素材制造情景 |
|
|
34
|
-
| 图片多张、音频生成、格式转换、完整撤销、更多重拍/ZIP等 | 只接实际前端能力;没有当前完整产品入口/契约时不造参数。普通图片当前单张;格式转换当前不支持 |
|
|
35
|
-
| 大小元数据 | 2026-11-03 15:24最新复测2069/2071记录大小与实际字节均一致、原摘要不变;旧失败证据保留 |
|
|
36
|
-
| N5、转绘、去字幕 | 继续排除/暂停;本地语法、回归及归档资源检查不是恢复这些专项 |
|
|
37
|
-
|
|
38
|
-
真实业务及收费历史见[补充验收记录](非转绘补充条件验收-20261103.md)。本次历史新增两个测试节点,网页采用旧图片并恢复2071;无新生成、审核、上传、入库或费用。
|
|
39
|
-
|
|
40
|
-
历史新增普通节点已接入history-add,预览/CAS/原operation只读恢复/读回核验及来源历史归属保护,真实图片/视频新增和网页重开通过。
|
|
41
|
-
|
|
42
|
-
## 2026-11-04 新协议v3真实续接通过
|
|
43
|
-
|
|
44
|
-
猫猫队实际v3未签状态下,CLI先持久化blocked_agreement(无生成POST/远端任务);本人阅读签署后,通过原recover复核账号、请求及报价,以原operation和同一幂等键提交一次,任务2078完成、实际16 OO,回填/下载/完整解码通过;再次recover无新提交。此项更新v2独立签署后“尚缺收费原任务续接”的历史状态。未向生成接口故意跳过前检制造4401;并发版本变化的服务端4401分支仍为模拟覆盖。正文版本更新必须重读当前服务端状态,不能把本次v3已签当作未来版本同意。
|
|
45
|
-
|
|
46
|
-
## 2026-11-04 任务2078下载元数据补验
|
|
47
|
-
|
|
48
|
-
新协议v3验收生成的2078已完成/charged/16 OO。两次均通过原任务专属下载入口重新取链,实际交付602870字节、SHA-256 b273d50132379c984106fd0d4cf07d92273715463460586c323d845130aeb2c7,两次完全一致;H.264 640×640/24fps,容器4.096秒,整片完整解码通过。原任务GET的result.file_size前后仍为937487,与实际交付不一致。
|
|
49
|
-
|
|
50
|
-
本次协议原operation续接及媒体交付可用通过;大小元数据一致性不通过,交后端核对最终交付版本/更新时点,未擅自认定根因。此前2069/2071大小一致复测仍是各自条目的有效历史证据,不扩大为新任务均已修复。未修改前后端、篡改凭证、转码、重新生成或覆盖旧文件。
|
|
51
|
-
|
|
52
|
-
证据:.local/frontend-conflict-20261102/agreement-v3-finish-1793757654901.json、size2078-recheck-1793757700987.json;两份MP4均保留。原operation=seedance-agreement-v3-20261104、task_id=2078。共享钱包2665→2641仅为快照,任务实际结算16 OO,不从余额差额推定其他消费。
|
|
53
|
-
|
|
54
|
-
## 2026-11-04 实际业务地址切换正式站
|
|
55
|
-
|
|
56
|
-
用户说明服务版前后端已更新,后续业务地址切换为https://uzooai.com,使用独立uzooai-online profile;原开发站配置、凭据、operation及产物保留,不跨服务改绑或重放。正式站live/ready均HTTP200/code0,database/redis均ok;更新后的CLI授权实测仍返回2110/cli_auth_disabled,未建立正式站CLI会话。等待部署方核对授权开关及HTTPS的CLI_AUTH_ORIGIN,尚未在正式站签署或提交业务。详见[正式站切换与验收](正式站切换与验收-20261104.md)。开发站此前验收不自动视为正式站业务通过。
|
|
57
|
-
|
|
58
|
-
## 2026-11-04 正式站授权已启用并完成登录
|
|
59
|
-
|
|
60
|
-
用户确认正式部署授权开关已启用生效后,重新运行uzoo-anime --profile uzooai-online auth login,正式站返回https://uzooai.com/auth/login授权页。用户本人登录并明确授权,CLI成功保存独立加密会话,cliSessionReplaced=false;此前2110/cli_auth_disabled阻塞已解除。
|
|
61
|
-
|
|
62
|
-
独立GET核验:API=https://uzooai.com/api/v1,live/ready均HTTP200/code0、database/redis均ok。实际账号LIU(uid=585603228375),唯一有效团队“SD2.5-Draft功能测试”(team_uid=519080401579),共享余额快照0 OO;协议required=true、agreed=true、version=v2。正式站账号/团队与开发站不同,不能复用开发站猫猫队、测试画布或任务ID。正式站v2已签不代表开发站v3发生变化,也不需要为切换再次签署。
|
|
63
|
-
|
|
64
|
-
后续真实业务明确使用uzooai-online profile和正式站实际对象。开发站stage3b-test及旧operation/产物保留,不将其改绑到正式站。抠图免费约束沿用用户说明;CLI登录成功只解除身份接入阻塞,不等于抠图执行/原结果恢复已经实现或已验收。
|
|
65
|
-
|
|
66
|
-
本次未创建/修改正式站画布、上传、签署协议或提交生成/抠图,未产生费用。证据:.local/frontend-conflict-20261102/production-switch-1793774998943.json;正式网页公开入口/assets/index-Da5Nhe9D.js已记录,公开HTML摘要b32df6a35c964ba2e813b66937ac075280bcdc04227d86d971213cbbf0639c72。页面资源不当作抠图推理服务或全部业务契约证明。
|
|
67
|
-
|
|
68
|
-
## 2026-11-04 正式站抠图执行更新(rc.4)
|
|
69
|
-
|
|
70
|
-
免费抠图已接入单次执行、透明PNG核验、缓存与已知原结果GET恢复、CAS落图及来源线;正式站7738原图返回0 OO,用户确认网页保存重开,独立102版读回通过。此前“仅预检/执行未实现”为历史阶段;无引用的未知提交服务端查回仍未接入,不重发。详情见[抠图接入与验收](图片抠图接入与验收-20261104.md)。
|
|
71
|
-
|
|
72
|
-
## 2026-11-04 独立后台执行更新(rc.5)
|
|
73
|
-
|
|
74
|
-
用户选择独立后台执行+原operation状态查询,保持现有同步PNG接口。新增matting-start/matting-status:后台独立Node进程仅缓存PNG,原recover确认后保存;本地状态可离线读取、不争profile锁,不冒称服务端实时进度。网络真正丢响应且无引用、关机/强杀后的未知提交仍不重发;不改前后端。
|
|
75
|
-
|
|
76
|
-
正式站新operation production-matting-background-7738-20261104,用户已授权一次免费处理并确认关闭画布,原图7738与旧operation保留。启动命令退出后worker独立接收完成,原PNG220×757/116567字节,SHA-256为3a9eaf344f95de7b1b81008beee2e866be706a0a23f7cffc4087c2620944dd8e;alpha0–255,透明87441/有效79099/半透明11493像素,实际响应0 OO。
|
|
77
|
-
|
|
78
|
-
后台完成时画布仍104版/6节点/5线,无结果节点且尚未尝试保存;原operation recover --yes一次CAS到105版/7节点/6线,独立读回及重复只读恢复canvas_verified=true,无再次处理或保存,不入库。新结果未重复做网页重开验收;旧结果用户已确认网页正常/保存重开仍在的记录不混作新结果证明。
|
|
79
|
-
|
|
80
|
-
脱敏证据.local/frontend-conflict-20261102/production-matting-background-verified-1793783196848.json及production-matting-background-7738-20261104.png。模拟覆盖启动进程退出、后台存活、离线状态、profile锁、重复启动、错误worker绑定、立即响应、网络丢响应/强杀不重放、缓存后同operation显式回填;测试结果以本轮实际执行记录为准。
|
|
81
|
-
|
|
82
|
-
本轮最终检修:43组完整npm test通过(含独立后台/立即响应/断网/强杀/离线查询及原operation恢复);npm run build语法检查与包运行资源检查通过,117个包文件、245个相对运行资源、235个包内文档链接、13个skill参考。skill校验、UTF-8/本地链接和git diff --check通过,原有混合换行文件保持。没有安装软件、执行N5、发布或Git提交。
|
|
83
|
-
|
|
84
|
-
## 2026-11-04 异步抠图接口适配(rc.6,真实验收待条件)
|
|
85
|
-
|
|
86
|
-
用户截图新增POST /api/v1/matting/jobs(multipart,202与job_id)和GET同路径/{job_id}(仅提交者,五种状态及成功result_ref/result_url/credit_cost);旧同步接口保留。本地anime-ai-engine/app/api/v1/matting.py与前端仍为旧同步实现,等待新代码位置/脱敏响应示例。正式站公开OpenAPI未给可用JSON;就绪探测通过,签名随机不存在job只读查询HTTP200/业务码3001、request_id=ee2da706-2111-4e61-8892-43e13168e68c,没有提交真实处理或写画布。
|
|
87
|
-
|
|
88
|
-
已实现matting-submit及按原operation的服务端查询/恢复,202及job_id立即持久化,五状态、实际免费约束、匿名原引用GET、透明PNG/尺寸核验、一次CAS及不重放保护;同步旧operation/本地后台记录保留。针对性模拟通过个人/团队、CLI重建client后的原ID查询、排队/处理/终态、失响应/不合法响应、费用/身份/来源/权限/PNG异常及保存冲突/丢响应。模拟不替代真实接口成功验收,当前未提交新真实job、未产生本轮费用或新画布变化。
|
|
89
|
-
|
|
90
|
-
提交没有job_id的失响应仍缺幂等/按请求键查询契约,不自动重提;已知job_id后无需本地进程持续存活。新路线真实处理及网页重开待用户确认本轮原图和画布关闭后验收。
|
|
91
|
-
|
|
92
|
-
## 异步抠图最新核验:前端已更新,正式站提交未确认
|
|
93
|
-
|
|
94
|
-
用户说明最新前端已有实现,并明确采用原图7738的一次免费验收、确认本轮画布关闭/保存。前端工作区原本干净,git fetch origin后确认当前提交为origin/master祖先,仅git merge --ff-only origin/master从3d3a2a84快进919c71b8,没有创建新提交/推送、安装或启动前端。实际media-tools/api/matting.js有createJob/getJob,services/matting.js的createAndPoll核对202、job_id、裸/code-data包装、五状态和结果字段;flow/services/nodeActionService.js画布入口调用createAndPoll,未开放threshold参数。
|
|
95
|
-
|
|
96
|
-
44组完整npm test通过;诊断补充后异步抠图针对性测试再次通过(含实际遇到的HTTP200/3001不重放)。新增test/matting-jobs-web-compat.mjs只读加载上述实际前端service,个人/团队表单、202与ID、裸/包装响应、queued→processing→succeeded及结果URL对照通过。使用现有Vite依赖,无安装。前端代码对照不是当前正式部署任务成功证明。
|
|
97
|
-
|
|
98
|
-
原图7738预览实际团队SD2.5-Draft功能测试(519080401579)、钱包0 OO、220×757,最新画布105版。仅一次POST /matting/jobs尝试使用operation production-matting-job-7738-20261104,返回HTTP200/业务码3001,没有job_id;安全request_id=bbb410d1-f06c-47ba-bbbb-32190b4cf766。保留submission_unknown及原诊断,没有重POST、启动新worker或换operation。当前不能证明已入队或未入队,费用未确认,不将原免费约定冒称本次服务结算证据。
|
|
99
|
-
|
|
100
|
-
失败后只读服务探测ready(数据库/Redis),随机job路径与任意不存在路由均返回HTTP200/3001“请求的资源不存在”,仅支持“疑似未挂载新路由”,不能证明某一任务状态。画布仍105版/7节点/6线,原图在、分配的新结果节点不存在,无本次画布变化。已请求服务端核对正式部署及原request_id,若有job则提供原job_id;不自动重新提交。后台worker上轮0 OO/104→105的成功证据与本轮失败分开。
|
|
101
|
-
|
|
102
|
-
脱敏证据.local/frontend-conflict-20261102/production-matting-jobs-route-diagnostic-1793785327626.json。原operation本地诊断保留;本轮新接口完整成功、原job恢复下载/落图和网页重开未通过。旧同步/本地后台功能继续保留。
|
|
103
|
-
|
|
104
|
-
2026-11-04用户明确选择“先保留阻塞,完成CLI开发测试与打包”。本轮停止真实异步补验,不等待或自动重试部署;保留production-matting-job-7738-20261104原未知提交、诊断及所有旧产物。44组完整回归及后续针对性诊断回归、最新前端异步service对照和实际asset factory/snapshot重开对照通过;候选rc.6本地构建/包资源检查通过(118文件、250相对运行资源、238包内文档链接、13 skill参考),private且不发布。新异步job成功查询/PNG恢复/落图/网页真实验收仍待服务端核对后另行推进;本次画布无变化,是否入队及费用未确认。
|
|
105
|
-
|
|
106
|
-
## 2026-11-05 异步抠图真实路线通过
|
|
107
|
-
|
|
108
|
-
用户通知CLI权限修复后,只读确认新查询已到达业务接口;用户另确认旧request_id经服务端核对未入队,并重新确认画布关闭。保留旧记录,新关联operation production-matting-job-7738-20261105仅提交一次202,job_id=42740a87-7308-4099-9d80-62c3781c5f17。提交CLI退出后新进程查询原job成功,实际0 OO;原operation取回220×757/116567字节透明PNG并一次CAS落图,105→106版、7→8节点、6→7线,原内容保持且重复恢复不再保存/处理。
|
|
109
|
-
|
|
110
|
-
用户确认本次网页显示正常、保存重开后结果及来源线仍在;其后只读109版/8节点/7线、原operation completed/canvas_verified=true,网页规范化后的canvas_exactly_matches=false不误报失败,不覆盖网页内容。本轮业务代码不变;前轮44组回归及前端对照属于历史已通过,本轮新增真实部署/任务/PNG/落图/用户网页及其后读回证据。候选rc.7同步记录、文档和skill,保持private,不发布、不做N5。
|
|
111
|
-
|
|
112
|
-
此前3001/403及等待修复为历史状态,当前阻塞已解除。无job_id的未知提交仍不能自动重提;这次旧请求未入队依据用户服务端核验,未篡改旧operation。完整证据和未覆盖边界见[本次真实验收](异步抠图真实验收-20261105.md)。
|
|
113
|
-
|
|
114
|
-
## 2026-11-05 最终收尾核对
|
|
115
|
-
|
|
116
|
-
本轮重新执行44组完整模拟回归通过,并核对最新真实证据。已修正skill能力表的旧验收状态;主线完成项、2078大小元数据交接、真实边界、条件性能力和npm发布前置项分开,详见[收尾清单](CLI缺口核对与收尾-20261105.md)。候选rc.8不改CLI业务实现,不做真实生成/处理/画布写入,不恢复N5/转绘/去字幕,不提交推送发布。
|
|
117
|
-
|
|
118
|
-
## 2026-11-05 组织确认与0.5.0发布准备
|
|
119
|
-
|
|
120
|
-
用户已创建npm组织uzooai;正常CLI只读核验当前账号liuwql为组织owner,npm本机登录成功。目标包未查到已发布版本;首次尚未发布的目标没有包级可写列表条目,不再把组织创建/owner身份误列为未确认。账户2FA最后读回disabled,仍需本人设置及再次读回。
|
|
121
|
-
|
|
122
|
-
用户明确选择正式0.5.0/latest,并同意先同步版本、发布配置和最终产物检查;该选择不授权实际上传。已准备package.json private=false与publishConfig public/https://registry.npmjs.org//latest,lock/CHANGELOG/说明同步。包检查改用统一显式策略:内部private候选仍可本地打包,公开包须完整匹配名称、入口、MIT、官方registry、稳定/RC通道。pack:local输出改读实际private与通道,不再硬编码private=true。安装专项脚本同样读取策略兼容,但本轮不执行N5。
|
|
123
|
-
|
|
124
|
-
新增npm run check:release(本地构建+版本/lock/独立更新记录/许可证/入口检查)及prepublishOnly挂钩;它们不执行登录、2FA、权限变更或发布。脚本和新运行依赖纳入包资源检查,拒绝缺失发布策略模块。新增策略模拟覆盖私有/公开、非官方registry、缺显式private、错误入口/许可、RC串latest等;具体检查结果按本轮实际执行记录,不因配置存在就宣称已发布。
|
|
125
|
-
|
|
126
|
-
等待2FA本人启用及最终归档复核后,才展示具体包/版本/通道/摘要并收集当次上传授权。当前不npm publish、不提交/推送,不新建真实业务任务/写画布,不恢复边界专项/N5/转绘/去字幕。旧候选包、全部凭据/profile/operation保留;公开发布配置并非切换平台账号或修改业务请求。
|
|
127
|
-
|
|
128
|
-
## 0.5.0本地发布准备最终检查
|
|
129
|
-
|
|
130
|
-
用户选择0.5.0/latest,配置与统一发布策略本地检查通过;Windows原子rename修复及策略测试加入后,46组完整npm test实际通过。此前两次45组在截帧Temp的EPERM中断、针对性复验和修正记录均保留,不抹掉失败,也不将重试描述为网络重放。完整回归仍只是模拟/本地检查,已有真实业务证据范围不扩大。
|
|
131
|
-
|
|
132
|
-
最新npm只读身份核验:本机已登录,liuwql为uzooai组织owner;two-factor auth仍disabled,目标包未查到可见已发布版本。正式发布配置已经准备,不表示已获实际上传授权。下一步为本人启用2FA并核验,然后展示最终归档与摘要取得当次发布确认;未执行npm publish、安装专项、Git提交/推送或真实业务写入。
|
|
133
|
-
|
|
134
|
-
本轮静态及包检查保留13份skill参考、公开运行模块和新的发布校验模块,排除.local、outputs、测试/凭据和内部远程联调记录;归档以本轮pack:local生成的独立目录和manifest校验为准。README安装入口使用版本/通道和条件性发布表述,避免归档发布后仍把“尚未上传”的准备快照当成用户功能状态。
|