diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fc133f4..8413053 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,6 @@ { "name": "Claude Runner VSCode Extension", + "runArgs": ["--name", "claude-runner-devcontainer"], "build": { "dockerfile": "./Dockerfile.devcontainer", "context": "..", @@ -17,6 +18,9 @@ "ghcr.io/devcontainers/features/python:1": { "version": "3.12", "installTools": true + }, + "ghcr.io/devcontainers/features/go:1": { + "version": "1.24.3" } }, "customizations": { diff --git a/.devcontainer/postinstall.sh b/.devcontainer/postinstall.sh index d9815da..b24eae6 100755 --- a/.devcontainer/postinstall.sh +++ b/.devcontainer/postinstall.sh @@ -13,7 +13,19 @@ npm install -g @anthropic-ai/claude-code # Add useful aliases for development echo 'alias ll="ls -alF"' >> ~/.bashrc echo 'alias cl="claude --dangerously-skip-permissions"' >> ~/.bashrc +echo 'alias g="git"' >> ~/.bashrc +echo 'alias gc="git add -A && git commit -m"' >> ~/.bashrc +echo 'alias gp="git fetch --all && git pull"' >> ~/.bashrc +echo 'alias gf="git fetch --all && git rebase origin/master"' >> ~/.bashrc +echo 'alias gn="git checkout -b"' >> ~/.bashrc +echo 'alias pr="git push origin $(git rev-parse --abbrev-ref HEAD)"' >> ~/.bashrc +echo 'alias gpr="gc pr"' >> ~/.bashrc echo 'export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1' >> ~/.bashrc +echo 'export SONAR_SCANNER_VERSION=7.0.2.4839' +echo 'export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux-x64' +echo 'export PATH=$SONAR_SCANNER_HOME/bin:$PATH' + +yes | npx playwright install --with-deps --no-shell # Setup SonarQube Scanner (optional for code quality) if [ -f .sonar ]; then diff --git a/.eslintrc.json b/.eslintrc.json index 1a26062..7eed155 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,12 +4,24 @@ "parserOptions": { "ecmaVersion": 6, "sourceType": "module", - "project": ["./tsconfig.json", "./tsconfig.test.json"], + "project": [ + "./tsconfig.json", + "./tsconfig.test.json", + "./tsconfig.cli.json", + "./tsconfig.cli-tests.json" + ], "ecmaFeatures": { "jsx": true } }, - "plugins": ["@typescript-eslint"], + "plugins": [ + "@typescript-eslint", + "complexity", + "sonarjs", + "import", + "unicorn", + "jsdoc" + ], "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], "rules": { "@typescript-eslint/naming-convention": [ @@ -21,8 +33,8 @@ ], "@typescript-eslint/semi": "warn", "curly": "warn", - "eqeqeq": "warn", - "no-throw-literal": "warn", + "eqeqeq": ["error", "always"], + "no-throw-literal": "error", "semi": "off", "@typescript-eslint/no-unused-vars": [ "error", @@ -33,11 +45,97 @@ "@typescript-eslint/no-explicit-any": "warn", "no-console": ["warn", { "allow": ["warn", "error"] }], "prefer-const": "error", - "@typescript-eslint/prefer-nullish-coalescing": "warn", - "@typescript-eslint/prefer-optional-chain": "warn", - "@typescript-eslint/no-non-null-assertion": "warn", + "@typescript-eslint/prefer-nullish-coalescing": "error", + "@typescript-eslint/prefer-optional-chain": "error", + "@typescript-eslint/no-non-null-assertion": "error", "@typescript-eslint/consistent-type-definitions": ["error", "interface"], - "@typescript-eslint/prefer-readonly": "warn" + "@typescript-eslint/prefer-readonly": "warn", + + "complexity": ["warn", { "max": 40 }], + "max-depth": ["warn", 8], + "max-lines": ["warn", 1000], + "max-lines-per-function": ["warn", 300], + "max-nested-callbacks": "off", + "max-params": ["warn", 10], + "max-statements": ["warn", 100], + "max-statements-per-line": "off", + + "sonarjs/cognitive-complexity": ["warn", 30], + "sonarjs/no-duplicate-string": ["warn", { "threshold": 8 }], + "sonarjs/no-identical-functions": "warn", + "sonarjs/no-redundant-jump": "off", + "sonarjs/prefer-immediate-return": "off", + "sonarjs/prefer-object-literal": "off", + "sonarjs/prefer-single-boolean-return": "off", + + "import/order": "off", + "import/no-unresolved": "off", + "import/no-unused-modules": "off", + "import/no-cycle": "warn", + "import/no-self-import": "warn", + "import/no-useless-path-segments": "off", + + "no-restricted-imports": [ + "error", + { + "paths": [ + "crypto", + "http", + "https", + "net", + "dgram", + "dns", + "url", + "stream", + "events", + "buffer", + "querystring", + "cluster", + "tls" + ], + "patterns": ["node:*"] + } + ], + + "unicorn/prevent-abbreviations": "off", + "unicorn/filename-case": "off", + "unicorn/no-null": "off", + "unicorn/prefer-module": "off", + "unicorn/prefer-node-protocol": "off", + "unicorn/no-array-reduce": "off", + "unicorn/no-process-exit": "off", + "unicorn/prefer-top-level-await": "off", + "unicorn/prefer-string-replace-all": "off", + "unicorn/no-useless-undefined": "off", + "unicorn/no-array-for-each": "off", + "unicorn/numeric-separators-style": "off", + "unicorn/switch-case-braces": "off", + "unicorn/better-regex": "off", + "unicorn/text-encoding-identifier-case": "off", + "unicorn/consistent-function-scoping": "off", + "unicorn/explicit-length-check": "off", + "unicorn/prefer-array-some": "off", + "unicorn/prefer-includes": "off", + "unicorn/prefer-string-starts-ends-with": "off", + "unicorn/prefer-ternary": "off", + "unicorn/import-style": "off", + + "jsdoc/require-jsdoc": "off", + "jsdoc/require-param-description": "off", + "jsdoc/require-returns-description": "off", + "jsdoc/require-description": "off", + "jsdoc/require-param": "off", + "jsdoc/require-returns": "off", + "jsdoc/check-param-names": "off", + "jsdoc/check-tag-names": "off", + "jsdoc/check-types": "off" + }, + "settings": { + "import/resolver": { + "node": { + "extensions": [".js", ".jsx", ".ts", ".tsx"] + } + } }, "ignorePatterns": ["out", "dist", "**/*.d.ts", "docs/**"], "env": { @@ -45,6 +143,28 @@ "es6": true }, "overrides": [ + { + "files": ["src/components/**/*.{ts,tsx}"], + "rules": { + "max-lines-per-function": ["warn", 600], + "complexity": "off", + "sonarjs/cognitive-complexity": "off" + } + }, + { + "files": ["src/contexts/**/*.{ts,tsx}"], + "rules": { + "max-lines-per-function": ["warn", 450], + "complexity": "off", + "sonarjs/cognitive-complexity": "off" + } + }, + { + "files": ["src/controllers/**/*.ts"], + "rules": { + "max-lines": ["warn", 1200] + } + }, { "files": ["src/webview/**/*.{ts,tsx}"], "env": { @@ -56,15 +176,40 @@ "plugin:@typescript-eslint/recommended" ], "rules": { - "no-undef": "off" + "no-undef": "off", + "unicorn/prefer-query-selector": "off", + "unicorn/prefer-dom-node-text-content": "off" } }, { - "files": ["**/test/**/*.{ts,tsx}", "**/utils/testUsageReport.ts"], + "files": [ + "**/test/**/*.{ts,tsx}", + "**/tests/**/*.{ts,tsx}", + "**/utils/testUsageReport.ts" + ], "rules": { "@typescript-eslint/no-explicit-any": "off", "no-console": "off", - "@typescript-eslint/prefer-readonly": "off" + "@typescript-eslint/prefer-readonly": "off", + "complexity": "off", + "max-lines": "off", + "max-lines-per-function": "off", + "max-statements": "off", + "max-nested-callbacks": "off", + "sonarjs/cognitive-complexity": "off", + "sonarjs/no-duplicate-string": "off", + "import/no-unused-modules": "off", + "import/no-unresolved": "off", + "unicorn/consistent-function-scoping": "off", + "unicorn/no-useless-undefined": "off", + "jsdoc/require-jsdoc": "off", + "no-restricted-imports": "off" + } + }, + { + "files": ["cli/**/*.{ts,tsx}", "scripts/**/*.{js,ts}"], + "rules": { + "no-restricted-imports": "off" } } ] diff --git a/.github/workflows/PIPELINE-DESIGN.md b/.github/workflows/PIPELINE-DESIGN.md deleted file mode 100644 index fbf88fe..0000000 --- a/.github/workflows/PIPELINE-DESIGN.md +++ /dev/null @@ -1,230 +0,0 @@ -# Pipeline Design Philosophy - -## The Problem with Inline Tests in CI/CD - -### โŒ What Was Wrong - -The original pipeline had several anti-patterns: - -#### 1. **Inline Test Code in YAML** - -```yaml -# BAD: Embedding test logic in pipeline -run: | - cat > test-claude-detection.js << 'EOF' - const { exec } = require('child_process'); - // ... complex test logic here - EOF - node test-claude-detection.js -``` - -**Problems**: - -- Test logic is not version controlled properly -- No IDE support for the embedded code -- Hard to debug and maintain -- Cannot be run locally for development -- No proper error handling or logging -- Duplicates test logic across pipeline steps - -#### 2. **Redundant Testing** - -```yaml -# BAD: Testing the same thing multiple times -- name: "Test A" -- name: "Test B that does the same as A" -- name: "Test C that also does the same" -``` - -**Problems**: - -- Wastes CI/CD time and resources -- Creates confusion about what's actually being tested -- Makes failures harder to diagnose - -#### 3. **Poor Separation of Concerns** - -```yaml -# BAD: Mixing infrastructure and test logic -run: | - # Setup stuff - export DISPLAY=:99 - # Test stuff embedded here - # More setup - # More test stuff -``` - -**Problems**: - -- Infrastructure concerns mixed with test logic -- Hard to understand what each step does -- Difficult to reuse or modify - -### โœ… The Correct Approach - -#### 1. **Tests in Codebase, Pipeline Runs Tests** - -```yaml -# GOOD: Pipeline just orchestrates, tests are in codebase -- name: Run Without Claude CLI tests - run: npm run test:ci:without-claude-cli -``` - -**Benefits**: - -- All test logic is in the codebase -- Can be run locally for debugging -- Proper version control and IDE support -- Clear separation of concerns -- Reusable across different CI systems - -#### 2. **Dedicated Test Scripts** - -```javascript -// GOOD: Proper test file with full functionality -// scripts/test-claude-detection.js -class ClaudeDetectionTester { - async runAllTests() { - // Comprehensive, well-structured test logic - } -} -``` - -**Benefits**: - -- Full programming language features -- Proper error handling and logging -- Can be unit tested itself -- Clear documentation and comments - -#### 3. **Clear Pipeline Responsibilities** - -**Pipeline Responsibilities**: - -- Environment setup (Docker, dependencies) -- Artifact management (build, upload, download) -- Test orchestration (run test commands) -- Result reporting (success/failure, summaries) - -**Test Code Responsibilities**: - -- Actual testing logic and assertions -- Error handling and reporting -- Test data management -- Mock setup and teardown - -## Our Two-Stage Testing Strategy - -### Without Claude CLI: Detection Tests - -```bash -# What it runs -npm run test:ci:without-claude-cli - -# What that includes -npm run test:unit # Unit tests -npm run test:main-window # VS Code extension test -npm run test:claude-detection # CLI detection logic -``` - -**Purpose**: Verify the extension handles missing Claude CLI gracefully - -### With Claude CLI: Integration Tests - -```bash -# What it runs -npm run test:ci:with-claude-cli - -# What that includes -npm run test:ci:without-claude-cli # All Without Claude CLI tests -npm run test:e2e # End-to-end workflows -npm run test:integration # Integration tests -``` - -**Purpose**: Verify full functionality when Claude CLI is available - -## Why This Design is Better - -### ๐Ÿ—๏ธ **Maintainability** - -- Test logic is in proper source files -- Can be modified with IDE support -- Version controlled like other code -- Can be refactored and improved - -### ๐Ÿงช **Testability** - -- Tests can be run locally during development -- Easy to debug when they fail -- Can add more tests without touching pipeline -- Test the tests themselves - -### ๐Ÿ”„ **Reusability** - -- Same tests work on different CI systems -- Developers can run the same tests locally -- Docker containers can use the same test commands -- Easy to create new test combinations - -### ๐Ÿ“Š **Clarity** - -- Pipeline shows high-level flow -- Test details are in appropriate files -- Clear separation between infrastructure and logic -- Easy to understand what each phase does - -### โšก **Performance** - -- No redundant testing -- Tests can be optimized independently -- Better caching and parallelization -- Faster feedback loops - -## Test Organization - -``` -โ”œโ”€โ”€ .github/workflows/ # CI/CD orchestration only -โ”‚ โ”œโ”€โ”€ test-pipeline.yml # Main 2-stage pipeline -โ”‚ โ””โ”€โ”€ docker-e2e.yml # Docker-based testing -โ”œโ”€โ”€ scripts/ # Utility test scripts -โ”‚ โ””โ”€โ”€ test-claude-detection.js -โ”œโ”€โ”€ tests/ # Test suites -โ”‚ โ”œโ”€โ”€ e2e/ # End-to-end tests -โ”‚ โ””โ”€โ”€ integration/ # Integration tests -โ”œโ”€โ”€ src/test/ # VS Code extension tests -โ”‚ โ””โ”€โ”€ suite/ -โ””โ”€โ”€ package.json # Test command definitions -``` - -## Commands and Their Purpose - -### Local Development - -```bash -npm run test:claude-detection # Test CLI detection logic -npm run test:main-window # Test VS Code integration -npm run test:unit # Test individual functions -``` - -### CI Simulation - -```bash -npm run test:ci:without-claude-cli # Simulate Without Claude CLI -npm run test:ci:with-claude-cli # Simulate With Claude CLI -``` - -### Individual Categories - -```bash -npm run test:e2e # End-to-end workflows -npm run test:integration # Service integration -npm run test:all:coverage # Full coverage report -``` - -This design ensures that: - -1. **Pipeline focuses on orchestration**, not test implementation -2. **Tests are proper code** with full language features -3. **Local development** mirrors CI/CD exactly -4. **Debugging is easy** when tests fail -5. **Maintenance is simple** with standard code practices diff --git a/.github/workflows/claude-test.yml b/.github/workflows/claude-test.yml index b2c44ca..d4c036f 100644 --- a/.github/workflows/claude-test.yml +++ b/.github/workflows/claude-test.yml @@ -19,6 +19,7 @@ jobs: model: claude-opus-4-20250514 allow_all_tools: true output_session: true + - id: task_1749136022714_z5t92m803 name: Task 2 uses: anthropics/claude-pipeline-action@v1 diff --git a/.github/workflows/claude-test3.yml b/.github/workflows/claude-test3.yml new file mode 100644 index 0000000..3b677bd --- /dev/null +++ b/.github/workflows/claude-test3.yml @@ -0,0 +1,27 @@ +name: test3 +'on': + workflow_dispatch: + inputs: + description: + description: Pipeline execution + required: false + type: string +jobs: + pipeline: + name: Pipeline Execution + runs-on: ubuntu-latest + steps: + - id: task_1751746549772_mdctcbm2g + name: Task 1 + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: hi + model: auto + allow_all_tools: true + - id: task_1751746550609_e0lnydxcc + name: Task 2 + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: hi + model: auto + allow_all_tools: true diff --git a/.gitignore b/.gitignore index 027973b..4882ea2 100644 --- a/.gitignore +++ b/.gitignore @@ -32,8 +32,16 @@ logs/ coverage/ *.lcov -# TypeScript +# TypeScript compilation artifacts *.tsbuildinfo +*.d.ts +*.d.ts.map + +# Generated JavaScript files (compiled from TypeScript) +src/**/*.js +src/**/*.js.map +!src/**/*.test.js +!src/**/*.spec.js # Editor directories and files .idea/ @@ -74,4 +82,24 @@ webview.css.map !.vscode/settings.json # CSS Analysis Reports -css-analysis-report.json \ No newline at end of file +css-analysis-report.json + +# CLI artifacts - Keep dist/ for packaging +cli/node_modules/ +cli/*.log +cli/*.tgz +cli/claude-runner-cli-*.tgz +.claude/.credentials.json +.claude/todos +vsix/ + +# NPM package artifacts +*.tgz +claude-runner-cli-*.tgz +.claude/projects +.claude/ +!.claude/command +.sonarlint/ +.github/workflows/*.json +claude-runner +eslint-report.json diff --git a/.lintstagedrc.json b/.lintstagedrc.json index cf8fa6a..b82cc3d 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,5 +1,5 @@ { - "*.{ts,tsx}": ["eslint --fix", "prettier --write"], + "*.{ts,tsx}": ["eslint --fix --max-warnings=1000", "prettier --write"], "*.{js,jsx,json,css,md}": ["prettier --write"], "package.json": ["prettier --write"] } diff --git a/.vscode/settings.json b/.vscode/settings.json index ee4ed9a..fe33ac2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,9 @@ { "claudeRunner.defaultRootPath": "/workspace", "claudeRunner.allowAllTools": true, - "claudeRunner.defaultModel": "auto" + "claudeRunner.defaultModel": "auto", + "sonarlint.connectedMode.project": { + "connectionId": "claude-runner", + "projectKey": "claude-runner" + } } diff --git a/CLAUDE.md b/CLAUDE.md index da5cd70..91bfcb3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -221,6 +221,7 @@ All changes must pass linting and TypeScript compilation. - Mock only external dependencies (VSCode API, file system, processes) - Test from simplest to most complex scenarios - Use `src/test/__mocks__/` for shared mocks +- Don't over complicate tests logic and mock and introduce complexity **Test Structure:** @@ -302,12 +303,15 @@ make build ### Testing ```bash -# Run all tests (Jest unit tests + VSCode integration tests) +# Run all tests (Jest unit tests + E2E tests + VSCode integration tests) make test # Run only Jest unit tests npm run test:unit +# Run E2E tests (complete workflow testing with UI simulation) +npm run test:e2e + # Unit test coverage npm run test:unit:coverage ``` diff --git a/Makefile b/Makefile index 399d400..46f264b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: setup setup-ci build build-vsix watch package clean test test-coverage lint dev install-local install-devcontainer help validate dev-prepare dev-install uninstall-extension get-extension-id version-patch version-minor version-major sync-version sonar scan-secrets generate-icons prepare-marketplace analyze-css cleanup-css cleanup-css-auto +.PHONY: setup build build-vsix watch package clean test lint dev install-local install-devcontainer serve-vsix help validate dev-prepare dev-install uninstall-extension get-extension-id version-patch version-minor version-major sync-version sonar scan-secrets generate-icons prepare-marketplace # Default target - show help help: @@ -12,12 +12,19 @@ help: @echo " make dev - Start development mode (alias for watch)" @echo " make clean - Remove build artifacts" @echo " make test - Run tests" - @echo " make test-coverage - Run tests with coverage report" + @echo " make test-main-window - Run main window load test only" + @echo " make test-unit - Run unit tests only" + @echo " make test-e2e - Run end-to-end tests only" + @echo " make test-integration - Run integration tests only" + @echo " make test-all-coverage - Run all tests with coverage" + @echo " make test-ci-phase1 - Run CI Phase 1 tests" + @echo " make test-ci-phase2 - Run CI Phase 2 tests" @echo " make test-watch - Run tests in watch mode" @echo " make lint - Run ESLint and fix issues" @echo " make validate - Run tests and linting" @echo " make install-local - Build and install extension locally" @echo " make install-devcontainer - Install in devcontainer environment" + @echo " make serve-vsix - Serve VSIX file via HTTP for download" @echo " make dev-prepare - Step 1: Uninstall extension and build VSIX" @echo " make dev-install - Step 2: Install extension only (manual reload required)" @echo "" @@ -35,61 +42,60 @@ help: @echo " make generate-icons - Generate VSCode extension icons from logo" @echo " make prepare-marketplace - Prepare assets and README for marketplace" @echo "" - @echo "CSS Analysis:" - @echo " make analyze-css - Analyze CSS usage and detect unused styles" - @echo " make cleanup-css - Show CSS cleanup plan" - @echo " make cleanup-css-auto - Auto-remove safe unused CSS rules" + @echo "Publishing:" + @echo " make publish-extension - Publish extension to VSCode Marketplace" # Install dependencies setup: - @echo "๐Ÿ“ฆ Installing dependencies..." + @echo "Installing dependencies..." @npm run sync-version @npm install - @echo "๐Ÿ”ง Setting up git hooks..." - @npx husky install || echo "โš ๏ธ Husky install failed - hooks may not work" - @echo "โœ… Dependencies installed" + @echo "Setting up git hooks..." + @npx husky install || echo "Husky install failed - hooks may not work" + @echo "Dependencies installed" # CI-specific setup (no git hooks) setup-ci: - @echo "๐Ÿ“ฆ Installing dependencies for CI environment..." + @echo "Installing dependencies for CI environment..." @npm run sync-version @npm install --prefer-offline --no-audit --progress=false - @echo "โœ… CI dependencies installed" + @echo "CI dependencies installed" # Build the extension (compile only) build: - @echo "๐Ÿ”ง Compiling TypeScript..." + @echo "Compiling TypeScript..." @npm run compile || true - @echo "โœ… Extension compiled successfully" + @echo "Extension compiled successfully" + # Build and package the VSIX file build-vsix: clean - @echo "๐Ÿ”จ Building Claude Runner VS Code Extension..." + @echo "Building Claude Runner VS Code Extension..." @echo "============================================" @echo "" - @echo "๐Ÿ“ฆ Creating VSIX package..." + @echo "Creating VSIX package..." @npm run package - @echo "โœ… VSIX package created successfully" + @echo "VSIX package created successfully" @echo "" @echo "============================================" - @echo "โœ… Build completed successfully!" + @echo "Build completed successfully!" @echo "" - @echo "๐Ÿ“ Build artifacts:" + @echo "Build artifacts:" @echo " Extension: dist/extension.js" @echo " Webview: dist/webview.js" @echo " VSIX Package: dist/claude-runner-$$(node -p "require('./package.json').version").vsix" @echo "" - @echo "๐Ÿ“Š File sizes:" + @echo "File sizes:" @ls -lh dist/extension.js 2>/dev/null | awk '{print " Extension: " $$5}' || echo " Extension: Not found" @ls -lh dist/webview.js 2>/dev/null | awk '{print " Webview: " $$5}' || echo " Webview: Not found" @ls -lh dist/claude-runner-*.vsix 2>/dev/null | awk '{print " VSIX Package: " $$5}' || echo " VSIX Package: Not found" @echo "" - @echo "๐Ÿ“ฅ To install the extension locally, run:" + @echo "To install the extension locally, run:" @echo " make install-local" # Watch for changes watch: - @echo "๐Ÿ‘€ Watching for changes..." + @echo "Watching for changes..." @npm run watch # Development mode (alias for watch) @@ -116,10 +122,53 @@ test: @echo "๐Ÿงช Running tests..." @npm run test -# Run tests with coverage -test-coverage: - @echo "๐Ÿงช Running tests with coverage..." - @npm run test:unit:coverage +# Run main window load test only +test-main-window: + @echo "๐Ÿงช Running main window load test..." + @npm run test:main-window + +# Run unit tests only +test-unit: + @echo "๐Ÿงช Running unit tests..." + @npm run test:unit + +# Run end-to-end tests only +test-e2e: + @echo "๐Ÿงช Running end-to-end tests..." + @npm run test:e2e + +# Run integration tests only +test-integration: + @echo "๐Ÿงช Running integration tests..." + @npm run test:integration + +# Run all Jest tests with coverage +test-all-coverage: + @echo "๐Ÿงช Running all tests with coverage..." + @npm run test:all:coverage + + +# Run CI Phase 1 tests +test-ci-phase1: + @echo "๐Ÿงช Running CI Phase 1 tests..." + @npm run test:ci:phase1 + +# Run CI Phase 2 tests +test-ci-phase2: + @echo "๐Ÿงช Running CI Phase 2 tests..." + @npm run test:ci:phase2 + +# Install system dependencies for CI +setup-ci-system: + @echo "Installing CI system dependencies..." + @sudo apt-get update + @sudo apt-get install -y xvfb make + +# Setup test environment for CI +setup-test-env: + @echo "Setting up test environment..." + @export DISPLAY=:99; Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & sleep 2 + # Run tests in watch mode test-watch: @@ -177,7 +226,11 @@ install-devcontainer: build-vsix echo " 3. Navigate to /workspaces/vsix/claude-runner/dist/"; \ echo " 4. Select: claude-runner-$$(node -p "require('./package.json').version").vsix"; \ echo ""; \ - echo "Option 2: Copy to host and install"; \ + echo "Option 2: Download via web server"; \ + echo " Run: make serve-vsix"; \ + echo " Then download from the provided URL"; \ + echo ""; \ + echo "Option 3: Copy to host and install"; \ echo " Use VS Code's Explorer to download the VSIX file"; \ echo " Then install it in your local VS Code"; \ else \ @@ -185,6 +238,18 @@ install-devcontainer: build-vsix echo "Use 'make install-local' instead"; \ fi +# Serve VSIX file via HTTP for easy download +serve-vsix: build-vsix + @echo "๐ŸŒ Starting HTTP server to serve VSIX file..." + @echo "" + @echo "๐Ÿ“ฆ VSIX file available at:" + @echo " http://localhost:8080/claude-runner-$$(node -p "require('./package.json').version").vsix" + @echo "" + @echo "๐Ÿ”— If running in devcontainer/Codespaces, use the forwarded port URL" + @echo "" + @echo "Press Ctrl+C to stop the server" + @cd dist && python3 -m http.server 8080 || python -m SimpleHTTPServer 8080 + # Get extension ID for uninstall get-extension-id: @node -pe "require('./package.json').publisher + '.' + require('./package.json').name" @@ -192,7 +257,7 @@ get-extension-id: # Uninstall the extension from VS Code uninstall-extension: @EXTENSION_ID=$$(node -pe "require('./package.json').publisher + '.' + require('./package.json').name"); \ - echo "๐Ÿ—‘๏ธ Uninstalling extension: $$EXTENSION_ID"; \ + echo "Uninstalling extension: $$EXTENSION_ID"; \ IPC_SOCKET=""; \ if [ -S "$$VSCODE_IPC_HOOK_CLI" ]; then \ IPC_SOCKET="$$VSCODE_IPC_HOOK_CLI"; \ @@ -202,74 +267,74 @@ uninstall-extension: export VSCODE_IPC_HOOK_CLI=$$IPC_SOCKET; \ fi; \ fi; \ - code --uninstall-extension $$EXTENSION_ID 2>/dev/null || echo "โš ๏ธ Extension not currently installed" + code --uninstall-extension $$EXTENSION_ID 2>/dev/null || echo "Extension not currently installed" # Development step 1: uninstall and build dev-prepare: uninstall-extension build-vsix @echo "" - @echo "โœ… Extension uninstalled and VSIX built." - @echo "๐Ÿ“ Next step: Run 'make dev-install' to install the new version" + @echo "Extension uninstalled and VSIX built." + @echo "Next step: Run 'make dev-install' to install the new version" # Development step 2: install only dev-install: - @echo "๐Ÿ› ๏ธ Development Step 2: Install extension..." + @echo "Development Step 2: Install extension..." @echo "===========================================" @EXTENSION_ID=$$(node -pe "require('./package.json').publisher + '.' + require('./package.json').name"); \ - echo "๐Ÿ“ฆ Extension ID: $$EXTENSION_ID"; \ + echo "Extension ID: $$EXTENSION_ID"; \ VSIX_FILE=$$(ls dist/claude-runner-*.vsix | head -1 2>/dev/null); \ if [ -z "$$VSIX_FILE" ]; then \ - echo "โŒ No VSIX file found. Run 'make dev-prepare' first."; \ + echo "No VSIX file found. Run 'make dev-prepare' first."; \ exit 1; \ fi; \ - echo "๐Ÿ“ฅ Installing: $$VSIX_FILE"; \ + echo "Installing: $$VSIX_FILE"; \ IPC_SOCKET=""; \ if [ -S "$$VSCODE_IPC_HOOK_CLI" ]; then \ IPC_SOCKET="$$VSCODE_IPC_HOOK_CLI"; \ - echo "๐Ÿ”Œ Using existing IPC socket: $$IPC_SOCKET"; \ + echo "Using existing IPC socket: $$IPC_SOCKET"; \ else \ IPC_SOCKET=$$(find /tmp -name "vscode-ipc-*.sock" -type s 2>/dev/null | head -1); \ if [ -n "$$IPC_SOCKET" ]; then \ export VSCODE_IPC_HOOK_CLI=$$IPC_SOCKET; \ - echo "๐Ÿ”Œ Found IPC socket: $$IPC_SOCKET"; \ + echo "Found IPC socket: $$IPC_SOCKET"; \ else \ - echo "โš ๏ธ No VS Code IPC socket found - using default CLI behavior"; \ + echo "No VS Code IPC socket found - using default CLI behavior"; \ fi; \ fi; \ code --install-extension $$VSIX_FILE --force; \ echo ""; \ - echo "โœ… Extension installed successfully"; \ + echo "Extension installed successfully"; \ echo ""; \ - echo "๐Ÿ”„ IMPORTANT: Manually reload VS Code to activate changes:"; \ + echo "IMPORTANT: Manually reload VS Code to activate changes:"; \ echo " - Press Ctrl/Cmd+Shift+P โ†’ 'Developer: Reload Window'"; \ echo " - Or use Ctrl/Cmd+R to reload the window" # Version Management sync-version: - @echo "๐Ÿ”„ Syncing version from VERSION file to package.json..." + @echo "Syncing version from VERSION file to package.json..." @node scripts/sync-version.js version-patch: - @echo "๐Ÿ“ˆ Bumping patch version..." + @echo "Bumping patch version..." @node scripts/bump-version.js patch - @echo "โœ… Patch version bumped successfully" + @echo "Patch version bumped successfully" version-minor: - @echo "๐Ÿ“ˆ Bumping minor version..." + @echo "Bumping minor version..." @node scripts/bump-version.js minor - @echo "โœ… Minor version bumped successfully" + @echo "Minor version bumped successfully" version-major: - @echo "๐Ÿ“ˆ Bumping major version..." + @echo "Bumping major version..." @node scripts/bump-version.js major - @echo "โœ… Major version bumped successfully" + @echo "Major version bumped successfully" # SonarQube Analysis sonar: - @echo "๐Ÿ“‹ Running test coverage before SonarQube analysis..." + @echo "Running test coverage before SonarQube analysis..." @npm run test:unit:coverage || true - @echo "๐Ÿ“‹ Starting SonarQube analysis with coverage data..." + @echo "Starting SonarQube analysis with coverage data..." @if [ ! -f coverage/lcov.info ]; then \ - echo "โš ๏ธ No coverage data found. Running tests again..."; \ + echo "No coverage data found. Running tests again..."; \ npm run test:unit:coverage || true; \ fi @export $$(cat .sonar | xargs) && \ @@ -278,34 +343,63 @@ sonar: -Dsonar.projectVersion=$$PROJECT_VERSION \ -Dsonar.host.url=$$SONAR_HOST_URL \ -Dsonar.token=$$SONAR_TOKEN - @echo "โœ… SonarQube analysis completed" - @echo "๐Ÿ“Š Coverage and code quality metrics sent to SonarQube" + @echo "SonarQube analysis completed" + @echo "Coverage and code quality metrics sent to SonarQube" # Secrets Scanning scan-secrets: - @echo "๐Ÿ” Scanning for secrets in codebase..." + @echo "Scanning for secrets in codebase..." @node scripts/scan-secrets.js --all - @echo "โœ… Secrets scan completed" + @echo "Secrets scan completed" # Prepare Marketplace Assets prepare-marketplace: - @echo "๐Ÿ“ฆ Preparing marketplace assets and README..." + @echo "Preparing marketplace assets and README..." @node scripts/prepare-marketplace.js - @echo "โœ… Marketplace preparation completed" + @echo "Marketplace preparation completed" # CSS Analysis analyze-css: - @echo "๐Ÿ” Analyzing CSS usage and detecting unused styles..." + @echo "Analyzing CSS usage and detecting unused styles..." @npm run analyze-css - @echo "โœ… CSS analysis completed" + @echo "CSS analysis completed" cleanup-css: - @echo "๐Ÿงน Generating CSS cleanup plan..." + @echo "Generating CSS cleanup plan..." @npm run cleanup-css - @echo "โœ… CSS cleanup plan generated" + @echo "CSS cleanup plan generated" cleanup-css-auto: - @echo "๐Ÿงน Auto-removing safe unused CSS rules..." + @echo "Auto-removing safe unused CSS rules..." @npm run cleanup-css:auto - @echo "โœ… Safe CSS cleanup completed" - @echo "๐Ÿ“Š Run 'make analyze-css' to see updated results" + @echo "Safe CSS cleanup completed" + @echo "Run 'make analyze-css' to see updated results" + + +# Convert JSON todo file to GitHub Actions workflow +converttodo: + @if [ -z "$(SOURCE)" ] || [ -z "$(TARGET)" ]; then \ + echo "Error: SOURCE and TARGET parameters are required"; \ + echo ""; \ + echo "Usage: make converttodo SOURCE=todo.json TARGET=workflow.yml"; \ + echo ""; \ + echo "Examples:"; \ + echo " make converttodo SOURCE=/workspaces/vsix/claude-code-docs/todo/refactor.json TARGET=.github/workflows/refactor.yml"; \ + echo " make converttodo SOURCE=todo/features.json TARGET=workflows/features.yml"; \ + exit 1; \ + fi + @if [ ! -f "$(SOURCE)" ]; then \ + echo "Error: Source file not found: $(SOURCE)"; \ + exit 1; \ + fi + @echo "Converting todo file to workflow..." + @echo "======================================" + @echo "Source: $(SOURCE)" + @echo "Target: $(TARGET)" + @echo "" + @npm run convert-todo "$(SOURCE)" "$(TARGET)" + +# Publishing targets +publish-extension: + @echo "Publishing extension to VSCode Marketplace..." + @npm run publish:extension diff --git a/README.md b/README.md index 0299474..c4ee867 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Claude Runner -**Seamlessly integrate Claude AI directly into your VS Code workflow with an intuitive, feature-rich interface.** +**Seamlessly integrate Claude AI directly into your VS Code and add automated workflow with an intuitive, feature-rich interface.** ![Claude Runner Logo](https://raw.githubusercontent.com/codingworkflow/claude-runner/main/assets/icon.png) -Claude Runner transforms your development experience by bringing Anthropic's powerful Claude AI models directly into Visual Studio Code. Whether you're debugging code, writing documentation, or architecting solutions, Claude Runner provides the tools you need to work smarter, not harder. +Claude Runner transforms your development experience by bringing Anthropic's powerful Claude AI models directly into Visual Studio Code. Whether you're debugging code, writing documentation, or architecting solutions, Claude Runner provides the tools you need to work smarter, not harder, automating tasking thru workflows. ## Key Features diff --git a/VERSION b/VERSION index 341cf11..9325c3c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.0 \ No newline at end of file +0.3.0 \ No newline at end of file diff --git a/claude-detection-report.json b/claude-detection-report.json deleted file mode 100644 index a0ef836..0000000 --- a/claude-detection-report.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "timestamp": "2025-06-26T06:15:09.388Z", - "claudeInstalled": false, - "testResults": [ - { - "timestamp": "2025-06-26T06:15:08.704Z", - "message": "๐Ÿš€ Starting Claude CLI detection tests...", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.705Z", - "message": "Checking Claude CLI installation status...", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.712Z", - "message": "Claude CLI not found in PATH", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.712Z", - "message": "Testing extension Claude CLI detection logic...", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.714Z", - "message": "Extension detection matches actual CLI state", - "type": "success" - }, - { - "timestamp": "2025-06-26T06:15:08.715Z", - "message": "Testing shell detection for Claude CLI...", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.719Z", - "message": "bash: Claude CLI not found", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.726Z", - "message": "zsh: Claude CLI not found", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.729Z", - "message": "fish: Claude CLI not found", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.733Z", - "message": "sh: Claude CLI not found", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.733Z", - "message": "Testing PATH-based Claude CLI detection...", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.736Z", - "message": "Claude CLI not found in PATH", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:08.736Z", - "message": "Testing npm global package detection...", - "type": "info" - }, - { - "timestamp": "2025-06-26T06:15:09.388Z", - "message": "Claude CLI found in npm global packages", - "type": "success" - } - ], - "environment": { - "node_version": "v23.11.1", - "platform": "linux", - "arch": "x64", - "ci": false, - "github_actions": false - } -} diff --git a/docs/workflow_specs.md b/docs/workflow_specs.md new file mode 100644 index 0000000..6f85d19 --- /dev/null +++ b/docs/workflow_specs.md @@ -0,0 +1,613 @@ +# Claude Runner Workflow Specifications + +This document provides comprehensive specifications for creating GitHub Actions workflows that use Claude Code pipeline actions. Based on analysis of existing workflows in the project, this guide covers all key patterns, session management, model selection, and conditional execution. + +## Workflow Structure + +### Basic Workflow Template + +```yaml +name: +on: + workflow_dispatch: + inputs: + description: + description: + required: false + type: string + +jobs: + : + name: + runs-on: ubuntu-latest + steps: + - id: + name: + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + + model: + allow_all_tools: true + output_session: + resume_session: +``` + +### Required Components + +1. **Workflow Name**: Descriptive name for the workflow +2. **Trigger**: `workflow_dispatch` with optional input description +3. **Job Configuration**: Single job with `ubuntu-latest` runner +4. **Steps**: One or more Claude pipeline action steps + +## Step Configuration + +### Step ID Format + +Step IDs follow these patterns: + +- **Descriptive**: `analyze_current_cli`, `implement_job_log_types` +- **Generated**: `task__` (e.g., `task_1751000902868_c0dsxdsgd`) + +### Step Properties + +```yaml +- id: + name: + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + + model: + allow_all_tools: true + output_session: + resume_session: +``` + +### Required Properties + +- `id`: Unique identifier for the step +- `name`: Display name for the step +- `uses`: Always `anthropics/claude-pipeline-action@v1` +- `prompt`: The instruction for Claude + +### Optional Properties + +- `model`: Model selection (defaults to `auto`) +- `allow_all_tools`: Enable all tools (typically `true`) +- `output_session`: Whether to output session ID for chaining +- `resume_session`: Reference to previous session for continuity + +## Session Management + +### Session Chaining Patterns + +**1. Simple Chain (Next Step)** + +```yaml +- id: step1 + name: First Step + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: Generate a random number + model: auto + allow_all_tools: true + output_session: true + +- id: step2 + name: Second Step + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: Use the previous number in calculation + model: auto + allow_all_tools: true + resume_session: ${{ steps.step1.outputs.session_id }} +``` + +**2. Long Chain (Multiple Steps)** + +```yaml +- id: task_1 + output_session: true + +- id: task_2 + resume_session: task_1 + +- id: task_3 + resume_session: task_2 + +- id: task_4 + resume_session: task_3 +``` + +**3. Branch from Earlier Step** + +```yaml +- id: analyze_step + output_session: true + +- id: implement_step1 + resume_session: analyze_step + +- id: implement_step2 + resume_session: analyze_step +``` + +### Session Reference Format + +The parser supports two formats: + +**Simple format (recommended):** + +```yaml +resume_session: +``` + +**Complex format (GitHub Actions style):** + +```yaml +resume_session: ${{ steps..outputs.session_id }} +``` + +## Model Selection + +### Available Models + +- `auto`: Automatic model selection (recommended - default) +- `claude-opus-4-20250514`: Claude Opus 4 (most capable, highest cost) +- `claude-sonnet-4-20250514`: Claude Sonnet 4 (balanced performance and cost) +- `claude-3-7-sonnet-20250219`: Claude Sonnet 3.7 (good performance, moderate cost) +- `claude-3-5-haiku-20241022`: Claude Haiku 3.5 (fastest, lowest cost) + +### Model Selection Guidelines + +```yaml +# For most tasks - let Claude choose appropriate model (default) +model: auto + +# For high-capability tasks requiring maximum performance +model: claude-opus-4-20250514 + +# For balanced performance and cost +model: claude-sonnet-4-20250514 + +# For fast, lightweight tasks +model: claude-3-5-haiku-20241022 +``` + +## Prompt Engineering + +### Prompt Structure + +```yaml +prompt: | + + + + + + + +``` + +### Effective Prompt Patterns + +**1. Reference-Based Prompts** + +```yaml +prompt: | + Read key plan /workspaces/vsix/claude-code-docs/docs/cli_plan.md + + Implement the JobLogManager class specified in Phase 1, Step 1.2: + - Create file: cli/src/utils/JobLogManager.ts + - Include all static methods as documented + - Ensure Go CLI compatibility +``` + +**2. Multi-Step Instructions** + +```yaml +prompt: | + Using the implementation plan from the documentation: + + 1. Analyze current CLI structure + 2. Identify missing components + 3. Provide focused implementation guidance + 4. Reference existing analysis for context +``` + +**3. Contextual Prompts** + +```yaml +prompt: | + Based on the detailed analysis from previous step: + + Implement rate limit detection exactly matching Go CLI: + - Use regex pattern: /Claude AI usage limit reached\|(\d+)/ + - Parse Unix timestamp and calculate wait time + - Return RateLimitInfo object with required fields +``` + +## Conditional Execution + +### Conditional Step Structure + +```yaml +- id: conditional_step + name: Conditional Task + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + + model: auto + allow_all_tools: true + check: + condition: +``` + +### Condition Types + +- `on_success`: Execute only if check command succeeds (exit code 0) +- `on_failure`: Execute only if check command fails (exit code != 0) +- `always`: Execute regardless of check command result + +### Common Check Commands + +```yaml +# Linting checks +check: "make lint" +condition: "on_failure" + +# Test checks +check: "npm run test" +condition: "on_success" + +# Type checking +check: "npm run type-check" +condition: "on_failure" + +# Build validation +check: "make build" +condition: "on_success" +``` + +## Job Log Integration + +### Job Log Structure + +Workflows automatically generate `.job.json` files with this structure: + +```json +{ + "workflow_name": "workflow-name", + "workflow_file": ".github/workflows/workflow.yml", + "execution_id": "20250701-162857", + "start_time": "2025-07-01T16:28:57.367712962Z", + "last_update_time": "2025-07-02T06:52:02.597354031Z", + "status": "paused|running|completed|failed", + "last_completed_step": 6, + "total_steps": 11, + "steps": [ + { + "step_index": 0, + "step_id": "step_name", + "step_name": "Display Name", + "status": "completed|failed|running", + "start_time": "2025-07-01T17:46:39.708971207Z", + "end_time": "2025-07-01T17:46:39.708971207Z", + "duration_ms": 0, + "output": "Step output text", + "session_id": "uuid-session-id", + "output_session": true, + "resume_session": "${{ steps.previous.outputs.session_id }}" + } + ] +} +``` + +### Resume Functionality + +Workflows support resume functionality with: + +- `--resume` or `-r` flag +- Automatic step skipping for completed steps +- Session restoration from job log +- Progress tracking and reporting + +## Complete Workflow Examples + +### 1. Simple Sequential Workflow + +```yaml +name: simple-sequential-test +on: + workflow_dispatch: + inputs: + description: + description: Simple sequential workflow test + required: false + type: string + +jobs: + test: + name: Sequential Test + runs-on: ubuntu-latest + steps: + - id: step1 + name: Generate Random Number + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Generate a random number between 1000 and 9999. + Output only the number, nothing else. + model: auto + allow_all_tools: true + output_session: true + + - id: step2 + name: Use Previous Number + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + What was the random number from our previous interaction? + Add 100 to it and output the result. + model: auto + allow_all_tools: true + resume_session: step1 +``` + +### 2. Complex Implementation Pipeline + +```yaml +name: feature-implementation +on: + workflow_dispatch: + inputs: + description: + description: Feature implementation pipeline + required: false + type: string + +jobs: + pipeline: + name: Feature Implementation + runs-on: ubuntu-latest + steps: + - id: analyze_requirements + name: Analyze Requirements + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Read and analyze the requirements document: + /workspaces/vsix/docs/feature_requirements.md + + Provide a detailed analysis of: + 1. Core functionality requirements + 2. Technical constraints + 3. Implementation approach + 4. Testing requirements + model: auto + allow_all_tools: true + output_session: true + + - id: create_types + name: Create Type Definitions + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Based on the requirements analysis, create TypeScript + interface definitions for the new feature. + + Create file: src/types/NewFeature.ts + Include comprehensive type definitions with JSDoc. + model: auto + allow_all_tools: true + resume_session: analyze_requirements + + - id: implement_core + name: Implement Core Logic + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Implement the core feature logic based on: + 1. Requirements analysis from first step + 2. Type definitions from previous step + + Create the main implementation file with proper + error handling and validation. + model: auto + allow_all_tools: true + resume_session: create_types + + - id: create_tests + name: Create Unit Tests + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Create comprehensive unit tests for the implementation: + + 1. Test all public methods + 2. Test error conditions + 3. Test edge cases + 4. Follow existing test patterns in the codebase + model: auto + allow_all_tools: true + resume_session: implement_core + + - id: update_documentation + name: Update Documentation + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Update project documentation for the new feature: + + 1. Add feature description to README.md + 2. Create usage examples + 3. Document API endpoints if applicable + 4. Update changelog + model: auto + allow_all_tools: true + resume_session: create_tests +``` + +### 3. Conditional Workflow with Quality Gates + +```yaml +name: quality-gate-pipeline +on: + workflow_dispatch: + inputs: + description: + description: Quality gate pipeline with conditional execution + required: false + type: string + +jobs: + pipeline: + name: Quality Gate Pipeline + runs-on: ubuntu-latest + steps: + - id: implement_feature + name: Implement Feature + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Implement the requested feature based on specifications + in /workspaces/vsix/docs/feature_spec.md + model: auto + allow_all_tools: true + output_session: true + + - id: fix_linting + name: Fix Linting Issues + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Run linting and fix any issues found: + 1. Run make lint to check for issues + 2. Fix any linting errors + 3. Ensure code follows project standards + model: auto + allow_all_tools: true + resume_session: implement_feature + check: "make lint" + condition: "on_failure" + + - id: run_tests + name: Run Tests + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Run the test suite and ensure all tests pass: + 1. Run make test + 2. Fix any failing tests + 3. Add new tests if needed + model: auto + allow_all_tools: true + resume_session: fix_linting + check: "make test" + condition: "on_success" + + - id: deploy_feature + name: Deploy Feature + uses: anthropics/claude-pipeline-action@v1 + with: + prompt: | + Feature is ready for deployment: + 1. Create deployment package + 2. Update version numbers + 3. Generate deployment documentation + model: auto + allow_all_tools: true + resume_session: run_tests + check: "make test && make lint" + condition: "on_success" +``` + +## Best Practices + +### 1. Session Management + +- Use `output_session: true` for steps that need to pass context +- Chain sessions logically based on task dependencies +- Avoid unnecessary session chaining for independent tasks + +### 2. Prompt Design + +- Be specific about file paths and requirements +- Reference existing documentation and analysis +- Include expected output format +- Provide context from previous steps + +### 3. Model Selection + +- Use `auto` for most cases to leverage automatic selection +- Specify models only when needed for consistency +- Consider model capabilities for specific tasks + +### 4. Error Handling + +- Plan for resume functionality with meaningful step names +- Include validation steps in complex workflows +- Use conditional execution for quality gates + +### 5. Workflow Organization + +- Group related steps logically +- Use descriptive step names and IDs +- Document complex workflows with comments + +## CLI Integration + +### Running Workflows + +```bash +# Basic execution +./claude-runner run .github/workflows/workflow.yml + +# With resume functionality +./claude-runner run .github/workflows/workflow.yml --resume + +# With bypass permissions +./claude-runner run .github/workflows/workflow.yml --yes + +# Combined flags +./claude-runner run .github/workflows/workflow.yml --resume --yes --verbose +``` + +### Job Log Files + +Job logs are automatically created as `.job.json` files alongside workflow files: + +- `.github/workflows/workflow.yml` โ†’ `.github/workflows/workflow.job.json` +- Enable resume functionality and progress tracking +- Compatible with Go CLI format for cross-platform usage + +## Troubleshooting + +### Common Issues + +1. **Session Chaining Errors** + + - Ensure `output_session: true` on referenced steps + - Check step ID references match exactly + - Verify session flow is logical + +2. **Model Selection Issues** + + - Use `auto` unless specific model required + - Check available models in documentation + - Verify model capabilities for task requirements + +3. **Prompt Execution Failures** + + - Check file paths are correct + - Ensure required files exist + - Verify tool permissions with `allow_all_tools: true` + +4. **Resume Functionality Problems** + - Check job log file exists and is valid + - Verify workflow file hasn't changed significantly + - Use `--verbose` flag for detailed resume information + +This specification provides a complete reference for creating effective Claude Runner workflows with proper session management, model selection, and conditional execution patterns. diff --git a/jest.config.js b/jest.config.js index 44024b1..2a1914d 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,6 +6,10 @@ module.exports = { "**/__tests__/**/*.+(ts|tsx|js)", "**/?(*.)+(spec|test).+(ts|tsx|js)", ], + testPathIgnorePatterns: [ + "/node_modules/", + "/tests/unit/suite/", // Exclude VSCode extension tests (they use Mocha, not Jest) + ], transform: { "^.+\\.(ts|tsx)$": [ "ts-jest", diff --git a/package-lock.json b/package-lock.json index 03c1e2d..f6c8148 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,11 @@ "@vscode/vsce": "^3.2.1", "css-loader": "^6.8.1", "eslint": "^8.56.0", + "eslint-plugin-complexity": "^1.0.2", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsdoc": "^46.10.1", + "eslint-plugin-sonarjs": "^3.0.4", + "eslint-plugin-unicorn": "^48.0.1", "glob": "^10.3.10", "husky": "^9.1.7", "identity-obj-proxy": "^3.0.0", @@ -45,6 +50,7 @@ "lint-staged": "^16.1.2", "mini-css-extract-plugin": "^2.7.6", "mocha": "^10.2.0", + "nyc": "^17.1.0", "prettier": "^3.1.1", "rimraf": "^5.0.5", "sinon": "^20.0.0", @@ -819,6 +825,21 @@ "node": ">=10.0.0" } }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", @@ -890,9 +911,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -960,9 +981,9 @@ } }, "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -1662,9 +1683,9 @@ } }, "node_modules/@jest/reporters/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -2169,6 +2190,13 @@ "node": ">=14" } }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, "node_modules/@secretlint/config-creator": { "version": "9.3.3", "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-9.3.3.tgz", @@ -3443,6 +3471,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -3998,9 +4033,9 @@ ] }, "node_modules/@vscode/vsce/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -4033,9 +4068,9 @@ } }, "node_modules/@vscode/vsce/node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4539,6 +4574,36 @@ "node": ">= 8" } }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4572,6 +4637,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -4582,6 +4670,88 @@ "node": ">=8" } }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -4599,6 +4769,16 @@ "dev": true, "license": "MIT" }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4934,9 +5114,9 @@ "license": "BSD-2-Clause" }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5069,6 +5249,19 @@ "dev": true, "license": "MIT" }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bundle-name": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", @@ -5085,6 +5278,78 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/caching-transform/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caching-transform/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/caching-transform/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/caching-transform/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -5327,6 +5592,19 @@ "dev": true, "license": "MIT" }, + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -5636,6 +5914,23 @@ "node": ">=18" } }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5914,6 +6209,60 @@ "node": ">=12" } }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -6082,6 +6431,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -6461,9 +6826,78 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", @@ -6545,6 +6979,44 @@ "node": ">= 0.4" } }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT" + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -6655,6 +7127,276 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-complexity": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-complexity/-/eslint-plugin-complexity-1.0.2.tgz", + "integrity": "sha512-6SwGZ2Kz3pNBfKDpT38bh6XTsrPCkPVgYYsXhtWVa88IrlQ8HnHbvfKqjL826jYEU0AQiiljNRJ5BQNJe45qNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-utils": "^3.0.0" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz", + "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/eslint-plugin-sonarjs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-3.0.4.tgz", + "integrity": "sha512-ftQcP811kRJNXapqpQXHErEoVOdTPfYPPYd7n3AExIPwv4qWKKHf4slFvXmodiOnfgy1Tl3waPZZLD7lcvJOtw==", + "dev": true, + "license": "LGPL-3.0-only", + "dependencies": { + "@eslint-community/regexpp": "4.12.1", + "builtin-modules": "3.3.0", + "bytes": "3.1.2", + "functional-red-black-tree": "1.0.1", + "jsx-ast-utils": "3.3.5", + "lodash.merge": "4.6.2", + "minimatch": "9.0.5", + "scslre": "0.3.0", + "semver": "7.7.2", + "typescript": ">=5" + }, + "peerDependencies": { + "eslint": "^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-sonarjs/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-plugin-unicorn": { + "version": "48.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-48.0.1.tgz", + "integrity": "sha512-FW+4r20myG/DqFcCSzoumaddKBicIPeFnTrifon2mWIzlfyvzwyqZjqVP7m4Cqr/ZYisS2aiLghkUWaPg6vtCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "@eslint-community/eslint-utils": "^4.4.0", + "ci-info": "^3.8.0", + "clean-regexp": "^1.0.0", + "esquery": "^1.5.0", + "indent-string": "^4.0.0", + "is-builtin-module": "^3.2.1", + "jsesc": "^3.0.2", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "read-pkg-up": "^7.0.1", + "regexp-tree": "^0.1.27", + "regjsparser": "^0.10.0", + "semver": "^7.5.4", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=8.44.0" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -6672,6 +7414,35 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", @@ -6719,9 +7490,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -7158,36 +7929,80 @@ "node": ">=8" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "license": "MIT", @@ -7201,9 +8016,9 @@ } }, "node_modules/flat-cache/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -7319,6 +8134,27 @@ "node": ">= 6" } }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -7374,6 +8210,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true, + "license": "MIT" + }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -7479,6 +8343,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -7560,6 +8442,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -7651,6 +8550,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -7680,6 +8595,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -8052,6 +8994,26 @@ "dev": true, "license": "MIT" }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", @@ -8098,6 +9060,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -8127,6 +9105,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-date-object": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", @@ -8170,6 +9166,22 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -8190,6 +9202,25 @@ "node": ">=6" } }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -8248,6 +9279,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -8411,6 +9455,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, "node_modules/is-unicode-supported": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", @@ -8437,6 +9504,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakset": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", @@ -8454,7 +9537,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-wsl": { + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", @@ -8504,6 +9597,19 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-instrument": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", @@ -8521,6 +9627,100 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "license": "ISC", + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", @@ -8667,9 +9867,9 @@ } }, "node_modules/jake/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -9170,9 +10370,9 @@ } }, "node_modules/jest-config/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -10410,9 +11610,9 @@ } }, "node_modules/jest-runtime/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -11036,6 +12236,16 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsdom": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", @@ -11247,6 +12457,22 @@ "npm": ">=6" } }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -11580,6 +12806,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -12115,7 +13348,6 @@ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", - "optional": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12440,6 +13672,19 @@ "dev": true, "license": "MIT" }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -12496,49 +13741,400 @@ "dev": true, "license": "ISC" }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", + "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz", + "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^3.3.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^6.0.2", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nyc/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/nyc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nyc/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/nyc/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nyc/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/nyc/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^3.0.0" + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" }, "engines": { "node": ">=8" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", "dependencies": { - "boolbase": "^1.0.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "engines": { + "node": ">=6" } }, - "node_modules/nwsapi": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", - "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", - "dev": true, - "license": "MIT" - }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -12600,6 +14196,59 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -12754,6 +14403,24 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -12812,6 +14479,22 @@ "node": ">=6" } }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -13366,6 +15049,19 @@ "dev": true, "license": "MIT" }, + "node_modules/process-on-spawn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", + "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -13708,10 +15404,183 @@ "type-fest": "^4.2.0" }, "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/read-pkg-up/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/read-pkg-up/node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" } }, "node_modules/read-pkg/node_modules/type-fest": { @@ -13790,6 +15659,66 @@ "node": ">=8" } }, + "node_modules/refa": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", + "integrity": "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp-ast-analysis": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz", + "integrity": "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.1" + }, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -13811,6 +15740,41 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regjsparser": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.10.0.tgz", + "integrity": "sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "license": "ISC", + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -13831,6 +15795,13 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -13999,6 +15970,33 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -14020,6 +16018,30 @@ ], "license": "MIT" }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/safe-regex-test": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", @@ -14094,6 +16116,21 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/scslre": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", + "integrity": "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.0", + "regexp-ast-analysis": "^0.7.0" + }, + "engines": { + "node": "^14.0.0 || >=16.0.0" + } + }, "node_modules/secretlint": { "version": "9.3.3", "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-9.3.3.tgz", @@ -14196,6 +16233,13 @@ "randombytes": "^2.1.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -14230,6 +16274,21 @@ "node": ">= 0.4" } }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -14501,88 +16560,216 @@ "is-fullwidth-code-point": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/spawn-wrap/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/spawn-wrap/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" }, "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/spawn-wrap/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "semver": "^6.0.0" }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/spawn-wrap/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" + "node": "*" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "node_modules/spawn-wrap/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/spawn-wrap/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/spawn-wrap/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } + "license": "ISC" }, "node_modules/spdx-correct": { "version": "3.2.0", @@ -14749,6 +16936,65 @@ "node": ">=8" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -15088,9 +17334,9 @@ } }, "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -15405,6 +17651,42 @@ "node": ">=8" } }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -15471,6 +17753,84 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typed-rest-client": { "version": "1.8.11", "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", @@ -15483,6 +17843,16 @@ "underscore": "^1.12.1" } }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -15504,6 +17874,25 @@ "dev": true, "license": "MIT" }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/underscore": { "version": "1.13.7", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", @@ -15933,6 +18322,41 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", @@ -15952,6 +18376,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, "node_modules/which-typed-array": { "version": "1.1.19", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", diff --git a/package.json b/package.json index 1846e8e..1a29bb3 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "name": "claude-runner", "displayName": "Claude Runner", "description": "Execute Claude Code commands directly from VS Code with an intuitive interface", - "version": "0.2.0", + "version": "0.3.0", "publisher": "Codingworkflow", - "private": true, + "private": false, "license": "GPL-3.0", "icon": "assets/icon.png", "readme": "README.md", @@ -76,7 +76,7 @@ }, { "command": "claude-runner.recheckClaude", - "title": "Claude Runner: Recheck Claude Installation" + "title": "Claude Runner: Recheck Claude API Connection" }, { "command": "claude-runner.refreshCommands", @@ -118,7 +118,7 @@ { "type": "webview", "id": "claude-runner.mainView", - "name": "Chat & Pipeline", + "name": "Chat & Workflows", "icon": "$(terminal)", "contextualTitle": "Claude Runner Control Panel" }, @@ -155,12 +155,12 @@ "claudeRunner.defaultRootPath": { "type": "string", "default": "", - "description": "Default root path for Claude commands (empty = current workspace)" + "description": "Default root path for Claude tasks (empty = current workspace)" }, "claudeRunner.allowAllTools": { "type": "boolean", "default": false, - "description": "Allow all tools by default (uses --dangerously-skip-permissions)" + "description": "Allow all tools by default" }, "claudeRunner.outputFormat": { "type": "string", @@ -234,7 +234,8 @@ "compile-tests": "tsc -p ./tsconfig.test.json --outDir out", "watch-tests": "tsc -p ./tsconfig.test.json -w --outDir out", "pretest": "npm run lint", - "lint": "eslint src --ext ts,tsx", + "lint": "eslint . --ext ts,tsx --ignore-path .gitignore", + "lint:fix": "eslint . --ext ts,tsx --fix --ignore-path .gitignore", "test": "npm run test:unit", "test:integration": "npm run compile-tests && node ./out/tests/unit/runTest.js", "test:unit": "jest", @@ -245,8 +246,7 @@ "test:integration:coverage": "jest --testPathPattern=tests/integration --coverage", "test:all": "npm run test:unit && npm run test:e2e && npm run test:integration", "test:all:coverage": "jest --coverage --testPathPattern=\"(tests/e2e|tests/integration|src/test/services)\"", - "test:claude-detection": "node scripts/test-claude-detection.js", - "test:ci:without-claude": "npm run test:unit && npm run test:claude-detection", + "test:ci:without-claude": "npm run test:unit", "test:ci:with-claude": "npm run test:ci:without-claude && npm run test:e2e && npm run test:integration", "test:watch": "npm run test -- --watch", "clean": "rimraf dist out coverage *.vsix *.log", @@ -266,13 +266,19 @@ "optimize-images": "node scripts/optimize-images.js", "quality": "npm run lint && npm run type-check && npm run format:check", "quality:fix": "npm run lint -- --fix && npm run format", + "quality:report": "npm run lint -- --format json --output-file eslint-report.json && npm run quality:analyze", + "quality:analyze": "node scripts/analyze-quality.js", + "quality:gate": "npm run lint -- --format json --output-file eslint-report.json && node scripts/sonar-quality-gate.js", + "quality:help": "node scripts/quality-help.js", "validate": "npm run quality && npm run test:unit", "ci": "npm run clean && npm run quality && npm run compile && npm run test:unit", "analyze-css": "node scripts/analyze-css.js", "analyze-css:clean": "npm run analyze-css && echo '\n๐Ÿงน To clean up unused CSS, review the report above and manually remove unused rules.'", "cleanup-css": "node scripts/cleanup-css.js plan", "cleanup-css:auto": "node scripts/cleanup-css.js auto-clean", - "cleanup-css:list": "node scripts/cleanup-css.js list" + "cleanup-css:list": "node scripts/cleanup-css.js list", + "convert-todo": "node scripts/convert-todo-to-workflow.js", + "publish:extension": "node scripts/publish-extension.js" }, "devDependencies": { "@fullhuman/postcss-purgecss": "^7.0.2", @@ -291,6 +297,11 @@ "@vscode/vsce": "^3.2.1", "css-loader": "^6.8.1", "eslint": "^8.56.0", + "eslint-plugin-complexity": "^1.0.2", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsdoc": "^46.10.1", + "eslint-plugin-sonarjs": "^3.0.4", + "eslint-plugin-unicorn": "^48.0.1", "glob": "^10.3.10", "husky": "^9.1.7", "identity-obj-proxy": "^3.0.0", @@ -299,6 +310,7 @@ "lint-staged": "^16.1.2", "mini-css-extract-plugin": "^2.7.6", "mocha": "^10.2.0", + "nyc": "^17.1.0", "prettier": "^3.1.1", "rimraf": "^5.0.5", "sinon": "^20.0.0", diff --git a/scripts/analyze-quality.js b/scripts/analyze-quality.js new file mode 100644 index 0000000..1363124 --- /dev/null +++ b/scripts/analyze-quality.js @@ -0,0 +1,200 @@ +#!/usr/bin/env node + +const fs = require("fs"); +const path = require("path"); + +/** + * Analyze ESLint quality report and provide insights + */ +async function analyzeQuality() { + const reportPath = path.join(__dirname, "..", "eslint-report.json"); + + if (!fs.existsSync(reportPath)) { + console.error( + "โŒ ESLint report not found. Run npm run quality:report first.", + ); + return; + } + + const report = JSON.parse(fs.readFileSync(reportPath, "utf8")); + + // Aggregate statistics + const stats = { + totalFiles: report.length, + filesWithIssues: report.filter( + (file) => file.errorCount > 0 || file.warningCount > 0, + ).length, + totalErrors: report.reduce((sum, file) => sum + file.errorCount, 0), + totalWarnings: report.reduce((sum, file) => sum + file.warningCount, 0), + ruleViolations: {}, + complexityIssues: {}, + securityIssues: {}, + qualityIssues: {}, + }; + + // Categorize issues + report.forEach((file) => { + file.messages.forEach((message) => { + const ruleId = message.ruleId; + if (!ruleId) return; + + if (!stats.ruleViolations[ruleId]) { + stats.ruleViolations[ruleId] = { count: 0, files: new Set() }; + } + stats.ruleViolations[ruleId].count++; + stats.ruleViolations[ruleId].files.add(file.filePath); + + // Categorize by type + if ( + ruleId.includes("complexity") || + ruleId.includes("max-") || + ruleId.includes("cognitive") + ) { + stats.complexityIssues[ruleId] = + (stats.complexityIssues[ruleId] || 0) + 1; + } else if (ruleId.includes("security") || ruleId.includes("sonarjs")) { + stats.securityIssues[ruleId] = (stats.securityIssues[ruleId] || 0) + 1; + } else if ( + ruleId.includes("unicorn") || + ruleId.includes("import") || + ruleId.includes("jsdoc") + ) { + stats.qualityIssues[ruleId] = (stats.qualityIssues[ruleId] || 0) + 1; + } + }); + }); + + // Generate report + console.log("๐Ÿ“Š QUALITY ANALYSIS REPORT"); + console.log("=".repeat(50)); + console.log(`๐Ÿ“ Total Files Analyzed: ${stats.totalFiles}`); + console.log(`โš ๏ธ Files with Issues: ${stats.filesWithIssues}`); + console.log(`๐Ÿ”ด Total Errors: ${stats.totalErrors}`); + console.log(`๐ŸŸก Total Warnings: ${stats.totalWarnings}`); + console.log( + `๐Ÿ“ˆ Quality Score: ${(((stats.totalFiles - stats.filesWithIssues) / stats.totalFiles) * 100).toFixed(1)}%`, + ); + console.log(""); + + // Top violating rules + console.log("๐Ÿ”ฅ TOP 10 RULE VIOLATIONS"); + console.log("-".repeat(50)); + const sortedRules = Object.entries(stats.ruleViolations) + .sort(([, a], [, b]) => b.count - a.count) + .slice(0, 10); + + sortedRules.forEach(([rule, data], index) => { + console.log( + `${index + 1}. ${rule}: ${data.count} violations (${data.files.size} files)`, + ); + }); + console.log(""); + + // Complexity issues + if (Object.keys(stats.complexityIssues).length > 0) { + console.log("๐Ÿงฎ COMPLEXITY ISSUES"); + console.log("-".repeat(50)); + Object.entries(stats.complexityIssues) + .sort(([, a], [, b]) => b - a) + .forEach(([rule, count]) => { + console.log(`โ€ข ${rule}: ${count} violations`); + }); + console.log(""); + } + + // Security issues + if (Object.keys(stats.securityIssues).length > 0) { + console.log("๐Ÿ”’ SECURITY/SONAR ISSUES"); + console.log("-".repeat(50)); + Object.entries(stats.securityIssues) + .sort(([, a], [, b]) => b - a) + .forEach(([rule, count]) => { + console.log(`โ€ข ${rule}: ${count} violations`); + }); + console.log(""); + } + + // Quality issues + if (Object.keys(stats.qualityIssues).length > 0) { + console.log("โœจ CODE QUALITY ISSUES"); + console.log("-".repeat(50)); + Object.entries(stats.qualityIssues) + .sort(([, a], [, b]) => b - a) + .slice(0, 15) + .forEach(([rule, count]) => { + console.log(`โ€ข ${rule}: ${count} violations`); + }); + console.log(""); + } + + // Worst files + console.log("๐Ÿ“„ FILES WITH MOST ISSUES"); + console.log("-".repeat(50)); + const worstFiles = report + .filter((file) => file.errorCount > 0 || file.warningCount > 0) + .sort( + (a, b) => b.errorCount + b.warningCount - (a.errorCount + a.warningCount), + ) + .slice(0, 10); + + worstFiles.forEach((file, index) => { + const relativePath = path.relative(process.cwd(), file.filePath); + console.log( + `${index + 1}. ${relativePath}: ${file.errorCount} errors, ${file.warningCount} warnings`, + ); + }); + console.log(""); + + // Recommendations + console.log("๐Ÿ’ก RECOMMENDATIONS"); + console.log("-".repeat(50)); + + const recommendations = []; + + if (stats.complexityIssues["max-lines"] > 20) { + recommendations.push( + "๐Ÿ“ Consider breaking down large files (max-lines violations)", + ); + } + + if (stats.complexityIssues["complexity"] > 10) { + recommendations.push("๐Ÿงฉ Reduce cyclomatic complexity in functions"); + } + + if (stats.ruleViolations["unicorn/no-array-for-each"]?.count > 20) { + recommendations.push( + "๐Ÿ”„ Replace .forEach() with for...of loops for better performance", + ); + } + + if (stats.ruleViolations["import/order"]?.count > 50) { + recommendations.push("๐Ÿ“ฆ Organize imports consistently across files"); + } + + if (stats.ruleViolations["unicorn/prefer-ternary"]?.count > 10) { + recommendations.push( + "๐Ÿ”€ Use ternary operators for simple if-else statements", + ); + } + + if (recommendations.length === 0) { + console.log( + "๐ŸŽ‰ No specific recommendations - consider fixing top violations first!", + ); + } else { + recommendations.forEach((rec) => console.log(rec)); + } + + console.log(""); + console.log("๐Ÿ› ๏ธ Run `npm run quality:fix` to automatically fix many issues"); + console.log( + "๐Ÿ“– Check ESLint docs for rule explanations: https://eslint.org/docs/rules/", + ); +} + +// Execute if run directly +if (require.main === module) { + analyzeQuality().catch(console.error); +} + +module.exports = { analyzeQuality }; diff --git a/scripts/convert-todo-to-workflow.js b/scripts/convert-todo-to-workflow.js new file mode 100644 index 0000000..cd20bbd --- /dev/null +++ b/scripts/convert-todo-to-workflow.js @@ -0,0 +1,143 @@ +#!/usr/bin/env node + +const fs = require("fs"); +const path = require("path"); +const yaml = require("js-yaml"); + +function generateRandomId() { + return Math.random().toString(36).substr(2, 9); +} + +function convertTodoToWorkflow(todoData, workflowName = "todo-pipeline") { + const todos = todoData.todos || []; + + // Filter pending todos or include all if specified + const tasks = todos.map((todo, index) => { + const taskId = `task_${Date.now()}_${generateRandomId()}`; + const stepNumber = index + 1; + + return { + id: taskId, + name: `Task ${stepNumber}`, + uses: "anthropics/claude-pipeline-action@v1", + with: { + prompt: todo.content, + model: "auto", + allow_all_tools: true, + // Chain tasks: first task outputs session, subsequent tasks resume from previous + ...(index === 0 ? { output_session: true } : {}), + ...(index > 0 + ? { + resume_session: `\${{ steps.task_${Date.now()}_prev.outputs.session_id }}`, + } + : {}), + }, + }; + }); + + // Fix resume_session references to point to actual previous task IDs + tasks.forEach((task, index) => { + if (index > 0) { + task.with.resume_session = `\${{ steps.${tasks[index - 1].id}.outputs.session_id }}`; + } + }); + + const workflow = { + name: workflowName, + on: { + workflow_dispatch: { + inputs: { + description: { + description: "Pipeline execution", + required: false, + type: "string", + }, + }, + }, + }, + jobs: { + pipeline: { + name: "Pipeline Execution", + "runs-on": "ubuntu-latest", + steps: tasks, + }, + }, + }; + + return workflow; +} + +function main() { + const args = process.argv.slice(2); + + if (args.length < 2) { + console.error( + "Usage: node convert-todo-to-workflow.js [workflow-name]", + ); + console.error(""); + console.error("Examples:"); + console.error( + " node convert-todo-to-workflow.js todo/refactor.json workflows/refactor.yml", + ); + console.error( + ' node convert-todo-to-workflow.js todo/features.json workflows/features.yml "feature-pipeline"', + ); + process.exit(1); + } + + const sourceFile = args[0]; + const targetFile = args[1]; + const workflowName = + args[2] || path.basename(targetFile, path.extname(targetFile)); + + // Check if source file exists + if (!fs.existsSync(sourceFile)) { + console.error(`โŒ Error: Source file not found: ${sourceFile}`); + process.exit(1); + } + + try { + // Read and parse JSON todo file + const todoJson = fs.readFileSync(sourceFile, "utf8"); + const todoData = JSON.parse(todoJson); + + console.log(`๐Ÿ“– Reading todo file: ${sourceFile}`); + console.log(`๐Ÿ“ Found ${todoData.todos?.length || 0} todo items`); + + // Convert to workflow format + const workflow = convertTodoToWorkflow(todoData, workflowName); + + console.log(`๐Ÿ”„ Converting to GitHub Actions workflow format...`); + console.log( + `๐Ÿ“‹ Creating ${workflow.jobs.pipeline.steps.length} chained tasks`, + ); + + // Ensure target directory exists + const targetDir = path.dirname(targetFile); + if (!fs.existsSync(targetDir)) { + fs.mkdirSync(targetDir, { recursive: true }); + console.log(`๐Ÿ“ Created directory: ${targetDir}`); + } + + // Write YAML workflow file + const yamlContent = yaml.dump(workflow, { + indent: 2, + lineWidth: 120, + noRefs: true, + }); + + fs.writeFileSync(targetFile, yamlContent); + + console.log(`โœ… Workflow created successfully: ${targetFile}`); + console.log(`๐Ÿš€ Run with: make pipeline PIPELINE=${targetFile}`); + } catch (error) { + console.error(`โŒ Error: ${error.message}`); + process.exit(1); + } +} + +if (require.main === module) { + main(); +} + +module.exports = { convertTodoToWorkflow }; diff --git a/scripts/publish-cli.js b/scripts/publish-cli.js new file mode 100644 index 0000000..50e14b6 --- /dev/null +++ b/scripts/publish-cli.js @@ -0,0 +1,44 @@ +#!/usr/bin/env node + +const { execSync } = require("child_process"); +const path = require("path"); +const fs = require("fs"); + +/** + * Publishes the CLI package to npm + */ +function publishCLI() { + const cliDir = path.join(__dirname, "..", "cli"); + + console.log("๐Ÿ“ฆ Publishing Claude Runner CLI to npm..."); + + // Ensure CLI is built + console.log("๐Ÿ”จ Building CLI..."); + execSync("npm run build-cli", { + cwd: path.join(__dirname, ".."), + stdio: "inherit", + }); + + // Check if package.json exists in CLI directory + const cliPackageJson = path.join(cliDir, "package.json"); + if (!fs.existsSync(cliPackageJson)) { + console.error("โŒ CLI package.json not found!"); + process.exit(1); + } + + // Publish CLI package + console.log("๐Ÿš€ Publishing to npm..."); + try { + execSync("npm publish", { cwd: cliDir, stdio: "inherit" }); + console.log("โœ… CLI published successfully!"); + } catch (error) { + console.error("โŒ Failed to publish CLI:", error.message); + process.exit(1); + } +} + +if (require.main === module) { + publishCLI(); +} + +module.exports = { publishCLI }; diff --git a/scripts/publish-extension.js b/scripts/publish-extension.js new file mode 100644 index 0000000..97fadc8 --- /dev/null +++ b/scripts/publish-extension.js @@ -0,0 +1,40 @@ +#!/usr/bin/env node + +const { execSync } = require("child_process"); +const path = require("path"); + +/** + * Publishes the VSCode extension to marketplace + */ +function publishExtension() { + const rootDir = path.join(__dirname, ".."); + + console.log("๐Ÿ“ฆ Publishing Claude Runner Extension to VSCode Marketplace..."); + + // Build extension + console.log("๐Ÿ”จ Building extension..."); + execSync("npm run compile-production", { cwd: rootDir, stdio: "inherit" }); + + // Package extension + console.log("๐Ÿ“ฆ Packaging extension..."); + execSync("npm run package", { cwd: rootDir, stdio: "inherit" }); + + // Publish to marketplace + console.log("๐Ÿš€ Publishing to VSCode Marketplace..."); + try { + execSync("vsce publish", { cwd: rootDir, stdio: "inherit" }); + console.log("โœ… Extension published successfully!"); + } catch (error) { + console.error("โŒ Failed to publish extension:", error.message); + console.log("๐Ÿ’ก Make sure you have vsce installed and are logged in:"); + console.log(" npm install -g @vscode/vsce"); + console.log(" vsce login "); + process.exit(1); + } +} + +if (require.main === module) { + publishExtension(); +} + +module.exports = { publishExtension }; diff --git a/scripts/quality-help.js b/scripts/quality-help.js new file mode 100644 index 0000000..9f2b108 --- /dev/null +++ b/scripts/quality-help.js @@ -0,0 +1,75 @@ +#!/usr/bin/env node + +console.log("๐Ÿ“Š CLAUDE RUNNER QUALITY TOOLS"); +console.log("=".repeat(50)); +console.log(""); + +console.log("๐Ÿ”ง AVAILABLE COMMANDS:"); +console.log(""); + +console.log( + "npm run quality - Full quality check (lint + typecheck + format)", +); +console.log( + "npm run quality:fix - Auto-fix linting and formatting issues", +); +console.log( + "npm run quality:report - Generate comprehensive quality analysis", +); +console.log( + "npm run quality:analyze - Analyze quality report with insights", +); +console.log("npm run quality:gate - Sonar-style quality gate check"); +console.log(""); + +console.log("๐Ÿ“ˆ QUALITY FEATURES:"); +console.log(""); +console.log( + "โœ… Complexity Analysis - Function complexity, cyclomatic complexity", +); +console.log( + "โœ… SonarJS Rules - Security, maintainability, reliability", +); +console.log( + "โœ… Import Organization - Import order and dependency analysis", +); +console.log("โœ… Modern JavaScript - Unicorn rules for best practices"); +console.log("โœ… Documentation Quality - JSDoc validation"); +console.log( + "โœ… Quality Gate - Pass/fail thresholds like SonarQube", +); +console.log(""); + +console.log("๐Ÿ“Š QUALITY METRICS:"); +console.log(""); +console.log("โ€ข Total violations by rule type"); +console.log("โ€ข Complexity violations (functions, files, statements)"); +console.log("โ€ข Security and maintainability issues"); +console.log("โ€ข Files with most issues"); +console.log("โ€ข Quality score percentage"); +console.log("โ€ข Improvement recommendations"); +console.log(""); + +console.log("๐ŸŽฏ QUALITY GATE THRESHOLDS:"); +console.log(""); +console.log("โ€ข Max Errors: 100"); +console.log("โ€ข Max Warnings: 200"); +console.log("โ€ข Max Complexity Violations: 20"); +console.log("โ€ข Max Security Violations: 5"); +console.log("โ€ข Max Duplicate Code: 10"); +console.log("โ€ข Min Quality Score: 80%"); +console.log(""); + +console.log("๐Ÿ’ก EXAMPLES:"); +console.log(""); +console.log("# Quick fix common issues"); +console.log("npm run quality:fix"); +console.log(""); +console.log("# Full quality analysis with detailed breakdown"); +console.log("npm run quality:report"); +console.log(""); +console.log("# Check if code passes quality gate"); +console.log("npm run quality:gate"); +console.log(""); + +console.log("๐Ÿ“– For more info: https://eslint.org/docs/rules/"); diff --git a/scripts/sonar-quality-gate.js b/scripts/sonar-quality-gate.js new file mode 100644 index 0000000..ffc8127 --- /dev/null +++ b/scripts/sonar-quality-gate.js @@ -0,0 +1,217 @@ +#!/usr/bin/env node + +const fs = require("fs"); +const path = require("path"); + +/** + * Sonar-style quality gate analysis + */ +async function checkQualityGate() { + const reportPath = path.join(__dirname, "..", "eslint-report.json"); + + if (!fs.existsSync(reportPath)) { + console.error( + "โŒ ESLint report not found. Run npm run quality:report first.", + ); + process.exit(1); + } + + const report = JSON.parse(fs.readFileSync(reportPath, "utf8")); + + // Quality Gate thresholds (configurable) + const qualityGate = { + maxErrors: 100, // Max errors allowed + maxWarnings: 200, // Max warnings allowed + maxComplexityViolations: 20, // Max complexity violations + maxSecurityViolations: 5, // Max security violations + maxDuplicateStrings: 10, // Max duplicate string violations + minQualityScore: 80, // Min quality score (%) + }; + + // Analyze violations + const violations = { + totalErrors: 0, + totalWarnings: 0, + complexityViolations: 0, + securityViolations: 0, + duplicateStrings: 0, + filesWithIssues: 0, + totalFiles: report.length, + }; + + const criticalRules = { + complexity: [ + "complexity", + "max-lines", + "max-lines-per-function", + "max-statements", + "sonarjs/cognitive-complexity", + ], + security: [ + "sonarjs/no-hardcoded-secrets", + "sonarjs/no-weak-cipher", + "sonarjs/no-hardcoded-passwords", + ], + duplicates: [ + "sonarjs/no-duplicate-string", + "sonarjs/no-identical-functions", + ], + }; + + report.forEach((file) => { + if (file.errorCount > 0 || file.warningCount > 0) { + violations.filesWithIssues++; + } + + violations.totalErrors += file.errorCount; + violations.totalWarnings += file.warningCount; + + file.messages.forEach((message) => { + const ruleId = message.ruleId; + if (!ruleId) return; + + if (criticalRules.complexity.includes(ruleId)) { + violations.complexityViolations++; + } else if (criticalRules.security.includes(ruleId)) { + violations.securityViolations++; + } else if (criticalRules.duplicates.includes(ruleId)) { + violations.duplicateStrings++; + } + }); + }); + + // Calculate quality score + const qualityScore = + ((violations.totalFiles - violations.filesWithIssues) / + violations.totalFiles) * + 100; + + // Check quality gate + const gateResults = { + errorGate: violations.totalErrors <= qualityGate.maxErrors, + warningGate: violations.totalWarnings <= qualityGate.maxWarnings, + complexityGate: + violations.complexityViolations <= qualityGate.maxComplexityViolations, + securityGate: + violations.securityViolations <= qualityGate.maxSecurityViolations, + duplicateGate: + violations.duplicateStrings <= qualityGate.maxDuplicateStrings, + qualityScoreGate: qualityScore >= qualityGate.minQualityScore, + }; + + const gatesPassed = Object.values(gateResults).filter(Boolean).length; + const totalGates = Object.keys(gateResults).length; + const overallPass = gatesPassed === totalGates; + + // Generate report + console.log("๐Ÿšช SONAR-STYLE QUALITY GATE REPORT"); + console.log("=".repeat(60)); + console.log( + `๐Ÿ“Š Overall Status: ${overallPass ? "โœ… PASSED" : "โŒ FAILED"} (${gatesPassed}/${totalGates})`, + ); + console.log(`๐Ÿ“ˆ Quality Score: ${qualityScore.toFixed(1)}%`); + console.log(""); + + console.log("๐ŸŽฏ QUALITY GATE RESULTS"); + console.log("-".repeat(60)); + + const gateChecks = [ + { + name: "Errors", + status: gateResults.errorGate, + current: violations.totalErrors, + threshold: qualityGate.maxErrors, + }, + { + name: "Warnings", + status: gateResults.warningGate, + current: violations.totalWarnings, + threshold: qualityGate.maxWarnings, + }, + { + name: "Complexity", + status: gateResults.complexityGate, + current: violations.complexityViolations, + threshold: qualityGate.maxComplexityViolations, + }, + { + name: "Security", + status: gateResults.securityGate, + current: violations.securityViolations, + threshold: qualityGate.maxSecurityViolations, + }, + { + name: "Duplicates", + status: gateResults.duplicateGate, + current: violations.duplicateStrings, + threshold: qualityGate.maxDuplicateStrings, + }, + { + name: "Quality Score", + status: gateResults.qualityScoreGate, + current: `${qualityScore.toFixed(1)}%`, + threshold: `${qualityGate.minQualityScore}%`, + }, + ]; + + gateChecks.forEach((check) => { + const status = check.status ? "โœ… PASS" : "โŒ FAIL"; + console.log( + `${status} ${check.name}: ${check.current} (threshold: ${check.threshold})`, + ); + }); + + console.log(""); + + if (!overallPass) { + console.log("โŒ QUALITY GATE FAILED"); + console.log("๐Ÿ”ง Actions needed:"); + + if (!gateResults.errorGate) { + console.log( + ` โ€ข Reduce errors from ${violations.totalErrors} to ${qualityGate.maxErrors} or below`, + ); + } + if (!gateResults.warningGate) { + console.log( + ` โ€ข Reduce warnings from ${violations.totalWarnings} to ${qualityGate.maxWarnings} or below`, + ); + } + if (!gateResults.complexityGate) { + console.log( + ` โ€ข Reduce complexity violations from ${violations.complexityViolations} to ${qualityGate.maxComplexityViolations} or below`, + ); + } + if (!gateResults.securityGate) { + console.log( + ` โ€ข Fix security issues: ${violations.securityViolations} violations found`, + ); + } + if (!gateResults.duplicateGate) { + console.log( + ` โ€ข Reduce code duplication: ${violations.duplicateStrings} violations found`, + ); + } + if (!gateResults.qualityScoreGate) { + console.log( + ` โ€ข Improve quality score to ${qualityGate.minQualityScore}% or above`, + ); + } + + console.log(""); + console.log( + "๐Ÿ› ๏ธ Run `npm run quality:fix` to automatically fix many issues", + ); + process.exit(1); + } else { + console.log("โœ… QUALITY GATE PASSED"); + console.log("๐ŸŽ‰ All quality thresholds met!"); + } +} + +// Execute if run directly +if (require.main === module) { + checkQualityGate().catch(console.error); +} + +module.exports = { checkQualityGate }; diff --git a/src/adapters/storage/WorkflowStorageAdapter.ts b/src/adapters/storage/WorkflowStorageAdapter.ts new file mode 100644 index 0000000..f8b867f --- /dev/null +++ b/src/adapters/storage/WorkflowStorageAdapter.ts @@ -0,0 +1,188 @@ +import * as vscode from "vscode"; +import { + WorkflowStateStorage, + WorkflowState, +} from "../../services/WorkflowStateService"; + +export class VSCodeWorkflowStorageAdapter implements WorkflowStateStorage { + private readonly storageKey = "claude-runner.workflow-states"; + private readonly maxStates = 50; // Limit stored states to prevent excessive memory usage + + constructor(private readonly context: vscode.ExtensionContext) {} + + async saveWorkflowState(state: WorkflowState): Promise { + try { + const existingStates = await this.loadAllStates(); + + // Update existing state or add new one + const existingIndex = existingStates.findIndex( + (s) => s.executionId === state.executionId, + ); + + if (existingIndex >= 0) { + existingStates[existingIndex] = state; + } else { + existingStates.push(state); + } + + // Limit the number of stored states + if (existingStates.length > this.maxStates) { + // Sort by start time (newest first) and keep only the most recent states + existingStates.sort( + (a, b) => + new Date(b.startTime).getTime() - new Date(a.startTime).getTime(), + ); + existingStates.splice(this.maxStates); + } + + await this.context.globalState.update(this.storageKey, existingStates); + } catch (error) { + console.error("Failed to save workflow state:", error); + throw new Error( + `Failed to save workflow state: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } + + async loadWorkflowState(executionId: string): Promise { + try { + const states = await this.loadAllStates(); + return states.find((state) => state.executionId === executionId) ?? null; + } catch (error) { + console.error("Failed to load workflow state:", error); + return null; + } + } + + async listWorkflowStates(): Promise { + try { + return await this.loadAllStates(); + } catch (error) { + console.error("Failed to list workflow states:", error); + return []; + } + } + + async deleteWorkflowState(executionId: string): Promise { + try { + const states = await this.loadAllStates(); + const filteredStates = states.filter( + (state) => state.executionId !== executionId, + ); + + await this.context.globalState.update(this.storageKey, filteredStates); + } catch (error) { + console.error("Failed to delete workflow state:", error); + throw new Error( + `Failed to delete workflow state: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } + + async cleanupOldStates(maxAgeMs: number): Promise { + try { + const states = await this.loadAllStates(); + const cutoffTime = Date.now() - maxAgeMs; + + const validStates = states.filter((state) => { + const stateTime = new Date(state.startTime).getTime(); + return stateTime > cutoffTime; + }); + + if (validStates.length !== states.length) { + await this.context.globalState.update(this.storageKey, validStates); + } + } catch (error) { + console.error("Failed to cleanup old workflow states:", error); + } + } + + private async loadAllStates(): Promise { + try { + const states = this.context.globalState.get( + this.storageKey, + [], + ); + + // Validate and sanitize the loaded states + return states.filter(this.isValidWorkflowState); + } catch (error) { + console.error("Failed to load workflow states from storage:", error); + return []; + } + } + + private isValidWorkflowState(state: unknown): state is WorkflowState { + if (!state || typeof state !== "object") { + return false; + } + + const s = state as Partial; + + return !!( + s.executionId && + typeof s.executionId === "string" && + s.workflowName && + typeof s.workflowName === "string" && + s.workflowPath && + typeof s.workflowPath === "string" && + s.startTime && + typeof s.startTime === "string" && + typeof s.currentStep === "number" && + typeof s.totalSteps === "number" && + s.status && + typeof s.status === "string" && + s.sessionMappings && + typeof s.sessionMappings === "object" && + Array.isArray(s.completedSteps) && + s.execution && + typeof s.execution === "object" && + typeof s.canResume === "boolean" + ); + } + + // Utility methods for storage management + async getStorageStats(): Promise<{ + totalStates: number; + totalSize: number; + oldestState?: string; + newestState?: string; + }> { + try { + const states = await this.loadAllStates(); + + if (states.length === 0) { + return { totalStates: 0, totalSize: 0 }; + } + + const sortedByTime = [...states].sort( + (a, b) => + new Date(a.startTime).getTime() - new Date(b.startTime).getTime(), + ); + + // Estimate storage size (rough calculation) + const totalSize = JSON.stringify(states).length; + + return { + totalStates: states.length, + totalSize, + oldestState: sortedByTime[0]?.startTime, + newestState: sortedByTime[sortedByTime.length - 1]?.startTime, + }; + } catch (error) { + console.error("Failed to get storage stats:", error); + return { totalStates: 0, totalSize: 0 }; + } + } + + async clearAllStates(): Promise { + try { + await this.context.globalState.update(this.storageKey, []); + } catch (error) { + console.error("Failed to clear all workflow states:", error); + throw new Error( + `Failed to clear workflow states: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } +} diff --git a/src/adapters/vscode/VSCodeConfigSource.ts b/src/adapters/vscode/VSCodeConfigSource.ts new file mode 100644 index 0000000..0634cfa --- /dev/null +++ b/src/adapters/vscode/VSCodeConfigSource.ts @@ -0,0 +1,16 @@ +import * as vscode from "vscode"; +import { IConfigSource } from "../../core/interfaces/IConfigManager"; + +export class VSCodeConfigSource implements IConfigSource { + private readonly configSection = "claude-runner"; + + async get(key: string): Promise { + const config = vscode.workspace.getConfiguration(this.configSection); + return config.get(key); + } + + async set(key: string, value: T): Promise { + const config = vscode.workspace.getConfiguration(this.configSection); + await config.update(key, value, vscode.ConfigurationTarget.Global); + } +} diff --git a/src/adapters/vscode/VSCodeFileSystem.ts b/src/adapters/vscode/VSCodeFileSystem.ts new file mode 100644 index 0000000..023a3c7 --- /dev/null +++ b/src/adapters/vscode/VSCodeFileSystem.ts @@ -0,0 +1,50 @@ +import * as fs from "fs/promises"; +import { IFileSystem } from "../../core/interfaces/IFileSystem"; + +export class VSCodeFileSystem implements IFileSystem { + async readFile(path: string): Promise { + return await fs.readFile(path, "utf-8"); + } + + async writeFile(path: string, content: string): Promise { + await fs.writeFile(path, content, "utf-8"); + } + + async exists(path: string): Promise { + try { + await fs.access(path); + return true; + } catch { + return false; + } + } + + async mkdir(path: string, options?: { recursive: boolean }): Promise { + await fs.mkdir(path, options); + } + + async readdir(path: string): Promise { + return await fs.readdir(path); + } + + async stat( + path: string, + ): Promise<{ + isDirectory: boolean; + size: number; + mtime: Date; + birthtime: Date; + }> { + const stats = await fs.stat(path); + return { + isDirectory: stats.isDirectory(), + size: stats.size, + mtime: stats.mtime, + birthtime: stats.birthtime, + }; + } + + async unlink(path: string): Promise { + await fs.unlink(path); + } +} diff --git a/src/adapters/vscode/VSCodeLogger.ts b/src/adapters/vscode/VSCodeLogger.ts new file mode 100644 index 0000000..384c3bf --- /dev/null +++ b/src/adapters/vscode/VSCodeLogger.ts @@ -0,0 +1,37 @@ +import { ILogger } from "../../core/interfaces/ILogger"; + +export class VSCodeLogger implements ILogger { + private readonly isTestEnvironment = + process.env.NODE_ENV === "test" || + process.env.JEST_WORKER_ID !== undefined || + global?.jest; + + info(message: string, ...args: unknown[]): void { + // eslint-disable-next-line no-console + console.log(message, ...args); + } + + warn(message: string, ...args: unknown[]): void { + // eslint-disable-next-line no-console + console.warn(message, ...args); + } + + error(message: string, error?: Error): void { + if (error) { + // eslint-disable-next-line no-console + console.error(message, error); + } else { + // eslint-disable-next-line no-console + console.error(message); + } + } + + debug(message: string, ...args: unknown[]): void { + // Suppress debug logging in test environment per CLAUDE.md logging rules + if (this.isTestEnvironment) { + return; + } + // eslint-disable-next-line no-console + console.debug(message, ...args); + } +} diff --git a/src/adapters/vscode/VSCodeNotification.ts b/src/adapters/vscode/VSCodeNotification.ts new file mode 100644 index 0000000..1201864 --- /dev/null +++ b/src/adapters/vscode/VSCodeNotification.ts @@ -0,0 +1,49 @@ +import * as vscode from "vscode"; +import { INotification, IProgress } from "../../core/interfaces/INotification"; + +class VSCodeProgress implements IProgress { + constructor( + private readonly progress: vscode.Progress<{ + message?: string; + increment?: number; + }>, + ) {} + + report(value: number, message?: string): void { + this.progress.report({ + increment: value, + message, + }); + } +} + +export class VSCodeNotification implements INotification { + async showInfo(message: string): Promise { + vscode.window.showInformationMessage(message); + } + + async showWarning(message: string): Promise { + vscode.window.showWarningMessage(message); + } + + async showError(message: string): Promise { + vscode.window.showErrorMessage(message); + } + + async showProgress( + title: string, + task: (progress: IProgress) => Promise, + ): Promise { + return vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title, + cancellable: false, + }, + async (progress) => { + const vsCodeProgress = new VSCodeProgress(progress); + return await task(vsCodeProgress); + }, + ); + } +} diff --git a/src/adapters/vscode/VSCodeStorage.ts b/src/adapters/vscode/VSCodeStorage.ts new file mode 100644 index 0000000..3095715 --- /dev/null +++ b/src/adapters/vscode/VSCodeStorage.ts @@ -0,0 +1,22 @@ +import * as vscode from "vscode"; +import { IStorage } from "../../core/interfaces/IStorage"; + +export class VSCodeStorage implements IStorage { + constructor(private readonly context: vscode.ExtensionContext) {} + + async get(key: string): Promise { + return this.context.globalState.get(key); + } + + async set(key: string, value: T): Promise { + await this.context.globalState.update(key, value); + } + + async delete(key: string): Promise { + await this.context.globalState.update(key, undefined); + } + + async keys(): Promise { + return Array.from(this.context.globalState.keys()); + } +} diff --git a/src/adapters/vscode/index.ts b/src/adapters/vscode/index.ts new file mode 100644 index 0000000..666ab95 --- /dev/null +++ b/src/adapters/vscode/index.ts @@ -0,0 +1,5 @@ +export * from "./VSCodeStorage"; +export * from "./VSCodeLogger"; +export * from "./VSCodeFileSystem"; +export * from "./VSCodeNotification"; +export * from "./VSCodeConfigSource"; diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx index 9c209a5..3dd729b 100644 --- a/src/components/common/Button.tsx +++ b/src/components/common/Button.tsx @@ -1,28 +1,95 @@ import React from "react"; +import { makeStyles } from "../../styles/makeStyles"; +import { tokens } from "../../styles/tokens"; interface ButtonProps extends React.ButtonHTMLAttributes { - variant?: "primary" | "secondary" | "success" | "error"; + variant?: "primary" | "secondary"; + size?: "small" | "medium" | "large"; loading?: boolean; children: React.ReactNode; } +const useButtonStyles = makeStyles({ + root: { + fontFamily: "var(--vscode-font-family)", + fontSize: "var(--vscode-font-size)", + border: "none", + borderRadius: tokens.borderRadius.sm, + cursor: "pointer", + backgroundColor: "var(--vscode-button-background)", + color: "var(--vscode-button-foreground)", + lineHeight: "1.2", + transition: "all 0.2s ease", + }, + primary: { + backgroundColor: "var(--vscode-button-background)", + color: "var(--vscode-button-foreground)", + }, + secondary: { + backgroundColor: "var(--vscode-button-secondaryBackground)", + color: "var(--vscode-button-secondaryForeground)", + }, + small: { + padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`, + fontSize: tokens.fontSize.sm, + }, + medium: { + padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`, + fontSize: "var(--vscode-font-size)", + }, + large: { + padding: `${tokens.spacing.sm} ${tokens.spacing.md}`, + fontSize: tokens.fontSize.lg, + }, + loading: { + opacity: "0.7", + position: "relative", + }, + loadingSpinner: { + width: "12px", + height: "12px", + border: "2px solid transparent", + borderTopColor: "currentColor", + borderLeftColor: "currentColor", + borderRadius: "50%", + animation: "spin 0.8s linear infinite", + marginRight: tokens.spacing.sm, + display: "inline-block", + verticalAlign: "middle", + }, +}); + const Button: React.FC = ({ variant = "primary", + size = "medium", loading = false, disabled, children, className = "", ...props }) => { - const classes = `${variant} ${className}`; + const styles = useButtonStyles(); + + const buttonStyle = { + ...styles.root, + ...styles[variant], + ...styles[size], + ...(loading ? styles.loading : {}), + }; + + const classNames = [variant, size, loading ? "loading" : "", className] + .filter(Boolean) + .join(" "); return ( - diff --git a/src/components/common/Input.tsx b/src/components/common/Input.tsx index 1fbc62b..942fac4 100644 --- a/src/components/common/Input.tsx +++ b/src/components/common/Input.tsx @@ -1,4 +1,6 @@ import React from "react"; +import { makeStyles } from "../../styles/makeStyles"; +import { tokens } from "../../styles/tokens"; interface InputProps extends React.InputHTMLAttributes { label?: string; @@ -6,6 +8,46 @@ interface InputProps extends React.InputHTMLAttributes { fullWidth?: boolean; } +const useInputStyles = makeStyles({ + inputGroup: { + display: "flex", + flexDirection: "column", + gap: tokens.spacing.xs, + }, + fullWidth: { + width: "100%", + flex: "1", + }, + label: { + fontSize: "var(--vscode-font-size)", + color: "var(--vscode-foreground)", + fontWeight: "500", + }, + input: { + fontFamily: "var(--vscode-font-family)", + fontSize: "var(--vscode-font-size)", + padding: tokens.spacing.xs + " " + tokens.spacing.sm, + backgroundColor: "var(--vscode-input-background)", + color: "var(--vscode-input-foreground)", + border: "1px solid var(--vscode-input-border)", + borderRadius: tokens.borderRadius.sm, + lineHeight: "1.2", + width: "100%", + }, + inputFocus: { + outline: "1px solid var(--vscode-focusBorder)", + outlineOffset: "-1px", + }, + inputError: { + borderColor: "var(--vscode-errorForeground)", + }, + error: { + fontSize: "var(--vscode-font-size)", + color: "var(--vscode-errorForeground)", + marginTop: tokens.spacing.xs, + }, +}); + const Input: React.FC = ({ label, error, @@ -16,16 +58,53 @@ const Input: React.FC = ({ }) => { // NOSONAR S2245 - Math.random() is safe for non-cryptographic HTML element IDs in VSCode extension const inputId = id ?? `input-${Math.random().toString(36).substring(2, 11)}`; + const styles = useInputStyles(); + + const inputGroupStyle = { + ...styles.inputGroup, + ...(fullWidth ? styles.fullWidth : {}), + }; + + const inputStyle = { + ...styles.input, + ...(error ? styles.inputError : {}), + }; + + const containerClasses = ["input-group", fullWidth ? "full-width" : ""] + .filter(Boolean) + .join(" "); + + const inputClasses = [className, error ? "error" : ""] + .filter(Boolean) + .join(" "); return ( -
- {label && } +
+ {label && ( + + )} { + Object.assign(e.target.style, styles.inputFocus); + props.onFocus?.(e); + }} + onBlur={(e) => { + e.target.style.outline = ""; + e.target.style.outlineOffset = ""; + props.onBlur?.(e); + }} {...props} /> - {error &&
{error}
} + {error && ( +
+ {error} +
+ )}
); }; diff --git a/src/components/common/ParallelTasksConfig.tsx b/src/components/common/ParallelTasksConfig.tsx deleted file mode 100644 index 976b8ef..0000000 --- a/src/components/common/ParallelTasksConfig.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from "react"; -import Card from "./Card"; -import Button from "./Button"; - -interface ParallelTasksConfigProps { - parallelTasksCount: number; - onUpdateParallelTasksCount: (value: number) => void; - disabled?: boolean; -} - -const ParallelTasksConfig: React.FC = ({ - parallelTasksCount, - onUpdateParallelTasksCount, - disabled = false, -}) => { - const [localValue, setLocalValue] = React.useState(parallelTasksCount); - const [loading, setLoading] = React.useState(false); - - React.useEffect(() => { - setLocalValue(parallelTasksCount); - }, [parallelTasksCount]); - - const handleUpdateParallelTasksCount = async () => { - setLoading(true); - onUpdateParallelTasksCount(localValue); - // Loading will be cleared when new props arrive - setTimeout(() => setLoading(false), 1000); - }; - - return ( - -
-

- Configure the number of tasks that can run in parallel. -

-
- - - -
-
-
- ); -}; - -export default React.memo(ParallelTasksConfig); diff --git a/src/components/hooks/useVSCodeAPI.ts b/src/components/hooks/useVSCodeAPI.ts index 03fd6bf..e3710c4 100644 --- a/src/components/hooks/useVSCodeAPI.ts +++ b/src/components/hooks/useVSCodeAPI.ts @@ -5,12 +5,16 @@ interface TaskItem { name?: string; prompt: string; resumePrevious: boolean; - status: "pending" | "running" | "completed" | "error"; + status: "pending" | "running" | "completed" | "error" | "paused" | "skipped"; results?: string; sessionId?: string; model?: string; dependsOn?: string[]; continueFrom?: string | null; + pausedUntil?: number; + check?: string; + condition?: "on_success" | "on_failure" | "always"; + skipReason?: string; } interface CommandFile { @@ -155,13 +159,6 @@ export const useVSCodeAPI = () => { [sendMessage], ); - const updateParallelTasksCount = useCallback( - (value: number) => { - sendMessage("updateParallelTasksCount", { value }); - }, - [sendMessage], - ); - const requestUsageReport = useCallback( ( period: "today" | "week" | "month" | "hourly", @@ -258,7 +255,6 @@ export const useVSCodeAPI = () => { updateChatPrompt, updateShowChatPrompt, updateOutputFormat, - updateParallelTasksCount, savePipeline, loadPipeline, pipelineAddTask, diff --git a/src/components/panels/ChatPanel.tsx b/src/components/panels/ChatPanel.tsx index 93930fc..09e7e56 100644 --- a/src/components/panels/ChatPanel.tsx +++ b/src/components/panels/ChatPanel.tsx @@ -4,7 +4,6 @@ import Button from "../common/Button"; import Toggle from "../common/Toggle"; import PathSelector from "../common/PathSelector"; import ModelSelector from "../common/ModelSelector"; -import ParallelTasksConfig from "../common/ParallelTasksConfig"; import ClaudeVersionDisplay from "../common/ClaudeVersionDisplay"; import { useExtension } from "../../contexts/ExtensionContext"; @@ -115,13 +114,6 @@ const ChatPanel: React.FC = ({ disabled }) => {
- - {/* Parallel Tasks Configuration */} - ); }; diff --git a/src/components/panels/PipelinePanel.tsx b/src/components/panels/PipelinePanel.tsx index a9fd5b5..a423429 100644 --- a/src/components/panels/PipelinePanel.tsx +++ b/src/components/panels/PipelinePanel.tsx @@ -24,6 +24,10 @@ const PipelinePanel: React.FC = ({ disabled }) => { model: defaultModel = DEFAULT_MODEL, status, currentTaskIndex, + discoveredWorkflows, + isPaused = false, + pausedPipelines = [], + resumableWorkflows = [], } = main; const isTasksRunning = status === "running"; @@ -51,7 +55,6 @@ const PipelinePanel: React.FC = ({ disabled }) => { id: `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, name: `Task ${nextNumber}`, prompt: "", - resumePrevious: false, status: "pending" as const, model: defaultModel, }; @@ -74,11 +77,25 @@ const PipelinePanel: React.FC = ({ disabled }) => { const handleLoadPipeline = () => { if (selectedPipeline) { - actions.loadPipeline(selectedPipeline); + // Check if it's a workflow file (contains .yml or .yaml) or a saved pipeline + if ( + selectedPipeline.includes(".yml") || + selectedPipeline.includes(".yaml") + ) { + // It's a discovered workflow file + actions.loadWorkflow(selectedPipeline); + } else { + // It's a saved pipeline + actions.loadPipeline(selectedPipeline); + } setSelectedPipeline(""); } }; + const clearPipeline = () => { + actions.pipelineClearAll(); + }; + const removeTask = (taskId: string) => { if (tasks.length > 1) { actions.pipelineRemoveTask(taskId); @@ -103,6 +120,12 @@ const PipelinePanel: React.FC = ({ disabled }) => { const canRunTasks = tasks.some((task) => task.prompt.trim()) && !isTasksRunning; + const isPipelineFinished = + !isTasksRunning && + !isPaused && + tasks.some((t) => t.prompt.trim().length > 0) && + tasks.some((t) => t.status === "completed" || t.status === "error"); + return (
= ({ disabled }) => { isTasksRunning={isTasksRunning} canRunTasks={canRunTasks} disabled={disabled} + status={status} + tasks={tasks} + currentTaskIndex={currentTaskIndex} addTask={addTask} cancelTask={actions.cancelTask} handleRunTasks={handleRunTasks} @@ -132,6 +158,17 @@ const PipelinePanel: React.FC = ({ disabled }) => { selectedPipeline={selectedPipeline} setSelectedPipeline={setSelectedPipeline} handleLoadPipeline={handleLoadPipeline} + discoveredWorkflows={discoveredWorkflows} + isPaused={isPaused} + pausedPipelines={pausedPipelines} + resumableWorkflows={resumableWorkflows} + onPausePipeline={actions.pausePipeline} + onResumePipeline={actions.resumePipeline} + onPauseWorkflow={actions.pauseWorkflow} + onResumeWorkflow={actions.resumeWorkflow} + onDeleteWorkflowState={actions.deleteWorkflowState} + isPipelineFinished={isPipelineFinished} + clearPipeline={clearPipeline} /> = ({ disabled }) => { + const { state, actions } = useExtension(); + const { main } = state; + const { + tasks = [], + outputFormat, + availablePipelines = [], + discoveredWorkflows, + status, + currentTaskIndex, + isPaused = false, + pausedPipelines = [], + resumableWorkflows = [], + } = main; + + const [selectedWorkflow, setSelectedWorkflow] = useState(""); + const [loadedWorkflowName, setLoadedWorkflowName] = useState(""); + + const isTasksRunning = status === "running"; + + const handleLoadWorkflow = () => { + if (selectedWorkflow) { + if ( + selectedWorkflow.includes(".yml") || + selectedWorkflow.includes(".yaml") + ) { + actions.loadWorkflow(selectedWorkflow); + } else { + actions.loadPipeline(selectedWorkflow); + } + setLoadedWorkflowName(selectedWorkflow); + setSelectedWorkflow(""); + } + }; + + const handleRunTasks = () => { + const validTasks = tasks.filter((task) => task.prompt.trim()); + if (validTasks.length > 0) { + actions.runTasks(validTasks, outputFormat); + } + }; + + const canRunTasks = + tasks.some((task) => task.prompt.trim()) && !isTasksRunning; + + const isPipelineFinished = + !isTasksRunning && + !isPaused && + tasks.some((t) => t.prompt.trim().length > 0) && + tasks.some((t) => t.status === "completed" || t.status === "error"); + + const clearResults = () => { + actions.pipelineClearAll(); + setLoadedWorkflowName(""); + }; + + return ( +
+
+ + +
+ + {loadedWorkflowName && ( +
+ Current: + + {loadedWorkflowName.split("/").pop()?.split("\\").pop()} + +
+ )} + +
+ {!isTasksRunning && !isPaused && ( + + )} + + {isTasksRunning && !isPaused && ( + + )} + + {isPaused && pausedPipelines.length > 0 && ( + + )} + + {isTasksRunning && ( + + )} + + {isPipelineFinished && ( + + )} +
+ + {(pausedPipelines.length > 0 || resumableWorkflows.length > 0) && ( +
+

Resumable Workflows

+ {pausedPipelines.map((pipeline) => ( +
+ Pipeline {pipeline.pipelineId} + + +
+ ))} + {resumableWorkflows.map((workflow) => ( +
+ {workflow.workflowName} + + +
+ ))} +
+ )} + + {tasks.some((t) => t.prompt.trim().length > 0) && ( +
+ +
+ )} +
+ ); +}; + +export default React.memo(RunnerPanel); diff --git a/src/components/panels/UsageReportPanel.tsx b/src/components/panels/UsageReportPanel.tsx index 0bbf13e..9ce912b 100644 --- a/src/components/panels/UsageReportPanel.tsx +++ b/src/components/panels/UsageReportPanel.tsx @@ -102,6 +102,8 @@ const UsageReportPanel: React.FC = ({ switch (period) { case "today": return "Today"; + case "yesterday": + return "Yesterday"; case "week": return "Last 7 Days"; case "month": @@ -139,10 +141,32 @@ const UsageReportPanel: React.FC = ({ className="dropdown" > + +
+ + actions.updateUsageState({ autoRefresh: e.target.checked }) + } + disabled={disabled || loading} + /> + +
@@ -244,27 +268,6 @@ const UsageReportPanel: React.FC = ({ /> -
- - actions.updateUsageState({ autoRefresh: e.target.checked }) - } - disabled={disabled || loading} - /> - -
{limitValue > 0 && report && (
@@ -329,7 +332,7 @@ const UsageReportPanel: React.FC = ({ {report && !loading && (
-

{getPeriodLabel(selectedPeriod)} Summary

+

{getPeriodLabel(selectedPeriod)}

{report.startDate} to {report.endDate}

@@ -388,72 +391,173 @@ const UsageReportPanel: React.FC = ({
- {report.dailyReports.length > 0 && ( -
-

- {selectedPeriod === "hourly" - ? "Hourly Breakdown" - : "Daily Breakdown"} -

-
- {report.dailyReports.map((dailyReport) => ( -
-
- {dailyReport.date} - - {formatCurrency(dailyReport.costUSD)} - -
- -
-
- Models: - - {dailyReport.models.length > 0 - ? dailyReport.models.join(", ") - : "None"} - -
- -
-
- Input: - - {formatNumber(dailyReport.inputTokens)} - -
-
- Output: - - {formatNumber(dailyReport.outputTokens)} - -
-
- Cache C: - - {formatNumber(dailyReport.cacheCreateTokens)} - -
-
- Cache R: - - {formatNumber(dailyReport.cacheReadTokens)} - -
-
- -
- Total Tokens: - - {formatNumber(dailyReport.totalTokens)} - -
-
+ {(() => { + const shouldShowBreakdown = + report.dailyReports.length > 0 && + !( + selectedPeriod === "week" && report.dailyReports.length === 1 + ) && + !( + selectedPeriod === "month" && report.dailyReports.length === 1 + ); + + return ( + shouldShowBreakdown && ( +
+

+ {selectedPeriod === "hourly" || + selectedPeriod === "today" || + selectedPeriod === "yesterday" + ? "Hourly Breakdown" + : "Daily Breakdown"} +

+
+ {(() => { + // Group per-model entries by time period + const groupedByTime = report.dailyReports.reduce( + (acc, entry) => { + const timeKey = entry.date; + if (!acc[timeKey]) { + acc[timeKey] = []; + } + acc[timeKey].push(entry); + return acc; + }, + {} as Record, + ); + + return Object.entries(groupedByTime).map( + ([timeKey, entries]) => { + // Calculate totals for this time period + const periodTotal = entries.reduce( + (sum, entry) => sum + entry.costUSD, + 0, + ); + const allModels = entries + .map((entry) => entry.models[0]) + .filter(Boolean); + + return ( +
+
+ {timeKey} + + {formatCurrency(periodTotal)} + +
+ +
+
+ Models: + + {allModels.length > 0 + ? allModels.join(", ") + : "None"} + +
+ + {/* Show per-model breakdown when multiple models */} + {entries.length > 1 && ( +
+ {entries.map((entry, idx) => ( +
+ + {entry.models[0]}: + + + {formatCurrency(entry.costUSD)} + + + ({formatNumber(entry.totalTokens)}{" "} + tokens) + +
+ ))} +
+ )} + +
+ + Total Tokens: + + + {formatNumber( + entries.reduce( + (sum, entry) => + sum + entry.totalTokens, + 0, + ), + )} + +
+
+ +
+
+ Input: + + {formatNumber( + entries.reduce( + (sum, entry) => + sum + entry.inputTokens, + 0, + ), + )} + +
+
+ + Output: + + + {formatNumber( + entries.reduce( + (sum, entry) => + sum + entry.outputTokens, + 0, + ), + )} + +
+
+ + Cache C: + + + {formatNumber( + entries.reduce( + (sum, entry) => + sum + entry.cacheCreateTokens, + 0, + ), + )} + +
+
+ + Cache R: + + + {formatNumber( + entries.reduce( + (sum, entry) => + sum + entry.cacheReadTokens, + 0, + ), + )} + +
+
+
+ ); + }, + ); + })()}
- ))} -
-
- )} +
+ ) + ); + })()} {report.dailyReports.length === 0 && (
diff --git a/src/components/panels/WorkflowPanel.tsx b/src/components/panels/WorkflowPanel.tsx index 20d6a79..f0cf7f3 100644 --- a/src/components/panels/WorkflowPanel.tsx +++ b/src/components/panels/WorkflowPanel.tsx @@ -4,7 +4,7 @@ import PathSelector from "../common/PathSelector"; import ModelSelector from "../common/ModelSelector"; import Card from "../common/Card"; import { useExtension } from "../../contexts/ExtensionContext"; -import { ClaudeStep, isClaudeStep } from "../../types/WorkflowTypes"; +import { isClaudeStep, Step } from "../../types/WorkflowTypes"; import { WorkflowParser } from "../../services/WorkflowParser"; interface WorkflowPanelProps { @@ -83,7 +83,7 @@ const WorkflowPanel: React.FC = ({ disabled }) => { return stepStatuses[stepId] || { status: "pending" }; }; - const renderStepStatus = (step: ClaudeStep, stepId: string) => { + const renderStepStatus = (step: Step, stepId: string) => { const status = getStepStatus(stepId); const statusColors = { pending: "text-gray-500", @@ -94,7 +94,7 @@ const WorkflowPanel: React.FC = ({ disabled }) => { return (
- Status: {status.status} + Status: {status.status} {status.output?.result && (
Output: @@ -259,6 +259,8 @@ const WorkflowPanel: React.FC = ({ disabled }) => {
{step.name ?? step.run ?? "Non-Claude step"}
+ {executionStatus !== "idle" && + renderStepStatus(step, stepId)}
); } diff --git a/src/components/panels/WorkflowsPanel.tsx b/src/components/panels/WorkflowsPanel.tsx new file mode 100644 index 0000000..ff17d69 --- /dev/null +++ b/src/components/panels/WorkflowsPanel.tsx @@ -0,0 +1,194 @@ +import React, { useState } from "react"; +import { useExtension } from "../../contexts/ExtensionContext"; +import { getModelIds, DEFAULT_MODEL } from "../../models/ClaudeModels"; +import { TaskItem } from "../../services/ClaudeCodeService"; +import TaskList from "../pipeline/TaskList"; + +interface WorkflowsPanelProps { + disabled: boolean; +} + +const WorkflowsPanel: React.FC = ({ disabled }) => { + const { state, actions } = useExtension(); + const { main } = state; + const { + tasks = [], + availablePipelines = [], + availableModels = getModelIds(), + model: defaultModel = DEFAULT_MODEL, + discoveredWorkflows, + } = main; + + const [showSaveDialog, setShowSaveDialog] = useState(false); + const [workflowName, setWorkflowName] = useState(""); + const [workflowDescription, setWorkflowDescription] = useState(""); + const [selectedWorkflow, setSelectedWorkflow] = useState(""); + + const addTask = () => { + const existingNumbers = tasks + .map((t) => { + const match = t.name?.match(/^Task (\d+)$/); + return match ? parseInt(match[1], 10) : 0; + }) + .filter((n) => n > 0); + + const nextNumber = + existingNumbers.length > 0 + ? Math.max(...existingNumbers) + 1 + : tasks.length + 1; + + const newTask: TaskItem = { + id: `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, + name: `Task ${nextNumber}`, + prompt: "", + status: "pending" as const, + model: defaultModel, + }; + actions.pipelineAddTask(newTask); + }; + + const removeTask = (taskId: string) => { + if (tasks.length > 1) { + actions.pipelineRemoveTask(taskId); + } + }; + + const updateTask = ( + taskId: string, + field: keyof TaskItem, + value: string | boolean, + ) => { + actions.pipelineUpdateTaskField(taskId, field, value); + }; + + const handleSaveWorkflow = () => { + if (workflowName.trim()) { + const validTasks = tasks.filter((task) => task.prompt.trim()); + actions.savePipeline( + workflowName.trim(), + workflowDescription.trim(), + validTasks, + ); + setShowSaveDialog(false); + setWorkflowName(""); + setWorkflowDescription(""); + } + }; + + const handleLoadWorkflow = () => { + if (selectedWorkflow) { + if ( + selectedWorkflow.includes(".yml") || + selectedWorkflow.includes(".yaml") + ) { + actions.loadWorkflow(selectedWorkflow); + } else { + actions.loadPipeline(selectedWorkflow); + } + setSelectedWorkflow(""); + } + }; + + const clearWorkflow = () => { + actions.pipelineClearAll(); + }; + + const canSave = tasks.some((task) => task.prompt.trim()); + + return ( +
+
+ + +
+ +
+ + + +
+ + + + {showSaveDialog && ( +
+
+

Save Workflow

+ setWorkflowName(e.target.value)} + autoFocus + /> +