 85bf1341f3
			
		
	
	85bf1341f3
	
	
	
		
			
			Frontend Enhancements: - Complete React TypeScript frontend with modern UI components - Distributed workflows management interface with real-time updates - Socket.IO integration for live agent status monitoring - Agent management dashboard with cluster visualization - Project management interface with metrics and task tracking - Responsive design with proper error handling and loading states Backend Infrastructure: - Distributed coordinator for multi-agent workflow orchestration - Cluster management API with comprehensive agent operations - Enhanced database models for agents and projects - Project service for filesystem-based project discovery - Performance monitoring and metrics collection - Comprehensive API documentation and error handling Documentation: - Complete distributed development guide (README_DISTRIBUTED.md) - Comprehensive development report with architecture insights - System configuration templates and deployment guides The platform now provides a complete web interface for managing the distributed AI cluster with real-time monitoring, workflow orchestration, and agent coordination capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			271 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			271 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "use strict";
 | |
| Object.defineProperty(exports, "__esModule", {
 | |
|     value: true
 | |
| });
 | |
| function _export(target, all) {
 | |
|     for(var name in all)Object.defineProperty(target, name, {
 | |
|         enumerable: true,
 | |
|         get: all[name]
 | |
|     });
 | |
| }
 | |
| _export(exports, {
 | |
|     formatVariantSelector: function() {
 | |
|         return formatVariantSelector;
 | |
|     },
 | |
|     eliminateIrrelevantSelectors: function() {
 | |
|         return eliminateIrrelevantSelectors;
 | |
|     },
 | |
|     finalizeSelector: function() {
 | |
|         return finalizeSelector;
 | |
|     },
 | |
|     handleMergePseudo: function() {
 | |
|         return handleMergePseudo;
 | |
|     }
 | |
| });
 | |
| const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
 | |
| const _unesc = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser/dist/util/unesc"));
 | |
| const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("../util/escapeClassName"));
 | |
| const _prefixSelector = /*#__PURE__*/ _interop_require_default(require("../util/prefixSelector"));
 | |
| const _pseudoElements = require("./pseudoElements");
 | |
| const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly");
 | |
| function _interop_require_default(obj) {
 | |
|     return obj && obj.__esModule ? obj : {
 | |
|         default: obj
 | |
|     };
 | |
| }
 | |
| /** @typedef {import('postcss-selector-parser').Root} Root */ /** @typedef {import('postcss-selector-parser').Selector} Selector */ /** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */ /** @typedef {import('postcss-selector-parser').Node} Node */ /** @typedef {{format: string, respectPrefix: boolean}[]} RawFormats */ /** @typedef {import('postcss-selector-parser').Root} ParsedFormats */ /** @typedef {RawFormats | ParsedFormats} AcceptedFormats */ let MERGE = ":merge";
 | |
| function formatVariantSelector(formats, { context , candidate  }) {
 | |
|     var _context_tailwindConfig_prefix;
 | |
|     let prefix = (_context_tailwindConfig_prefix = context === null || context === void 0 ? void 0 : context.tailwindConfig.prefix) !== null && _context_tailwindConfig_prefix !== void 0 ? _context_tailwindConfig_prefix : "";
 | |
|     // Parse the format selector into an AST
 | |
|     let parsedFormats = formats.map((format)=>{
 | |
|         let ast = (0, _postcssselectorparser.default)().astSync(format.format);
 | |
|         return {
 | |
|             ...format,
 | |
|             ast: format.respectPrefix ? (0, _prefixSelector.default)(prefix, ast) : ast
 | |
|         };
 | |
|     });
 | |
|     // We start with the candidate selector
 | |
|     let formatAst = _postcssselectorparser.default.root({
 | |
|         nodes: [
 | |
|             _postcssselectorparser.default.selector({
 | |
|                 nodes: [
 | |
|                     _postcssselectorparser.default.className({
 | |
|                         value: (0, _escapeClassName.default)(candidate)
 | |
|                     })
 | |
|                 ]
 | |
|             })
 | |
|         ]
 | |
|     });
 | |
|     // And iteratively merge each format selector into the candidate selector
 | |
|     for (let { ast  } of parsedFormats){
 | |
|         [formatAst, ast] = handleMergePseudo(formatAst, ast);
 | |
|         // 2. Merge the format selector into the current selector AST
 | |
|         ast.walkNesting((nesting)=>nesting.replaceWith(...formatAst.nodes[0].nodes));
 | |
|         // 3. Keep going!
 | |
|         formatAst = ast;
 | |
|     }
 | |
|     return formatAst;
 | |
| }
 | |
