@uzooai/anime-ai-cli 0.0.0-stage → 0.5.0

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 (123) hide show
  1. package/.agents/skills/uzoo-anime-cli/SKILL.md +83 -0
  2. package/.agents/skills/uzoo-anime-cli/references/agreement-workflow.md +51 -0
  3. package/.agents/skills/uzoo-anime-cli/references/canvas-workflow.md +53 -0
  4. package/.agents/skills/uzoo-anime-cli/references/commands.md +250 -0
  5. package/.agents/skills/uzoo-anime-cli/references/generation-workflow.md +152 -0
  6. package/.agents/skills/uzoo-anime-cli/references/image-tools-workflow.md +175 -0
  7. package/.agents/skills/uzoo-anime-cli/references/interaction-workflow.md +67 -0
  8. package/.agents/skills/uzoo-anime-cli/references/material-graph-workflow.md +123 -0
  9. package/.agents/skills/uzoo-anime-cli/references/node-capabilities.md +95 -0
  10. package/.agents/skills/uzoo-anime-cli/references/node-workflow.md +94 -0
  11. package/.agents/skills/uzoo-anime-cli/references/remake-workflow.md +54 -0
  12. package/.agents/skills/uzoo-anime-cli/references/repaint-workflow.md +300 -0
  13. package/.agents/skills/uzoo-anime-cli/references/seedance-review-workflow.md +41 -0
  14. package/.agents/skills/uzoo-anime-cli/references/video-tools-workflow.md +71 -0
  15. package/CHANGELOG.md +92 -0
  16. package/LICENSE +21 -0
  17. package/README.md +242 -3
  18. package/assets/README.md +4 -0
  19. package/assets/favicon-uzoo.png +0 -0
  20. package/assets/logo-uzoo.svg +7 -0
  21. 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 +134 -0
  22. 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 +540 -0
  23. 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 +65 -0
  24. 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 +52 -0
  25. package/docs/M0-M5/345/256/236/346/226/275/344/270/216/351/252/214/346/224/266.md +89 -0
  26. 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 +151 -0
  27. 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 +107 -0
  28. 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 +311 -0
  29. 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 +47 -0
  30. 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 +34 -0
  31. 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 +110 -0
  32. package/docs//345/274/200/345/217/221/350/256/241/345/210/222.md +127 -0
  33. 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 +50 -0
  34. 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 +44 -0
  35. 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 +79 -0
  36. 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 +61 -0
  37. package/docs//346/231/256/351/200/232/346/265/217/350/247/210/345/231/250/347/231/273/345/275/225.md +53 -0
  38. 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 +90 -0
  39. 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 +136 -0
  40. 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 +183 -0
  41. 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 +59 -0
  42. 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 +1004 -0
  43. 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 +52 -0
  44. package/docs//351/230/266/346/256/2653B/351/252/214/346/224/266/344/272/244/346/216/245.md +44 -0
  45. package/docs//351/230/266/346/256/265/344/270/200/351/252/214/346/224/266.md +60 -0
  46. 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 +76 -0
  47. 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 +39 -0
  48. 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 +113 -0
  49. 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 +71 -0
  50. package/examples/matting.json +5 -0
  51. package/examples/real-business/image-request.template.json +7 -0
  52. package/examples/real-business/node-patch.template.json +11 -0
  53. package/extensions/uzoo-cli-login/manifest.json +9 -0
  54. package/extensions/uzoo-cli-login/popup.css +1 -0
  55. package/extensions/uzoo-cli-login/popup.html +14 -0
  56. package/extensions/uzoo-cli-login/popup.js +65 -0
  57. package/package.json +56 -6
  58. package/scripts/check-package-resources.mjs +56 -0
  59. package/scripts/check-release.mjs +19 -0
  60. package/scripts/pack-local.mjs +33 -0
  61. package/scripts/release-policy.mjs +22 -0
  62. package/src/agreement-page.js +62 -0
  63. package/src/agreement.js +419 -0
  64. package/src/annotation-media.js +386 -0
  65. package/src/api.js +168 -0
  66. package/src/browser-login.js +13 -0
  67. package/src/callback-page.js +44 -0
  68. package/src/canvas.js +105 -0
  69. package/src/cli-authorization.js +122 -0
  70. package/src/cli.js +459 -0
  71. package/src/download-name.js +17 -0
  72. package/src/draft-finalize.js +229 -0
  73. package/src/generation-graph.js +124 -0
  74. package/src/generation-input.js +472 -0
  75. package/src/graph-disconnect.js +89 -0
  76. package/src/graph.js +431 -0
  77. package/src/group-edit.js +53 -0
  78. package/src/group-layout.js +113 -0
  79. package/src/group-membership.js +126 -0
  80. package/src/history-add.js +119 -0
  81. package/src/image-annotation.js +246 -0
  82. package/src/image-crop.js +283 -0
  83. package/src/image-matting.js +82 -0
  84. package/src/image-media.js +89 -0
  85. package/src/image-output.js +385 -0
  86. package/src/local-output.js +23 -0
  87. package/src/material-download.js +55 -0
  88. package/src/material-save.js +254 -0
  89. package/src/materials.js +147 -0
  90. package/src/matting-background.js +73 -0
  91. package/src/matting-jobs.js +63 -0
  92. package/src/matting-worker.js +49 -0
  93. package/src/matting.js +170 -0
  94. package/src/media-copy.js +53 -0
  95. package/src/media.js +343 -0
  96. package/src/model-options.js +76 -0
  97. package/src/multipart.js +28 -0
  98. package/src/node-copy.js +95 -0
  99. package/src/node-delete.js +49 -0
  100. package/src/node-history.js +231 -0
  101. package/src/normal-login.js +118 -0
  102. package/src/package-info.js +8 -0
  103. package/src/png-alpha.js +60 -0
  104. package/src/protocol.js +83 -0
  105. package/src/remake.js +738 -0
  106. package/src/repaint-archive.js +53 -0
  107. package/src/repaint-delivery.js +783 -0
  108. package/src/repaint-export.js +63 -0
  109. package/src/repaint-graph.js +214 -0
  110. package/src/repaint-history.js +267 -0
  111. package/src/repaint-materials.js +601 -0
  112. package/src/repaint-reverse.js +614 -0
  113. package/src/repaint-sequence.js +132 -0
  114. package/src/repaint-settings.js +576 -0
  115. package/src/repaint-video.js +798 -0
  116. package/src/repaint.js +326 -0
  117. package/src/resource.js +110 -0
  118. package/src/review.js +435 -0
  119. package/src/service.js +85 -0
  120. package/src/store.js +100 -0
  121. package/src/video-clip.js +381 -0
  122. package/src/video-frame.js +296 -0
  123. package/src/workflows.js +214 -0
