mcpField
A
agent-panel

agent-panel

github.com/editframeDevelopment1972 installsUpdated 2w ago
Repository

About agent-panel

Agent Panel is a skill for the `ef-edit` event pipeline in a GUI composition editor. It collects and deduplicates meaningful edits, groups them by selector, and creates a coding-agent prompt that can be copied.

Key features

  1. 01Capture `ef-edit` events
  2. 02Deduplicate edits by element and property
  3. 03Group edits by selector
  4. 04Build a copyable coding-agent prompt
  5. 05Document event routing and test patterns

Use cases

  1. 01Summarizing GUI composition edits for a coding agent
  2. 02Avoiding duplicate records of property changes
  3. 03Generating prompts grouped by edited element
  4. 04Testing DOM and shadow DOM edit events

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/editframe/skills --skill agent-panel

After installing, type/agent-panelin Claude Code to confirm it loaded.

Details

From the project README

Agent Panel

The EFAgentPanel captures ef-edit CustomEvents dispatched whenever a user makes a meaningful composition edit in the GUI, deduplicates them by element+property via a keyed registry, groups them by selector, and renders a copy-able coding-agent prompt.

Event Pipeline

GUI interaction (canvas drag, inspector change, trim drag, loop toggle)
  └─ component.dispatchEvent(createEditCustomEvent(editEvent))
       └─ [bubbles: true, composed: true]
            └─ EFWorkbench listener → agentPanel.addEdit(event)
                 └─ Map<editChangeKey, EditEvent> registry (deduplicates)
                      └─ groupEditsBySelector() → buildAgentPrompt() → copy button

EFWorkbench registers addEventListener('ef-edit', ...) on itself — because ef-edit bubbles and is composed, any component in any slot (timeline, hierarchy, canvas) can dispatch it without special routing.

Key Types (editEvents.ts)

// EditEvent — what the panel accumulates
interface EditEvent {
  operation: EditOperation;
  description: string;   // human sentence
  selector: string;      // CSS path from composition root
  elementHtml: string;   // cleaned outerHTML snippet
  timestamp: number;
}

// Operation union — extend here when adding new interaction types
type EditOperation =
  | { type: "element-property-changed"; elementId; tagName; label; property; oldValue; newValue }
  | { type: "element-moved";   elementId; tagName; label; fromX; fromY; toX; toY }
  | { type: "element-resized"; elementId; tagName; label; x; y; width; height }
  | { type: "element-rotated"; elementId; tagName; label; rotation }

Registry key format — determines deduplication:

  • Property change: selector::prop:propName
  • Move/resize/rotate: selector::move, selector::resize, selector::rotate

Pattern: Adding a New ef-edit Dispatch Point

import {
  createEditCustomEvent, buildSelectorPath, getElementHtml,
  buildEditDescription, type ElementPropertyChangedOperation,
} from "../../editEvents.js";

const oldValue = element.someProperty;
element.someProperty = newValue;

const op: ElementPropertyChangedOperation = {
  type: "element-property-changed",
  elementId: el.id,
  tagName: el.tagName.toLowerCase(),
  label: el.textContent?.trim().slice(0, 30) || el.id || el.tagName.toLowerCase(),
  property: "attr-name",   // attribute name as used in HTML source
  oldValue,
  newValue,
};
this.dispatchEvent(createEditCustomEvent({
  operation: op,
  description: buildEditDescription(op),
  selector: buildSelectorPath(el),
  elementHtml: getElementHtml(el),
  timestamp: Date.now(),
}));

buildPropertyEditEvent(element, property, oldValue, newValue) in EFInspector.ts is a shorter form for simple property edits.

Finding Current Dispatch Points

# Every call site that produces an ef-edit event
rg 'createEditCustomEvent' elements/packages/elements/src/

# Track subclasses that override render() — each must bind @trim-change-end
rg 'override render' elements/packages/elements/src/gui/timeline/tracks/

# Registered element schemas
rg 'SCHEMA_REGISTRY' elements/packages/elements/src/gui/elementPropertySchema.ts

What is NOT Wired (intentional)

Playback controls (play/pause/seek), pan-zoom/zoom level, and toolbar settings are display-only state — they should not produce ef-edit events. Hierarchy reorder (hierarchy-reorder from EFHierarchy) would require a new ElementReorderedOperation type; not yet implemented.

Shadow DOM Event Routing Gotcha

trim-change-end bubbles with composed: true from EFTrimHandles. TrackItem.render() binds @trim-change-end on the ef-trim-handles element. EFVideoTrack overrides render() entirely and provides its own ef-trim-handles binding. Any future track subclass that overrides render() and includes ef-trim-handles must bind both @trim-change and @trim-change-end — the base TrackItem.render() handlers are not inherited when render() is overridden.

Element Property Schema (elementPropertySchema.ts)

Static descriptors drive the inspector UI. Register new element types at the bottom via SCHEMA_REGISTRY. Use the factory functions:

  • timeDescriptor(attr, label, opts) — time values (stored as ${ms}ms attributes)
  • enumDescriptor(attr, label, options, condition?)
  • boolDescriptor(attr, label, condition?)
  • numberDescriptor(attr, label, opts)
  • stringDescriptor(attr, label)

Elements with no registry entry are invisible to the inspector. Check elementPropertySchema.test.ts for the test pattern.

Testing ef-edit Events

Unit tests (Node/vitest): use for editEvents.ts helpers — editChangeKey, rollUpEdits, groupEditsBySelector, buildAgentPrompt.

Browser tests (Chromium/vitest): required for any test involving DOM events or shadow DOM.

For trim ef-edit, dispatch trim-change-end directly on the ef-trim-handles host element — do not try to simulate full pointer events through shadow DOM layers, as pointer capture mechanics are unreliable in test environments:

const trimHandles = track.shadowRoot?.querySelector("ef-trim-handles");
trimHandles?.dispatchEvent(new CustomEvent("trim-change-end", {
  detail: { elementId: video.id, type: "start" },
  bubbles: true, composed: true,
}));

For loop ef-edit, click the loop button via shadowRoot.querySelector("button[title='Loop']").click().

Listen at document level — ef-edit is bubbles: true, composed: true, so it propagates from any component to document.

Comments

Markdown supported