# UI Context Capture

[English](./README.md)

`ui-context-capture` 是一个框架无关的 Vite UI 上下文采集插件。直接在页面中选择元素，即可获得 DOM 信息、框架组件层级、源码位置和匹配的 CSS 规则，减少在 DevTools 中反复定位的时间。

插件仅在 Vite 开发服务器运行期间生效，不会向生产构建注入客户端运行时。

## 功能特性

- 浮动按钮和快捷键控制采集模式
- 鼠标悬停时高亮目标元素
- 使用标签、ID 和最多两个 class 生成精简元素签名
- 通过可选框架 integration 获取组件名称、组件栈和源码位置
- 在控制台输出 DOM 信息、选择器路径、HTML 片段和匹配的 CSS 规则
- 通过精简浮层填写需求并复制适合发送给模型的上下文
- 独立的 Vue 3 与 Vue 2.7 integration，可消费外部提供的源码位置元数据
- 框架无关核心以及公开的 adapter/integration 扩展协议
- 支持 Vite 4、5、6、7 和 8

## 安装

```bash
pnpm add -D ui-context-capture
```

如需使用下文展示的 Vue 精确源码位置配置，请另外安装：

```bash
pnpm add -D vite-plugin-vue-inspector
```

也可以使用 npm 或 Yarn：

```bash
npm install -D ui-context-capture
yarn add -D ui-context-capture
```

## 使用方式

在 Vite 配置中注册插件：

```ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Inspector from 'vite-plugin-vue-inspector'
import { uiContextCapture } from 'ui-context-capture/vite'
import { vueIntegration } from 'ui-context-capture/vue'

export default defineConfig({
  plugins: [
    vue(),
    Inspector({
      enabled: false,
      toggleButtonVisibility: 'never',
      toggleComboKey: false,
      cleanHtml: true,
    }),
    uiContextCapture({
      integrations: [vueIntegration()],
    }),
  ],
})
```

### Vue 2.7

Vue 2.7 应用使用独立 integration 和 Vite 的 Vue 2 插件：

```bash
pnpm add -D @vitejs/plugin-vue2
```

```ts
import vue2 from '@vitejs/plugin-vue2'
import Inspector from 'vite-plugin-vue-inspector'
import { defineConfig } from 'vite'
import { uiContextCapture } from 'ui-context-capture/vite'
import { vue2Integration } from 'ui-context-capture/vue2'

export default defineConfig({
  plugins: [
    vue2(),
    Inspector({
      vue: 2,
      enabled: false,
      toggleButtonVisibility: 'never',
      toggleComboKey: false,
      cleanHtml: false,
    }),
    uiContextCapture({
      integrations: [vue2Integration()],
    }),
  ],
})
```

Inspector 是可选的。未注册时，Vue 2.7 adapter 仍会从 runtime metadata 获取组件名称、文件和 `$parent` 组件栈；精确元素行列号需要保留 `data-v-inspector` attribute。

启动开发服务器后，点击页面右下角的浮动按钮进入采集模式。鼠标悬停元素时会显示高亮框，点击元素即可采集上下文。采集模式会抑制目标页面元素的原生 pointer、mouse 和 click 行为；更早在 `window` 或 `document` 上执行的捕获监听器无法被事后阻止。

快捷键：

- `Shift + C`：开启或关闭采集模式
- `Escape`：退出采集模式

选中元素后，高亮框和浮层会在页面滚动或布局变化时跟随目标。关闭浮层会退出采集模式；点击 **Copy** 会复制上下文并退出。

点击 **Copy** 会生成精简的文本摘要：

```text
You are a senior frontend engineer. Use the UI context below to implement the requested change. Treat the `request` field as the user's primary instruction. Preserve unrelated behavior. If information is insufficient, explain what is missing.

element: article#featured-card.card.card-featured
componentName: ExampleCard
componentStack: ExampleCard > HomePage > App
sourceLocation: src/components/ExampleCard.vue:12:5
request: 调整移动端间距
```

