Skip to content

Latest commit

 

History

History
805 lines (690 loc) · 40.9 KB

File metadata and controls

805 lines (690 loc) · 40.9 KB

Changelog - agnt

[0.15.4] - 2026-08-07

Fixed

  • PROXY EXEC / agent navigation works after page navigation. The frame identity lived only in the ?__devtool_frame= URL marker and the injector's first-load inline script, so a location.assign/reload left the re-injected page with no frame id — every exec from then on targeted a ghost frame and hung (interim state:"running" status, never delivered). frames.js now persists the frame id to sessionStorage on the first wrapped load and recovers it on later documents in the same frame (content-role only — same-origin frames share the tab's sessionStorage, so the shell must never read it). Multi-hop agent navigation works.

[0.15.3] - 2026-08-06

Fixed

  • Design-mode preview iframe follows the page theme. renderInFrame hardcoded background:#fff, so alternatives for dark-themed apps previewed as dark text on a forced white sheet. The frame and srcdoc now inherit the page body's computed background and color.
  • design.applyAlternative() no longer corrupts state when called with no argument. The index was unguarded, so a bare call set currentIndex to undefined and the panel badge rendered NaN / N. Non-numeric or out-of-range indexes are now a no-op; the docs note the function is preview navigation only (shipping an alternative is a source edit + HMR).

[0.15.2] - 2026-08-06

Added

  • Design mode payloads now carry page-level and neighborhood context. design_state gains a whole-page thumbnail (saved as a JPEG, page_thumb_path), the parent container's slot geometry (box + grid tracks / flex mode), and up to two same-signature exemplar components from elsewhere on the page. design_request and design_chat gain an explicit constraints block: preserve (scheme axes that stay fixed), vary (layout, hierarchy, density, affordance — UX variation over core-UI variation), and steer (the user's latest message, highest precedence). Alternatives now default to staying on-scheme and on-slot while remaining steerable by the prompt.

Fixed

  • saveScreenshot picks the file extension from the data-URL MIME instead of hardcoding .png (design page thumbnails are JPEG).

[0.15.1] - 2026-08-06

Fixed

  • Sketch mode default ink is now theme-aware. The Excalidraw-style default stroke #1e1e1e is invisible on dark UIs — most of what sketch mode gets opened on. sketch.init() now measures the page's effective background through the frame-context adapter (__devtool_context.contentFrame()) and opens with light ink (#e8e9ee) when the page is dark. The override only applies while the factory default is untouched, so a saved or chosen stroke color is never overridden.

[0.15.0] - 2026-08-05

Added

  • auditDesign — delay-loaded design anti-pattern audit (__devtool.audit.auditDesign). Backed by the vendored Impeccable browser detector (Apache-2.0): 59 deterministic rules for the design tells AI-generated frontends share — overused fonts, purple-to-blue gradients, gradient text, cards nested in cards, gray text on colored backgrounds, side-tab borders, low contrast. Only Impeccable's live-DOM engine is bound; the package's static-HTML and source-tree engines are deliberately out of scope, because an audit answers for the rendered page. The ~366KB detector never enters the injected instrumentation: the first call injects it from /__devtool_impeccable (served charset=utf-8 — the bundle carries UTF-8 regex character classes) with auto-scan disabled. Advisory findings surface as info and never score. Not folded into auditAll, which would make the aggregate's first run silently heavyweight.

[0.14.0] - 2026-08-04

Added

  • auditAnimations — compositor-load audit (__devtool.audit.auditAnimations, new audit-animations module in the injected bundle). Finds the performance class every JS profiler is blind to: work that runs entirely on the compositor thread. An infinite CSS animation (Tailwind animate-pulse on a status dot is the canonical case) never touches the DOM, never runs script, and reads as an ordinary visible element — yet it forces a compositor commit at display refresh rate forever, pegging the browser's GPU process from a visually static page on high-refresh HiDPI displays and draining batteries on mobile.

    Detectors: infinite-animation (the frame pump, from document.getAnimations() — the one registry MutationObserver and visual-state snapshots cannot see), layout-property-animation (width/top/margin animations forcing main-thread layout per frame), viewport-overlay-amplifier (full-viewport noise/grain layers), backdrop-filter-amplifier (large-area filters only — a small composer-bar blur is not flagged), and will-change-overuse. Amplifiers escalate to error only while a frame pump is live; without one they cost a single paint and report as info.

    {sampleMs: N} adds a bounded requestAnimationFrame idle sample (frameSample.effectiveFps at refresh rate on a static page = conviction; ≤5 fps = the page idles). The probe is time-bounded and honest: a backgrounded/occluded tab resolves rafStarved: true and reports the sample inconclusive instead of hanging or faking an idle reading; a browser without document.getAnimations() returns notApplicable, never an unmeasured passing grade.

    Because the audit ships inside the proxy-injected instrumentation, it runs on-device — point a phone at the proxy URL (or a tunnel) and the same call answers for that device's own refresh rate, animation registry, and GPU. No USB debugging, no desktop inspector attach. Guide with a full reproduction of the T3 Code / "Fable Broke My App" incident: docs-site/docs/guides/gpu-compositor-debugging-ai.md.

