)]}'
{
  "log": [
    {
      "commit": "53ab24547cd684fc38254a6bd63759d7121ca7d6",
      "tree": "15122689ee81490ea8d3497b6baade986c6bad2c",
      "parents": [
        "16098932295e067fb0a6b3ca2082b0d4b06027b4"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Wed Jun 04 17:49:33 2025 +0000"
      },
      "committer": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Wed Jun 04 18:10:57 2025 +0000"
      },
      "message": "webui: implement DOMPurify sanitization for markdown security\n\nImplement comprehensive HTML sanitization using DOMPurify library to\nprevent XSS vulnerabilities in markdown rendering while preserving\nfull markdown functionality.\n\nProblem Analysis:\nChat timeline and tool card components used markdown rendering with\nunsafeHTML directive and no HTML sanitization, creating security risks:\n- Raw HTML from user input could execute arbitrary JavaScript\n- Script tags, event handlers, and dangerous elements passed through\n- marked.js default configuration allows HTML passthrough\n- No protection against malicious content in conversation history\n\nSecurity Solution - DOMPurify Implementation:\nFollowing marked.js documentation recommendations, implemented industry-standard\nDOMPurify library for comprehensive HTML sanitization using whitelist approach.\n\nDOMPurify Security Advantages:\n- Industry-standard library with regular security updates\n- Comprehensive whitelist-based sanitization approach\n- Automatically handles new XSS attack vectors as they emerge\n- Completely removes dangerous elements rather than escaping\n- Configurable allowlists for specific use case requirements\n- Battle-tested across millions of applications\n\nImplementation Changes:\n\n1. Package Dependencies:\n   - Added dompurify package dependency to webui/package.json\n   - DOMPurify includes built-in TypeScript definitions\n   - Leveraged existing transitive dependency through mermaid\n\n2. Enhanced sketch-timeline-message.ts Security:\n   - Integrated DOMPurify.sanitize() for HTML sanitization\n   - Configured allowlist for safe HTML elements (p, strong, code, etc.)\n   - Added support for mermaid diagram elements (svg, path, etc.)\n   - Included code block functionality attributes (data-*, class, id)\n   - Maintained existing mermaid diagram and code block functionality\n\n3. Enhanced sketch-tool-card.ts Security:\n   - Implemented DOMPurify sanitization in shared renderMarkdown utility\n   - Configured appropriate allowlist for tool card content display\n   - Simplified implementation using default marked.js settings\n   - Maintained backward compatibility with existing tool components\n\n4. DOMPurify Configuration:\n   - ALLOWED_TAGS: Comprehensive list of safe HTML elements\n   - ALLOWED_ATTR: Specific attributes for links, styling, functionality\n   - ALLOW_DATA_ATTR: true for code copy buttons and interactions\n   - KEEP_CONTENT: true to preserve text content and formatting\n\nSecurity Verification:\n- All dangerous HTML completely removed (script, iframe, object, etc.)\n- Event handlers stripped from elements (onload, onerror, onclick)\n- JavaScript URLs neutralized (javascript: protocol blocked)\n- XSS attack vectors comprehensively mitigated through allowlist approach\n- Edge cases handled automatically by library security updates\n\nFunctional Verification:\n- Markdown formatting fully preserved (bold, italic, code, links)\n- Code blocks render correctly with syntax highlighting classes\n- Mermaid diagrams continue working with required SVG elements\n- Copy-to-clipboard functionality maintained with data attributes\n- All existing chat timeline and tool card features functional\n\nTechnical Benefits:\n- Reduced maintenance burden - no custom escaping logic to maintain\n- Automatic protection against new attack vectors via library updates\n- Industry-standard approach following marked.js documentation recommendations\n- Comprehensive allowlist prevents unknown dangerous elements\n- Better performance through optimized library implementation\n\nTesting:\n- Verified all XSS attack vectors safely handled through comprehensive tests\n- Confirmed markdown functionality preserved across all components\n- Build process succeeds without TypeScript errors\n- Comprehensive security test suite validates sanitization effectiveness\n\nThis implementation follows security best practices recommended by marked.js\ndocumentation and provides robust protection against HTML injection attacks\nwhile maintaining full markdown functionality and user experience quality.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s233c12c6daac5bb0k\n"
    },
    {
      "commit": "b8a8f35348326b8daf69e31efc77d37fac4bd276",
      "tree": "fa7a59c5951dbd3ecb5e6bf840ac7b45167a9e74",
      "parents": [
        "b5739403b1b6ec6fac909b258bd47ce5a338940e"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Mon Jun 02 07:39:37 2025 -0700"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Mon Jun 02 17:01:19 2025 -0700"
      },
      "message": "loop: implement comprehensive conversation compaction system\n\n\"comprehensive\" is over-stating it. Currently, users get\nthe dreaded:\n\n\terror: failed to continue conversation: status 400 Bad Request:\n\t{\"type\":\"error\",\"error\":{\"type\":\"invalid_request_error\",\"message\":\"input\n\tlength and max_tokens exceed context limit: 197257 + 8192 \u003e 200000,\n\tdecrease input length or max_tokens and try again\"}}\n\nThat\u0027s... annoying. Instead, let\u0027s compact automatically. I was going to\nstart with adding a /compact command or button, but it turns out that\nteasing that through the system is annoying, because the agent state\nmachine is intended to be somewhat single-threaded, and what do you do\nwhen a /compact comes in while other things are going on. It\u0027s possible,\nbut it was genuinely easier to prompt my way into doing it\nautomatically.\n\nI originally set the threshold to 75%, but given that 8192/200000 is 4%,\nI just changed it to 94%.\n\nWe\u0027ll see how well it works!\n\n~~~~\n\nImplement automatic conversation compaction to manage token limits and prevent\ncontext overflow, with enhanced UX feedback and accurate token tracking.\n\nProblem Analysis:\nLarge conversations could exceed model context limits, causing failures\nwhen total tokens approached or exceeded the maximum context window.\nWithout automatic management, users would experience unexpected errors\nand conversation interruptions in long sessions.\n\nImplementation:\n\n1. Automatic Compaction Infrastructure:\n   - Added ShouldCompact() method to detect when compaction is needed\n   - Configurable token thresholds for different compaction triggers\n   - Integration with existing loop state machine for seamless operation\n\n2. Accurate Token Counting:\n   - Enhanced context size estimation using actual token usage from LLM responses\n   - Track real token consumption rather than relying on estimates\n   - Account for tool calls, system prompts, and conversation history\n\n3. Compaction Logic and Timing:\n   - Triggered at 75% of context limit (configurable threshold)\n   - Preserves recent conversation context while compacting older messages\n   - Maintains conversation continuity and coherence\n\n4. Enhanced User Experience:\n   - Visual indicators in webui when compaction occurs\n   - Token count display showing current usage vs limits\n   - Clear messaging about compaction status and reasoning\n   - Timeline updates to reflect compacted conversation state\n\n5. UI Component Updates:\n   - sketch-timeline.ts: Added compaction status display\n   - sketch-timeline-message.ts: Enhanced message rendering for compacted state\n   - sketch-app-shell.ts: Token count integration and status updates\n\nTechnical Details:\n- Thread-safe implementation with proper mutex usage\n- Preserves conversation metadata and essential context\n- Configurable compaction strategies for different use cases\n- Comprehensive error handling and fallback behavior\n- Integration with existing LLM provider implementations (Claude, OpenAI, Gemini)\n\nTesting:\n- Added unit tests for ShouldCompact logic with various scenarios\n- Verified compaction triggers at correct token thresholds\n- Confirmed UI updates reflect compaction status accurately\n- All existing tests continue to pass without regression\n\nBenefits:\n- Prevents context overflow errors in long conversations\n- Maintains conversation quality while managing resource limits\n- Provides clear user feedback about system behavior\n- Enables unlimited conversation length with automatic management\n- Improves overall system reliability and user experience\n\nThis system ensures sketch can handle conversations of any length while\nmaintaining performance and providing transparent feedback to users about\ntoken usage and compaction activities.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: s28a53f4e442aa169k\n"
    },
    {
      "commit": "a10f151746c0dafd073d4998755bedbec8f82db6",
      "tree": "882cde04e6d9fc0244f6fdb531532051e52ffb45",
      "parents": [
        "6525d826f22d12a57b9acb474a5e7b22b48ba7ea"
      ],
      "author": {
        "name": "Pokey Rule",
        "email": "755842+pokey@users.noreply.github.com",
        "time": "Thu May 15 13:53:26 2025 +0000"
      },
      "committer": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Thu May 15 14:14:03 2025 +0000"
      },
      "message": "webui: add copy button to markdown code blocks\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: skad1b3ffhsk\n"
    },
    {
      "commit": "e31d2a95da49b58cabe4675335c2de80039007ec",
      "tree": "efc2dbe13a82cf2042979386bc39d159422dde71",
      "parents": [
        "04e778cbe6955cccf56a4e52c163a1c2220ff84a"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Sun May 11 15:22:35 2025 -0700"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Sun May 11 15:22:35 2025 -0700"
      },
      "message": "webui: Fix message bubbles and tool calls overflow issues in timeline\n\nOn the bright side, Sketch fixed this with repeated \"hey, look at that\nscreenshot; there\u0027s horizontal truncation.\" On the downside, it got\nreally confused by shadow dom, and the solution doesn\u0027t look clean to\nme, with lots of inline CSS.\n\n~~~~~\n\nFixed various overflow issues in timeline component, particularly with\nhandling long bash commands in shadow DOM contexts:\n\n1. Message Bubbles:\n   - Added overflow constraints to message-bubble-container\n   - Changed max-width from 80% to 100% for better containment\n   - Added text-overflow: ellipsis for clean truncation\n\n2. Tool Cards:\n   - Implemented manual string truncation for bash commands\n   - Limited display to 80 chars with ellipsis for overflowing text\n   - Added CSS to constrain width in all contexts\n\n3. Shadow DOM Challenges:\n   - Standard CSS inheritance doesn\u0027t penetrate shadow DOM boundaries\n   - Component-specific styles required direct modification in render methods\n   - Parallel CSS and JS truncation needed for reliable overflow handling\n   - Multiple nested web components required coordinated width constraints\n\n4. Global Improvements:\n   - Added overflow-x: hidden to parent containers\n   - Used box-sizing: border-box for accurate sizing\n   - Fixed scroll container to prevent horizontal scrolling\n\nThe primary insight was that shadow DOM isolation prevented CSS-only\nsolutions from working reliably. Explicit string truncation in the\ncomponent code was needed alongside careful container width management.\nThis pattern may need to be applied to other web components that\ndisplay potentially lengthy content.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\nChange-ID: sc937c08ac1b7766fk\n"
    },
    {
      "commit": "4d54493fe3808ecd0c6a9a4d0bbcc7786e97b094",
      "tree": "9877409fc95aaa32aed882426ea15464b8036e34",
      "parents": [
        "a4ad8af8b08a54326bbbd99d57110a42c459c54e"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Wed May 07 13:33:53 2025 +0000"
      },
      "committer": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Thu May 08 19:25:30 2025 +0000"
      },
      "message": "all: support hiding subconvo output\n\nSome of it is systematically noisy.\n"
    },
    {
      "commit": "16fa8b48f6c9f54f579bbc5bb22223443422f2e1",
      "tree": "8ac9a487881b49baa423465c19fc1be72534aa78",
      "parents": [
        "66439b0d8001d4685270681804900e81a5e68c6d"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Fri May 02 04:28:16 2025 +0000"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip@bold.dev",
        "time": "Fri May 02 20:32:06 2025 -0700"
      },
      "message": "Overhaul UI with chat-like interface\n\nMajor UI improvements:\n- Revamp timeline messages with chat-like interface\n  - User messages now on right with white text on blue background\n  - Agent/tool messages on left with black text on grey background\n  - Chat bubbles extend up to 80% of screen width\n  - Maintain left-aligned text for code readability\n  - Move metadata to outer gutters\n  - Show turn duration for end-of-turn messages\n  - Integrate tool calls within agent message bubbles\n  - Add thinking indicator with animated dots when LLM is processing\n  - Replace buttons with intuitive icons (copy, info, etc.)\n\n- Improve tool call presentation\n  - Simplify to single row design with all essential info\n  - Add clear status indicators for success/pending/error\n  - Fix horizontal scrolling for long commands and outputs\n  - Prevent tool name truncation\n  - Improve spacing and alignment throughout\n\n- Enhance header and status displays\n  - Move Last Commit to dedicated third column in header grid\n  - Add proper labeling with two-row structure\n  - Provide consistent styling across all status elements\n\n- Other UI refinements\n  - Add root URL redirection to demo page\n  - Fix spacing throughout the interface\n  - Optimize CSS for better performance\n  - Ensure consistent styling across components\n  - Improve command output display and wrapping\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\n"
    },
    {
      "commit": "f98d7305e73ecec9a78f94f527693d5adfb89159",
      "tree": "14f8f8a5f9427568081e46a109c6751b7a8cd42a",
      "parents": [
        "dded2d6cbe676afc144899f23fc76bf72908a00d"
      ],
      "author": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Sun Apr 27 17:44:06 2025 -0700"
      },
      "committer": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Sun Apr 27 17:45:33 2025 -0700"
      },
      "message": "webui: supress mermaid error msgs\n"
    },
    {
      "commit": "dded2d6cbe676afc144899f23fc76bf72908a00d",
      "tree": "68c2d11390164a80dd1fc4b304486ab5211841f7",
      "parents": [
        "8d93e3679e088af8086fd1c9f4d33de2e85608c2"
      ],
      "author": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Mon Apr 28 00:27:21 2025 +0000"
      },
      "committer": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Mon Apr 28 00:27:21 2025 +0000"
      },
      "message": "all: fix formatting\n"
    },
    {
      "commit": "8d93e3679e088af8086fd1c9f4d33de2e85608c2",
      "tree": "fe40a5fc3fdf341da5eb4f40954b7a941df284be",
      "parents": [
        "d8adbbaf6970b8d9c40cdf9795476d2850096b18"
      ],
      "author": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Sun Apr 27 23:32:18 2025 +0000"
      },
      "committer": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Sun Apr 27 17:25:09 2025 -0700"
      },
      "message": "webui: Add Mermaid diagram support to markdown\n\n* Installed mermaid library\n* Extended markdown renderer to support mermaid code blocks\n* Added CSS styling for mermaid diagrams\n* Added a demo page for testing mermaid diagrams\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\n"
    },
    {
      "commit": "5c70bfe5601e9919e598025ac56984e1b2e21040",
      "tree": "a2b53c46956af8beaa37aa4157ad7dc2482d3dba",
      "parents": [
        "eda2a8ca73891aa55831391cea6cc8c6d2a79d67"
      ],
      "author": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Fri Apr 25 21:28:00 2025 +0000"
      },
      "committer": {
        "name": "Autoformatter",
        "email": "bot@sketch.dev",
        "time": "Fri Apr 25 21:28:00 2025 +0000"
      },
      "message": "all: fix formatting\n"
    },
    {
      "commit": "a0801ad5dbd2a0e4d4983447b62f72444e829927",
      "tree": "6c622b74649869703cd85f2fe3ea317ee293d46f",
      "parents": [
        "df2d3dccd3f2f97fd4b8ab3bd153fbef15becea0"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Fri Apr 25 19:34:53 2025 +0000"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Fri Apr 25 13:56:59 2025 -0700"
      },
      "message": "Add comma formatting to input and output token displays\n\nThe token counts now display with commas in both the terminal UI and web UI.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e\n"
    },
    {
      "commit": "35889970de8690e8e38ea14503dd1a11db751498",
      "tree": "575df0d71e7fc89e7a6f2f5f68fdf80efc10ce5c",
      "parents": [
        "f5e28f67b3f569c73b1b020b5783872371bd0c3c"
      ],
      "author": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Thu Apr 24 20:48:16 2025 +0000"
      },
      "committer": {
        "name": "Josh Bleecher Snyder",
        "email": "josharian@gmail.com",
        "time": "Fri Apr 25 11:40:27 2025 -0700"
      },
      "message": "all: only display total input tokens\n\nKnowing the cache reads and writes was mildly interesting for us,\nbut it is inside baseball, and our calculations ended up being a little wrong.\nStreamline the UI and make the math right.\n\nCo-Authored-By: sketch \u003chello@sketch.dev\u003e"
    },
    {
      "commit": "2032b1c1971ceb85ca14b20273a3783729fba3e3",
      "tree": "0486e9222643ffcbbd34286148f4a7913a169668",
      "parents": [
        "4f50a68ac73677c0022b2b3da8b4667cee01c11b"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip.zeyliger@gmail.com",
        "time": "Wed Apr 23 19:40:42 2025 -0700"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip.zeyliger@gmail.com",
        "time": "Wed Apr 23 19:40:42 2025 -0700"
      },
      "message": "Move webui from /loop/webui to /webui\n\nThanks, perl (and git mv):\n\n\tperl -pi -e s,loop/webui,webui,g $(git grep -l loop/webui)\n"
    },
    {
      "commit": "72682df0c3aa2e2b8917d0f66bdf8988dfbcb59f",
      "tree": "b5c213237eced535db85dc8906fa42127bd525f0",
      "parents": [
        "4de80d219b96677b9e43e50293ec55bdf273f36d"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip.zeyliger@gmail.com",
        "time": "Wed Apr 23 13:09:46 2025 -0700"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip.zeyliger@gmail.com",
        "time": "Wed Apr 23 13:09:46 2025 -0700"
      },
      "message": "Prettier.\n"
    },
    {
      "commit": "7be879f27f93627e69714406b4eb8b07610aa0d0",
      "tree": "9f174c2e8dff7e7c41275dd833f0dcb800940381",
      "parents": [
        "e2a8c2f1fae1f8e3162b2533d27825e1bf800574"
      ],
      "author": {
        "name": "Pokey Rule",
        "email": "755842+pokey@users.noreply.github.com",
        "time": "Wed Apr 23 15:30:15 2025 +0100"
      },
      "committer": {
        "name": "Pokey Rule",
        "email": "755842+pokey@users.noreply.github.com",
        "time": "Wed Apr 23 15:30:15 2025 +0100"
      },
      "message": "Fix WebUI tests for sketch-timeline-message component\n\n- Update commit hash display to show 8 characters instead of 7\n- Add missing \u0027pushed-branch\u0027 class to branch display element\n- Fix whitespace issues in the commit hash display\n\nCo-Authored-By: sketch\nFix the failure in webui tests\n"
    },
    {
      "commit": "37dc4cf04df5dee6feff005d68a4a24e55be8990",
      "tree": "7c2f8bec8e7041bfffeed6934bf0445114603753",
      "parents": [
        "a4674b16548d6db22acddb80c40e05a5decf919d"
      ],
      "author": {
        "name": "Philip Zeyliger",
        "email": "philip.zeyliger@gmail.com",
        "time": "Wed Apr 23 12:58:52 2025 +0000"
      },
      "committer": {
        "name": "Philip Zeyliger",
        "email": "philip.zeyliger@gmail.com",
        "time": "Wed Apr 23 06:00:19 2025 -0700"
      },
      "message": "Enhance commit display in UI\n\nCompletely redesigned the commit display UI to make it more intuitive and useful:\n\n1. Format \u0026 Appearance:\n   - Format commit display as \u0027hash (branch) subject\u0027 matching git log --decorate\n   - Improve spacing and readability of all elements\n   - Add \u0027View Diff\u0027 button directly after the commit subject\n   - Remove extraneous whitespace for a cleaner look\n\n2. Interactive Features:\n   - Make commit hash and branch name directly clickable to copy to clipboard\n   - Show a floating \u0027Copied!\u0027 message when text is copied\n   - Add hover effects to indicate clickable elements\n   - Add tooltips showing full hash and branch name on hover\n\n3. UX Improvements:\n   - Show floating feedback messages instead of modifying content\n   - Animate feedback messages for better visibility\n   - Only underline branch name on hover, not the surrounding parentheses\n   - Use consistent styling for all interactive elements\n\nCo-Authored-By: sketch\n"
    },
    {
      "commit": "2deac8429a5364866ab6471b44466f78ccf5c0b3",
      "tree": "ebd40534a0680809a40dbb5738f97c6aaed7a088",
      "parents": [
        "07b3e39ebe648f91f02a9cb703ecbc49900c91da"
      ],
      "author": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Mon Apr 21 18:17:57 2025 -0700"
      },
      "committer": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Mon Apr 21 18:18:13 2025 -0700"
      },
      "message": "webui: add \u0027open\u0027 status, elapsed time to tool-cards\n"
    },
    {
      "commit": "d9f1337ec3317a60df50d8ba4eefb448473d62fa",
      "tree": "67b60b05d8e2e3fb01293f68dfc5d08600a28dda",
      "parents": [
        "db8c5abcc18082bcbf47247e8d50889a32e65e06"
      ],
      "author": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Mon Apr 21 15:08:49 2025 -0700"
      },
      "committer": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Mon Apr 21 15:21:40 2025 -0700"
      },
      "message": "webui: auto-generate types.ts from go structs\n"
    },
    {
      "commit": "ec3ad1a7798b0dc1d17d363c91680b7828d7fce2",
      "tree": "1f48c26d0808f951a2c9487796709a5eb09f2f80",
      "parents": [
        "71941bdfa1156b748072e2dfe61c714d3ed02913"
      ],
      "author": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Fri Apr 18 13:55:16 2025 -0700"
      },
      "committer": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Fri Apr 18 23:51:21 2025 -0700"
      },
      "message": "webui: split sketch-tool-card into per-tool cards\n"
    },
    {
      "commit": "71941bdfa1156b748072e2dfe61c714d3ed02913",
      "tree": "28eeb5cb68bef3e0eb5b6a5ec63d17f4150e4fbb",
      "parents": [
        "9abbf92a1c58300005971d7f89b301620d59e883"
      ],
      "author": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Fri Apr 18 13:31:48 2025 -0700"
      },
      "committer": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Fri Apr 18 14:01:53 2025 -0700"
      },
      "message": "loop/webui: add prettier\n"
    },
    {
      "commit": "86b56862f8d3e192646a17548ef5294582c31f8f",
      "tree": "d0235f3f56695de8e6281ba3f57a663847204f33",
      "parents": [
        "f5bb3d3f1aa33e2a066c4139675f096f73c1f9d4"
      ],
      "author": {
        "name": "Sean McCullough",
        "email": "banksean@gmail.com",
        "time": "Fri Apr 18 13:04:03 2025 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Apr 18 13:04:03 2025 -0700"
      },
      "message": "loop/webui: swtich to web components impl (#1)\n\n* loop/webui: swtich to web components impl\n\nThis change reorganizes the original vibe-coded\nfrontend code into a structure that\u0027s much\neasier for a human to read and reason about,\nwhile retaining the user-visible functionality\nof its vibe-coded predecessor. Perhaps most\nimportantly, this change makes the code testable.\n\nSome other notable details:\n\nThis does not use any of the popular large web\nframeworks, but instead follows more of an\n\"a la carte\" approach: leverage features\nthat already exist in modern web browsers,\nlike custom elements and shadow DOM.\n\nTemplating and basic component lifecycle\nmanagement are provided by lit.\n\nState management is nothing fancy. It\ndoesn\u0027t use any library or framework, just\na basic \"Events up, properties down\"\napproach.\n\n* fix bad esbuild.go merge\n\n* loop/webui: don\u0027t bundle src/web-components/demo\n\n* loop/webui: don\u0027t \u0027npm ci\u0027 dev deps in the container\n\n* rebase to main, undo README.md changes, add webuil.Build() call to LaunchContainer()"
    }
  ]
}