内置上下文字段为空时会自动省略；已配置且存在的自定义属性即使值为空也会保留。浏览器控制台仍会输出完整上下文，包括 DOM 路径、HTML 片段和匹配的 CSS 规则。

元素签名最长为 80 个字符，最多包含前两个 class。它用于提供紧凑、易读的元素标识，不保证可以直接作为 CSS 选择器；完整的 class 列表仍可在控制台上下文中查看。

启用截图后，选择元素并点击 **Capture**，PNG 会保存到 `.ucc/screenshots`，同时在浮层中显示缩略图。**Retake** 会更新当前预览和路径，**Remove** 会从当前复制提示词中移除截图。插件不会自动截图。

## 配置项

```ts
uiContextCapture({
  enabled: true,
  integrations: [vueIntegration()],
  contextPrompt: 'You are a senior frontend engineer. Use the UI context below to implement the requested change. Treat the `request` field as the user\'s primary instruction. Preserve unrelated behavior. If information is insufficient, explain what is missing.',
  customAttributes: ['data-scope', 'aa-bb'],
  shortcuts: {
    toggleKey: 'c',
    exitKey: 'Escape',
  },
  initialActive: false,
  trigger: {
    visible: true,
    position: 'bottom-right',
    offset: 16,
    size: 40,
  },
  popover: {
    width: 320,
  },
  screenshot: {
    enabled: false,
    cacheDir: '.ucc/screenshots',
    maxSizeMb: 10,
    retention: 50,
    backgroundColor: '#ffffff',
    // token: 'local-dev-token',
  },
  appearance: {
    theme: 'dark',
    accentColor: '#22c55e',
  },
  consoleLog: true,
})
```

| 配置 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `enabled` | `boolean` | `true` | 是否在 Vite 开发环境注入客户端运行时。 |
| `integrations` | `UiContextCaptureIntegration[]` | `[]` | 显式启用的框架集成，按照配置顺序执行。 |
| `contextPrompt` | `string` | 见上文 | 复制文本的前置提示词；传入非空字符串会替换默认提示词，设为 `''` 可关闭提示词。 |
| `customAttributes` | `string[]` | `[]` | 将匹配的元素属性加入浮层、复制文本和控制台上下文。 |
| `shortcuts` | `ShortcutOptions` | `{ toggleKey: 'c', exitKey: 'Escape' }` | 替换或关闭切换键与退出键；切换键固定与 Shift 组合。 |
| `initialActive` | `boolean` | `false` | 初始化完成后立即进入采集模式。 |
| `trigger` | `TriggerOptions` | 见下文 | 配置浮动按钮显隐、所在角落、偏移和尺寸。 |
| `popover` | `PopoverOptions` | `{ width: 320 }` | 配置浮层宽度，单位为像素。 |
| `screenshot` | `ScreenshotOptions` | `{ enabled: false, cacheDir: '.ucc/screenshots', maxSizeMb: 10, retention: 50, backgroundColor: '#ffffff' }` | 配置手动 PNG 截图、画布底色和旧文件清理；设为 `transparent` 可保留透明背景。 |
| `screenshot.token` | `string` | 关闭 | 可选的截图上传固定 token；未配置时截图上传不要求 token。 |
| `appearance` | `AppearanceOptions` | `{ theme: 'dark', accentColor: '#22c55e' }` | 配置主题和统一强调色。 |
| `consoleLog` | `boolean` | `true` | 是否向控制台输出成功采集的上下文；错误仍会输出。 |

浮动按钮位置支持 `top-left`、`top-right`、`bottom-left` 和 `bottom-right`。按钮会吸附到对应的视口左侧或右侧；`offset.y` 控制距顶部或底部的距离，水平 offset 不再参与定位。`size` 表示 hover、键盘聚焦和激活时的展开尺寸，限制在 32–64px；空闲尺寸自动取其 70%，最小为 24px。浮层宽度限制在 240–480px，偏移限制在 0–256px。

