@lingjingai/lj-awb-cli-pre 0.4.0 → 0.4.5
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/README.md +45 -0
- package/build/_shared.mjs +54 -5
- package/build/prod.mjs +12 -3
- package/package.json +2 -2
- package/packages/awb-cli/package.json +2 -2
- package/packages/awb-core/package.json +1 -1
- package/packages/awb-core/src/api.js +22 -0
- package/packages/awb-core/src/commands.js +112 -39
- package/packages/awb-core/src/common.js +8 -0
- package/packages/awb-core/src/output.js +166 -9
- package/packages/awb-core/src/services.js +1669 -186
- package/packages/awb-core/src/standalone.js +110 -12
- package/packages/awb-core/src/update.js +327 -0
- package/skills/lj-awb/SKILL.md +29 -9
- package/skills/lj-awb/VERSION +1 -1
- package/skills/lj-awb/compat.json +3 -3
- package/skills/lj-awb/modules/asset.md +10 -1
- package/skills/lj-awb/modules/auth.md +9 -1
- package/skills/lj-awb/modules/create-contract.md +5 -2
- package/skills/lj-awb/modules/create.md +4 -2
- package/skills/lj-awb/modules/driver.md +1 -0
- package/skills/lj-awb/modules/image.md +3 -1
- package/skills/lj-awb/modules/model.md +5 -4
- package/skills/lj-awb/modules/task.md +4 -1
- package/skills/lj-awb/modules/upload.md +1 -1
- package/skills/lj-awb/modules/video.md +11 -2
- package/skills/lj-awb/modules/workflows.md +3 -1
- package/skills/lj-awb/references/error-codes.md +24 -0
- package/skills/lj-awb/references/model-options-read.md +7 -6
- package/skills/lj-awb/references/output-fields.md +8 -5
- package/skills/lj-awb/scripts/resolve-lj-awb-cmd.sh +106 -4
package/README.md
CHANGED
|
@@ -63,6 +63,18 @@ lj-awb auth verify
|
|
|
63
63
|
|
|
64
64
|
可用 `LINGJING_AWB_SKILL_INSTALL_DIR` 指定单一安装目录;如果传入的是以 `skills` 结尾的根目录,安装器会自动追加 `lj-awb`。也可用 `LINGJING_AWB_SKIP_SKILL_INSTALL=1` 跳过 skill 安装。
|
|
65
65
|
|
|
66
|
+
只分发 skill 也可以作为完整入口:`skills/lj-awb/scripts/resolve-lj-awb-cmd.sh` 会在首次使用时检查 `lj-awb`,缺失或版本低于 `skills/lj-awb/compat.json` 的 `minCliVersion` 时自动执行:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install -g @lingjingai/lj-awb-cli@<minCliVersion>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
预发环境可在 bootstrap 前设置:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
export LINGJING_AWB_CLI_PACKAGE=@lingjingai/lj-awb-cli-pre
|
|
76
|
+
```
|
|
77
|
+
|
|
66
78
|
源码运行:
|
|
67
79
|
|
|
68
80
|
```bash
|
|
@@ -75,8 +87,37 @@ packages/awb-cli/bin/lj-awb auth status
|
|
|
75
87
|
|
|
76
88
|
macOS 本地 wrapper `packages/awb-cli/bin/lj-awb` 会自动补充 Node 证书链,适合直接调试 HTTPS 平台接口。
|
|
77
89
|
|
|
90
|
+
自动更新检查默认每天最多访问一次 npm registry,并会在源码 checkout、CI 或设置 `LINGJING_AWB_DISABLE_UPDATE_CHECK=1` / `AWB_DISABLE_UPDATE_CHECK=1` 时跳过。调试时可用 `LINGJING_AWB_UPDATE_CHECK=force` 强制检查。
|
|
91
|
+
|
|
78
92
|
## 认证
|
|
79
93
|
|
|
94
|
+
### 浏览器授权登录(推荐)
|
|
95
|
+
|
|
96
|
+
不需要手动复制 access key,直接登录:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
lj-awb auth login
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
CLI 会创建登录任务、展示授权链接,等你在浏览器登录并确认授权后,自动拿到 access key 并保存到本地。命令默认阻塞轮询,最长约 10 分钟。
|
|
103
|
+
|
|
104
|
+
AI agent / 无法实时查看命令输出的场景,分两步走(避免阻塞):
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
lj-awb auth login --no-wait --json # 返回 flowId / verifyUrl,把链接给用户去授权
|
|
108
|
+
lj-awb auth login --flow-id <flowId> # 用户授权后续轮询,拿到并保存 access key
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> 不要重复执行不带 `--flow-id` 的 login,否则会生成新的 flowId 导致旧授权链接失效。
|
|
112
|
+
|
|
113
|
+
退出登录(清除本地 access key):
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
lj-awb auth logout
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 直接使用 access key
|
|
120
|
+
|
|
80
121
|
保存 access key 到本地认证文件:
|
|
81
122
|
|
|
82
123
|
```bash
|
|
@@ -110,6 +151,8 @@ lj-awb account info
|
|
|
110
151
|
```bash
|
|
111
152
|
lj-awb doctor
|
|
112
153
|
lj-awb doctor --verify
|
|
154
|
+
lj-awb update --check
|
|
155
|
+
lj-awb update
|
|
113
156
|
lj-awb schema --brief -f json
|
|
114
157
|
lj-awb schema -f json
|
|
115
158
|
lj-awb schema --domain create -f json
|
|
@@ -159,6 +202,8 @@ lj-awb doctor --verify
|
|
|
159
202
|
|
|
160
203
|
`auth status` 只检查本地是否配置 access key;`auth verify` 会联网校验 key 是否远端有效。`doctor` 默认只做本地检查;追加 `--verify` 后会联网校验 access key、当前用户和项目组。精确 `schema` 返回每个命令的 `options[].key`,Agent 应使用这些 key 生成 CLI 参数,而不是解析自然语言 help。
|
|
161
204
|
|
|
205
|
+
`lj-awb` 在普通命令结束后会做非阻塞更新检查;如果有新版本,JSON 输出会在 `meta._notice.update` 里带上更新提示。Skill / Agent 看到这个提示后,应在完成当前任务后告诉用户当前版本和最新版本,并建议或直接运行 `lj-awb update`。真正安装更新只走显式 `lj-awb update`,`--check` 只检查不安装。
|
|
206
|
+
|
|
162
207
|
`schema` 还包含面向 Agent 的执行约束:
|
|
163
208
|
|
|
164
209
|
- `requiredOptions`:必须提供的参数 key。
|
package/build/_shared.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
|
-
import { cpSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { cpSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
4
5
|
import path from 'node:path';
|
|
5
6
|
import { fileURLToPath } from 'node:url';
|
|
6
7
|
|
|
@@ -19,13 +20,16 @@ export function run(command, args, options = {}) {
|
|
|
19
20
|
process.stderr.write(`$ ${[command, ...args].join(' ')}\n`);
|
|
20
21
|
const result = spawnSync(command, args, {
|
|
21
22
|
cwd: options.cwd || repoRoot,
|
|
23
|
+
env: options.env ? { ...process.env, ...options.env } : process.env,
|
|
22
24
|
stdio: 'inherit',
|
|
23
25
|
});
|
|
24
26
|
if (result.error) {
|
|
27
|
+
options.beforeExit?.();
|
|
25
28
|
process.stderr.write(`${result.error.message}\n`);
|
|
26
29
|
process.exit(1);
|
|
27
30
|
}
|
|
28
31
|
if (result.status !== 0) {
|
|
32
|
+
options.beforeExit?.();
|
|
29
33
|
process.exit(result.status || 1);
|
|
30
34
|
}
|
|
31
35
|
}
|
|
@@ -33,11 +37,53 @@ export function run(command, args, options = {}) {
|
|
|
33
37
|
export function capture(command, args, options = {}) {
|
|
34
38
|
return spawnSync(command, args, {
|
|
35
39
|
cwd: options.cwd || repoRoot,
|
|
40
|
+
env: options.env ? { ...process.env, ...options.env } : process.env,
|
|
36
41
|
encoding: 'utf8',
|
|
37
42
|
stdio: ['inherit', 'pipe', 'pipe'],
|
|
38
43
|
});
|
|
39
44
|
}
|
|
40
45
|
|
|
46
|
+
export function createNpmPublishAuthConfig(registry) {
|
|
47
|
+
const tokenSource = ['NPM_PUBLISH_TOKEN', 'NPM_TOKEN', 'NODE_AUTH_TOKEN']
|
|
48
|
+
.find((name) => process.env[name]?.trim());
|
|
49
|
+
if (!tokenSource) {
|
|
50
|
+
return {
|
|
51
|
+
env: {},
|
|
52
|
+
cleanup() {},
|
|
53
|
+
tokenSource: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const token = process.env[tokenSource].trim();
|
|
58
|
+
const normalizedRegistry = registry.endsWith('/') ? registry : `${registry}/`;
|
|
59
|
+
const registryUrl = new URL(normalizedRegistry);
|
|
60
|
+
const registryPath = registryUrl.pathname.endsWith('/') ? registryUrl.pathname : `${registryUrl.pathname}/`;
|
|
61
|
+
const npmrcDir = mkdtempSync(path.join(os.tmpdir(), 'lj-awb-npm-'));
|
|
62
|
+
const npmrcPath = path.join(npmrcDir, '.npmrc');
|
|
63
|
+
writeFileSync(
|
|
64
|
+
npmrcPath,
|
|
65
|
+
[
|
|
66
|
+
`registry=${normalizedRegistry}`,
|
|
67
|
+
`//${registryUrl.host}${registryPath}:_authToken=${token}`,
|
|
68
|
+
'strict-ssl=false',
|
|
69
|
+
'always-auth=true',
|
|
70
|
+
'',
|
|
71
|
+
].join('\n'),
|
|
72
|
+
{ mode: 0o600 },
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
env: {
|
|
77
|
+
NPM_CONFIG_USERCONFIG: npmrcPath,
|
|
78
|
+
NPM_CONFIG_REGISTRY: normalizedRegistry,
|
|
79
|
+
},
|
|
80
|
+
cleanup() {
|
|
81
|
+
rmSync(npmrcDir, { recursive: true, force: true });
|
|
82
|
+
},
|
|
83
|
+
tokenSource,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
41
87
|
export function packageFilePaths(cwd = repoRoot) {
|
|
42
88
|
const result = capture('npm', ['pack', '--dry-run', '--json'], { cwd });
|
|
43
89
|
if (result.error) {
|
|
@@ -101,12 +147,13 @@ export function packTarball(stageDir) {
|
|
|
101
147
|
return path.join(stageDir, tarball);
|
|
102
148
|
}
|
|
103
149
|
|
|
104
|
-
export function ensureLoggedIn(registry) {
|
|
105
|
-
const result = capture('npm', ['whoami', `--registry=${registry}`]);
|
|
150
|
+
export function ensureLoggedIn(registry, options = {}) {
|
|
151
|
+
const result = capture('npm', ['whoami', `--registry=${registry}`], { env: options.env });
|
|
106
152
|
if (result.status === 0) {
|
|
107
153
|
process.stderr.write(`npm user: ${result.stdout.trim()}\n`);
|
|
108
154
|
return;
|
|
109
155
|
}
|
|
156
|
+
options.beforeExit?.();
|
|
110
157
|
process.stderr.write([
|
|
111
158
|
`npm is not logged in for ${registry}.`,
|
|
112
159
|
`Run: npm login --registry=${registry}`,
|
|
@@ -115,14 +162,16 @@ export function ensureLoggedIn(registry) {
|
|
|
115
162
|
process.exit(1);
|
|
116
163
|
}
|
|
117
164
|
|
|
118
|
-
export function ensureVersionNotPublished({ name, version, registry }) {
|
|
165
|
+
export function ensureVersionNotPublished({ name, version, registry }, options = {}) {
|
|
119
166
|
const spec = `${name}@${version}`;
|
|
120
|
-
const result = capture('npm', ['view', spec, 'version', `--registry=${registry}`]);
|
|
167
|
+
const result = capture('npm', ['view', spec, 'version', `--registry=${registry}`], { env: options.env });
|
|
121
168
|
if (result.status === 0) {
|
|
169
|
+
options.beforeExit?.();
|
|
122
170
|
process.stderr.write(`${spec} already exists on npm. Bump the version before publishing.\n`);
|
|
123
171
|
process.exit(1);
|
|
124
172
|
}
|
|
125
173
|
if (!/E404|404 Not Found|Not found/i.test(`${result.stderr}\n${result.stdout}`)) {
|
|
174
|
+
options.beforeExit?.();
|
|
126
175
|
process.stderr.write(`Could not verify whether ${spec} exists on npm.\n`);
|
|
127
176
|
process.stderr.write(result.stderr || result.stdout || '');
|
|
128
177
|
process.exit(1);
|
package/build/prod.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import {
|
|
5
|
+
createNpmPublishAuthConfig,
|
|
5
6
|
ensureLoggedIn,
|
|
6
7
|
ensureVersionNotPublished,
|
|
7
8
|
findArgValue,
|
|
@@ -33,14 +34,21 @@ function ensureProductionDefaultApiOrigin() {
|
|
|
33
34
|
ensureProductionDefaultApiOrigin();
|
|
34
35
|
|
|
35
36
|
process.stderr.write(`Preparing ${pkg.name}@${pkg.version} for npm ${dryRun ? 'dry-run' : 'publish'} with default API origin ${PROD_API_ORIGIN}.\n`);
|
|
37
|
+
const publishAuth = createNpmPublishAuthConfig(registry);
|
|
38
|
+
if (!dryRun && publishAuth.tokenSource) {
|
|
39
|
+
process.stderr.write(`Using npm publish token from ${publishAuth.tokenSource}; NPM_CONFIG_USERCONFIG points to an isolated temporary npmrc.\n`);
|
|
40
|
+
}
|
|
36
41
|
|
|
37
42
|
if (process.env.SKIP_CHECK !== '1') {
|
|
38
43
|
run('npm', ['run', 'check:local']);
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
ensureVersionNotPublished(
|
|
46
|
+
ensureVersionNotPublished(
|
|
47
|
+
{ name: pkg.name, version: pkg.version, registry },
|
|
48
|
+
{ env: publishAuth.env, beforeExit: publishAuth.cleanup },
|
|
49
|
+
);
|
|
42
50
|
if (!dryRun) {
|
|
43
|
-
ensureLoggedIn(registry);
|
|
51
|
+
ensureLoggedIn(registry, { env: publishAuth.env, beforeExit: publishAuth.cleanup });
|
|
44
52
|
}
|
|
45
53
|
|
|
46
54
|
run('npm', [
|
|
@@ -49,4 +57,5 @@ run('npm', [
|
|
|
49
57
|
'public',
|
|
50
58
|
`--registry=${registry}`,
|
|
51
59
|
...passthroughArgs,
|
|
52
|
-
]);
|
|
60
|
+
], { env: publishAuth.env, beforeExit: publishAuth.cleanup });
|
|
61
|
+
publishAuth.cleanup();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingjingai/lj-awb-cli-pre",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Lingjing AWB CLI monorepo with shared core, standalone CLI, and agent skills (pre-release build pointing to https://animeworkbench-pre.lingjingai.cn)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"build:pre-publish": "node build/pre-publish.mjs",
|
|
24
24
|
"build:prod": "node build/prod.mjs",
|
|
25
25
|
"check": "npm run check:local && npm run check:real",
|
|
26
|
-
"check:local": "node --check install.mjs && node --check packages/awb-core/src/common.js && node --check packages/awb-core/src/api.js && node --check packages/awb-core/src/artifact.js && node --check packages/awb-core/src/auth.js && node --check packages/awb-core/src/output.js && node --check packages/awb-core/src/services.js && node --check packages/awb-core/src/commands.js && node --check packages/awb-core/src/standalone.js && sh -n packages/awb-cli/bin/lj-awb && node --check packages/awb-cli/bin/lj-awb.js && node --check build/build.mjs && node --check build/_shared.mjs && node --check build/pre.mjs && node --check build/pre-publish.mjs && node --check build/prod.mjs && node --check scripts/run-openapi-cli-examples-real.mjs && node --check scripts/validate-cli-schema.mjs && node --check scripts/validate-cli-output-contract.mjs && node --check scripts/validate-cli-command-coverage.mjs && node scripts/validate-skill-meta.mjs && node scripts/validate-cli-schema.mjs && node scripts/validate-cli-command-coverage.mjs",
|
|
26
|
+
"check:local": "node --check install.mjs && node --check packages/awb-core/src/common.js && node --check packages/awb-core/src/api.js && node --check packages/awb-core/src/artifact.js && node --check packages/awb-core/src/auth.js && node --check packages/awb-core/src/output.js && node --check packages/awb-core/src/update.js && node --check packages/awb-core/src/services.js && node --check packages/awb-core/src/commands.js && node --check packages/awb-core/src/standalone.js && sh -n packages/awb-cli/bin/lj-awb && bash -n skills/lj-awb/scripts/resolve-lj-awb-cmd.sh && node --check packages/awb-cli/bin/lj-awb.js && node --check build/build.mjs && node --check build/_shared.mjs && node --check build/pre.mjs && node --check build/pre-publish.mjs && node --check build/prod.mjs && node --check scripts/run-openapi-cli-examples-real.mjs && node --check scripts/validate-cli-schema.mjs && node --check scripts/validate-cli-output-contract.mjs && node --check scripts/validate-cli-command-coverage.mjs && node scripts/validate-skill-meta.mjs && node scripts/validate-cli-schema.mjs && node scripts/validate-cli-command-coverage.mjs",
|
|
27
27
|
"check:real": "node scripts/validate-cli-output-contract.mjs && node scripts/validate-openapi-cli-examples.mjs",
|
|
28
28
|
"test:openapi-real": "node scripts/run-openapi-cli-examples-real.mjs",
|
|
29
29
|
"smoke": "packages/awb-cli/bin/lj-awb --help && packages/awb-cli/bin/lj-awb auth status -f json && packages/awb-cli/bin/lj-awb system && packages/awb-cli/bin/lj-awb auth && packages/awb-cli/bin/lj-awb account && packages/awb-cli/bin/lj-awb project && packages/awb-cli/bin/lj-awb credits && packages/awb-cli/bin/lj-awb upload && packages/awb-cli/bin/lj-awb model && packages/awb-cli/bin/lj-awb create && packages/awb-cli/bin/lj-awb task && packages/awb-cli/bin/lj-awb artifact && packages/awb-cli/bin/lj-awb schema -f json >/dev/null",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingjingai/awb-cli-bin",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Standalone CLI for Lingjing AWB",
|
|
5
5
|
"private": true,
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,6 +13,6 @@
|
|
|
13
13
|
"README.md"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@lingjingai/awb-core": "0.4.
|
|
16
|
+
"@lingjingai/awb-core": "0.4.5"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -109,6 +109,14 @@ export async function fetchUserInfo() {
|
|
|
109
109
|
return await apiFetch('/api/anime/user/account/userInfo', { body: {} });
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
export async function createLoginFlow() {
|
|
113
|
+
return await apiFetch('/api/anime/user/cli/createLoginFlow', { body: {}, auth: false });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function queryLoginFlowStatus(flowId) {
|
|
117
|
+
return await apiFetch('/api/anime/user/cli/queryFlowStatus', { body: { flowId }, auth: false });
|
|
118
|
+
}
|
|
119
|
+
|
|
112
120
|
export async function fetchTeams() {
|
|
113
121
|
return await apiFetch('/api/anime/user/group/getOwnGroupList', { body: {} });
|
|
114
122
|
}
|
|
@@ -230,6 +238,20 @@ export async function createVideoSubtitleRemovalTask(payload = {}) {
|
|
|
230
238
|
return await apiFetch('/api/material/creation/videoSubtitleRemoval', { body: payload });
|
|
231
239
|
}
|
|
232
240
|
|
|
241
|
+
export async function fetchVideoSuperResolutionFee(payload = {}) {
|
|
242
|
+
return await apiFetch('/api/material/creation/videoUpResolutionCal', {
|
|
243
|
+
method: 'GET',
|
|
244
|
+
query: payload,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export async function createVideoSuperResolutionTask(payload = {}) {
|
|
249
|
+
return await apiFetch('/api/material/creation/videoUpResolution', {
|
|
250
|
+
method: 'POST',
|
|
251
|
+
query: payload,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
233
255
|
export async function fetchTaskFeed(payload = {}) {
|
|
234
256
|
return await apiFetch('/api/material/creation/task/feedPull', {
|
|
235
257
|
query: payload,
|
|
@@ -2,6 +2,7 @@ import { fetchProjectGroupUsers, fetchTeams, fetchUserInfo } from './api.js';
|
|
|
2
2
|
import * as artifact from './artifact.js';
|
|
3
3
|
import { clearAuth, loadAuth, saveAccessKey, summarizeAuth } from './auth.js';
|
|
4
4
|
import { LingjingAwbCliError, maskSecret, toBool, trimSecret } from './common.js';
|
|
5
|
+
import { runCliUpdate } from './update.js';
|
|
5
6
|
import {
|
|
6
7
|
assetGroupCreate,
|
|
7
8
|
assetGroupGet,
|
|
@@ -10,6 +11,8 @@ import {
|
|
|
10
11
|
assetMatchActor,
|
|
11
12
|
assetReviewModels,
|
|
12
13
|
assetRegister,
|
|
14
|
+
authLogin,
|
|
15
|
+
authLogout,
|
|
13
16
|
creditsBalance,
|
|
14
17
|
creditsUsageSummary,
|
|
15
18
|
createProjectGroupCommand,
|
|
@@ -39,6 +42,9 @@ import {
|
|
|
39
42
|
subjectWait,
|
|
40
43
|
subtitleRemove,
|
|
41
44
|
subtitleStatus,
|
|
45
|
+
videoSuperResolution,
|
|
46
|
+
videoSuperResolutionFee,
|
|
47
|
+
videoSuperResolutionStatus,
|
|
42
48
|
taskList,
|
|
43
49
|
taskRecordPoll,
|
|
44
50
|
taskRecords,
|
|
@@ -85,6 +91,9 @@ const MODEL_LIST_ARGS = [
|
|
|
85
91
|
const TASK_RECORD_ARG = { name: 'task-record-file', valueName: 'path', description: '任务台账 JSONL 文件;也可用 LINGJING_AWB_TASK_RECORD_FILE' };
|
|
86
92
|
const RESOURCE_ARG = { name: 'resource', valueName: 'spec', description: '统一素材,格式 type:usage[:key]=path|url|asset,可重复传;音频参考用 audio:reference=./music.mp3' };
|
|
87
93
|
const RESOURCES_JSON_ARG = { name: 'resources-json', valueName: 'json|path', description: 'resources 数组 JSON 或 JSON 文件路径' };
|
|
94
|
+
const MODEL_PARAM_ARG = { name: 'model-param', valueName: 'key=value', description: '通用模型配置参数,可重复传;key 来自 model options.params[],例如 generation_effort=high' };
|
|
95
|
+
const MODEL_PARAMS_JSON_ARG = { name: 'model-params-json', valueName: 'json|path', description: '通用模型配置参数对象 JSON 或 JSON 文件路径;显式 --ratio/--quality 等命令参数优先' };
|
|
96
|
+
const MODEL_PARAM_ARGS = [MODEL_PARAM_ARG, MODEL_PARAMS_JSON_ARG];
|
|
88
97
|
const CREATE_WAIT_ARGS = [
|
|
89
98
|
{ name: 'wait-seconds', valueName: 'seconds', description: '提交后顺带等待结果的秒数;默认 0 不等待' },
|
|
90
99
|
{ name: 'poll-interval-ms', valueName: 'ms', description: '任务轮询间隔毫秒数,默认 5000' },
|
|
@@ -125,6 +134,25 @@ export function registerAwbCommands(cli) {
|
|
|
125
134
|
func: async (_ctx, kwargs) => doctor(kwargs),
|
|
126
135
|
});
|
|
127
136
|
|
|
137
|
+
cli({
|
|
138
|
+
name: 'update',
|
|
139
|
+
description: commandHelp('检查并更新 CLI 到最新版本;默认只在需要时安装新版本', {
|
|
140
|
+
examples: [
|
|
141
|
+
'lj-awb update --check',
|
|
142
|
+
'lj-awb update',
|
|
143
|
+
'lj-awb update --force',
|
|
144
|
+
],
|
|
145
|
+
hint: '普通命令只会做非阻塞更新检查;真正安装请显式运行 update。',
|
|
146
|
+
}),
|
|
147
|
+
args: [
|
|
148
|
+
{ name: 'check', description: '只检查是否有新版本,不安装' },
|
|
149
|
+
{ name: 'force', description: '强制重新检查并执行安装,忽略缓存' },
|
|
150
|
+
{ name: 'registry', valueName: 'url', description: 'npm registry 地址;默认读取环境变量或 npm 默认 registry' },
|
|
151
|
+
{ name: 'package-name', valueName: 'name', description: '要更新的包名;默认自动识别当前 CLI 包' },
|
|
152
|
+
],
|
|
153
|
+
func: async (_ctx, kwargs) => runCliUpdate(kwargs),
|
|
154
|
+
});
|
|
155
|
+
|
|
128
156
|
cli({
|
|
129
157
|
name: 'auth status',
|
|
130
158
|
description: commandHelp('查看本地 access key 是否已配置;不联网', {
|
|
@@ -163,50 +191,27 @@ export function registerAwbCommands(cli) {
|
|
|
163
191
|
|
|
164
192
|
cli({
|
|
165
193
|
name: 'auth login',
|
|
166
|
-
description: commandHelp('
|
|
194
|
+
description: commandHelp('登录:默认走浏览器授权登录;也支持直接传 access key 保存', {
|
|
167
195
|
examples: [
|
|
196
|
+
'lj-awb auth login',
|
|
197
|
+
'lj-awb auth login --no-wait',
|
|
198
|
+
'lj-awb auth login --flow-id <flowId>',
|
|
168
199
|
'lj-awb auth login --access-key <key>',
|
|
169
200
|
'LINGJING_AWB_ACCESS_KEY=<key> lj-awb auth login',
|
|
170
201
|
'lj-awb auth login --access-key <key> --skip-verify',
|
|
171
202
|
],
|
|
172
|
-
hint: '
|
|
203
|
+
hint: '不传 --access-key(且无 LINGJING_AWB_ACCESS_KEY 环境变量)时走浏览器授权:创建登录任务、展示链接、轮询直到授权成功并自动保存 access key。命令最长阻塞约 10 分钟;AI agent 可先用 --no-wait --json 拿 flow_id,再用 --flow-id <id> 续轮询,不要重复发起新的 login。',
|
|
173
204
|
}),
|
|
174
205
|
args: [
|
|
175
|
-
{ name: 'access-key', valueName: 'key', description: '平台 access key
|
|
206
|
+
{ name: 'access-key', valueName: 'key', description: '平台 access key;传了则跳过浏览器授权直接保存,不传时读取环境变量' },
|
|
207
|
+
{ name: 'flow-id', valueName: 'flowId', description: '复用已有登录任务的 flow_id 继续轮询;不传则新建登录任务' },
|
|
208
|
+
{ name: 'no-wait', description: '只创建登录任务并返回 flow_id / verify_url,不阻塞轮询;适合 AI agent / 脚本' },
|
|
209
|
+
{ name: 'wait-seconds', valueName: 'seconds', description: '浏览器授权最长轮询秒数,默认 600' },
|
|
210
|
+
{ name: 'poll-interval-ms', valueName: 'ms', description: '授权状态轮询间隔毫秒数,默认 3000' },
|
|
176
211
|
{ name: 'skip-verify', description: '只保存 key,不调用 userInfo 校验;仅用于本地调试' },
|
|
177
212
|
DRY_RUN_ARG,
|
|
178
213
|
],
|
|
179
|
-
func: async (_ctx, kwargs) =>
|
|
180
|
-
const skipVerify = toBool(kwargs.skipVerify);
|
|
181
|
-
const accessKey = trimSecret(kwargs.accessKey || process.env.LINGJING_AWB_ACCESS_KEY || '');
|
|
182
|
-
if (!accessKey) {
|
|
183
|
-
throw new LingjingAwbCliError('缺少 access key', {
|
|
184
|
-
type: 'argument_error',
|
|
185
|
-
exitCode: 2,
|
|
186
|
-
hint: '传 --access-key <key>,或设置 LINGJING_AWB_ACCESS_KEY 环境变量。',
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
if (toBool(kwargs.dryRun)) {
|
|
190
|
-
return {
|
|
191
|
-
dryRun: true,
|
|
192
|
-
saved: false,
|
|
193
|
-
verified: false,
|
|
194
|
-
accessKey: maskSecret(accessKey),
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
let user = null;
|
|
198
|
-
if (!skipVerify) {
|
|
199
|
-
process.env.LINGJING_AWB_ACCESS_KEY = accessKey;
|
|
200
|
-
user = normalizeUserInfo(await fetchUserInfo());
|
|
201
|
-
}
|
|
202
|
-
const { auth } = await saveAccessKey(accessKey, { verified: !skipVerify });
|
|
203
|
-
return {
|
|
204
|
-
auth: summarizeAuth(auth, { accessKey, source: 'saved', sourceName: 'auth' }),
|
|
205
|
-
accessKey: maskSecret(accessKey),
|
|
206
|
-
verified: !skipVerify,
|
|
207
|
-
user,
|
|
208
|
-
};
|
|
209
|
-
},
|
|
214
|
+
func: async (_ctx, kwargs) => authLogin(kwargs),
|
|
210
215
|
});
|
|
211
216
|
|
|
212
217
|
cli({
|
|
@@ -224,6 +229,16 @@ export function registerAwbCommands(cli) {
|
|
|
224
229
|
},
|
|
225
230
|
});
|
|
226
231
|
|
|
232
|
+
cli({
|
|
233
|
+
name: 'auth logout',
|
|
234
|
+
description: commandHelp('退出登录:清除本地保存的 access key', {
|
|
235
|
+
examples: ['lj-awb auth logout'],
|
|
236
|
+
hint: '只清本地认证文件,不清当前 shell 中的 LINGJING_AWB_ACCESS_KEY 环境变量;下次使用前重新运行 lj-awb auth login。',
|
|
237
|
+
}),
|
|
238
|
+
args: [],
|
|
239
|
+
func: async () => authLogout(),
|
|
240
|
+
});
|
|
241
|
+
|
|
227
242
|
cli({
|
|
228
243
|
name: 'account info',
|
|
229
244
|
description: commandHelp('查看当前 AWB 用户、团队、项目组和积分摘要', {
|
|
@@ -497,10 +512,12 @@ export function registerAwbCommands(cli) {
|
|
|
497
512
|
{ name: 'ratio', valueName: 'ratio', description: '画幅比例,如 9:16' },
|
|
498
513
|
{ name: 'quality', valueName: 'quality', description: '清晰度,如 2K' },
|
|
499
514
|
{ name: 'generate-num', valueName: 'n', description: '生成张数' },
|
|
515
|
+
...MODEL_PARAM_ARGS,
|
|
500
516
|
RESOURCE_ARG,
|
|
501
517
|
RESOURCES_JSON_ARG,
|
|
502
518
|
FEE_DRY_RUN_ARG,
|
|
503
519
|
],
|
|
520
|
+
allowDynamicModelParams: true,
|
|
504
521
|
func: async (_ctx, kwargs) => imageFee(kwargs),
|
|
505
522
|
});
|
|
506
523
|
|
|
@@ -521,6 +538,7 @@ export function registerAwbCommands(cli) {
|
|
|
521
538
|
{ name: 'ratio', valueName: 'ratio', description: '画幅比例' },
|
|
522
539
|
{ name: 'quality', valueName: 'quality', description: '清晰度' },
|
|
523
540
|
{ name: 'generate-num', valueName: 'n', description: '生成张数' },
|
|
541
|
+
...MODEL_PARAM_ARGS,
|
|
524
542
|
RESOURCE_ARG,
|
|
525
543
|
RESOURCES_JSON_ARG,
|
|
526
544
|
TASK_RECORD_ARG,
|
|
@@ -528,6 +546,7 @@ export function registerAwbCommands(cli) {
|
|
|
528
546
|
DRY_RUN_ARG,
|
|
529
547
|
YES_ARG,
|
|
530
548
|
],
|
|
549
|
+
allowDynamicModelParams: true,
|
|
531
550
|
func: async (_ctx, kwargs) => imageCreate(kwargs),
|
|
532
551
|
});
|
|
533
552
|
|
|
@@ -538,17 +557,19 @@ export function registerAwbCommands(cli) {
|
|
|
538
557
|
'lj-awb create image-batch --input-file ./prompts.txt --model-group-code <code> --dry-run',
|
|
539
558
|
'lj-awb create image-batch --input-file ./image-input.jsonl --model-group-code <code> --concurrency 3 --yes',
|
|
540
559
|
],
|
|
541
|
-
hint: 'JSON/JSONL 每项只写任务差异字段:prompt、ratio、quality、generate_num、resources、resource、customBizId
|
|
560
|
+
hint: 'JSON/JSONL 每项只写任务差异字段:prompt、ratio、quality、generate_num、resources、resource、model_params、customBizId;新增模型配置参数也可直接写入每项。',
|
|
542
561
|
}),
|
|
543
562
|
args: [
|
|
544
563
|
{ name: 'input-file', valueName: 'path', description: '批量输入文件' },
|
|
545
564
|
MODEL_GROUP_ARG,
|
|
546
565
|
PROJECT_GROUP_ARG,
|
|
566
|
+
...MODEL_PARAM_ARGS,
|
|
547
567
|
{ name: 'concurrency', valueName: 'n', description: '并发数,默认 1' },
|
|
548
568
|
TASK_RECORD_ARG,
|
|
549
569
|
DRY_RUN_ARG,
|
|
550
570
|
YES_ARG,
|
|
551
571
|
],
|
|
572
|
+
allowDynamicModelParams: true,
|
|
552
573
|
func: async (_ctx, kwargs) => imageCreateBatch(kwargs),
|
|
553
574
|
});
|
|
554
575
|
|
|
@@ -577,10 +598,12 @@ export function registerAwbCommands(cli) {
|
|
|
577
598
|
{ name: 'quality', valueName: 'quality', description: '清晰度,如 720' },
|
|
578
599
|
{ name: 'duration', valueName: 'seconds', description: '生成时长秒数' },
|
|
579
600
|
{ name: 'need-audio', valueName: 'bool', description: '输出音效开关:是否让模型在视频中生成音效(true/false)。不接收音频文件;参考音频请用 --resource audio:reference=...' },
|
|
601
|
+
...MODEL_PARAM_ARGS,
|
|
580
602
|
RESOURCE_ARG,
|
|
581
603
|
RESOURCES_JSON_ARG,
|
|
582
604
|
FEE_DRY_RUN_ARG,
|
|
583
605
|
],
|
|
606
|
+
allowDynamicModelParams: true,
|
|
584
607
|
func: async (_ctx, kwargs) => videoFee(kwargs),
|
|
585
608
|
});
|
|
586
609
|
|
|
@@ -604,6 +627,7 @@ export function registerAwbCommands(cli) {
|
|
|
604
627
|
{ name: 'quality', valueName: 'quality', description: '清晰度' },
|
|
605
628
|
{ name: 'duration', valueName: 'seconds', description: '生成时长秒数' },
|
|
606
629
|
{ name: 'need-audio', valueName: 'bool', description: '输出音效开关:是否让模型在视频中生成音效(true/false)。不接收音频文件;参考音频请用 --resource audio:reference=...' },
|
|
630
|
+
...MODEL_PARAM_ARGS,
|
|
607
631
|
RESOURCE_ARG,
|
|
608
632
|
RESOURCES_JSON_ARG,
|
|
609
633
|
TASK_RECORD_ARG,
|
|
@@ -611,6 +635,7 @@ export function registerAwbCommands(cli) {
|
|
|
611
635
|
DRY_RUN_ARG,
|
|
612
636
|
YES_ARG,
|
|
613
637
|
],
|
|
638
|
+
allowDynamicModelParams: true,
|
|
614
639
|
func: async (_ctx, kwargs) => videoCreate(kwargs),
|
|
615
640
|
});
|
|
616
641
|
|
|
@@ -621,17 +646,19 @@ export function registerAwbCommands(cli) {
|
|
|
621
646
|
'lj-awb create video-batch --input-file ./prompts.txt --model-group-code <code> --dry-run',
|
|
622
647
|
'lj-awb create video-batch --input-file ./video-input.jsonl --model-group-code <code> --concurrency 2 --yes',
|
|
623
648
|
],
|
|
624
|
-
hint: 'JSON/JSONL 每项只写任务差异字段:prompt、ratio、quality、duration、need_audio、resources、resource、customBizId
|
|
649
|
+
hint: 'JSON/JSONL 每项只写任务差异字段:prompt、ratio、quality、duration、need_audio、resources、resource、model_params、customBizId;新增模型配置参数也可直接写入每项。',
|
|
625
650
|
}),
|
|
626
651
|
args: [
|
|
627
652
|
{ name: 'input-file', valueName: 'path', description: '批量输入文件' },
|
|
628
653
|
MODEL_GROUP_ARG,
|
|
629
654
|
PROJECT_GROUP_ARG,
|
|
655
|
+
...MODEL_PARAM_ARGS,
|
|
630
656
|
{ name: 'concurrency', valueName: 'n', description: '并发数,默认 1' },
|
|
631
657
|
TASK_RECORD_ARG,
|
|
632
658
|
DRY_RUN_ARG,
|
|
633
659
|
YES_ARG,
|
|
634
660
|
],
|
|
661
|
+
allowDynamicModelParams: true,
|
|
635
662
|
func: async (_ctx, kwargs) => videoCreateBatch(kwargs),
|
|
636
663
|
});
|
|
637
664
|
|
|
@@ -660,6 +687,35 @@ export function registerAwbCommands(cli) {
|
|
|
660
687
|
func: async (_ctx, kwargs) => subtitleRemove(kwargs),
|
|
661
688
|
});
|
|
662
689
|
|
|
690
|
+
cli({
|
|
691
|
+
name: 'create video-super-resolution-fee',
|
|
692
|
+
description: commandHelp('计算视频超分预计积分;传入 objectName', {
|
|
693
|
+
examples: ['lj-awb create video-super-resolution-fee --object-name material/video-super/example.mp4 --project-group-no <no>'],
|
|
694
|
+
hint: 'objectName 通常是 material backendPath 或 COS 对象路径;正式超分前先看一次估价。',
|
|
695
|
+
}),
|
|
696
|
+
args: [
|
|
697
|
+
{ name: 'object-name', valueName: 'path', description: '视频对象路径;通常是 material backendPath 或 COS 对象路径' },
|
|
698
|
+
PROJECT_GROUP_ARG,
|
|
699
|
+
],
|
|
700
|
+
func: async (_ctx, kwargs) => videoSuperResolutionFee(kwargs),
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
cli({
|
|
704
|
+
name: 'create video-super-resolution',
|
|
705
|
+
description: commandHelp('基于 objectName 提交视频超分任务', {
|
|
706
|
+
examples: ['lj-awb create video-super-resolution --object-name material/video-super/example.mp4 --project-group-no <no> --dry-run'],
|
|
707
|
+
hint: '正式执行需要 --yes;会先按 objectName 读取视频信息,再选择 1080P / 2K 模型组。',
|
|
708
|
+
}),
|
|
709
|
+
args: [
|
|
710
|
+
{ name: 'object-name', valueName: 'path', description: '视频对象路径;通常是 material backendPath 或 COS 对象路径' },
|
|
711
|
+
PROJECT_GROUP_ARG,
|
|
712
|
+
TASK_RECORD_ARG,
|
|
713
|
+
DRY_RUN_ARG,
|
|
714
|
+
YES_ARG,
|
|
715
|
+
],
|
|
716
|
+
func: async (_ctx, kwargs) => videoSuperResolution(kwargs),
|
|
717
|
+
});
|
|
718
|
+
|
|
663
719
|
cli({
|
|
664
720
|
name: 'task video-subtitle-status',
|
|
665
721
|
description: commandHelp('查询 material 去字幕任务状态', {
|
|
@@ -672,13 +728,25 @@ export function registerAwbCommands(cli) {
|
|
|
672
728
|
func: async (_ctx, kwargs) => subtitleStatus(kwargs),
|
|
673
729
|
});
|
|
674
730
|
|
|
731
|
+
cli({
|
|
732
|
+
name: 'task video-super-resolution-status',
|
|
733
|
+
description: commandHelp('查询 material 视频超分任务状态', {
|
|
734
|
+
examples: ['lj-awb task video-super-resolution-status --task-id <superResolutionTaskId>'],
|
|
735
|
+
}),
|
|
736
|
+
args: [
|
|
737
|
+
{ name: 'task-id', valueName: 'id', description: 'material 视频超分任务 ID' },
|
|
738
|
+
PROJECT_GROUP_ARG,
|
|
739
|
+
],
|
|
740
|
+
func: async (_ctx, kwargs) => videoSuperResolutionStatus(kwargs),
|
|
741
|
+
});
|
|
742
|
+
|
|
675
743
|
cli({
|
|
676
744
|
name: 'task list',
|
|
677
745
|
description: commandHelp('查询项目组近期任务流', {
|
|
678
746
|
examples: ['lj-awb task list --task-type IMAGE_CREATE --project-group-no <no>'],
|
|
679
747
|
}),
|
|
680
748
|
args: [
|
|
681
|
-
{ name: 'task-type', valueName: 'type', description: 'IMAGE_CREATE / IMAGE_EDIT / VIDEO_GROUP' },
|
|
749
|
+
{ name: 'task-type', valueName: 'type', description: 'IMAGE_CREATE / IMAGE_EDIT / VIDEO_GROUP / VIDEO_SUPER_RESOLUTION / VIDEO_SUBTITLE_REMOVAL' },
|
|
682
750
|
PROJECT_GROUP_ARG,
|
|
683
751
|
{ name: 'page-size', valueName: 'n', description: '每页任务数' },
|
|
684
752
|
{ name: 'min-time', valueName: 'ms', description: '任务流 minTime,默认当前时间' },
|
|
@@ -694,7 +762,7 @@ export function registerAwbCommands(cli) {
|
|
|
694
762
|
}),
|
|
695
763
|
args: [
|
|
696
764
|
{ name: 'task-id', valueName: 'id', description: '任务 ID' },
|
|
697
|
-
{ name: 'task-type', valueName: 'type', description: 'IMAGE_CREATE / VIDEO_GROUP' },
|
|
765
|
+
{ name: 'task-type', valueName: 'type', description: 'IMAGE_CREATE / VIDEO_GROUP;material 扩展任务优先用 task video-subtitle-status / task video-super-resolution-status' },
|
|
698
766
|
PROJECT_GROUP_ARG,
|
|
699
767
|
...TASK_WAIT_ARGS,
|
|
700
768
|
],
|
|
@@ -811,7 +879,11 @@ export function registerAwbCommands(cli) {
|
|
|
811
879
|
cli({
|
|
812
880
|
name: 'create asset',
|
|
813
881
|
description: commandHelp('把 COS 路径 / URL / 本地文件注册成平台素材', {
|
|
814
|
-
examples: [
|
|
882
|
+
examples: [
|
|
883
|
+
'lj-awb create asset --group-id <id> --platform JIMENG --url "asset-review/upload/a.png" --name "女主正面" --dry-run',
|
|
884
|
+
'lj-awb create asset --group-id <id> --platform JIMENG --file ./clip.mp4 --name "参考视频" --dry-run',
|
|
885
|
+
],
|
|
886
|
+
hint: 'CLI 会按扩展名自动设置 assetType=Image/Video/Audio;本地文件会用 ffprobe 预校验图片/视频尺寸、视频时长/FPS/像素数和音频时长,缺少 ffprobe/ffmpeg 时 macOS + Homebrew 会自动安装 ffmpeg。',
|
|
815
887
|
}),
|
|
816
888
|
args: [
|
|
817
889
|
{ name: 'group-id', valueName: 'id', description: '素材组 ID' },
|
|
@@ -819,6 +891,7 @@ export function registerAwbCommands(cli) {
|
|
|
819
891
|
{ name: 'file', valueName: 'path', description: '本地素材文件;会先上传' },
|
|
820
892
|
{ name: 'url', valueName: 'url', description: '素材 URL 或 COS 路径' },
|
|
821
893
|
{ name: 'backend-path', valueName: 'path', description: 'upload files 返回的 backendPath' },
|
|
894
|
+
{ name: 'auto-convert', description: '本地素材不符合加白规格时自动转换为合法规格后继续' },
|
|
822
895
|
ASSET_PLATFORM_ARG,
|
|
823
896
|
DRY_RUN_ARG,
|
|
824
897
|
YES_ARG,
|
|
@@ -318,11 +318,19 @@ export function guessMimeType(filePath) {
|
|
|
318
318
|
return 'image/png';
|
|
319
319
|
case '.jpg':
|
|
320
320
|
case '.jpeg':
|
|
321
|
+
case '.jfif':
|
|
321
322
|
return 'image/jpeg';
|
|
323
|
+
case '.tif':
|
|
324
|
+
case '.tiff':
|
|
325
|
+
return 'image/tiff';
|
|
322
326
|
case '.webp':
|
|
323
327
|
return 'image/webp';
|
|
324
328
|
case '.gif':
|
|
325
329
|
return 'image/gif';
|
|
330
|
+
case '.heic':
|
|
331
|
+
return 'image/heic';
|
|
332
|
+
case '.heif':
|
|
333
|
+
return 'image/heif';
|
|
326
334
|
case '.mp3':
|
|
327
335
|
return 'audio/mpeg';
|
|
328
336
|
case '.wav':
|