Fixed

  • automation {action:"evaluate"} no longer silently runs content-scoped scripts in the proxy shell. The content-frame wrapper used to fall back to window when the app iframe was not yet available, so an evaluate racing a navigation executed in the SHELL realm — the exact wrong-frame failure the content default exists to remove. A wrapped shell now waits (bounded, 5s) for the app frame to become ready — its realm carries the injected content role, or a non-instrumented document has fully loaded off about:blank — and on timeout fails loud, naming the real states and the frame:"top" escape hatch. Only a genuinely unwrapped page still evaluates in window directly.

Removed

  • get_errors is gone. get_incidents is the only error surface. The migration was gated on a measured superset, not a judgement call: an oracle drove both tools' real filter builders and projections over one seeded state and reduced every difference to a recorded divergence. It was allowed to land only once no divergence remained where information was unreachable.

    Closing the last four blockers changed real behaviour, so read this even if you never called get_errors:

    • Incidents now carry context.location (file:line:col, resolved by the browser adapter at ingest) and context.frame_id.
    • Browser incident fingerprints changed. The emitting content frame is part of the fingerprint, so the same error raised in two content frames is now two incidents rather than one. Incidents with no frame attribution fingerprint exactly as before.
    • get_incidents returns collection_warnings, naming every way the view is partial — events the bus dropped before reaching any inbox, and detail:"full" payloads the blob store could not hydrate. The latter was previously swallowed and rendered as an incident that simply had no payload.
    • The readiness gate's agnt_proxy_not_ready 503 is filtered at ingest (incident.FromHTTPEntry) instead of in get_errors. Without that move, retiring the tool would have filled the inbox with agnt's own retry signal for the whole startup race.

    Migration is a rename in most cases: get_incidents already accepted error_id/tag/action with get_errors spelling. Two things do not carry over — include_warnings:false becomes severity:["critical","error"], and there is no global, because the inbox is per-session hard-isolated, which is a stronger guarantee than the project scoping global overrode.

    proc {action:"snapshot"} is unchanged: it kept the per-source collectors, now in internal/tools/unified_error.go, because it is project-scoped and may be global where the inbox cannot be.

  • ALERTS PIN / UNPIN / CLEAR and the alert-store pin are gone with it. get_errors was their only client, so nothing could set an alert-store pin any more — internal/alert/pinned.go, the pinned field on ALERTS QUERY, and the AlertPin/AlertUnpin/AlertClear daemonclient methods were unreachable code. Pinning lives on get_incidents, which is per-session rather than per-project. The automatic retention triggers (alerts.retention) are untouched; they call the store directly and never used these verbs.

Fixed

  • Background run no longer opens a dedicated daemon connection. Only the foreground modes, which block until the process exits, need to stay off the shared connection's per-request mutex. Background runs reuse the resilient client and keep its reconnect/retry behavior.
  • Sessions with no project path get the reconnect grace period. A dropped connection used to reap an acp one-shot / cooked-REPL session's process group inline, so a client that reconnected within the grace window had its process tree killed out from under it — and the hub's disconnect callback blocked for the SIGTERM→SIGKILL escalation. Session-host sessions are never reaped on disconnect, which surviving client disconnect is the whole point of.
  • Session-host PTY fd is closed exactly once. A SESSION-HOST KILL racing the child's own exit reached both close sites; once the fd number was recycled, the second close landed on whatever then owned it.
  • Shutdown breadcrumbs no longer evict startup errors. The startup-log ring is shared across projects and does not outlive the process, so ~36 daemon-wide info entries emitted during Stop were displacing real project errors for a reader that no longer exists. Warnings and errors during shutdown still land.
  • Subprocess accept backoff no longer delays Stop (go-cli-server v0.5.2).

[0.13.32] - 2026-07-09

