 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>
		
			
				
	
	
		
			397 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			397 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| const {
 | |
|   ArrayPrototypeForEach,
 | |
|   ArrayPrototypeIncludes,
 | |
|   ArrayPrototypeMap,
 | |
|   ArrayPrototypePush,
 | |
|   ArrayPrototypePushApply,
 | |
|   ArrayPrototypeShift,
 | |
|   ArrayPrototypeSlice,
 | |
|   ArrayPrototypeUnshiftApply,
 | |
|   ObjectEntries,
 | |
|   ObjectPrototypeHasOwnProperty: ObjectHasOwn,
 | |
|   StringPrototypeCharAt,
 | |
|   StringPrototypeIndexOf,
 | |
|   StringPrototypeSlice,
 | |
|   StringPrototypeStartsWith,
 | |
| } = require('./internal/primordials');
 | |
| 
 | |
| const {
 | |
|   validateArray,
 | |
|   validateBoolean,
 | |
|   validateBooleanArray,
 | |
|   validateObject,
 | |
|   validateString,
 | |
|   validateStringArray,
 | |
|   validateUnion,
 | |
| } = require('./internal/validators');
 | |
| 
 | |
| const {
 | |
|   kEmptyObject,
 | |
| } = require('./internal/util');
 | |
| 
 | |
| const {
 | |
|   findLongOptionForShort,
 | |
|   isLoneLongOption,
 | |
|   isLoneShortOption,
 | |
|   isLongOptionAndValue,
 | |
|   isOptionValue,
 | |
|   isOptionLikeValue,
 | |
|   isShortOptionAndValue,
 | |
|   isShortOptionGroup,
 | |
|   useDefaultValueOption,
 | |
|   objectGetOwn,
 | |
|   optionsGetOwn,
 | |
| } = require('./utils');
 | |
| 
 | |
| const {
 | |
|   codes: {
 | |
|     ERR_INVALID_ARG_VALUE,
 | |
|     ERR_PARSE_ARGS_INVALID_OPTION_VALUE,
 | |
|     ERR_PARSE_ARGS_UNKNOWN_OPTION,
 | |
|     ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL,
 | |
|   },
 | |
| } = require('./internal/errors');
 | |
| 
 | |
