🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@01.works/diff-layer

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@01.works/diff-layer

Event-driven browser overlay for visualizing AI-authored UI changes.

dev
latest
Source
npmnpm
Version
0.0.1-dev.0
Version published
Maintainers
1
Created
Source

@01.works/diff-layer

Event-driven browser overlay for visualizing UI changes authored by AI agents.

This package does not track React renders. It renders explicit change events provided by an app, AI tool, browser extension, or test harness.

Resolved changes render as persistent target outlines with compact AI markers. Click a marker or timeline item to inspect one selected change in the timeline panel. This keeps multiple nearby changes visible without stacking detail cards over the app.

Quick Start In Your App

Install the dogfood channel:

pnpm add @01.works/diff-layer@dev

1. Install the overlay in development

import { installAIChangeOverlay } from '@01.works/diff-layer/client';

installAIChangeOverlay({
  mutationRetryMs: 1000,
});

Without an explicit enabled option, the overlay installs only when runtime NODE_ENV is exactly development. Browser runtimes with no detectable NODE_ENV default to disabled. For those bundlers, pass the bundler's own development flag, such as enabled: import.meta.env.DEV in Vite.

2. Mark the UI you want to review

export function BillingSummary() {
  return (
    <section data-ai-id="billing-summary">
      <h2 data-ai-id="billing-title">Current plan</h2>
      <button data-ai-id="upgrade-cta">Upgrade</button>
    </section>
  );
}

Stable data-ai-id hooks make explicit AI change events easy to map back to visible UI without depending on brittle generated class names.

3. Push a change from an AI tool, extension, or test harness

window.__AI_CHANGE_OVERLAY__?.push({
  id: crypto.randomUUID(),
  source: 'ai',
  label: 'Upgrade CTA copy changed',
  selector: "[data-ai-id='upgrade-cta']",
  before: 'Upgrade',
  after: 'Compare plans',
  reason: 'Clarified that the next step shows plan options before purchase.',
  filePath: 'app/billing/page.tsx',
  line: 38,
  timestamp: Date.now(),
});

The event is explicit: the overlay shows what changed, where it changed, why it changed, and which source location is associated with the update.

window.dispatchEvent(
  new CustomEvent('ai-change-overlay:push', {
    detail: {
      id: crypto.randomUUID(),
      source: 'ai',
      label: 'Billing summary risk note added',
      selector: "[data-ai-id='billing-summary']",
      reason: 'Called out a plan limit that reviewers should verify.',
      filePath: 'app/billing/page.tsx',
      line: 52,
      timestamp: Date.now(),
    },
  }),
);

Use this path when the producer cannot import the package directly.

Public API

Root export:

import {
  CHANGE_OVERLAY_EVENT_NAME,
  CHANGE_OVERLAY_GLOBAL_NAME,
  getAIChangeOverlay,
  installAIChangeOverlay,
  registerChangeTarget,
  unregisterChangeTarget,
  type AIChangeOverlayGlobal,
  type ChangeEvent,
  type ChangeOverlayOptions,
  type ChangeSource,
  type CreateChangeEventInput,
  type PushChangeInput,
  type SourceLocation,
} from '@01.works/diff-layer';

Client export:

import {
  getAIChangeOverlay,
  installAIChangeOverlay,
} from '@01.works/diff-layer/client';

Options

OptionDefaultDescription
enabledNODE_ENV === 'development'Enables the overlay client.
maxHistory20Maximum changes kept in the timeline.
mutationRetryMs0How long to watch for targets that render after the event.
rootdocument.bodyDOM node that receives overlay and timeline elements.
onOpenSourceundefinedCallback for the timeline source action.

Change outlines and markers stay visible until the reviewer clears active overlays from the timeline or destroys the client. The selected change remains available in the timeline inspector while it is still in history. This package is a review aid for explicit AI-authored changes, not a transient render flash.

Change Event

type ChangeEvent = {
  id: string;
  source: 'ai' | 'manual' | 'system';
  label: string;
  selector?: string;
  componentName?: string;
  filePath?: string;
  line?: number;
  before?: string;
  after?: string;
  reason?: string;
  timestamp: number;
};

Malformed global or event payloads are ignored at runtime.

CustomEvent API

Non-importing producers can dispatch the event name directly:

window.dispatchEvent(
  new CustomEvent('ai-change-overlay:push', {
    detail: {
      id: crypto.randomUUID(),
      source: 'ai',
      label: 'Pricing card layout changed',
      selector: "[data-ai-id='pricing-card']",
      reason: 'Improved scanability of the primary plan',
      timestamp: Date.now(),
    },
  }),
);

Component Targets

Use component names when a component boundary is easier to identify than a selector:

import { registerChangeTarget } from '@01.works/diff-layer';

registerChangeTarget('BillingSummary', "[data-ai-id='billing-summary']");

Remove registrations when the target is no longer valid:

import { unregisterChangeTarget } from '@01.works/diff-layer';

unregisterChangeTarget('BillingSummary');

Queue Before Install

Events can be queued before installation by assigning the global to an array:

window.__AI_CHANGE_OVERLAY__ = window.__AI_CHANGE_OVERLAY__ ?? [];

if (Array.isArray(window.__AI_CHANGE_OVERLAY__)) {
  window.__AI_CHANGE_OVERLAY__.push({
    id: crypto.randomUUID(),
    source: 'ai',
    label: 'Billing title changed',
    selector: "[data-ai-id='billing-title']",
    before: 'Plan',
    after: 'Current plan',
    timestamp: Date.now(),
  });
}

Late Targets

Enable mutationRetryMs when events can arrive before the target is mounted:

installAIChangeOverlay({
  enabled: true,
  mutationRetryMs: 1000,
});

Source Hook

Clicking a rendered source action copies filePath or filePath:line to the clipboard by default. Provide onOpenSource when you also want the source action to open a trusted editor link.

Keep editor opening enabled only in development and only for trusted workspace-relative paths. Only a trusted local bridge that validates workspace containment should handle absolute paths.

installAIChangeOverlay({
  onOpenSource: (change) => {
    if (change.filePath === undefined) return;

    const workspaceRoot = '/absolute/path/to/your/project';
    const relativePath = change.filePath.replaceAll('\\', '/');

    if (
      relativePath.startsWith('/') ||
      relativePath.split('/').includes('..') ||
      /^[a-z][a-z0-9+.-]*:/i.test(relativePath)
    ) {
      return;
    }

    const absolutePath = `${workspaceRoot}/${relativePath}`;
    const suffix = change.line === undefined ? '' : `:${change.line}`;

    window.location.href = `vscode://file/${encodeURI(absolutePath)}${suffix}`;
  },
});

The callback runs after the copy attempt. Clipboard failures are ignored so a trusted editor-opening callback can still run.

Verification

pnpm --filter @01.works/diff-layer test
pnpm --filter @01.works/diff-layer typecheck
pnpm --filter @01.works/diff-layer build
pnpm --filter @01.works/diff-layer test:packaged

Dev-Tag Publishing

This package is configured for dogfood releases on npm's dev dist-tag:

pnpm version:dev
pnpm publish:dev

Every npm publish still needs a unique version. Consumers install the dogfood channel explicitly:

pnpm add @01.works/diff-layer@dev

Do not publish dogfood builds with the latest dist-tag.

Keywords

diff-layer

FAQs

Package last updated on 28 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts