@ alive- game/ alive- tagger
元素选择和源标记为活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活 启用点击到选择带有源文件信息的UI元素,使克洛德能够准确知道用户指的是哪个组件并归档.
特征
- JSX 源代码:在构建时将源文件信息(文件名,行号,列号)附加到每个 DOM 元素中
- 元素选择: 点击到选择元素的客户端脚本, 有视觉反馈( 由 workbench 选择按钮激活)
- 后桥: 将选定的元素上下文发送给克洛德集成的父框架
安装
# In your Vite React project
bun add @alive-game/alive-tagger
使用量
虚拟插件( 需要)
将插件添加到您的 vite.config.ts数字 :
import { aliveTagger } from "@alive-game/alive-tagger"
export default defineConfig(({ mode }) => ({
plugins: [
react(),
mode === "development" && aliveTagger()
].filter(Boolean),
}))
客户端脚本( 可选 - 用于 Iframe 选择 UI)
客户端脚本提供点击到选择并带有视觉反馈. 导入时自动初始化 :
// In your app entry point (only needed if in iframe)
import "@alive-game/alive-tagger/client"
或通过 HTML 注入 :
<script type="module">
import { initAliveTagger } from "@alive-game/alive-tagger/client"
initAliveTagger()
</script>
如何运作
1. 联合来文X来源标签(Vite插件)
插件拦截 React 的 jsx-dev-runtime 并包装 jsxDEV 在 DOM 节点上存储源信息的函数
// Every DOM element gets this attached via Symbol:
element[Symbol.for("__aliveSource__")] = {
fileName: "client/pages/Index.tsx",
lineNumber: 42,
columnNumber: 8,
displayName: "Button"
}
// Global map for reverse lookups:
window.aliveSourceMap = Map<string, Set<WeakRef<Element>>>
2. 元素选择( Client 脚本)
在 Iframe 中运行时 :
- 启动: 父框架选项
TAGGER_ACTIVATE(工作台选择按钮); 光标变为横线 - 缓冲: 以绿色边框和标签突出显示源信息元素
ComponentName · path/to/file.tsx:line - 点击: 抓取元素上下文,并通过 Message 发送到父框架
3. 信后通信
选定元素上下文发送给父框架 :
window.parent.postMessage({
type: "alive-element-selected",
context: {
fileName: "client/pages/Index.tsx",
lineNumber: 42,
columnNumber: 8,
displayName: "Button",
html: "<button class='...'>Click me</button>",
tagName: "button",
className: "btn-primary",
id: "submit-btn",
parentComponents: ["Form", "Page"]
}
}, "*")
API 参考
插件选项
interface AliveTaggerOptions {
/** Enable source tagging (default: true in dev mode) */
enabled?: boolean
/** Enable debug logging */
debug?: boolean
}
aliveTagger({ enabled: true, debug: false })
类型
import {
SOURCE_KEY, // Symbol.for("__aliveSource__")
ELEMENT_SELECTED_MESSAGE_TYPE, // "alive-element-selected"
type SourceInfo,
type ElementSelectedContext,
type ElementSelectedMessage,
type AliveTaggerOptions,
} from "@alive-game/alive-tagger"
工具函数
import {
getElementSource, // Get source info from element
hasSourceInfo, // Check if element has source info
formatSourceLocation, // Format as "file.tsx:42:8"
isElementSelectedMessage, // Type guard for messages
} from "@alive-game/alive-tagger"
// Example usage
const source = getElementSource(document.querySelector("button"))
if (source) {
console.log(formatSourceLocation(source)) // "client/pages/Index.tsx:42:8"
}
客户端函数
import { initAliveTagger } from "@alive-game/alive-tagger/client"
// Initialize selector (auto-called on import, but can be manual)
const cleanup = initAliveTagger()
// Later: cleanup()
建筑
┌─────────────────────────────────────────────────────────────────────────┐
│ Alive (terminal.alive.best) │
│ ┌──────────────────────┐ ┌──────────────────────────────────────────┐ │
│ │ Chat Interface │ │ Workbench Component │ │
│ │ │ │ - Listens for 'alive-element-selected' │ │
│ │ Shows selected │◀─┤ - Displays source info to user │ │
│ │ element context │ │ - Injects into next Claude message │ │
│ └──────────────────────┘ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
▲
│ postMessage
┌─────────────────────────────────────────────────────────────────────────┐
│ User Site (in preview iframe) │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ alive-tagger plugin (Vite) │ │
│ │ - Intercepts jsx-dev-runtime │ │
│ │ - Attaches Symbol.for('__aliveSource__') to every DOM element │ │
│ │ - Maintains window.aliveSourceMap for lookups │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ alive-tagger/client (optional) │ │
│ │ - Handles click-to-select (button-activated) │ │
│ │ - Visual highlight on hover │ │
│ │ - Posts context to parent frame │ │
│ └───────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
比较:活捉对反应抓取
| 特性 | 活猎手 | 反应抓取 |
|---|---|---|
| 方针 | Vite 插件 + 客户端 | 运行时纤维转动 |
| 数据附件 | 通过 refs 构建时间 | 运行时间纤维检查 |
| 符号密钥 | __aliveSource__ | __jsxSource__ |
| 选择 UI | 内建( 按钮激活点击) | 内建 |
| 通讯 | 邮件 | HTTP 本地主机: 4567 |
| 信封要求 | 无( dev 模式自动) | 无 |
| 设计用途 | 活着的 Iframe | 克劳德特工SDK CLI |
与活着的融合
活捉者与"活捉"的工作台预览集成. 当用户激活选定的按钮并单击元素时:
- 工作室接收邮件数字 :
Workbench.tsx财务报告和审定财务报表WorkbenchMobile.tsx听着alive-element-selected信件 - 通过WorkbenchContext传播背景: 选择通过
useWorkbenchContext() - 聊天输入自动填充: 选定的元素格式为
@ComponentName in src/path/file.tsx:lineNumber插入到聊天输入中 - 用户可以发送到 Claude: 参考文献帮助克洛德准确了解要修改的元素/组件
关键文件 :
apps/web/features/chat/lib/workbench-context.tsx- 与setSelectedElement财务报告和审定财务报表registerElementSelectHandlerapps/web/features/chat/components/workbench/Workbench.tsx- 听后Message,电话setSelectedElementapps/web/app/chat/page.tsx- 登记处理器,将选择插入聊天输入
凯迪配置
HMR 要在工作底盘内正常工作, 预览域 绝对不能 使用情况 forward_auth。认证检查干扰了WebSocket的连接,并导致iframe每几秒钟闪出/重装一次.
预览域 Caddy 配置必须生成而不包含 forward_auth 避免这个问题.
发展
# Build
bun run build
# Watch mode
bun run dev
# Type check
bun run type-check
# Run tests
bun run test
文件
packages/alive-tagger/
├── src/
│ ├── index.ts # Main exports (plugin + utilities)
│ ├── plugin.ts # Vite plugin
│ ├── client.ts # Client selection script
│ └── types.ts # TypeScript types
├── dist/ # Built output
├── package.json
├── tsconfig.json
└── tsup.config.ts
安全考虑
- 只发展: 来源标记只活跃于dev模式
- 无生产影响: 插件在生产架构中不做任何工作
- 文件路径: 已曝光的相对路径(不是完整的系统路径)
- 节点已过滤: 图书馆内部没有标记
许可证
麻省理工学院