| function getMainArgs() {
 | |
|   // Work out where to slice process.argv for user supplied arguments.
 | |
| 
 | |
|   // Check node options for scenarios where user CLI args follow executable.
 | |
|   const execArgv = process.execArgv;
 | |
|   if (ArrayPrototypeIncludes(execArgv, '-e') ||
 | |
|       ArrayPrototypeIncludes(execArgv, '--eval') ||
 | |
|       ArrayPrototypeIncludes(execArgv, '-p') ||
 | |
|       ArrayPrototypeIncludes(execArgv, '--print')) {
 | |
|     return ArrayPrototypeSlice(process.argv, 1);
 | |
|   }
 | |
| 
 | |
|   // Normally first two arguments are executable and script, then CLI arguments
 | |
|   return ArrayPrototypeSlice(process.argv, 2);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * In strict mode, throw for possible usage errors like --foo --bar
 | |
|  *
 | |
|  * @param {object} token - from tokens as available from parseArgs
 | |
|  */
 | |
| function checkOptionLikeValue(token) {
 | |
|   if (!token.inlineValue && isOptionLikeValue(token.value)) {
 | |
|     // Only show short example if user used short option.
 | |
|     const example = StringPrototypeStartsWith(token.rawName, '--') ?
 | |
|       `'${token.rawName}=-XYZ'` :
 | |
|       `'--${token.name}=-XYZ' or '${token.rawName}-XYZ'`;
 | |
|     const errorMessage = `Option '${token.rawName}' argument is ambiguous.
 | |
| Did you forget to specify the option argument for '${token.rawName}'?
 | |
| To specify an option argument starting with a dash use ${example}.`;
 | |
|     throw new ERR_PARSE_ARGS_INVALID_OPTION_VALUE(errorMessage);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * In strict mode, throw for usage errors.
 | |
|  *
 | |
|  * @param {object} config - from config passed to parseArgs
 | |
|  * @param {object} token - from tokens as available from parseArgs
 | |
|  */
 | |
| function checkOptionUsage(config, token) {
 | |
|   if (!ObjectHasOwn(config.options, token.name)) {
 | |
|     throw new ERR_PARSE_ARGS_UNKNOWN_OPTION(
 | |
|       token.rawName, config.allowPositionals);
 | |
|   }
 | |
| 
 | |
|   const short = optionsGetOwn(config.options, token.name, 'short');
 | |
|   const shortAndLong = `${short ? `-${short}, ` : ''}--${token.name}`;
 | |
|   const type = optionsGetOwn(config.options, token.name, 'type');
 | |
|   if (type === 'string' && typeof token.value !== 'string') {
 | |
|     throw new ERR_PARSE_ARGS_INVALID_OPTION_VALUE(`Option '${shortAndLong} <value>' argument missing`);
 | |
|   }
 | |
|   // (Idiomatic test for undefined||null, expecting undefined.)
 | |
|   if (type === 'boolean' && token.value != null) {
 | |
|     throw new ERR_PARSE_ARGS_INVALID_OPTION_VALUE(`Option '${shortAndLong}' does not take an argument`);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Store the option value in `values`.
 | |
|  *
 | |
|  * @param {string} longOption - long option name e.g. 'foo'
 | |
|  * @param {string|undefined} optionValue - value from user args
 | |
|  * @param {object} options - option configs, from parseArgs({ options })
 | |
|  * @param {object} values - option values returned in `values` by parseArgs
 | |
|  */
 | |
| function storeOption(longOption, optionValue, options, values) {
 | |
|   if (longOption === '__proto__') {
 | |
|     return; // No. Just no.
 | |
|   }
 | |
| 
 | |
|   // We store based on the option value rather than option type,
 | |
|   // preserving the users intent for author to deal with.
 | |
|   const newValue = optionValue ?? true;
 | |
|   if (optionsGetOwn(options, longOption, 'multiple')) {
 | |
|     // Always store value in array, including for boolean.
 | |
|     // values[longOption] starts out not present,
 | |
|     // first value is added as new array [newValue],
 | |
|     // subsequent values are pushed to existing array.
 | |
|     // (note: values has null prototype, so simpler usage)
 | |
|     if (values[longOption]) {
 | |
|       ArrayPrototypePush(values[longOption], newValue);
 | |
|     } else {
 | |
|       values[longOption] = [newValue];
 | |
|     }
 | |
|   } else {
 | |
|     values[longOption] = newValue;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Store the default option value in `values`.
 | |
|  *
 | |
|  * @param {string} longOption - long option name e.g. 'foo'
 | |
|  * @param {string
 | |
|  *         | boolean
 | |
|  *         | string[]
 | |
|  *         | boolean[]} optionValue - default value from option config
 | |
|  * @param {object} values - option values returned in `values` by parseArgs
 | |
|  */
 | |
| function storeDefaultOption(longOption, optionValue, values) {
 | |
|   if (longOption === '__proto__') {
 | |
|     return; // No. Just no.
 | |
|   }
 | |
| 
 | |
|   values[longOption] = optionValue;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Process args and turn into identified tokens:
 | |
|  * - option (along with value, if any)
 | |
|  * - positional
 | |
|  * - option-terminator
 | |
|  *
 | |
|  * @param {string[]} args - from parseArgs({ args }) or mainArgs
 | |
|  * @param {object} options - option configs, from parseArgs({ options })
 | |
|  */
 | |
| function argsToTokens(args, options) {
 | |
|   const tokens = [];
 | |
|   let index = -1;
 | |
|   let groupCount = 0;
 | |
| 
 | |
|   const remainingArgs = ArrayPrototypeSlice(args);
 | |
|   while (remainingArgs.length > 0) {
 | |
|     const arg = ArrayPrototypeShift(remainingArgs);
 | |
|     const nextArg = remainingArgs[0];
 | |
|     if (groupCount > 0)
 | |
|       groupCount--;
 | |
|     else
 | |
|       index++;
 | |
| 
 | |
|     // Check if `arg` is an options terminator.
 | |
|     // Guideline 10 in https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html
 | |
|     if (arg === '--') {
 | |
|       // Everything after a bare '--' is considered a positional argument.
 | |
|       ArrayPrototypePush(tokens, { kind: 'option-terminator', index });
 | |
|       ArrayPrototypePushApply(
 | |
|         tokens, ArrayPrototypeMap(remainingArgs, (arg) => {
 | |
|           return { kind: 'positional', index: ++index, value: arg };
 | |
|         })
 | |
|       );
 | |
|       break; // Finished processing args, leave while loop.
 | |
|     }
 | |
| 
 | |
|     if (isLoneShortOption(arg)) {
 | |
|       // e.g. '-f'
 | |
|       const shortOption = StringPrototypeCharAt(arg, 1);
 | |
|       const longOption = findLongOptionForShort(shortOption, options);
 | |
|       let value;
 | |
|       let inlineValue;
 | |
|       if (optionsGetOwn(options, longOption, 'type') === 'string' &&
 | |
|           isOptionValue(nextArg)) {
 | |
|         // e.g. '-f', 'bar'
 | |
|         value = ArrayPrototypeShift(remainingArgs);
 | |
|         inlineValue = false;
 | |
|       }
 | |
|       ArrayPrototypePush(
 | |
|         tokens,
 | |
|         { kind: 'option', name: longOption, rawName: arg,
 | |
|           index, value, inlineValue });
 | |
|       if (value != null) ++index;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (isShortOptionGroup(arg, options)) {
 | |
|       // Expand -fXzy to -f -X -z -y
 | |
|       const expanded = [];
 | |
|       for (let index = 1; index < arg.length; index++) {
 | |
|         const shortOption = StringPrototypeCharAt(arg, index);
 | |
|         const longOption = findLongOptionForShort(shortOption, options);
 | |
|         if (optionsGetOwn(options, longOption, 'type') !== 'string' ||
 | |
|           index === arg.length - 1) {
 | |
|           // Boolean option, or last short in group. Well formed.
 | |
|           ArrayPrototypePush(expanded, `-${shortOption}`);
 | |
|         } else {
 | |
|           // String option in middle. Yuck.
 | |
|           // Expand -abfFILE to -a -b -fFILE
 | |
|           ArrayPrototypePush(expanded, `-${StringPrototypeSlice(arg, index)}`);
 | |
|           break; // finished short group
 | |
|         }
 | |
|       }
 | |
|       ArrayPrototypeUnshiftApply(remainingArgs, expanded);
 | |
|       groupCount = expanded.length;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (isShortOptionAndValue(arg, options)) {
 | |
|       // e.g. -fFILE
 | |
|       const shortOption = StringPrototypeCharAt(arg, 1);
 | |
|       const longOption = findLongOptionForShort(shortOption, options);
 | |
|       const value = StringPrototypeSlice(arg, 2);
 | |
|       ArrayPrototypePush(
 | |
|         tokens,
 | |
|         { kind: 'option', name: longOption, rawName: `-${shortOption}`,
 | |
|           index, value, inlineValue: true });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (isLoneLongOption(arg)) {
 | |
|       // e.g. '--foo'
 | |
|       const longOption = StringPrototypeSlice(arg, 2);
 | |
|       let value;
 | |
|       let inlineValue;
 | |
|       if (optionsGetOwn(options, longOption, 'type') === 'string' &&
 | |
|           isOptionValue(nextArg)) {
 | |
|         // e.g. '--foo', 'bar'
 | |
|         value = ArrayPrototypeShift(remainingArgs);
 | |
|         inlineValue = false;
 | |
|       }
 | |
|       ArrayPrototypePush(
 | |
|         tokens,
 | |
|         { kind: 'option', name: longOption, rawName: arg,
 | |
|           index, value, inlineValue });
 | |
|       if (value != null) ++index;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (isLongOptionAndValue(arg)) {
 | |
|       // e.g. --foo=bar
 | |
|       const equalIndex = StringPrototypeIndexOf(arg, '=');
 | |
|       const longOption = StringPrototypeSlice(arg, 2, equalIndex);
 | |
|       const value = StringPrototypeSlice(arg, equalIndex + 1);
 | |
|       ArrayPrototypePush(
 | |
|         tokens,
 | |
|         { kind: 'option', name: longOption, rawName: `--${longOption}`,
 | |
|           index, value, inlineValue: true });
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     ArrayPrototypePush(tokens, { kind: 'positional', index, value: arg });
 | |
|   }
 | |
| 
 | |
|   return tokens;
 | |
| }
 | |
| 
 | |
| const parseArgs = (config = kEmptyObject) => {
 | |
|   const args = objectGetOwn(config, 'args') ?? getMainArgs();
 | |
|   const strict = objectGetOwn(config, 'strict') ?? true;
 | |
|   const allowPositionals = objectGetOwn(config, 'allowPositionals') ?? !strict;
 | |
|   const returnTokens = objectGetOwn(config, 'tokens') ?? false;
 | |
|   const options = objectGetOwn(config, 'options') ?? { __proto__: null };
 | |
|   // Bundle these up for passing to strict-mode checks.
 | |
|   const parseConfig = { args, strict, options, allowPositionals };
 | |
| 
 | |
|   // Validate input configuration.
 | |
|   validateArray(args, 'args');
 | |
|   validateBoolean(strict, 'strict');
 | |
|   validateBoolean(allowPositionals, 'allowPositionals');
 | |
|   validateBoolean(returnTokens, 'tokens');
 | |
|   validateObject(options, 'options');
 | |
|   ArrayPrototypeForEach(
 | |
|     ObjectEntries(options),
 | |
|     ({ 0: longOption, 1: optionConfig }) => {
 | |
|       validateObject(optionConfig, `options.${longOption}`);
 | |
| 
 | |
|       // type is required
 | |
|       const optionType = objectGetOwn(optionConfig, 'type');
 | |
|       validateUnion(optionType, `options.${longOption}.type`, ['string', 'boolean']);
 | |
| 
 | |
|       if (ObjectHasOwn(optionConfig, 'short')) {
 | |
|         const shortOption = optionConfig.short;
 | |
|         validateString(shortOption, `options.${longOption}.short`);
 | |
|         if (shortOption.length !== 1) {
 | |
|           throw new ERR_INVALID_ARG_VALUE(
 | |
|             `options.${longOption}.short`,
 | |
|             shortOption,
 | |
|             'must be a single character'
 | |
|           );
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       const multipleOption = objectGetOwn(optionConfig, 'multiple');
 | |
|       if (ObjectHasOwn(optionConfig, 'multiple')) {
 | |
|         validateBoolean(multipleOption, `options.${longOption}.multiple`);
 | |
|       }
 | |
| 
 | |
|       const defaultValue = objectGetOwn(optionConfig, 'default');
 | |
|       if (defaultValue !== undefined) {
 | |
|         let validator;
 | |
|         switch (optionType) {
 | |
|           case 'string':
 | |
|             validator = multipleOption ? validateStringArray : validateString;
 | |
|             break;
 | |
| 
 | |
|           case 'boolean':
 | |
|             validator = multipleOption ? validateBooleanArray : validateBoolean;
 | |
|             break;
 | |
|         }
 | |
|         validator(defaultValue, `options.${longOption}.default`);
 | |
|       }
 | |
|     }
 | |
|   );
 | |
| 
 | |
|   // Phase 1: identify tokens
 | |
|   const tokens = argsToTokens(args, options);
 | |
| 
 | |
|   // Phase 2: process tokens into parsed option values and positionals
 | |
|   const result = {
 | |
|     values: { __proto__: null },
 | |
|     positionals: [],
 | |
|   };
 | |
|   if (returnTokens) {
 | |
|     result.tokens = tokens;
 | |
|   }
 | |
|   ArrayPrototypeForEach(tokens, (token) => {
 | |
|     if (token.kind === 'option') {
 | |
|       if (strict) {
 | |
|         checkOptionUsage(parseConfig, token);
 | |
|         checkOptionLikeValue(token);
 | |
|       }
 | |
|       storeOption(token.name, token.value, options, result.values);
 | |
|     } else if (token.kind === 'positional') {
 | |
|       if (!allowPositionals) {
 | |
|         throw new ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL(token.value);
 | |
|       }
 | |
|       ArrayPrototypePush(result.positionals, token.value);
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   // Phase 3: fill in default values for missing args
 | |
|   ArrayPrototypeForEach(ObjectEntries(options), ({ 0: longOption,
 | |
|                                                    1: optionConfig }) => {
 | |
|     const mustSetDefault = useDefaultValueOption(longOption,
 | |
|                                                  optionConfig,
 | |
|                                                  result.values);
 | |
|     if (mustSetDefault) {
 | |
|       storeDefaultOption(longOption,
 | |
|                          objectGetOwn(optionConfig, 'default'),
 | |
|                          result.values);
 | |
|     }
 | |
|   });
 | |
| 
 | |
| 
 | |
|   return result;
 | |
| };
 | |
| 
 | |
| module.exports = {
 | |
|   parseArgs,
 | |
| };
 |