Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/yummy-adults-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@varo-ui/cli": major
---

Support third-party local and HTTP registries and self-contained shadcn-vue exports. Registry resolution now returns a Promise; await resolveRegistryItems().

Reject lossy non-UTF-8 exports and conflicting file/ancestor destinations before emitting an export or writing consumer files, while preserving byte-for-byte binary installs.

Accept standard shadcn-vue catalog and item definitions for local/HTTP installation and self-contained export, resolve consumer aliases, and relocate imports between installed Vue/TypeScript files without requiring Varo-specific manifest fields.
48 changes: 47 additions & 1 deletion apps/docs/blocks/build-your-own.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ pnpm test

# 打包 CLI 后在临时目录验证安装
pnpm --filter @varo-ui/cli build
pnpm dlx @varo-ui/cli add --target weapp blocks/status-filter
pnpm dlx @varo-ui/cli add --registry ./registry --target weapp blocks/status-filter
```

确认:
Expand All @@ -269,8 +269,54 @@ pnpm dlx @varo-ui/cli add --target weapp blocks/status-filter
- 需要覆盖时使用显式 force 流程
- 安装结果不带私有域名、token、内部任务号

### 独立发布第三方 Registry

不必先贡献回 Varo。把 `registry/` 目录及其所有传递依赖的 manifest 和源码部署到自己的静态站点,即可从业务项目安装:

```bash
pnpm dlx @varo-ui/cli add --registry https://ui.example.com/registry/ --target weapp blocks/status-filter
```

CLI 从该地址下的 `blocks/status-filter/registry.json` 读取元数据,按 `files.from` 去掉 `registry/` 前缀后的路径下载源码。普通和 target-specific 的 `registryDependencies` 都在同一个 Registry 内解析;缺失依赖会报错,不会回退到官方 Registry。也可以用 `--registry ./registry` 验证本地目录。

只安装信任的源码。远端地址只支持 HTTP(S),不能携带凭证、查询参数或 fragment,不跟随重定向;单个响应上限为 10 MiB、30 秒。安装保留 `src/` 路径限制、符号链接检查、文件冲突检查和失败回滚,不自动安装 npm 依赖。

### 直接使用标准 shadcn-vue 清单

也支持标准 `registry.json` 目录(`name`、`homepage`、`items`)和独立 `registry-item.json`,无需改写成 Varo 的 `from/to/targets`:

```bash
pnpm dlx @varo-ui/cli add --registry ./registry.json hello-world
pnpm dlx @varo-ui/cli add --registry ./hello-world.json hello-world
pnpm dlx @varo-ui/cli add --registry https://ui.example.com/r/registry.json hello-world
pnpm dlx @varo-ui/cli export --registry ./registry.json hello-world > hello-world.json
```

`files.path` 相对清单目录读取;已包含 `content` 的发布条目无需源文件。组件、UI、hook、lib 默认分别进入 `src/components`、`src/components/ui`、`src/composables`、`src/lib`,保留组件子目录;显式 `target` 优先,但必须留在 `src/`。也会读取消费项目的 `components.json` 和 TypeScript/JSONC 别名配置,并用 AST 重写随文件移动而变化的 JS/TS/Vue script 导入。

标准清单默认 H5;Weapp 条目需明确声明 `meta.varo.target: "weapp"`。目录内依赖按名称解析,独立条目可读取同目录的 `<name>.json`,跨 Registry 依赖使用明确的 HTTP(S) 条目 URL。支持 `registry:block/component/ui/hook/composable/lib/page/file/theme/style` 的文件语义;`page/file` 文件必须提供明确目标。不支持 `registry:base/font`、框架转换或 npm 自动安装;`css`、`cssVars`、`tailwind`、`envVars` 与样式继承 `extends` 会明确报错,不会静默忽略,也不会自动回退到公共 Registry。

### 供 shadcn-vue 生态安装

导出一个条目时会内联当前 target 的全部传递依赖和源码,生成符合 [shadcn-vue Registry 协议](https://www.shadcn-vue.com/docs/registry/registry-item-json) 的 JSON:

```bash
mkdir -p public/r
pnpm dlx @varo-ui/cli export --registry ./registry --target weapp blocks/status-filter > public/r/status-filter.json
# 部署 public/ 后,在已配置 components.json 和 TypeScript 路径别名的消费项目执行:
pnpm dlx shadcn-vue@latest add https://ui.example.com/r/status-filter.json
```

输出采用 `registry:file`、内联 `content` 和显式 `~/src/...` 安装路径,可由 shadcn-vue 以及委托它安装的生态工具消费;已用 shadcn-vue 2.8.2 验证。Varo 的 `add --registry` 也可以直接读取导出的单项 JSON。

导出要求文件内容为有效 UTF-8;非 UTF-8 字节会明确报错,不会被替换字符静默损坏。`add` 仍按原始字节复制二进制资源。安装与导出都会拒绝“同一路径既是文件又是其他文件的父目录”的冲突,包括仅大小写不同的路径冲突。

H5 与 Weapp 必须分别导出。`meta.varo.target` 记录目标,但第三方安装器不会替你检查运行时,也不会把 Vue 转成 Wevu;消费工程仍需安装匹配的依赖并接入主题。CLI API 调用方须使用 `await resolveRegistryItems(...)`,现在本地与远端解析均返回 Promise。

## 10. 贡献回 Varo

这是可选的上游贡献流程,不是发布第三方 Registry 的前置条件。

提交前过一遍隐私与可移植清单:

- [ ] 无真实 API / 凭证 / 私有 URL
Expand Down
48 changes: 47 additions & 1 deletion apps/docs/en/blocks/build-your-own.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ pnpm test

# pack the CLI and install into a temporary fixture
pnpm --filter @varo-ui/cli build
pnpm dlx @varo-ui/cli add --target weapp blocks/status-filter
pnpm dlx @varo-ui/cli add --registry ./registry --target weapp blocks/status-filter
```

Confirm:
Expand All @@ -269,8 +269,54 @@ Confirm:
- overwrite requires an explicit force path
- installed files contain no private domains, tokens, or internal IDs

### Publish an independent registry

No upstream contribution is required. Host the `registry/` directory, including manifests and source for every transitive dependency, on your own static site:

```bash
pnpm dlx @varo-ui/cli add --registry https://ui.example.com/registry/ --target weapp blocks/status-filter
```

The CLI loads `blocks/status-filter/registry.json` below that URL. Source URLs use `files.from` with the leading `registry/` removed. Both ordinary and target-specific `registryDependencies` resolve within the selected registry; missing dependencies fail rather than falling back to Varo's bundled registry. Use `--registry ./registry` to verify a local directory.

Only install sources you trust. Remote roots use HTTP(S), cannot contain credentials, queries, or fragments, and do not follow redirects. Each response is limited to 10 MiB and 30 seconds. Installs retain `src/` confinement, symlink checks, collision checks, and rollback. npm dependencies are reported, not installed.

### Use standard shadcn-vue manifests directly

Standard `registry.json` catalogs (`name`, `homepage`, `items`) and individual `registry-item.json` definitions are accepted without adding Varo `from/to/targets` fields:

```bash
pnpm dlx @varo-ui/cli add --registry ./registry.json hello-world
pnpm dlx @varo-ui/cli add --registry ./hello-world.json hello-world
pnpm dlx @varo-ui/cli add --registry https://ui.example.com/r/registry.json hello-world
pnpm dlx @varo-ui/cli export --registry ./registry.json hello-world > hello-world.json
```

`files.path` is relative to the manifest directory; published files with inline `content` need no backing source file. Components, UI, hooks, and libs default to `src/components`, `src/components/ui`, `src/composables`, and `src/lib`, preserving nested component directories. Explicit `target` wins but must stay inside `src/`. Consumer `components.json` and TypeScript/JSONC aliases are honored, and JS/TS/Vue script imports between relocated files are rewritten through AST parsing.

Standard manifests default to H5; Weapp items must declare `meta.varo.target: "weapp"`. Catalog dependencies resolve by name, individual items can load sibling `<name>.json` files, and cross-registry dependencies use explicit HTTP(S) item URLs. Supported file semantics cover `registry:block/component/ui/hook/composable/lib/page/file/theme/style`; `page/file` entries require an explicit target. `registry:base/font`, framework conversion, and npm auto-install are unsupported. `css`, `cssVars`, `tailwind`, `envVars`, and style inheritance through `extends` fail explicitly rather than being silently ignored. There is no implicit public-registry fallback.

### Install through the shadcn-vue ecosystem

Exporting one item inlines its selected target's complete dependency closure and source into a [shadcn-vue registry item](https://www.shadcn-vue.com/docs/registry/registry-item-json):

```bash
mkdir -p public/r
pnpm dlx @varo-ui/cli export --registry ./registry --target weapp blocks/status-filter > public/r/status-filter.json
# Host public/, then run in a consumer configured with components.json and TypeScript path aliases:
pnpm dlx shadcn-vue@latest add https://ui.example.com/r/status-filter.json
```

The payload uses `registry:file`, inline `content`, and explicit `~/src/...` destinations. shadcn-vue and tools delegating installation to it can consume this JSON; compatibility was exercised with shadcn-vue 2.8.2. Varo's `add --registry` can also read the exported single-item JSON directly.