Changed

  • Daemon socket moved to a per-uid subdirectory: /tmp/agnt-<uid>/agnt.sock, replacing /tmp/agnt-<uid>.sock. The hardened socket bind requires the socket's parent directory to be uid-owned and 0700, and /tmp is root-owned.

    Upgrade note: a daemon started by a pre-0.13.32 binary keeps listening on the old path, where the new client cannot see it — it would linger holding its managed processes and their ports. On startup the daemon now finds that legacy socket, asks the old daemon to shut down gracefully (stopping the processes it owns rather than orphaning them), and removes the stale file. If the old daemon cannot be stopped, the reason is recorded in the startup log rather than swallowed. Only applies to the default socket path; an explicit AGNT_SOCKET or --socket is left alone.

Fixed

  • get_incidents no longer drops the oldest incident. The inbox returns the oldest unseen page; the hub truncated it to the newest entries and then published a cursor above the record it had just discarded, so with a forward-only since cursor that incident could never be returned again.
  • AUTOSTART RECONCILE and OVERLAY FORWARDING now dispatch. Both were routable but unregistered as sub-verbs, so the parser left the token in the argument list. Reconcile answered "unknown action" — live .agnt.kdl reconcile never ran — and forwarding silently fell through to OVERLAY GET, reporting success while pausing nothing. Sub-verbs are now derived from the router that dispatches them, so the two lists cannot drift.
  • Editing a script's run in .agnt.kdl no longer stops it restarting. The script registry rejects a re-register under a changed config; live reconcile relies on exactly that re-register, so the script never came back.
  • Scheduler retry backoff no longer panics on a negative attempt count read from a persisted task file, nor overflows into a past deadline (hot retry loop).
  • DETECT and DOCTOR reject a malformed payload instead of silently falling back to the daemon's own working directory.
  • snapshot {raw: true} reports partial-collection failures. They were only appended to the text rendering, so a raw consumer read an incomplete snapshot as a clean one.
  • get_incidents rejects an unparseable since instead of ignoring it and returning the whole inbox.
  • Daemon client leak: agnt run could create a resilient client that nothing ever closed, leaving its reconnect loop retrying for the life of the process.

Internal

  • go-cli-server upgraded to v0.5.1 and the vendored tree un-patched. It carried local modifications to the hub command registry that were never upstream, so go install github.com/standardbeagle/agnt/cmd/agnt@latest — which ignores vendor/ — could not build. That API is now released upstream.

Added

  • agnt skills command — one-shot install of the agnt agent skills + agnt MCP registration. Uses Vercel's open skills CLI (npx -y skills add standardbeagle-tools/agnt --all -a claude-code) then registers the MCP server (claude mcp add agnt -s user -- agnt mcp for Claude Code; prints the MCP config for other agents). --agent / --source override the target agent and skills source. Requires Node.js (npx).
  • First-run setup flow for agnt run. When agnt run claude is invoked in a project with no .agnt.kdl, agnt drives a one-time setup run (the agent configures the project via the agnt:setup-project skill) then relaunches the coding agent with autostart enabled, replaying the original arguments.
    • Per-project first-run marker under XDG state; positive outcome is permanent, a declined setup re-nudges after a configurable TTL (setup { renudge-ttl-days 7 }, default 7 days).
    • Per-agent install guidance from a support matrix (docs/agent-support-matrix.md): each agent is classified marketplace-install / skill-file / none with the correct install text.
  • agnt init command — runs only the setup phase (configure the project, write .agnt.kdl) without relaunching into a coding session. agnt init defaults to claude; agnt init <agent> uses another agent. A successful init records the permanent marker so a later agnt run skips the setup nudge.
  • id parameter alias across single-reference MCP tools. currentpage, proxylog, responsive_audit, channel_reply, snapshot, and proc now accept id as an alias for their canonical proxy_id / process_id parameter. Canonical name wins when both are set. Skill docs updated to guide toward the preferred form.
  • snapshot {action:"screenshot"} captures the current page of a running proxy via __devtool.screenshot() in one call. Accepts proxy_id (or id alias), optional name, selector, and full_page. File path is returned in the next proxylog {types:["screenshot"]} entry. Daemon mode only.
  • Incident pipeline opt-in (alerts.incident-pipeline in .agnt.kdl): New alert path in internal/incident/ that normalises signals from 11 sources (browser JS, HTTP 5xx/4xx, process crashes, build failures, port conflicts, hook stop-failures, etc.) into a deduped, coalesced, priority-ordered inbox with four severity bands.
    • get_incidents MCP tool: cursor-based pull with remediation_hint and next_tools fields. Supersedes get_errors when the pipeline is enabled.
    • get_errors is retained as a legacy shim; it continues to work unchanged when alerts.incident-pipeline false (the default).
    • Feature flag is all-or-nothing per session; daemon restart required to toggle. Phase A default is false (opt-in only).

[0.8.0] - 2026-01-11

Added

  • Debug logging infrastructure: Comprehensive debug logging for proxy and tools
    • Enable with AGNT_DEBUG=1 environment variable
    • Logs to stderr to avoid interfering with MCP stdio communication
  • Enhanced indicator metadata: Attachment metadata in panel messages for richer context
  • 'run' shorthand for script commands: Simplified .agnt.kdl configuration with run "command" syntax
  • SVG wireframe generation: Generate SVG wireframes from DOM elements via __devtool API
  • AI-optimized audit output: New default output format designed for token efficiency
    • Grouped issues by type with limited examples
    • Use raw: true for verbose detailed format
  • Process/proxy restart functionality: proc {action: "restart"} and proxy {action: "restart"}
  • forAutomation mode: AI-powered analysis with forAutomation: true flag for audit functions
  • Audit system overhaul: Action-oriented output with clear remediation steps
  • User interaction recorder: Script for tracking and replaying user interactions
  • Response stream UI components: Visual components for streaming responses
  • Shell completion command: agnt completion [bash|zsh|fish|powershell]
  • Feature licensing framework: Foundation for premium feature licensing
  • Activity monitoring: Output preview broadcast for real-time activity tracking
  • EADDRINUSE auto-recovery: Automatic port conflict recovery for script startup
  • Multi-level data store: MCP and JS API for structured data storage
  • Modern compression support: Brotli (br) and Zstandard (zstd) decompression in proxy
    • Automatic decompression for HTML injection
    • Pass-through with logging for unsupported compression formats
    • Maintains backward compatibility with gzip and deflate

Changed

  • Accessibility audit overhaul: Action-oriented output with clear pass/fail criteria
  • Refactored overlay code: Reduced cyclomatic complexity in high-risk functions
  • Progressive disclosure in currentpage tool: action: "list" now returns lightweight summaries
    • Returns only counts (interaction_count, mutation_count, error_count, resource_count)
    • Omits detailed arrays to prevent token bloat (was sending 11.7k tokens for 69 interactions)
    • Use action: "get" with specific session_id for full interaction/mutation details
    • Typical token reduction: ~90% for list views with many interactions

Fixed

  • Code quality improvements eliminating shotgun surgery patterns

[0.5.0] - 2025-12-10

Added

  • Sketch-driven development: Fully integrated Excalidraw-like sketch mode for wireframing
    • Automatic page screenshot capture when entering sketch mode
    • Background image with 40% overlay for drawing context
    • Wireframe elements: buttons, input fields, sticky notes, image placeholders
    • Shape tools: rectangle, ellipse, line, arrow, freehand drawing, text
    • JSON export/import for sketch persistence
    • Save & Send integration to send sketches to MCP for AI processing
    • Sketches include full page context so AI can understand component placement
  • New proxylog types documented: interaction, mutation, panel_message, sketch
    • AI agents can now query proxylog {types: ["sketch"]} to retrieve wireframes

Fixed

  • MCP client CWD resolution: detect and run tools now resolve relative paths (like .) to absolute paths before sending to daemon, ensuring the daemon uses the MCP client's working directory instead of its own
  • Sketch overlay visibility: Reduced background opacity and improved grid dot visibility

[0.15.0] - 2026-08-05

[0.9.0] - 2025-01-23

Added

  • Enhanced diagnostics panel with tabbed interface: Floating indicator now features a comprehensive 7-tab diagnostics dashboard
    • Overview tab: Health cards showing framework detection, error counts, failed API calls, DOM update rates, and React-specific metrics (rerender rate, input lag)
    • Errors tab: Deduplicated error tracking with console.error/console.warn interception and JS error aggregation
    • Network tab: API call history with status codes, timing, and URL sanitization for sensitive params
    • Performance tab: DOM mutation rate analysis across multiple time windows (1s, 5s, 30s)
    • Quality tab: Placeholder for upcoming quality audits
    • Interactions tab: User interaction history tracking
    • Compose tab: Original message composition interface
    • Active tab persistence via localStorage
    • Real-time badge updates showing error counts, failed calls, and performance status
    • Auto-refresh every second while panel is expanded
  • Framework detection module (framework-detector.js): Automatic detection of frontend frameworks (React, Vue, Angular, Svelte, etc.) with version extraction
  • API call tracking module (api-tracker.js): Intercepts fetch and XMLHttpRequest to track API calls with sanitization for sensitive parameters (tokens, API keys, passwords)
  • Error buffer API (window.__devtool_errors): In-memory error tracking with deduplication, statistics, and examples
    • getJSErrors(), getConsoleErrors(), getConsoleWarnings()
    • getDeduplicatedErrors() returns grouped errors with counts, timestamps, and stack traces
    • getStats() returns total counts across all error types
    • clear() resets all error buffers
  • Console override: Enhanced console.error and console.warn to capture console output for diagnostics

Changed

  • Automation processor: Removed deprecated TimeoutSecs parameter from claude-go API calls
  • Script module ordering: Framework detector and API tracker now load before indicator module

Fixed

  • go.mod formatting: Added trailing newline for consistency

Technical Details

  • Error buffers: Circular buffer with max 100 entries per type (JS errors, console errors, console warnings)
  • Deduplication key: First 100 characters of error message
  • Tab content updates: Only active tab refreshes every 1 second to minimize performance impact
  • React-specific metrics: Correlate input events with DOM mutations to detect rerender hotspots and input lag
  • API sanitization: Automatically truncates sensitive query parameters (token, api_key, key, secret, password, auth)

[0.8.0] - 2025-01-19

Added

  • Session-scoped API: Processes and proxies are now scoped to sessions, preventing interference between multiple AI coding sessions
    • SESSION FIND: Locate session by directory ancestry (walks up the directory tree)
    • SESSION ATTACH: Attach MCP client to an existing session for shared resource access
    • DirectoryFilter extended with SessionCode for session-based filtering
    • Auto-attach behavior: MCP clients automatically find and attach to sessions in parent directories
    • --no-attach CLI flag to disable auto-attach and operate globally
    • proc list and proxy list now filter by session code when attached
  • PID tracking for orphan cleanup: Implemented persistent PID tracking to prevent orphaned processes after daemon crashes
    • Tracks process PIDs to ~/.local/state/devtool-mcp/pids.json with daemon PID for crash detection
    • Automatic cleanup of orphaned processes on daemon startup
    • Changed Unix process group behavior: children now inherit daemon's PGID for automatic cleanup on daemon termination
    • Comprehensive test suite (7 tests) for PID tracking operations
    • Documentation: docs/orphan-cleanup.md with implementation details and scenarios
  • AI channel model configuration: Claude Code CLI now defaults to haiku model for fast, cost-effective summaries
    • Model is configurable via Config.Model field
    • Added --model flag to Claude Code CLI invocations
  • AI channel error handling: SendAndParse now returns ErrAgentError when Claude Code reports an error (is_error: true)
    • Errors are reported to users instead of being passed to downstream LLM calls
    • Error includes subtype context (e.g., "agent error (error): message")
  • JSON extraction improvements: Enhanced response parsing with two distinct extraction strategies
    • extractClaudeCodeJSON: For Claude Code CLI wrapped responses (finds type: "result" objects)
    • extractEmbeddedJSON: For AI-embedded JSON in prose responses
    • Helper functions BuildEmbeddedJSONPrompt and BuildEmbeddedJSONSystemPrompt for structured data extraction
  • --no-autostart flag: Skip auto-starting scripts and proxies from .agnt.kdl when running agnt run claude
  • Spinner animation: Status summary now shows animated spinner while loading
  • Production release build: New make release target with optimized flags (-s -w, -trimpath)
  • Setup project improvements: Updated /setup-project command with better documentation about:
    • Status bar information and CTRL+Y overlay menu
    • OAuth redirect URL configuration for both dev and proxy ports
    • How to skip autostart and restart services

Fixed

  • Process/proxy filtering after agnt run restart: Fixed issue where processes and proxies started from agnt run claude would disappear from proc list and proxy list after restarting the CLI. Root cause was MCP server using its own working directory instead of the original project directory.
    • Added AGNT_PROJECT_PATH environment variable, injected by agnt run into child processes
    • MCP tools now use AGNT_PROJECT_PATH to filter by the correct project directory
    • Fixed both Unix (run.go) and Windows (run_windows.go) implementations
  • Windows path case sensitivity: Fixed path comparison issues on Windows where C:\Users and c:\users were treated as different directories
    • Added case normalization (lowercase) for Windows paths in both daemon and MCP tools
    • UNC paths (\\server\share) handled correctly
  • Version parsing with daemon status: Fixed --version output parsing in upgrade tests where multi-line output (including daemon status) caused test failures

Added

  • Tests for getProjectPath() function covering environment variable handling, path edge cases
  • Tests for normalizePath() function covering Windows case-insensitivity, UNC paths, special characters
  • Session-scoped resource cleanup: When a client that registered a session disconnects, only resources (processes, proxies) for that session's project path are cleaned up
    • Added sessionCode field to Connection to track which session each connection registered
    • Added StopByProjectPath() to ProxyManager (matching existing ProcessManager method)
    • Added CleanupSessionResources() to Daemon for session-targeted cleanup
    • Comprehensive test TestSessionBasedCleanup verifying isolation between sessions
    • Fixes issue where exiting one session would leave orphaned processes, causing port conflicts for new dev servers

Changed

  • Hash-based default proxy port: Proxy now auto-assigns a stable port based on FNV-1a hash of target URL (range 10000-60000)
    • Same target URL always gets the same port (consistent across restarts)
    • Different URLs get different ports (avoids conflicts)
    • Avoids well-known ports, registered ports, and ephemeral port ranges
    • Port parameter is now optional - only specify if you need a specific port
    • The listen_addr response field always shows the assigned port

Fixed

  • Screenshot Firefox compatibility: Switch from html2canvas@1.4.1 to html2canvas-pro@1.5.8 to support modern CSS color functions (lab(), oklch(), oklab(), lch()) that Firefox and modern browsers use in computed styles

Added

  • Progressive disclosure for __devtool API documentation:
    • proxy {action: "exec", help: true} - Full API overview with all 60+ functions grouped by category
    • proxy {action: "exec", describe: "functionName"} - Detailed documentation for individual functions
    • New internal/tools/apidocs.go with comprehensive API documentation
  • New proxy input parameters: help and describe for accessing API documentation without executing code
  • Updated proxy tool description with common __devtool examples for screenshot, logging, interactions, mutations, inspection, and accessibility auditing

[0.3.0] - 2025-12-07

Added

Daemon Architecture

  • Background daemon for persistent state across MCP client disconnections
  • Session handoff: Multiple MCP clients can interact with the same processes/proxies
  • Auto-start: Daemon starts automatically on first tool call
  • Socket-based IPC: Text protocol for client-daemon communication
  • New daemon MCP tool with status, info, start, stop, restart actions

Publishing Infrastructure

  • npm package: @standardbeagle/devtool-mcp with automatic binary download
  • PyPI package: devtool-mcp for pip/uv installation
  • Bash installer: One-liner installation via curl
  • GitHub Actions: Automated release workflow for all platforms

Documentation

  • Reorganized Frontend API docs into hierarchical categories
  • Added daemon tool documentation
  • Fixed MDX parsing issues in documentation

Changed

  • Version bumped to 0.3.0
  • Makefile uses install -m 755 instead of cp for proper permissions
  • CLAUDE.md refocused on development guidance

Installation Methods

npm:

npm install -g @standardbeagle/devtool-mcp

pip/uv:

pip install devtool-mcp
# or
uv pip install devtool-mcp

Bash (one-liner):

curl -fsSL https://raw.githubusercontent.com/standardbeagle/devtool-mcp/main/install.sh | bash

From source:

git clone https://github.com/standardbeagle/devtool-mcp.git
cd devtool-mcp
make build
make install-local

[0.15.0] - 2026-08-05 - 2025-12-05

Added - Async JavaScript Execution & Response Logging

1. Async JavaScript Execution with Result Waiting

  • Changed: proxy exec tool now waits for JavaScript execution results instead of fire-and-forget
  • Added: Result channels for pending executions (sync.Map in ProxyServer)
  • Added: 30-second timeout for execution responses
  • Result: Users now receive immediate feedback with execution results:
    JavaScript executed successfully.
    Result: "My Page Title"
    Duration: 2.5ms
    

2. Response Logging System

  • Added: New log type LogTypeResponse for tracking MCP client responses
  • Added: ExecutionResponse struct with execution metadata
  • Added: LogResponse() method in TrafficLogger
  • Updated: proxylog tool now supports types: ["response"] filter
  • Result: Full audit trail of JavaScript executions and their responses
  • Query: proxylog {proxy_id: "dev", types: ["response"]}

3. Enhanced Screenshot Capabilities

Full Page Screenshots:

  • window.__devtool.screenshot() - Auto-generated name
  • window.__devtool.screenshot('homepage') - Custom name

