museav-cli 2.0.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.
- package/.github/workflows/ci.yml +19 -0
- package/.github/workflows/publish.yml +79 -0
- package/AGENTS.md +90 -0
- package/CHANGELOG.md +49 -0
- package/LICENSE +21 -0
- package/README.md +490 -0
- package/SECURITY.md +11 -0
- package/dist/client.d.ts +387 -0
- package/dist/client.js +372 -0
- package/dist/commands/assets.d.ts +14 -0
- package/dist/commands/assets.js +30 -0
- package/dist/commands/balance.d.ts +3 -0
- package/dist/commands/balance.js +11 -0
- package/dist/commands/bind-feishu.d.ts +3 -0
- package/dist/commands/bind-feishu.js +63 -0
- package/dist/commands/gen.d.ts +16 -0
- package/dist/commands/gen.js +88 -0
- package/dist/commands/image-to-template.d.ts +24 -0
- package/dist/commands/image-to-template.js +111 -0
- package/dist/commands/jobs.d.ts +11 -0
- package/dist/commands/jobs.js +27 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.js +67 -0
- package/dist/commands/models.d.ts +3 -0
- package/dist/commands/models.js +9 -0
- package/dist/commands/products.d.ts +9 -0
- package/dist/commands/products.js +16 -0
- package/dist/commands/reverse.d.ts +3 -0
- package/dist/commands/reverse.js +16 -0
- package/dist/commands/skills.d.ts +5 -0
- package/dist/commands/skills.js +22 -0
- package/dist/commands/templates.d.ts +28 -0
- package/dist/commands/templates.js +79 -0
- package/dist/commands/upload.d.ts +9 -0
- package/dist/commands/upload.js +8 -0
- package/dist/commands/video-templates.d.ts +21 -0
- package/dist/commands/video-templates.js +71 -0
- package/dist/commands/welcome.d.ts +6 -0
- package/dist/commands/welcome.js +93 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.js +14 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.js +93 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +292 -0
- package/dist/tenant-client.d.ts +31 -0
- package/dist/tenant-client.js +84 -0
- package/package.json +55 -0
- package/src/client.ts +636 -0
- package/src/commands/assets.ts +47 -0
- package/src/commands/balance.ts +12 -0
- package/src/commands/bind-feishu.ts +77 -0
- package/src/commands/gen.ts +111 -0
- package/src/commands/image-to-template.ts +150 -0
- package/src/commands/jobs.ts +37 -0
- package/src/commands/login.ts +80 -0
- package/src/commands/models.ts +12 -0
- package/src/commands/products.ts +38 -0
- package/src/commands/reverse.ts +21 -0
- package/src/commands/skills.ts +29 -0
- package/src/commands/templates.ts +98 -0
- package/src/commands/upload.ts +18 -0
- package/src/commands/video-templates.ts +89 -0
- package/src/commands/welcome.ts +108 -0
- package/src/commands/whoami.ts +19 -0
- package/src/config.ts +114 -0
- package/src/index.ts +318 -0
- package/src/tenant-client.ts +90 -0
- package/src/types/update-notifier.d.ts +31 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
typecheck:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-node@v4
|
|
15
|
+
with:
|
|
16
|
+
node-version: '20'
|
|
17
|
+
- run: npm ci
|
|
18
|
+
- run: npx tsc --noEmit
|
|
19
|
+
- run: npm run build
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: Publish to npm
|
|
2
|
+
|
|
3
|
+
# 触发:推 v* tag(推荐),或手动跑一次
|
|
4
|
+
# git tag v1.0.1 && git push origin v1.0.1
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ['v*']
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
publish:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
id-token: write # Trusted Publishing(OIDC) 与 --provenance 都依赖它
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: '22'
|
|
22
|
+
registry-url: 'https://registry.npmjs.org'
|
|
23
|
+
|
|
24
|
+
# Trusted Publishing 需要 npm >= 11.5.1,runner 自带的通常更旧
|
|
25
|
+
- name: 升级 npm
|
|
26
|
+
run: npm install -g npm@latest
|
|
27
|
+
|
|
28
|
+
- run: npm ci
|
|
29
|
+
- run: npx tsc --noEmit
|
|
30
|
+
- run: npm run build
|
|
31
|
+
|
|
32
|
+
# 防手滑:tag 触发时校验 tag 与 package.json 的 version 一致
|
|
33
|
+
- name: 校验版本号与 tag 一致
|
|
34
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
35
|
+
run: |
|
|
36
|
+
TAG="${GITHUB_REF#refs/tags/v}"
|
|
37
|
+
PKG=$(node -p "require('./package.json').version")
|
|
38
|
+
if [ "$TAG" != "$PKG" ]; then
|
|
39
|
+
echo "::error::tag v$TAG 与 package.json 的 $PKG 不一致,先对齐再发"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
echo "版本一致:$PKG"
|
|
43
|
+
|
|
44
|
+
- name: 冒烟测试(命令能起、版本对得上)
|
|
45
|
+
run: |
|
|
46
|
+
node dist/index.js --version
|
|
47
|
+
node dist/index.js --help | head -3
|
|
48
|
+
|
|
49
|
+
# 认证走哪条由仓库配置决定,二选一,不用改这个文件:
|
|
50
|
+
# ① Trusted Publishing(推荐,无 token)——在 npmjs.com 的包设置里
|
|
51
|
+
# 绑定本仓库 + 本 workflow 文件名(publish.yml),然后别设 NPM_TOKEN secret。
|
|
52
|
+
# ② NPM_TOKEN 兜底——建 Granular token(Read and write,范围勾 @museav scope
|
|
53
|
+
# 或 All packages,别只勾单个包),存进仓库 Secrets 的 NPM_TOKEN。
|
|
54
|
+
- name: 发布
|
|
55
|
+
run: npm publish --access public --provenance
|
|
56
|
+
env:
|
|
57
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
58
|
+
|
|
59
|
+
# 发布后回调业务中台(2026-08-15):POST /api/cli-release,
|
|
60
|
+
# 由中台统一记录更新日志 + 用 App 发卡片通知到目标群(mzmeso/好易美等)。
|
|
61
|
+
# 群配置在业务中台(CLI_RELEASE_CHAT_IDS),GitHub 只存一个回调 token。
|
|
62
|
+
# 版本号由 /api/cli-guide 动态查 npm registry 同步,同样不用手动改。
|
|
63
|
+
- name: 回调业务中台(记录发布 + 群通知)
|
|
64
|
+
env:
|
|
65
|
+
CLI_RELEASE_TOKEN: ${{ secrets.CLI_RELEASE_TOKEN }}
|
|
66
|
+
run: |
|
|
67
|
+
# GitHub Actions 的 if: 表达式不能直接用 secrets(Unrecognized named-value),
|
|
68
|
+
# 只能把 secret 放进 env,再在 run 里判断是否配置。
|
|
69
|
+
if [ -z "$CLI_RELEASE_TOKEN" ]; then
|
|
70
|
+
echo "未配置 CLI_RELEASE_TOKEN,跳过发布通知(不影响 npm 发布)"
|
|
71
|
+
exit 0
|
|
72
|
+
fi
|
|
73
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
74
|
+
BODY=$(awk '/^## /{if(n++) exit} {print}' CHANGELOG.md | head -15)
|
|
75
|
+
curl -s -X POST "https://manager.museav.top/api/cli-release" \
|
|
76
|
+
-H "Authorization: Bearer $CLI_RELEASE_TOKEN" \
|
|
77
|
+
-H "Content-Type: application/json" \
|
|
78
|
+
-d "$(jq -n --arg v "$VERSION" --arg c "$BODY" '{version: $v, changes: $c}')" \
|
|
79
|
+
|| echo "回调业务中台失败(忽略,不影响发布)"
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This CLI is designed to be used directly by coding agents (Claude Code, Codex, etc.), not just humans. Read this before shelling out to `museav`.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
A command-line client for the "studio" image-generation platform (`https://manager.museav.top`). It generates images from a prompt, reverse-engineers a prompt from an existing image, and lists your own generation history. All output is designed for machine consumption: **stdout carries only the final result** (a URL, a prompt string, or JSON); progress and human-readable info goes to stderr.
|
|
8
|
+
|
|
9
|
+
## Auth: pick one identity, not both
|
|
10
|
+
|
|
11
|
+
- **You're acting as an individual user** (a person's own account): `museav login` — opens a device-authorization flow (prints a code + URL, polls until the user approves in a browser). Token cached in `~/.museav.json`, valid 7 days.
|
|
12
|
+
- **You're acting as a tenant/service** (no human in the loop, e.g. CI, a backend job): set `STUDIO_API_KEY=sk-studio-xxx` as an environment variable, or run `museav config --apiKey sk-studio-xxx`.
|
|
13
|
+
|
|
14
|
+
Don't try both — whichever credential is present is what gets used (env var `STUDIO_API_KEY` always wins over the config file). If neither is configured, every command exits 1 with a message telling you which one to set up; that error is your signal to either run `login` interactively (if a human is present to approve it) or ask for an apiKey (if not).
|
|
15
|
+
|
|
16
|
+
## Core commands
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Generate an image, wait for it, get the URL on stdout
|
|
20
|
+
museav gen --prompt 'a poster, neon lights, cyberpunk' --ratio 9:16
|
|
21
|
+
|
|
22
|
+
# Generate a video (文生视频/图生视频), wait, get the mp4 URL on stdout
|
|
23
|
+
museav gen --video --prompt 'a cat stretching on a windowsill, cinematic' --model seedance-2-fast --ratio 9:16
|
|
24
|
+
museav gen --video --image logo.png --prompt 'logo glows slowly, background fades' --ratio 1:1
|
|
25
|
+
|
|
26
|
+
# Generate from a pre-configured image template instead of a raw prompt (deterministic
|
|
27
|
+
# placeholder substitution server-side, no chat cost). List available templates first —
|
|
28
|
+
# the output shows which placeholder keys (if any) each template needs.
|
|
29
|
+
museav templates
|
|
30
|
+
museav gen --template <id> --fields '{"artist":"name","city":"place"}'
|
|
31
|
+
|
|
32
|
+
# Create a new image template (tenant-apiKey or platform-admin identity only; a personal
|
|
33
|
+
# login gets rejected server-side). Ownership is NOT a flag you pass — the server derives it
|
|
34
|
+
# from who's calling: a tenant apiKey auto-attaches its own tenant_id (private to that tenant),
|
|
35
|
+
# a platform-admin identity creates a tenant_id=null template shared across all tenants.
|
|
36
|
+
# Placeholder keys are auto-extracted from {key} in --prompt if --fields is omitted.
|
|
37
|
+
museav templates create --name '演唱会海报' --prompt '{artist} 在 {city} 的演唱会海报' --ratio 9:16
|
|
38
|
+
|
|
39
|
+
# Reverse-engineer a prompt from an existing image (stdout: English prompt only).
|
|
40
|
+
# This READS the image and nothing else — it will NOT build a template. Passing any
|
|
41
|
+
# template-ish flag to the underlying API is a hard 400 since 2026-08-16.
|
|
42
|
+
museav reverse ./photo.png
|
|
43
|
+
|
|
44
|
+
# Chain them: regenerate in the same style
|
|
45
|
+
museav gen --prompt "$(museav reverse ./photo.png)"
|
|
46
|
+
|
|
47
|
+
# Turn an image INTO a reusable template (read image + reverse its text layers +
|
|
48
|
+
# variabilize + create the template, with the original welded on as its reference
|
|
49
|
+
# image). Async by default; stage progress is printed to stderr, template id to stdout.
|
|
50
|
+
museav image-to-template ./poster.jpg --name '暗金演唱会主视觉' --variables title,subject,location
|
|
51
|
+
museav image-to-template ./poster.jpg --no-create # dry run: draft JSON on stdout, nothing created
|
|
52
|
+
|
|
53
|
+
# Upload a file (image/audio/video; type is detected from the bytes, not the extension)
|
|
54
|
+
museav upload ./face.png
|
|
55
|
+
|
|
56
|
+
# List your own (or, if using a tenant apiKey, your tenant's) recent jobs as JSON
|
|
57
|
+
museav jobs --limit 10 --status failed
|
|
58
|
+
|
|
59
|
+
# Tenant-apiKey-only: list the tenant's OWN product catalog / asset library.
|
|
60
|
+
# This data does NOT live on the studio platform — it lives on the tenant's own
|
|
61
|
+
# backend (a different domain), which this CLI calls directly using the same apiKey.
|
|
62
|
+
# Not every tenant has both (or either) endpoint; a 404/401-ish error here means
|
|
63
|
+
# that tenant hasn't opened it up, not a bug. Use this to pick a reference image,
|
|
64
|
+
# then feed its URL into `gen --template <id> --ref <url>` for "pick a product photo
|
|
65
|
+
# + a template" combo generation.
|
|
66
|
+
museav products
|
|
67
|
+
museav assets
|
|
68
|
+
|
|
69
|
+
# Check who you're logged in as and whether the account is affiliated with a tenant
|
|
70
|
+
# (personal login only — apiKey callers get an error, they're already acting as the tenant)
|
|
71
|
+
museav whoami
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Full flag reference: `museav <command> --help`. Full command table and auth details: see [README.md](./README.md).
|
|
75
|
+
|
|
76
|
+
## Failure modes worth knowing
|
|
77
|
+
|
|
78
|
+
- `gen` polls until the job finishes or times out (default 600s controlled by the underlying `generateAndWait`); a timeout throws, it does not hang forever.
|
|
79
|
+
- `jobs --limit`/`--status` are filtered **client-side** — the server always returns your most recent 50 jobs; you cannot page past that.
|
|
80
|
+
- Non-zero exit code + a message on stderr is the only failure signal; there's no separate machine-readable error format on stdout.
|
|
81
|
+
|
|
82
|
+
## Programmatic use (no shell-out)
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { StudioClient } from 'museav-cli'
|
|
86
|
+
|
|
87
|
+
const studio = new StudioClient({ baseUrl: 'https://manager.museav.top', apiKey: process.env.STUDIO_API_KEY! })
|
|
88
|
+
const job = await studio.generateAndWait({ prompt: 'a cat on the moon', ratio: '3:4' })
|
|
89
|
+
console.log(job.cdn_url)
|
|
90
|
+
```
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.0.0 · 2026-08-16
|
|
4
|
+
|
|
5
|
+
**改名:npm 包 `museav-cli`,命令 `museav`。** 产品叫 MUSE AV,命令却叫另一个名字,同一个东西两个叫法——这次统一到产品名。
|
|
6
|
+
|
|
7
|
+
不用 `@museav/cli` 是因为 npm 的 scope 规则:`@<用户名>` 自动可用(旧包 `@kubor/studio-cli` 就是这么来的),而 `@museav` 属于组织 scope,得先在 npmjs.com 建一个同名组织。发布账号是个人的,为一个 CLI 去建公司组织不值当,无 scope 的 `museav-cli` 跟命令名也更一致。
|
|
8
|
+
|
|
9
|
+
- 迁移:`npm uninstall -g` 旧包后 `npm install -g museav-cli`,脚本里的旧命令换成 `museav`,参数和行为完全不变。
|
|
10
|
+
- 配置文件改到 `~/.museav.json`,**旧路径仍会自动读取**(apiKey 明文中台只在创建时给一次,很多人唯一的一份就在那个文件里,直接不读等于逼人重置密钥)。
|
|
11
|
+
- 环境变量新增 `MUSEAV_API_KEY` / `MUSEAV_BASE_URL` / `MUSEAV_NO_WELCOME`;旧的 `STUDIO_*` 继续有效(中台对外文档和已经跑起来的 CI 写的都是旧名,不能说停就停),两个都设时新名优先。
|
|
12
|
+
- 自报身份头新增 `X-Museav-Client`,旧的 `X-Studio-Client` **过渡期继续发**,值统一改成 `museav-cli/<version>`。中台靠这个头把渠道记成 `cli`,两个头一起发是为了让中台能在不中断渠道统计的前提下切过去;等所有客户端升上来、中台停读旧头之后,这里再把旧头删掉。同时显式带上 `User-Agent: museav-cli/<version>`(中台有 UA 兜底匹配,Node 默认的 `node` 什么信息都没有)。
|
|
13
|
+
|
|
14
|
+
**新增 `image-to-template <file|url>`**:一张图 → 一个可复用的图片模板。读图(SCULPT)+ 文字层逆向 + 变量化 + 建模板,原图自动转存并焊进模板当参考图,所以换了文字还能出同款。支持 `--no-create`(只看草稿)、`--name` / `--slug` / `--category`、`--variables` 收窄变量白名单、`--labels` 把通用变量映射成你的业务叫法、`--async`。异步时按「接收图片 → 解析图片 → 抽取文字层 → 创建模板」逐阶段打进度,不是干转圈。
|
|
15
|
+
|
|
16
|
+
- `reverse` 保持**纯读图**不变。中台 2026-08-16 把读图和做模板拆成了两个接口,`/api/reverse` 现在收到任何模板类参数都会 400——本 CLI 的 `reverse` 一直只发图片,不受影响。
|
|
17
|
+
- `upload` 明确成通用素材上传:图片 / 音频 / 视频都收,类型按字节内容判定,上限分别是 8MB / 20MB / 50MB,输出里会标出识别到的类型。上传的 multipart 现在带上原文件名,出问题时日志里认得出是哪个文件。
|
|
18
|
+
|
|
19
|
+
## 1.3.0
|
|
20
|
+
|
|
21
|
+
- 新增 `templates create`:命令行直接建图片模板,不用再依赖网页后台。归属不是自己传的参数——服务端根据调用身份自动决定:租户 apiKey 建的自动归该租户(其他租户看不到),平台管理员账号建的是 `tenant_id` 为空的平台共享模板,个人登录会被拒绝。不传 `--fields` 时会自动从 `--prompt` 里的 `{key}` 占位符提取字段。
|
|
22
|
+
- 修复:`templates create --category <x>` 的值被静默吞掉——父命令 `templates` 也声明了同名的 `--category`(列表过滤用),commander 会在分发到 `create` 子命令之前把这个参数值算到父命令头上。用 `program.enablePositionalOptions()` 修复。
|
|
23
|
+
- 新增 `products` / `assets`:查所属租户自己的产品目录 / 素材库,数据在租户自己的后台(不在 studio 中台),仅租户 apiKey 身份可用。新增 `TenantClient`,从内置的小映射表(`hym`、`mzmeso`)或 `config --tenantBaseUrl` 解析租户后台域名。
|
|
24
|
+
|
|
25
|
+
## 1.2.0
|
|
26
|
+
|
|
27
|
+
- `gen --template <id> --fields '{"key":"值"}'`: generate from an image template. Same black-box philosophy as `--skill` — the prompt template is expanded server-side and never sent back — but deterministic placeholder substitution instead of a chat-model expansion, so no chat cost. Template list comes from your own tenant's templates plus platform-shared ones.
|
|
28
|
+
- `templates` command: list available image templates (`--category` to filter), mirrors `skills`.
|
|
29
|
+
- Fixed: `-r, --ratio` had a hardcoded `3:4` default that silently overrode a skill's or template's own aspect ratio even when you didn't ask for one. It's now unset unless you pass it explicitly.
|
|
30
|
+
|
|
31
|
+
## 0.4.0
|
|
32
|
+
|
|
33
|
+
- `whoami`: show the logged-in account and its tenant affiliation (if the account was registered via a tenant's invite code), using the existing `/api/me` endpoint. `login` now prints this automatically right after signing in.
|
|
34
|
+
- Update check: `update-notifier` checks npm for a newer version at most once per 12h and prints a notice — no more silently running stale versions.
|
|
35
|
+
- `--version` now reads from `package.json` at runtime instead of a hardcoded string in `index.ts` (the two had already drifted out of sync once before 0.3.0).
|
|
36
|
+
|
|
37
|
+
## 0.3.0
|
|
38
|
+
|
|
39
|
+
- `jobs`: query your own (or your tenant's) recent image-generation history. `--limit`/`--status` are filtered client-side — the server always returns the 50 most recent jobs, no pagination.
|
|
40
|
+
- Fixed a bug where `gen` (and the new `jobs`) would crash before ever calling the API: the `withClient` wrapper dropped the `options` object for any command with flags but no positional argument.
|
|
41
|
+
|
|
42
|
+
## 0.2.0
|
|
43
|
+
|
|
44
|
+
- `login`/`logout`: device-authorization flow for individual platform users — no need to request a tenant apiKey just to generate images from your own account.
|
|
45
|
+
- Config file (`~/.studio-image.json`) now stored with `0600` permissions (it can hold a personal login token, not just a tenant apiKey).
|
|
46
|
+
|
|
47
|
+
## 0.1.0
|
|
48
|
+
|
|
49
|
+
- Initial release: `gen`, `reverse`, `upload`, `models`, `balance`, `config` — a CLI client for the studio image-generation platform, authenticated via tenant apiKey.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 webkubor
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|