Exports require valid UTF-8 contents; non-UTF-8 bytes fail explicitly instead of being silently replaced. `add` still copies binary assets byte-for-byte. Installation and export both reject destinations where a file is also another file's parent directory, including case-insensitive conflicts.

Export H5 and Weapp separately. `meta.varo.target` records the target, but external installers do not enforce it or convert Vue to Wevu. Consumers still need matching runtime dependencies and theme setup. Programmatic CLI consumers must use `await resolveRegistryItems(...)`: both local and remote resolution now return a Promise.

## 10. Contribute to Varo

Upstream contribution is optional, not a prerequisite for publishing a third-party registry.

Privacy and portability checklist:

- [ ] no real APIs / credentials / private URLs
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/en/guide/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Components land in `src/components/ui/*`; blocks land in `src/components/blocks/

The H5 registry covers all 56 runtime component families. The mini-program registry covers 45 high-consensus families. Copy-owned mini-program renderers ship as target-specific native Wevu SFCs that compile directly to WXML/WXSS/JSON; pure adapters may re-export target primitives, and only types, pure functions, and headless primitives are shared across targets.

Third-party components do not need to be merged upstream: use `add --registry <local-directory-or-http(s)-url>` to install an independent registry. Authors can also use `export --target h5|weapp <item>` to generate JSON for shadcn-vue. See [Publish an independent registry](/en/blocks/build-your-own#publish-an-independent-registry) for layouts, publishing commands, and runtime boundaries.

## Agent streaming

`@varo-ui/ai` is model-provider neutral. A backend emits `message.start`, `text.delta`, `reasoning.*`, `tool.*`, `approval.*`, `message.end`, and `done` events. H5 can connect Fetch/SSE; a mini program can feed `wx.request({ enableChunked: true })` chunks into `createAgentSseEventSource()`.
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/guide/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pnpm dlx @varo-ui/cli add --target h5 button select card components/agent-ui

H5 Registry 覆盖 56 个 runtime 组件族;小程序 Registry 覆盖 45 个高共识组件族。copy-owned 小程序 renderer 均以 target-specific 原生 Wevu SFC 交付并直接编译为 WXML/WXSS/JSON;纯 adapter 可重导出目标 primitives,双端只共享类型、纯函数和 headless primitives。

第三方组件无需先合并到 Varo:用 `add --registry <本地目录或 HTTP(S) 地址>` 安装独立 Registry。作者也可以用 `export --target h5|weapp <条目>` 生成供 shadcn-vue 安装的 JSON。完整目录约定、发布命令和运行时边界见 [独立发布第三方 Registry](/blocks/build-your-own#独立发布第三方-registry)。

## Agent 流式接入

`@varo-ui/ai` 不绑定模型厂商。服务端只需输出 `message.start`、`text.delta`、`reasoning.*`、`tool.*`、`approval.*`、`message.end` 与 `done` 事件;H5 可接 Fetch/SSE,小程序可把 `wx.request({ enableChunked: true })` 的分块交给 `createAgentSseEventSource()`。
Expand Down
2 changes: 1 addition & 1 deletion apps/realworld-weapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"postinstall": "wv prepare -p weapp",
"prepare:weapp": "wv prepare -p weapp",
"test": "vitest run --passWithNoTests",
"typecheck": "vue-tsc --noEmit -p .weapp-vite/tsconfig.app.json",
"typecheck": "vue-tsc --noEmit -p tsconfig.typecheck.json",
"verify:migration": "node scripts/verify-migration.mjs"
},
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion apps/realworld-weapp/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"references": [
{
"path": "./.weapp-vite/tsconfig.app.json"
"path": "./tsconfig.typecheck.json"
},
{
"path": "./.weapp-vite/tsconfig.server.json"
Expand Down
10 changes: 10 additions & 0 deletions apps/realworld-weapp/tsconfig.typecheck.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "./.weapp-vite/tsconfig.app.json",
"compilerOptions": {
"paths": {
"@/*": ["./src/*"],
"weapp-vite/typed-components": ["./.weapp-vite/typed-components.d.ts"],
"@varo-ui/theme/weapp": ["../../packages/theme/src/weapp.ts"]
}
}
}
15 changes: 15 additions & 0 deletions apps/realworld-weapp/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { resolve } from 'node:path'
import { defineConfig } from 'vitest/config'

export default defineConfig({
test: {
environment: 'node',
},
resolve: {
alias: {
'@': resolve(import.meta.dirname, 'src'),
'src': resolve(import.meta.dirname, 'src'),
'@varo-ui/theme': resolve(import.meta.dirname, '../../packages/theme/src'),
},
},
})
Loading