npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@alive-game/alive-tagger

v0.1.1

Published

Element selection and source tagging for Claude Bridge sandbox

Downloads

448

Readme

@webalive/alive-tagger

Element selection and source tagging for Claude Bridge sandbox. Enables click-to-select UI elements with source file information, allowing Claude to know exactly which component and file the user is referring to.

Features

  • JSX Source Tagging: Attaches source file info (fileName, lineNumber, columnNumber) to every DOM element at build time
  • Element Selection: Client script for Cmd/Ctrl+Click element selection with visual feedback
  • PostMessage Bridge: Sends selected element context to parent frame for Claude integration

Installation

# In your Vite React project
bun add @webalive/alive-tagger

Usage

Vite Plugin (Required)

Add the plugin to your vite.config.ts:

import { aliveTagger } from "@webalive/alive-tagger"

export default defineConfig(({ mode }) => ({
  plugins: [
    react(),
    mode === "development" && aliveTagger()
  ].filter(Boolean),
}))

Client Script (Optional - for iframe selection UI)

The client script provides Cmd/Ctrl+Click selection with visual feedback. It's automatically initialized when imported:

// In your app entry point (only needed if in iframe)
import "@webalive/alive-tagger/client"

Or inject via HTML:

<script type="module">
  import { initAliveTagger } from "@webalive/alive-tagger/client"
  initAliveTagger()
</script>

How It Works

1. JSX Source Tagging (Vite Plugin)

The plugin intercepts React's jsx-dev-runtime and wraps the jsxDEV function to inject refs that store source information on DOM nodes:

// 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. Element Selection (Client Script)

When running in an iframe:

  1. Hold Cmd/Ctrl: Activates selection mode, cursor becomes crosshair
  2. Hover: Elements with source info get highlighted with green border and label showing ComponentName · path/to/file.tsx:line
  3. Click: Captures element context and sends to parent frame via postMessage

3. PostMessage Communication

Selected element context is sent to the parent frame:

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 Reference

Plugin Options

interface AliveTaggerOptions {
  /** Enable source tagging (default: true in dev mode) */
  enabled?: boolean
  /** Enable debug logging */
  debug?: boolean
}

aliveTagger({ enabled: true, debug: false })

Types

import {
  SOURCE_KEY,                    // Symbol.for("__aliveSource__")
  ELEMENT_SELECTED_MESSAGE_TYPE, // "alive-element-selected"
  type SourceInfo,
  type ElementSelectedContext,
  type ElementSelectedMessage,
  type AliveTaggerOptions,
} from "@webalive/alive-tagger"

Utility Functions

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 "@webalive/alive-tagger"

// Example usage
const source = getElementSource(document.querySelector("button"))
if (source) {
  console.log(formatSourceLocation(source)) // "client/pages/Index.tsx:42:8"
}

Client Functions

import { initAliveTagger } from "@webalive/alive-tagger/client"

// Initialize selector (auto-called on import, but can be manual)
const cleanup = initAliveTagger()

// Later: cleanup()

Architecture

┌─────────────────────────────────────────────────────────────────────────┐
│  Claude Bridge (terminal.goalive.nl)                                    │
│  ┌──────────────────────┐  ┌──────────────────────────────────────────┐ │
│  │  Chat Interface      │  │  Sandbox 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 Cmd/Ctrl+Click detection                               │  │
│  │  - Visual highlight on hover                                      │  │
│  │  - Posts context to parent frame                                  │  │
│  └───────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────┘

Comparison: alive-tagger vs React Grab vs lovable-tagger

| Feature | alive-tagger | React Grab | lovable-tagger | |---------|-------------|------------|----------------| | Approach | Vite plugin + client | Runtime fiber traversal | Vite plugin | | Data attachment | Build-time via refs | Runtime fiber inspection | Build-time via refs | | Symbol key | __aliveSource__ | __jsxSource__ | __jsxSource__ | | Selection UI | Built-in (Cmd+Click) | Built-in | None | | Communication | postMessage | HTTP localhost:4567 | None | | Env requirement | None (dev mode auto) | None | LOVABLE_DEV_SERVER=true | | Designed for | Claude Bridge iframe | Claude Code CLI | Lovable.dev |

Integration with Claude Bridge

The alive-tagger is integrated with Claude Bridge's sandbox preview. When a user Cmd+Clicks an element:

  1. Sandbox receives postMessage: Sandbox.tsx and SandboxMobile.tsx listen for alive-element-selected messages
  2. Context propagates via SandboxContext: The selection is passed through useSandboxContext()
  3. Chat input auto-fills: The selected element is formatted as @ComponentName in src/path/file.tsx:lineNumber and inserted into the chat input
  4. User can send to Claude: The reference helps Claude understand exactly which element/component to modify

Key files:

  • apps/web/features/chat/lib/sandbox-context.tsx - Context with setSelectedElement and registerElementSelectHandler
  • apps/web/features/chat/components/Sandbox.tsx - Listens for postMessage, calls setSelectedElement
  • apps/web/app/chat/page.tsx - Registers handler to insert selection into chat input

Caddy Configuration

For HMR to work properly in the sandbox iframe, the preview domain must NOT use forward_auth. The auth check interferes with WebSocket connections and causes the iframe to flash/reload every few seconds.

The site-controller at packages/site-controller/scripts/05-caddy-inject.sh generates preview domain configs WITHOUT forward_auth to avoid this issue.

Development

# Build
bun run build

# Watch mode
bun run dev

# Type check
bun run type-check

# Run tests
bun run test

Files

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

Security Considerations

  1. Development only: Source tagging only active in dev mode
  2. No production impact: Plugin does nothing in production builds
  3. File paths: Relative paths exposed (not full system paths)
  4. node_modules filtered: Library internals not tagged

License

MIT