将任一快捷键设置为 `false` 即可单独关闭。主题支持 `dark`、`light` 和 `auto`；`auto` 会实时跟随 `prefers-color-scheme`。强调色会统一作用于激活按钮、高亮框、字段标签、Copy 按钮和焦点环。
客户端会为强调色控件自动选择黑色或白色文字。如果指定颜色与浅色或深色主题背景的对比度不足，对应主题会改用可见的默认强调色。

核心不会自动探测或加载框架。Vue 3 使用 `vueIntegration()`，Vue 2.7 使用 `vue2Integration()`；两者都只读取对应 runtime metadata，不会安装或配置源码检查插件。

需要精确元素行列号时，应由应用自行安装并注册 `vite-plugin-vue-inspector`。Vue adapter 同时支持 DOM 上的 `data-v-inspector` 和 `cleanHtml: true` 生成的隐藏 VNode 元数据。没有构建期源码元数据时，Vue runtime 通常只能提供组件文件，不能推导元素在模板中的精确行号。

integration 名称必须唯一。运行时 adapter 按配置顺序执行，第一个返回非 `null` 上下文的 adapter 生效；单个 adapter 出错不会阻断 DOM 上下文采集。

自定义属性按名称精确匹配，并按照配置顺序展示。目标元素缺少的属性会被省略，已存在但值为空的属性仍会保留。

启用截图后，可以通过 `screenshot.token` 要求上传请求携带固定 token。未配置、空字符串或仅包含空白的值都会关闭 token 校验。由于 token 会注入开发页面，它适合作为本地开发访问门槛，不应当当作生产环境密钥。

`contextPrompt` 仅加入复制文本，不会显示在浮层或写入浏览器控制台上下文。设为 `''`（或仅包含空白字符）时会关闭提示词，只复制上下文。浮层中的 `request` 输入会作为模型需要优先处理的用户需求复制。

截图保存仅适用于 Vite 插件集成，不适用于手动初始化客户端。服务端接受 PNG 上传，并按配置决定是否校验 token，由服务端生成文件名，将存储限制在项目根目录内，并只保留配置数量的最新截图。`screenshotPath` 使用相对于项目的路径，方便本地 coding agent 检查而不会暴露绝对机器路径。

## 手动初始化

自定义注入场景可以使用独立的客户端入口：

```ts
import { init } from 'ui-context-capture'

init({
  contextPrompt: 'Please help implement the requested UI change using the context below.',
  customAttributes: ['data-scope', 'aa-bb'],
  shortcuts: { toggleKey: 'g', exitKey: 'Escape' },
  appearance: { theme: 'auto', accentColor: '#2563eb' },
})
```

普通 Vite 项目建议使用插件接入，由插件自动处理仅限开发环境的注入逻辑。

手动初始化时如需 Vue 上下文：

```ts
import { init } from 'ui-context-capture'
import { createVueAdapter } from 'ui-context-capture/vue/runtime'

init({}, {
  adapters: [createVueAdapter()],
})
```

Vue 2.7 手动初始化时改为从 `ui-context-capture/vue2/runtime` 导入 `createVue2Adapter`。

## 自定义集成

integration 用于组合构建期 Vite 插件和浏览器端 adapter。`clientModule` 指向的模块必须默认导出同步工厂函数并返回 `ContextAdapter`；`clientOptions` 必须可 JSON 序列化。

```ts
uiContextCapture({
  integrations: [{
    name: 'my-framework',
    clientModule: '/src/my-framework-adapter.ts',
  }],
})
```

## 环境要求

- Vite `^4.0.0`、`^5.0.0`、`^6.0.0`、`^7.0.0` 或 `^8.0.0`
- Vue 为可选依赖；`vueIntegration()` 支持 Vue `^3.0.0`，`vue2Integration()` 支持 Vue `^2.7.0`
- `vite-plugin-vue-inspector` 不再是运行时或 peer 依赖；应用可自行安装并注册，用于获取精确 Vue 元素位置

## 参与开发

仓库初始化、本地示例、构建命令和发布说明参见[开发指南](./docs/development.md)。

## 许可证

[MIT](./LICENSE)