@@ -0,0 +1,65 @@
1
+ const SITE = 'https://uzooai.com'
2
+ const $ = id => document.getElementById(id)
3
+ const button = $('action')
4
+ let action
5
+
6
+ function bridgeFromUrl(value) {
7
+ const url = new URL(value)
8
+ const token = url.hash.slice(1)
9
+ if (url.protocol !== 'http:' || url.hostname !== '127.0.0.1' || !url.port || url.username || url.password || url.pathname !== '/connect' || !/^[A-Za-z0-9_-]{43}$/.test(token)) return null
10
+ return { callback: url.origin, token }
11
+ }
12
+ async function bridgeFetch(pairing, endpoint, body) {
13
+ const response = await fetch(`${pairing.callback}${endpoint}`, {
14
+ method: body === undefined ? 'GET' : 'POST',
15
+ headers: { 'X-Uzoo-Bridge': pairing.token, ...(body === undefined ? {} : { 'Content-Type': 'application/json' }) },
16
+ ...(body === undefined ? {} : { body: JSON.stringify(body) }),
17
+ redirect: 'error', credentials: 'omit', mode: 'cors', signal: AbortSignal.timeout(10000),
18
+ })
19
+ if (!response.ok) { const data = await response.json().catch(() => ({})); throw new Error(`CLI 连接失败(${data.error || response.status});请重新运行 auth login 并连接`) }
20
+ return response.json()
21
+ }
22
+
23
+ async function init() {
24
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
25
+ if (!tab?.id || !tab.url) throw new Error('无法读取当前标签页,请在 CLI 连接页面或 Uzoo 网站打开扩展')
26
+ const pairing = bridgeFromUrl(tab.url)
27
+ if (pairing) {
28
+ $('description').textContent = '连接当前本机 CLI,然后在正常网站完成登录。'
29
+ button.textContent = '连接 CLI 并打开登录页'
30
+ action = async () => {
31
+ const config = await bridgeFetch(pairing, '/config', {})
32
+ const api = new URL(config.api), login = new URL(config.loginUrl)
33
+ if (config.origin !== SITE || api.origin !== SITE || api.pathname !== '/api/v1' || api.search || api.hash || login.origin !== SITE || login.username || login.password) throw new Error('扩展只允许授权 uzooai.com;CLI 的网站配置不匹配')
34
+ const redirect = login.searchParams.get('redirect')
35
+ if (redirect && new URL(redirect, SITE).origin !== SITE) throw new Error('登录跳转地址不受支持')
36
+ await chrome.storage.session.set({ pairing: { ...pairing, ...config, tabId: tab.id } })
37
+ await chrome.tabs.update(tab.id, { url: login.href })
38
+ $('status').textContent = '请正常登录,进入工作区后再点击本扩展授权。'
39
+ }
40
+ } else {
41
+ const pending = (await chrome.storage.session.get('pairing')).pairing
42
+ if (!pending) throw new Error('尚未连接 CLI。先运行 auth login,再在打开的本机连接页面点击扩展')
43
+ if (new URL(tab.url).origin !== SITE || tab.id !== pending.tabId) throw new Error('请在刚才由 CLI 打开的 Uzoo 标签页完成登录并授权')
44
+ $('description').textContent = '请先完成网站登录。点击下方按钮会将当前账号的网页会话(含刷新 Cookie)交给已连接的本机 CLI。'
45
+ button.textContent = '授权当前会话给 CLI'
46
+ action = async () => {
47
+ const results = await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: () => ({ origin: location.origin, accessToken: localStorage.getItem('access_token') || '', deviceId: localStorage.getItem('sign_v2_device_id') || '' }) })
48
+ const value = results[0]?.result
49
+ if (value?.origin !== SITE || !value.accessToken) throw new Error('当前页面尚未登录,请完成登录后再授权')
50
+ const cookies = await chrome.cookies.getAll({ url: `${pending.api}/auth/refresh` })
51
+ const jar = new Map()
52
+ for (const cookie of cookies.sort((a,b) => b.path.length-a.path.length)) if (!jar.has(cookie.name)) jar.set(cookie.name,cookie.value)
53
+ value.cookie = [...jar].map(([name, data]) => `${name}=${data}`).join('; ')
54
+ await bridgeFetch(pending, '/session', value)
55
+ await chrome.storage.session.remove('pairing')
56
+ $('status').textContent = '会话已交给本机 CLI,请查看终端中的身份验证结果。请关闭使用该会话的网页,避免与 CLI 同时刷新。建议使用独立的普通浏览器用户配置文件。'
57
+ }
58
+ }
59
+ button.disabled = false
60
+ }
61
+ button.addEventListener('click', async () => {
62
+ button.disabled = true; $('status').textContent = '处理中…'
63
+ try { await action() } catch (error) { $('status').textContent = error.message; button.disabled = false }
64
+ })
65
+ init().catch(error => { $('description').textContent = error.message; button.textContent = '请按提示操作' })
package/package.json CHANGED
@@ -1,6 +1,56 @@
1
- {
2
- "name": "@uzooai/anime-ai-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "@uzooai/anime-ai-cli",
3
+ "version": "0.5.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
9
+ "bin": {
10
+ "uzoo-anime": "src/cli.js"
11
+ },
12
+ "scripts": {
13
+ "build": "npm run check && npm run check:resources",
14
+ "pack:local": "node scripts/pack-local.mjs",
15
+ "prepack": "npm run build",
16
+ "start": "node src/cli.js",
17
+ "check": "node --check src/cli.js && node --check src/api.js && node --check src/canvas.js && node --check src/draft-finalize.js && node --check src/media-copy.js && node --check src/group-edit.js && node --check src/group-layout.js && node --check src/node-copy.js && node --check src/node-delete.js && node --check src/materials.js && node --check src/material-save.js && node --check src/service.js && node --check src/video-clip.js && node --check src/media.js && node --check src/image-media.js && node --check src/image-output.js && node --check src/image-crop.js && node --check src/image-annotation.js && node --check src/image-matting.js && node --check src/matting.js && node --check src/png-alpha.js && node --check src/annotation-media.js && node --check src/video-frame.js && node --check src/graph.js && node --check src/graph-disconnect.js && node --check src/group-membership.js && node --check src/model-options.js && node --check src/generation-input.js && node --check src/review.js && node --check src/resource.js && node --check src/generation-graph.js && node --check src/repaint.js && node --check src/repaint-reverse.js && node --check src/repaint-delivery.js && node --check src/repaint-video.js && node --check src/repaint-history.js && node --check src/multipart.js && node --check src/repaint-materials.js && node --check src/repaint-settings.js && node --check src/remake.js && node --check src/repaint-graph.js && node --check src/store.js && node --check src/workflows.js && node --check src/agreement.js && node --check src/agreement-page.js && node --check src/protocol.js && node --check src/cli-authorization.js && node --check src/browser-login.js && node --check src/normal-login.js && node --check extensions/uzoo-cli-login/popup.js && node --check src/local-output.js && node --check src/repaint-archive.js && node --check src/repaint-export.js && node --check src/repaint-sequence.js && node --check src/node-history.js && node --check src/history-add.js && node --check src/material-download.js && node --check src/download-name.js && node --check scripts/pack-local.mjs && node --check src/package-info.js && node --check src/matting-background.js && node --check src/matting-worker.js && node --check src/matting-jobs.js && node --check scripts/release-policy.mjs && node --check scripts/check-release.mjs",
18
+ "test": "node test/smoke.mjs && node test/atomic-file.mjs && node test/phase1.mjs && node test/agreement.mjs && node test/canvas.mjs && node test/material-graph.mjs && node test/graph-rename.mjs && node test/graph-ungroup.mjs && node test/graph-disconnect.mjs && node test/node-copy.mjs && node test/node-copy-batch.mjs && node test/draft-finalize.mjs && node test/media-copy.mjs && node test/group-edit.mjs && node test/node-delete.mjs && node test/material-save.mjs && node test/service.mjs && node test/video-clip.mjs && node test/video-frame.mjs && node test/image-crop.mjs && node test/image-annotation.mjs && node test/image-matting.mjs && node test/matting.mjs && node test/matting-background.mjs && node test/matting-jobs.mjs && node test/model-options.mjs && node test/generation-input.mjs && node test/review.mjs && node test/repaint.mjs && node test/repaint-reverse.mjs && node test/repaint-delivery.mjs && node test/repaint-video.mjs && node test/repaint-settings.mjs && node test/repaint-materials.mjs && node test/remake.mjs && node test/normal-login.mjs && node test/login-extension.mjs && node test/browser-login.mjs && node test/cli-authorization.mjs && node test/store-recovery.mjs && node test/store-concurrency.mjs && node test/repaint-archive.mjs && node test/node-history.mjs && node test/file-transfer.mjs && node test/material-download.mjs && node test/release-policy.mjs",
19
+ "test:browser": "node test/normal-login.mjs && node test/login-extension.mjs && node test/browser-login.mjs",
20
+ "test:media": "node test/media.mjs && node test/image-media.mjs && node test/annotation-media.mjs",
21
+ "check:resources": "node scripts/check-package-resources.mjs",
22
+ "test:package": "node scripts/verify-package.mjs",
23
+ "check:release": "npm run build && node scripts/check-release.mjs",
24
+ "prepublishOnly": "npm run check:release"
25
+ },
26
+ "files": [
27
+ "src/",
28
+ "assets/",
29
+ ".agents/skills/uzoo-anime-cli/",
30
+ "extensions/uzoo-cli-login/",
31
+ "examples/",
32
+ "docs/",
33
+ "!docs/阶段3B远程后端联调记录.md",
34
+ "scripts/check-package-resources.mjs",
35
+ "scripts/pack-local.mjs",
36
+ "README.md",
37
+ "CHANGELOG.md",
38
+ "LICENSE",
39
+ "scripts/release-policy.mjs",
40
+ "scripts/check-release.mjs"
41
+ ],
42
+ "description": "Uzoo Anime CLI for canvas, media references and authorized generation workflows",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/UzooAI/uzooai-cli.git"
46
+ },
47
+ "bugs": {
48
+ "url": "https://github.com/UzooAI/uzooai-cli/issues"
49
+ },
50
+ "license": "MIT",
51
+ "publishConfig": {
52
+ "access": "public",
53
+ "registry": "https://registry.npmjs.org/",
54
+ "tag": "latest"
55
+ }
56
+ }
@@ -0,0 +1,56 @@
1
+ import assert from 'node:assert/strict'
2
+ import fs from 'node:fs/promises'
3
+ import path from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
5
+ import { spawn } from 'node:child_process'
6
+ import {releasePolicy} from './release-policy.mjs'
7
+ const repository = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
8
+ assert(process.env.npm_execpath, '通过 npm run check:resources 执行')
9
+ const output = await new Promise((resolve, reject) => {
10
+ const child = spawn(process.execPath, [process.env.npm_execpath, 'pack', '--dry-run', '--json', '--offline', '--ignore-scripts'],
11
+ { cwd: repository, windowsHide: true, stdio: ['ignore','pipe','pipe'] })
12
+ let out = '', err = ''
13
+ child.stdout.on('data', b => { out += b }); child.stderr.on('data', b => { err += b })
14
+ child.on('error', reject)
15
+ child.on('close', code => code === 0 ? resolve(out) : reject(new Error('资源清单检查失败:' + err.slice(-1000))))
16
+ })
17
+ const [packed] = JSON.parse(output), names = new Set(packed.files.map(f => f.path))
18
+ const metadata = JSON.parse(await fs.readFile(path.join(repository, 'package.json'), 'utf8'))
19
+ const release=releasePolicy(metadata)
20
+ const lock=JSON.parse(await fs.readFile(path.join(repository,'package-lock.json'),'utf8'))
21
+ assert.equal(metadata.name,lock.name);assert.equal(metadata.version,lock.version)
22
+ assert.equal(metadata.name,lock.packages[''].name);assert.equal(metadata.version,lock.packages[''].version)
23
+ assert.equal(metadata.license,'MIT')
24
+ assert((await fs.readFile(path.join(repository,'CHANGELOG.md'),'utf8')).includes(metadata.version),'更新记录缺少当前版本')
25
+ assert(names.has('LICENSE')&&names.has('CHANGELOG.md')&&names.has('src/package-info.js'),'版本/许可证资源缺失')
26
+ assert(Array.isArray(metadata.files) && metadata.files.includes('src/') && metadata.files.includes('.agents/skills/uzoo-anime-cli/'), '缺少显式运行资源白名单')
27
+ for (const file of ['scripts/release-policy.mjs','scripts/check-release.mjs','src/download-name.js','src/cli.js','src/draft-finalize.js','src/media-copy.js','src/group-edit.js','src/group-layout.js',
28
+ 'src/agreement-page.js','src/callback-page.js','assets/logo-uzoo.svg','assets/favicon-uzoo.png','.agents/skills/uzoo-anime-cli/SKILL.md'])
29
+ assert(names.has(file), '包内缺少运行资源:' + file)
30
+ let imports = 0
31
+ for (const file of [...names].filter(f => /^(?:src\/.*\.js|scripts\/.*\.mjs)$/.test(f))) {
32
+ const source = await fs.readFile(path.join(repository, file), 'utf8')
33
+ for (const match of source.matchAll(/(?:from\s*|import\s*\(|new URL\(\s*)['"](\.[^'"]+)['"]/g)) {
34
+ const target = path.posix.normalize(path.posix.join(path.posix.dirname(file), match[1]))
35
+ assert(names.has(target), '运行模块相对资源遗漏:' + file + ' → ' + target); imports++
36
+ }
37
+ }
38
+ let links=0,externalWorkspaceReferences=0
39
+ for(const file of [...names].filter(f=>f.endsWith('.md'))){
40
+ const source=await fs.readFile(path.join(repository,file),'utf8')
41
+ for(const match of source.matchAll(/\]\(([^\s)]+)\)/g)){
42
+ const value=match[1].split('#')[0].replace(/^<|>$/g,'')
43
+ if(!value || /^[a-z][a-z0-9+.-]*:/i.test(value))continue
44
+ const target=path.posix.normalize(path.posix.join(path.posix.dirname(file),decodeURIComponent(value)))
45
+ // Historical maintainer documents may cite sibling repositories. Those links
46
+ // are evidence pointers, never installed runtime or skill dependencies.
47
+ if(file.startsWith('docs/')&&target.startsWith('../')){externalWorkspaceReferences++;continue}
48
+ assert(names.has(target)||[...names].some(n=>n.startsWith(target+'/')),'包内文档引用遗漏:'+file+' → '+target);links++
49
+ }
50
+ }
51
+ const references = [...names].filter(f => f.startsWith('.agents/skills/uzoo-anime-cli/references/'))
52
+ assert.equal(references.length, 13)
53
+ assert(![...names].some(f => /(^|\/)(\.local|outputs|node_modules|\.git)(\/|$)|\.dpapi$|(^|\/)(credentials[^/]*\.json|\.env[^/]*)$/.test(f)), '包内包含本地产物或敏感配置')
54
+ assert(![...names].some(f=>/^test\//.test(f)||f==='AGENTS.md'||f==='scripts/verify-package.mjs'||f==='docs/阶段3B远程后端联调记录.md'||/\.tgz$/.test(f)), '包内包含测试、宿主规则、内部联调记录、安装专项或历史归档')
55
+ console.log(JSON.stringify({ files: names.size, relative_runtime_resources: imports, package_document_links:links, external_workspace_references:externalWorkspaceReferences, skill_references: references.length,...release,
56
+ install_performed: false, upgrade_tested: false, published: false }))
@@ -0,0 +1,19 @@
1
+ import assert from 'node:assert/strict'
2
+ import fs from 'node:fs/promises'
3
+ import path from 'node:path'
4
+ import {fileURLToPath} from 'node:url'
5
+ import {releasePolicy} from './release-policy.mjs'
6
+
7
+ const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..')
8
+ const read=name=>fs.readFile(path.join(root,name),'utf8')
9
+ const metadata=JSON.parse(await read('package.json')),lock=JSON.parse(await read('package-lock.json'))
10
+ const policy=releasePolicy(metadata,{requirePublic:true})
11
+ assert.equal(metadata.version,lock.version);assert.equal(metadata.name,lock.name)
12
+ assert.equal(metadata.version,lock.packages[''].version);assert.equal(metadata.name,lock.packages[''].name)
13
+ const heading='## '+metadata.version
14
+ assert((await read('CHANGELOG.md')).split(/\r?\n/).some(line=>line===heading||line.startsWith(heading+' ')),'缺少本版本独立更新记录')
15
+ assert((await read('LICENSE')).startsWith('MIT License'),'MIT授权文件缺失')
16
+ assert((await read('README.md')).includes('npm install --global @uzooai/anime-ai-cli@latest'),'缺少安装用户入口')
17
+ console.log(JSON.stringify({name:metadata.name,version:metadata.version,...policy,local_release_check:'passed',
18
+ registry_account_checked:false,two_factor_checked:false,publication_authorized:false,published:false,
19
+ next:'本命令仅检查本地产物;发布前另核对scope权限、2FA及当次明确授权'}))
@@ -0,0 +1,33 @@
1
+ import fs from 'node:fs/promises'
2
+ import path from 'node:path'
3
+ import crypto from 'node:crypto'
4
+ import assert from 'node:assert/strict'
5
+ import {fileURLToPath} from 'node:url'
6
+ import {spawn} from 'node:child_process'
7
+ import {releasePolicy} from './release-policy.mjs'
8
+
9
+ const repository=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..')
10
+ assert(process.env.npm_execpath,'通过 npm run pack:local 执行')
11
+ async function npm(args,capture=false){
12
+ return new Promise((resolve,reject)=>{
13
+ const child=spawn(process.execPath,[process.env.npm_execpath,...args],{cwd:repository,windowsHide:true,stdio:capture?['ignore','pipe','pipe']:'inherit'})
14
+ let out='',err=''
15
+ if(capture){child.stdout.on('data',b=>out+=b);child.stderr.on('data',b=>err+=b)}
16
+ child.on('error',reject)
17
+ child.on('close',code=>code===0?resolve(out):reject(Error('本地打包检查失败(exit '+code+')'+(capture?': '+err.slice(-1500):''))))
18
+ })
19
+ }
20
+ // Build validates native ESM and package resources; there is no transpilation.
21
+ await npm(['run','build'])
22
+ const destination=path.join(repository,'outputs','npm',new Date().toISOString().replace(/[:.]/g,'-')+'-'+crypto.randomUUID().slice(0,8))
23
+ await fs.mkdir(destination,{recursive:true})
24
+ // prepack's build has just run. Suppress it here to keep the manifest pure JSON.
25
+ const [packed]=JSON.parse(await npm(['pack','--offline','--ignore-scripts','--json','--pack-destination',destination],true))
26
+ assert(packed && packed.filename===path.basename(packed.filename),'打包未返回安全产物文件名')
27
+ const archive=path.join(destination,packed.filename),bytes=await fs.readFile(archive)
28
+ assert.equal(crypto.createHash('sha1').update(bytes).digest('hex'),packed.shasum,'归档摘要不匹配')
29
+ assert.equal('sha512-'+crypto.createHash('sha512').update(bytes).digest('base64'),packed.integrity,'归档integrity不匹配')
30
+ assert.equal(bytes.length,packed.size,'归档长度不匹配')
31
+ await fs.writeFile(path.join(destination,'manifest.json'),JSON.stringify(packed,null,2)+'\n',{flag:'wx'})
32
+ const metadata=JSON.parse(await fs.readFile(path.join(repository,'package.json'),'utf8'))
33
+ console.log(JSON.stringify({archive,manifest:path.join(destination,'manifest.json'),bytes:bytes.length,files:packed.files.length,integrity:packed.integrity,...releasePolicy(metadata),publication_authorized:false,installed:false,published:false},null,2))
@@ -0,0 +1,22 @@
1
+ import assert from 'node:assert/strict'
2
+
3
+ // This product's explicit release policy. Validation never logs in, changes
4
+ // access, or publishes; the registry account and action authorization are separate.
5
+ export function releasePolicy(metadata,{requirePublic=false}={}){
6
+ assert.equal(metadata.name,'@uzooai/anime-ai-cli','正式包名不匹配')
7
+ assert.equal(typeof metadata.private,'boolean','必须显式声明private,不能意外开放发布')
8
+ if(metadata.private){
9
+ assert(!requirePublic,'当前为private内部包,不能作为公开发布产物')
10
+ return {private:true,public_package:false,registry:null,tag:null}
11
+ }
12
+ assert.equal(metadata.license,'MIT','发布许可证须保持已确认的MIT')
13
+ assert.equal(metadata.bin?.['uzoo-anime'],'src/cli.js','发布命令入口不匹配')
14
+ assert.match(metadata.version,/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-rc\.(0|[1-9]\d*))?$/,'发布版本须为x.y.z或x.y.z-rc.N')
15
+ const config=metadata.publishConfig
16
+ assert(config&&typeof config==='object'&&!Array.isArray(config),'公开包缺少publishConfig')
17
+ assert.equal(config.access,'public','scoped公开包必须明确access=public')
18
+ assert.equal(config.registry,'https://registry.npmjs.org/','发布registry必须明确为npm官方HTTPS地址')
19
+ const tag=metadata.version.includes('-')?'next':'latest'
20
+ assert.equal(config.tag,tag,'稳定版须latest,RC须next,不能串用通道')
21
+ return {private:false,public_package:true,registry:config.registry,tag}
22
+ }
@@ -0,0 +1,62 @@
1
+ const escape = (value) =>
2
+ String(value ?? '').replace(
3
+ /[&<>"']/g,
4
+ (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[c]
5
+ )
6
+
7
+ // Theme only the isolated display copy; document.html and its consent digest stay original.
8
+ function darkDocument(html) {
9
+ const style = `<style data-uzoo-agreement-theme>
10
+ :root{color-scheme:dark}html,body{background:#202020!important;color:#ededed!important}body{padding:16px;font:15px/1.8 system-ui,"Microsoft YaHei",sans-serif;overflow-wrap:anywhere}body *{color:#ededed!important;background-color:transparent!important;background-image:none!important;border-color:#444!important}a,a *{color:#8bc8ff!important}::selection{background:#38566c;color:#fff}
11
+ </style>`
12
+ return html + style
13
+ }
14
+
15
+ // Remote published HTML is isolated in an opaque, scriptless sandbox. Only the
16
+ // local parent page can send a human decision; no API credentials enter HTML.
17
+ export function agreementPage({
18
+ protocol,
19
+ document,
20
+ account,
21
+ actionPath,
22
+ csrf,
23
+ nonce,
24
+ continuation
25
+ }) {
26
+ const script = `const box=document.getElementById('accepted'),yes=document.getElementById('agree'),no=document.getElementById('decline'),status=document.getElementById('status');
27
+ let busy=false,finished=false,timer;
28
+ box.addEventListener('change',()=>yes.disabled=!box.checked||busy||finished);
29
+ function finish(message){finished=true;box.disabled=true;yes.disabled=true;no.disabled=true;status.textContent=message;clearInterval(timer);}
30
+ function receive(r,d){
31
+ if(finished)return;
32
+ if(r.ok&&(d.status==='agreed'||d.status==='not_required')){
33
+ finish(d.status==='agreed'?'协议状态已核验并同步 CLI,可关闭此页。':'当前无需签署协议,状态已同步 CLI,可关闭此页。');
34
+ try{window.close()}catch{}
35
+ }else if(d.status==='declined'||d.status==='changed'||d.status==='cancelled'||d.status==='rejected')finish(d.message);
36
+ else if(d.message)status.textContent=d.message;
37
+ }
38
+ async function decision(agreed){
39
+ if(busy||finished||agreed&&!box.checked)return;
40
+ busy=true;yes.disabled=true;no.disabled=true;
41
+ status.textContent=agreed?'正在核验并记录协议确认…':'已选择不同意,正在结束本次确认…';
42
+ try{
43
+ const r=await fetch(${JSON.stringify(actionPath)},{method:'POST',headers:{'Content-Type':'application/json','X-Uzoo-Agreement':${JSON.stringify(csrf)}},body:JSON.stringify({agreed})});
44
+ receive(r,await r.json());
45
+ }catch{if(!finished)status.textContent='确认结果尚未核实。CLI 将继续只读查询,请勿重复签署。';}
46
+ finally{busy=false;}
47
+ }
48
+ yes.addEventListener('click',()=>decision(true));no.addEventListener('click',()=>decision(false));
49
+ timer=setInterval(async()=>{
50
+ if(finished||busy)return;
51
+ try{const r=await fetch(${JSON.stringify(actionPath.replace('/decision', '/status'))});receive(r,await r.json())}catch{}
52
+ },2500);`
53
+ const resume = continuation
54
+ ? `<aside>确认后 CLI 将重新核验原请求和费用,再继续本次任务:${escape(continuation.operation)} · ${escape(continuation.model)} · 本次已确认 ${escape(continuation.cost)} OO。参数或费用变化时会停止。</aside>`
55
+ : '<aside>本页只记录协议确认,不提交生成,也不扣除生成费用。</aside>'
56
+ return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Uzoo · Seedance 协议确认</title><style>
57
+ *{box-sizing:border-box}html{color-scheme:dark}body{margin:0;background:#111;color:#ededed;font:15px/1.65 system-ui,"Microsoft YaHei",sans-serif;padding:28px}main{max-width:980px;margin:auto;border:1px solid #444;border-radius:12px;background:#1c1c1c;overflow:hidden}header,section,footer{padding:20px 28px}header{border-bottom:1px solid #444}h1{font-size:23px;margin:0}h2{font-size:17px;margin:8px 0}.meta,aside{color:#b9b9b9}.meta{margin-top:10px}aside{background:#252525;padding:12px;border-radius:6px;margin:14px 0}iframe{width:100%;height:45vh;min-height:260px;border:1px solid #444;border-radius:6px;background:#202020}label{display:flex;gap:10px;margin:20px 0;align-items:flex-start}input{width:20px;height:20px;flex-shrink:0;margin-top:3px;accent-color:#2e9fe6}button{border:0;border-radius:6px;padding:11px 20px;font:inherit;cursor:pointer}#agree{background:#2e9fe6;color:white}#decline{background:#333;color:white}button:disabled{background:#444!important;color:#999!important;cursor:not-allowed}footer{display:flex;justify-content:flex-end;gap:12px;border-top:1px solid #444}#status{min-height:26px;color:#b9b9b9}a{color:#8bc8ff}</style></head>
58
+ <body><main><header><h1>《统一协议》</h1><h2>《${escape(document.title)}》</h2><div class="meta">协议版本:${escape(protocol.version || '当前版本')} · 当前 CLI 账号:${escape(account.name)}(${escape(account.uid)})<br>服务:${escape(account.origin)}</div></header><section>
59
+ <p>${escape(protocol.message)}</p>${resume}<p>请阅读下方当前已发布的完整协议,由你本人决定是否同意。</p><iframe title="Seedance 模型使用承诺书正文" sandbox="" referrerpolicy="no-referrer" srcdoc="${escape(darkDocument(document.html))}"></iframe>
60
+ <label><input id="accepted" type="checkbox"><span>我已阅读并同意上述《${escape(document.title)}》(${escape(protocol.version || '当前版本')})。</span></label><p id="status" role="status" aria-live="polite">尚未确认。首次使用或协议版本更新后需要重新确认。</p></section>
61
+ <footer><button id="decline" type="button">不同意</button><button id="agree" type="button" disabled>同意并继续</button></footer></main><script nonce="${escape(nonce)}">${script}</script></body></html>`
62
+ }