| /**
 | |
|  * Given any node in a selector this gets the "simple" selector it's a part of
 | |
|  * A simple selector is just a list of nodes without any combinators
 | |
|  * Technically :is(), :not(), :has(), etc… can have combinators but those are nested
 | |
|  * inside the relevant node and won't be picked up so they're fine to ignore
 | |
|  *
 | |
|  * @param {Node} node
 | |
|  * @returns {Node[]}
 | |
|  **/ function simpleSelectorForNode(node) {
 | |
|     /** @type {Node[]} */ let nodes = [];
 | |
|     // Walk backwards until we hit a combinator node (or the start)
 | |
|     while(node.prev() && node.prev().type !== "combinator"){
 | |
|         node = node.prev();
 | |
|     }
 | |
|     // Now record all non-combinator nodes until we hit one (or the end)
 | |
|     while(node && node.type !== "combinator"){
 | |
|         nodes.push(node);
 | |
|         node = node.next();
 | |
|     }
 | |
|     return nodes;
 | |
| }
 | |
| /**
 | |
|  * Resorts the nodes in a selector to ensure they're in the correct order
 | |
|  * Tags go before classes, and pseudo classes go after classes
 | |
|  *
 | |
|  * @param {Selector} sel
 | |
|  * @returns {Selector}
 | |
|  **/ function resortSelector(sel) {
 | |
|     sel.sort((a, b)=>{
 | |
|         if (a.type === "tag" && b.type === "class") {
 | |
|             return -1;
 | |
|         } else if (a.type === "class" && b.type === "tag") {
 | |
|             return 1;
 | |
|         } else if (a.type === "class" && b.type === "pseudo" && b.value.startsWith("::")) {
 | |
|             return -1;
 | |
|         } else if (a.type === "pseudo" && a.value.startsWith("::") && b.type === "class") {
 | |
|             return 1;
 | |
|         }
 | |
|         return sel.index(a) - sel.index(b);
 | |
|     });
 | |
|     return sel;
 | |
| }
 | |
| function eliminateIrrelevantSelectors(sel, base) {
 | |
|     let hasClassesMatchingCandidate = false;
 | |
|     sel.walk((child)=>{
 | |
|         if (child.type === "class" && child.value === base) {
 | |
|             hasClassesMatchingCandidate = true;
 | |
|             return false // Stop walking
 | |
|             ;
 | |
|         }
 | |
|     });
 | |
|     if (!hasClassesMatchingCandidate) {
 | |
|         sel.remove();
 | |
|     }
 | |
| // We do NOT recursively eliminate sub selectors that don't have the base class
 | |
| // as this is NOT a safe operation. For example, if we have:
 | |
| // `.space-x-2 > :not([hidden]) ~ :not([hidden])`
 | |
| // We cannot remove the [hidden] from the :not() because it would change the
 | |
| // meaning of the selector.
 | |
| // TODO: Can we do this for :matches, :is, and :where?
 | |
| }
 | |
| function finalizeSelector(current, formats, { context , candidate , base  }) {
 | |
|     var _context_tailwindConfig;
 | |
|     var _context_tailwindConfig_separator;
 | |
|     let separator = (_context_tailwindConfig_separator = context === null || context === void 0 ? void 0 : (_context_tailwindConfig = context.tailwindConfig) === null || _context_tailwindConfig === void 0 ? void 0 : _context_tailwindConfig.separator) !== null && _context_tailwindConfig_separator !== void 0 ? _context_tailwindConfig_separator : ":";
 | |
|     // Split by the separator, but ignore the separator inside square brackets:
 | |
|     //
 | |
|     // E.g.: dark:lg:hover:[paint-order:markers]
 | |
|     //           ┬  ┬     ┬            ┬
 | |
|     //           │  │     │            ╰── We will not split here
 | |
|     //           ╰──┴─────┴─────────────── We will split here
 | |
|     //
 | |
|     base = base !== null && base !== void 0 ? base : (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(candidate, separator).pop();
 | |
|     // Parse the selector into an AST
 | |
|     let selector = (0, _postcssselectorparser.default)().astSync(current);
 | |
|     // Normalize escaped classes, e.g.:
 | |
|     //
 | |
|     // The idea would be to replace the escaped `base` in the selector with the
 | |
|     // `format`. However, in css you can escape the same selector in a few
 | |
|     // different ways. This would result in different strings and therefore we
 | |
|     // can't replace it properly.
 | |
|     //
 | |
|     //               base: bg-[rgb(255,0,0)]
 | |
|     //   base in selector: bg-\\[rgb\\(255\\,0\\,0\\)\\]
 | |
|     //       escaped base: bg-\\[rgb\\(255\\2c 0\\2c 0\\)\\]
 | |
|     //
 | |
|     selector.walkClasses((node)=>{
 | |
|         if (node.raws && node.value.includes(base)) {
 | |
|             node.raws.value = (0, _escapeClassName.default)((0, _unesc.default)(node.raws.value));
 | |
|         }
 | |
|     });
 | |
|     // Remove extraneous selectors that do not include the base candidate
 | |
|     selector.each((sel)=>eliminateIrrelevantSelectors(sel, base));
 | |
|     // If ffter eliminating irrelevant selectors, we end up with nothing
 | |
|     // Then the whole "rule" this is associated with does not need to exist
 | |
|     // We use `null` as a marker value for that case
 | |
|     if (selector.length === 0) {
 | |
|         return null;
 | |
|     }
 | |
|     // If there are no formats that means there were no variants added to the candidate
 | |
|     // so we can just return the selector as-is
 | |
|     let formatAst = Array.isArray(formats) ? formatVariantSelector(formats, {
 | |
|         context,
 | |
|         candidate
 | |
|     }) : formats;
 | |
|     if (formatAst === null) {
 | |
|         return selector.toString();
 | |
|     }
 | |
|     let simpleStart = _postcssselectorparser.default.comment({
 | |
|         value: "/*__simple__*/"
 | |
|     });
 | |
|     let simpleEnd = _postcssselectorparser.default.comment({
 | |
|         value: "/*__simple__*/"
 | |
|     });
 | |
|     // We can safely replace the escaped base now, since the `base` section is
 | |
|     // now in a normalized escaped value.
 | |
|     selector.walkClasses((node)=>{
 | |
|         if (node.value !== base) {
 | |
|             return;
 | |
|         }
 | |
|         let parent = node.parent;
 | |
|         let formatNodes = formatAst.nodes[0].nodes;
 | |
|         // Perf optimization: if the parent is a single class we can just replace it and be done
 | |
|         if (parent.nodes.length === 1) {
 | |
|             node.replaceWith(...formatNodes);
 | |
|             return;
 | |
|         }
 | |
|         let simpleSelector = simpleSelectorForNode(node);
 | |
|         parent.insertBefore(simpleSelector[0], simpleStart);
 | |
|         parent.insertAfter(simpleSelector[simpleSelector.length - 1], simpleEnd);
 | |
|         for (let child of formatNodes){
 | |
|             parent.insertBefore(simpleSelector[0], child.clone());
 | |
|         }
 | |
|         node.remove();
 | |
|         // Re-sort the simple selector to ensure it's in the correct order
 | |
|         simpleSelector = simpleSelectorForNode(simpleStart);
 | |
|         let firstNode = parent.index(simpleStart);
 | |
|         parent.nodes.splice(firstNode, simpleSelector.length, ...resortSelector(_postcssselectorparser.default.selector({
 | |
|             nodes: simpleSelector
 | |
|         })).nodes);
 | |
|         simpleStart.remove();
 | |
|         simpleEnd.remove();
 | |
|     });
 | |
|     // Remove unnecessary pseudo selectors that we used as placeholders
 | |
|     selector.walkPseudos((p)=>{
 | |
|         if (p.value === MERGE) {
 | |
|             p.replaceWith(p.nodes);
 | |
|         }
 | |
|     });
 | |
|     // Move pseudo elements to the end of the selector (if necessary)
 | |
|     selector.each((sel)=>(0, _pseudoElements.movePseudos)(sel));
 | |
|     return selector.toString();
 | |
| }
 | |
| function handleMergePseudo(selector, format) {
 | |
|     /** @type {{pseudo: Pseudo, value: string}[]} */ let merges = [];
 | |
|     // Find all :merge() pseudo-classes in `selector`
 | |
|     selector.walkPseudos((pseudo)=>{
 | |
|         if (pseudo.value === MERGE) {
 | |
|             merges.push({
 | |
|                 pseudo,
 | |
|                 value: pseudo.nodes[0].toString()
 | |
|             });
 | |
|         }
 | |
|     });
 | |
|     // Find all :merge() "attachments" in `format` and attach them to the matching selector in `selector`
 | |
|     format.walkPseudos((pseudo)=>{
 | |
|         if (pseudo.value !== MERGE) {
 | |
|             return;
 | |
|         }
 | |
|         let value = pseudo.nodes[0].toString();
 | |
|         // Does `selector` contain a :merge() pseudo-class with the same value?
 | |
|         let existing = merges.find((merge)=>merge.value === value);
 | |
|         // Nope so there's nothing to do
 | |
|         if (!existing) {
 | |
|             return;
 | |
|         }
 | |
|         // Everything after `:merge()` up to the next combinator is what is attached to the merged selector
 | |
|         let attachments = [];
 | |
|         let next = pseudo.next();
 | |
|         while(next && next.type !== "combinator"){
 | |
|             attachments.push(next);
 | |
|             next = next.next();
 | |
|         }
 | |
|         let combinator = next;
 | |
|         existing.pseudo.parent.insertAfter(existing.pseudo, _postcssselectorparser.default.selector({
 | |
|             nodes: attachments.map((node)=>node.clone())
 | |
|         }));
 | |
|         pseudo.remove();
 | |
|         attachments.forEach((node)=>node.remove());
 | |
|         // What about this case:
 | |
|         // :merge(.group):focus > &
 | |
|         // :merge(.group):hover &
 | |
|         if (combinator && combinator.type === "combinator") {
 | |
|             combinator.remove();
 | |
|         }
 | |
|     });
 | |
|     return [
 | |
|         selector,
 | |
|         format
 | |
|     ];
 | |
| }
 |