Element Screenshots:

  • window.__devtool.screenshot('#selector') - Capture specific element
  • window.__devtool.screenshot('button', '.my-button') - Element with custom name
  • Smart parameter detection: Automatically detects CSS selectors (starting with ., #, [)
  • Error handling: Returns clear errors for invalid selectors or missing elements
  • Scroll compensation: Properly handles scroll offsets for accurate captures

Screenshot Metadata:

  • Added Selector field to Screenshot struct
  • Logs now include which element was captured (body for full page, or CSS selector)
  • Query: proxylog {proxy_id: "dev", types: ["screenshot"]}

Technical Details

Architecture Changes:

  1. ProxyServer.pendingExecs - Lock-free sync.Map for execution tracking
  2. ExecuteJavaScript() signature change: Returns (string, <-chan *ExecutionResult, error)
  3. WebSocket handler notifies waiting channels when results arrive
  4. Tool handler blocks until result received or timeout

JavaScript Enhancements:

  • html2canvas configured for full-page and element capture
  • Automatic scroll offset compensation
  • Comprehensive error handling for selectors
  • Flexible parameter combinations for screenshot API

Logging Improvements:

  • All MCP responses now logged for audit trail
  • Timeout responses logged as failed executions
  • Screenshot logs include selector information
  • Response logs separate from execution logs for clarity

Usage Examples

Execute JavaScript and Get Result:

proxy {action: "exec", id: "dev", code: "document.title"}
// Returns: "JavaScript executed successfully.\nResult: \"My Page\"\nDuration: 1.2ms"

Capture Full Page:

proxy {action: "exec", id: "dev", code: "window.__devtool.screenshot('homepage')"}

Capture Specific Element:

proxy {action: "exec", id: "dev", code: "window.__devtool.screenshot('#header')"}

Query All Responses:

proxylog {proxy_id: "dev", types: ["response"], limit: 50}

Breaking Changes

  • None - All changes are backward compatible
  • Old logs and execution patterns continue to work
  • New features are opt-in through new log types

Performance Impact

  • Minimal: Execution tracking uses lock-free sync.Map
  • Timeout default: 30 seconds (configurable)
  • Channel cleanup automatic on result or timeout
  • Screenshot performance depends on html2canvas (typically <1s)

[0.15.0] - 2026-08-05 - 2025-12-05

Added - Comprehensive Diagnostic Primitives (~50 Functions)

Overview

Implemented ~50 primitive, composable JavaScript functions in window.__devtool that enable LLMs to perform comprehensive DOM inspection, layout analysis, visual debugging, and interactive diagnostics. All primitives are designed to be small, focused, and composable.

Architecture Principles

  1. Primitives over monoliths: Small, focused functions (~20-30 lines each)
  2. Composability: Functions return rich data structures that other functions consume
  3. Synchronous by default: Async only when necessary (screenshots, user interaction)
  4. Error resilient: Return partial results with error fields, don't throw
  5. Selector flexibility: Accept CSS selectors, elements, or arrays

Core Infrastructure (Phase 1)

  • resolveElement(selector) - Convert selector/element to element
  • generateSelector(element) - Create unique CSS selector for element
  • safeGetComputed(element, properties) - Safe getComputedStyle wrapper
  • Overlay management system with SVG-based rendering

Element Inspection Primitives (Phase 2) - 9 Functions

  • getElementInfo(selector){ element, selector, tag, id, classes, attributes }
  • getPosition(selector){ rect, viewport, document, scroll }
  • getComputed(selector, properties){ property: computedValue }
  • getBox(selector){ margin, border, padding, content }
  • getLayout(selector){ display, position, flexbox, grid, float }
  • getContainer(selector){ type, size, name } (CSS containment)
  • getStacking(selector){ context, zIndex, order, parent }
  • getTransform(selector){ matrix, translate, rotate, scale }
  • getOverflow(selector){ x, y, scrollWidth, scrollHeight }

Tree Walking Primitives (Phase 3) - 3 Functions

  • walkChildren(selector, depth, filter){ elements, count }
  • walkParents(selector){ parents, count }
  • findAncestor(selector, condition){ element, selector }

Visual State Primitives (Phase 4) - 3 Functions

  • isVisible(selector){ visible, reason, area }
  • isInViewport(selector){ intersecting, ratio, rect }
  • checkOverlap(selector1, selector2){ overlaps, area, percentage }

Layout Diagnostic Primitives (Phase 5) - 3 Functions

  • findOverflows(){ overflows, count }
  • findStackingContexts(){ contexts, count }
  • findOffscreen(){ offscreen, count }

Visual Overlay System (Phase 6) - 3 Functions

  • highlight(selector, config)highlightId
    • config: { color, borderColor, duration, pulse, label }
    • Renders visual overlay showing element boundaries
  • removeHighlight(highlightId)void
  • clearAllOverlays()void

Interactive Primitives (Phase 7) - 4 Functions

  • selectElement()Promise<{ element, selector }>
    • Full interactive element picker with hover preview
    • Click to select, Escape to cancel
  • measureBetween(sel1, sel2){ distance: { x, y, diagonal }, direction }
  • waitForElement(selector, timeout)Promise<element>
    • Uses MutationObserver to wait for dynamic elements
  • ask(question, options)Promise<answer>
    • Shows modal dialog for user interaction
    • Returns selected option or cancelled

State Capture Primitives (Phase 8) - 4 Functions

  • captureDOM(){ snapshot: HTML, hash, timestamp, url, size }
  • captureStyles(selector){ computed, inline, timestamp }
  • captureState(keys){ localStorage, sessionStorage, cookies }
  • captureNetwork(){ resources, count, timestamp }

Accessibility Primitives (Phase 9) - 5 Functions

  • getA11yInfo(selector){ role, aria, tabindex, focusable, label }
  • getContrast(selector){ fg, bg, ratio, passes: { AA, AAA } }
    • Implements WCAG 2.0 contrast ratio calculation
  • getTabOrder(container){ elements, count }
  • getScreenReaderText(selector)string
  • auditAccessibility(){ errors, warnings, score }
    • Scans for missing alt text, unlabeled buttons, missing labels
    • Returns score 0-100 based on issues found

Composite Convenience Functions (Phase 10) - 3 Functions

Built from primitives - high-value for LLMs:

  • inspect(selector) - Comprehensive element inspection

    {
      info: getElementInfo(),
      position: getPosition(),
      box: getBox(),
      layout: getLayout(),
      stacking: getStacking(),
      container: getContainer(),
      visibility: isVisible(),
      viewport: isInViewport()
    }
  • diagnoseLayout(selector) - Find layout issues

    {
      overflows: findOverflows(),
      stackingContexts: findStackingContexts(),
      offscreen: findOffscreen()
    }
  • showLayout(config) - Visual debugging overlay

    // Combines highlight() with smart defaults
    { overlayId, active: { borders, boxes } }

Testing Infrastructure

  • Created test-diagnostics.html comprehensive test page
  • Includes test buttons for all primitive categories
  • Examples of Flex, Grid, Stacking, Overflow, Transform layouts
  • Hidden elements for visibility testing
  • Console usage examples

Technical Details

Browser API Usage:

  • getBoundingClientRect() - Element positioning
  • getComputedStyle() - CSS property values
  • IntersectionObserver - Viewport visibility (future)
  • MutationObserver - Dynamic element detection
  • Container Query APIs - CSS containment detection
  • WCAG 2.0 formulas - Accessibility contrast ratios

Error Handling Pattern: All primitives follow consistent error handling:

function primitive(selector) {
  try {
    var el = resolveElement(selector);
    if (!el) return { error: 'Element not found' };
    // Do work
    return { /* data */ };
  } catch (e) {
    return { error: e.message };
  }
}

ES5 Compatibility:

  • All code uses ES5 syntax for broad browser support
  • No arrow functions, template literals, or modern features
  • Tested in modern browsers (Chrome, Firefox, Safari)

Usage Examples

Comprehensive Element Inspection:

proxy {action: "exec", id: "dev", code: "window.__devtool.inspect('#my-element')"}
// Returns 8+ data structures with complete element analysis

Interactive Element Selection:

proxy {action: "exec", id: "dev", code: "window.__devtool.selectElement()"}
// User clicks element, returns selector and element reference

Accessibility Audit:

proxy {action: "exec", id: "dev", code: "window.__devtool.auditAccessibility()"}
// Returns: { errors: [...], warnings: [...], score: 85 }

Layout Diagnostics:

proxy {action: "exec", id: "dev", code: "window.__devtool.diagnoseLayout()"}
// Finds all overflows, stacking contexts, offscreen elements

Contrast Checking:

proxy {action: "exec", id: "dev", code: "window.__devtool.getContrast('.my-button')"}
// Returns: { ratio: 4.52, passes: { AA: true, AAA: false } }

Benefits

  1. LLM Composability: LLMs can create unlimited combinations from primitives
  2. Debuggability: Rich data structures for analysis instead of strings
  3. Interactivity: Ask questions, select elements, measure distances
  4. Visual Feedback: Overlays show layout structure before screenshots
  5. Performance: All primitives O(1) or O(n) where n is small
  6. Maintainability: Small functions with clear responsibilities
  7. Accessibility: Built-in WCAG compliance checking

Breaking Changes

  • None - All changes are backward compatible
  • Existing screenshot and logging functionality unchanged
  • New primitives are purely additive

Performance Impact

  • Code size: +~3500 lines JavaScript (~100KB uncompressed, ~30KB gzipped)
  • Runtime: All primitives complete in <10ms on typical pages
  • Memory: Minimal - most functions are stateless
  • Interactive functions (selectElement, ask) wait for user input