diff --git a/baselines/after-navigation-1.png b/baselines/after-navigation-1.png new file mode 100644 index 000000000..9491a3edf Binary files /dev/null and b/baselines/after-navigation-1.png differ diff --git a/baselines/after-navigation-2.png b/baselines/after-navigation-2.png new file mode 100644 index 000000000..eec76e647 Binary files /dev/null and b/baselines/after-navigation-2.png differ diff --git a/baselines/after-selection.png b/baselines/after-selection.png new file mode 100644 index 000000000..eec76e647 Binary files /dev/null and b/baselines/after-selection.png differ diff --git a/baselines/before-navigation.png b/baselines/before-navigation.png new file mode 100644 index 000000000..052be912c Binary files /dev/null and b/baselines/before-navigation.png differ diff --git a/baselines/final-state.png b/baselines/final-state.png new file mode 100644 index 000000000..eec76e647 Binary files /dev/null and b/baselines/final-state.png differ diff --git a/baselines/initial-state.png b/baselines/initial-state.png new file mode 100644 index 000000000..d472ba478 Binary files /dev/null and b/baselines/initial-state.png differ diff --git a/diffs/diff-after-navigation-1-1740485960249.png b/diffs/diff-after-navigation-1-1740485960249.png new file mode 100644 index 000000000..166645d68 Binary files /dev/null and b/diffs/diff-after-navigation-1-1740485960249.png differ diff --git a/diffs/diff-after-navigation-1-1740486604089.png b/diffs/diff-after-navigation-1-1740486604089.png new file mode 100644 index 000000000..1e79225a1 Binary files /dev/null and b/diffs/diff-after-navigation-1-1740486604089.png differ diff --git a/diffs/diff-after-navigation-1-1740487075727.png b/diffs/diff-after-navigation-1-1740487075727.png new file mode 100644 index 000000000..90dc5e884 Binary files /dev/null and b/diffs/diff-after-navigation-1-1740487075727.png differ diff --git a/diffs/diff-after-navigation-1-1740487613763.png b/diffs/diff-after-navigation-1-1740487613763.png new file mode 100644 index 000000000..7b3b3e421 Binary files /dev/null and b/diffs/diff-after-navigation-1-1740487613763.png differ diff --git a/diffs/diff-after-navigation-1-1740487853287.png b/diffs/diff-after-navigation-1-1740487853287.png new file mode 100644 index 000000000..89c67deeb Binary files /dev/null and b/diffs/diff-after-navigation-1-1740487853287.png differ diff --git a/diffs/diff-after-navigation-1-1740497659921.png b/diffs/diff-after-navigation-1-1740497659921.png new file mode 100644 index 000000000..bc4fb39e2 Binary files /dev/null and b/diffs/diff-after-navigation-1-1740497659921.png differ diff --git a/diffs/diff-after-navigation-1-1740497753870.png b/diffs/diff-after-navigation-1-1740497753870.png new file mode 100644 index 000000000..e5ff12485 Binary files /dev/null and b/diffs/diff-after-navigation-1-1740497753870.png differ diff --git a/diffs/diff-after-navigation-2-1740485960468.png b/diffs/diff-after-navigation-2-1740485960468.png new file mode 100644 index 000000000..76a5ae011 Binary files /dev/null and b/diffs/diff-after-navigation-2-1740485960468.png differ diff --git a/diffs/diff-after-navigation-2-1740486604304.png b/diffs/diff-after-navigation-2-1740486604304.png new file mode 100644 index 000000000..682f1709b Binary files /dev/null and b/diffs/diff-after-navigation-2-1740486604304.png differ diff --git a/diffs/diff-after-navigation-2-1740487075939.png b/diffs/diff-after-navigation-2-1740487075939.png new file mode 100644 index 000000000..1f3ce4904 Binary files /dev/null and b/diffs/diff-after-navigation-2-1740487075939.png differ diff --git a/diffs/diff-after-navigation-2-1740487613974.png b/diffs/diff-after-navigation-2-1740487613974.png new file mode 100644 index 000000000..1d103a8d4 Binary files /dev/null and b/diffs/diff-after-navigation-2-1740487613974.png differ diff --git a/diffs/diff-after-navigation-2-1740487853503.png b/diffs/diff-after-navigation-2-1740487853503.png new file mode 100644 index 000000000..1e79d9036 Binary files /dev/null and b/diffs/diff-after-navigation-2-1740487853503.png differ diff --git a/diffs/diff-after-navigation-2-1740497660139.png b/diffs/diff-after-navigation-2-1740497660139.png new file mode 100644 index 000000000..2724f87ae Binary files /dev/null and b/diffs/diff-after-navigation-2-1740497660139.png differ diff --git a/diffs/diff-after-navigation-2-1740497754090.png b/diffs/diff-after-navigation-2-1740497754090.png new file mode 100644 index 000000000..c0170a55a Binary files /dev/null and b/diffs/diff-after-navigation-2-1740497754090.png differ diff --git a/diffs/diff-after-selection-1740485960707.png b/diffs/diff-after-selection-1740485960707.png new file mode 100644 index 000000000..76a5ae011 Binary files /dev/null and b/diffs/diff-after-selection-1740485960707.png differ diff --git a/diffs/diff-after-selection-1740486604535.png b/diffs/diff-after-selection-1740486604535.png new file mode 100644 index 000000000..682f1709b Binary files /dev/null and b/diffs/diff-after-selection-1740486604535.png differ diff --git a/diffs/diff-after-selection-1740487076168.png b/diffs/diff-after-selection-1740487076168.png new file mode 100644 index 000000000..1f3ce4904 Binary files /dev/null and b/diffs/diff-after-selection-1740487076168.png differ diff --git a/diffs/diff-after-selection-1740487614203.png b/diffs/diff-after-selection-1740487614203.png new file mode 100644 index 000000000..1d103a8d4 Binary files /dev/null and b/diffs/diff-after-selection-1740487614203.png differ diff --git a/diffs/diff-after-selection-1740487853742.png b/diffs/diff-after-selection-1740487853742.png new file mode 100644 index 000000000..1e79d9036 Binary files /dev/null and b/diffs/diff-after-selection-1740487853742.png differ diff --git a/diffs/diff-after-selection-1740497660333.png b/diffs/diff-after-selection-1740497660333.png new file mode 100644 index 000000000..2724f87ae Binary files /dev/null and b/diffs/diff-after-selection-1740497660333.png differ diff --git a/diffs/diff-after-selection-1740497754285.png b/diffs/diff-after-selection-1740497754285.png new file mode 100644 index 000000000..39c6d747b Binary files /dev/null and b/diffs/diff-after-selection-1740497754285.png differ diff --git a/diffs/diff-before-navigation-1740485960018.png b/diffs/diff-before-navigation-1740485960018.png new file mode 100644 index 000000000..663b353d7 Binary files /dev/null and b/diffs/diff-before-navigation-1740485960018.png differ diff --git a/diffs/diff-before-navigation-1740486603864.png b/diffs/diff-before-navigation-1740486603864.png new file mode 100644 index 000000000..c70ab09c5 Binary files /dev/null and b/diffs/diff-before-navigation-1740486603864.png differ diff --git a/diffs/diff-before-navigation-1740487075507.png b/diffs/diff-before-navigation-1740487075507.png new file mode 100644 index 000000000..22afe2218 Binary files /dev/null and b/diffs/diff-before-navigation-1740487075507.png differ diff --git a/diffs/diff-before-navigation-1740487613539.png b/diffs/diff-before-navigation-1740487613539.png new file mode 100644 index 000000000..91750cf05 Binary files /dev/null and b/diffs/diff-before-navigation-1740487613539.png differ diff --git a/diffs/diff-before-navigation-1740487853060.png b/diffs/diff-before-navigation-1740487853060.png new file mode 100644 index 000000000..feb4aa8bb Binary files /dev/null and b/diffs/diff-before-navigation-1740487853060.png differ diff --git a/diffs/diff-before-navigation-1740497659723.png b/diffs/diff-before-navigation-1740497659723.png new file mode 100644 index 000000000..bd04c4528 Binary files /dev/null and b/diffs/diff-before-navigation-1740497659723.png differ diff --git a/diffs/diff-before-navigation-1740497753642.png b/diffs/diff-before-navigation-1740497753642.png new file mode 100644 index 000000000..fa4e76cac Binary files /dev/null and b/diffs/diff-before-navigation-1740497753642.png differ diff --git a/diffs/diff-final-state-1740485960904.png b/diffs/diff-final-state-1740485960904.png new file mode 100644 index 000000000..76a5ae011 Binary files /dev/null and b/diffs/diff-final-state-1740485960904.png differ diff --git a/diffs/diff-final-state-1740486604723.png b/diffs/diff-final-state-1740486604723.png new file mode 100644 index 000000000..682f1709b Binary files /dev/null and b/diffs/diff-final-state-1740486604723.png differ diff --git a/diffs/diff-final-state-1740487076377.png b/diffs/diff-final-state-1740487076377.png new file mode 100644 index 000000000..1f3ce4904 Binary files /dev/null and b/diffs/diff-final-state-1740487076377.png differ diff --git a/diffs/diff-final-state-1740487614414.png b/diffs/diff-final-state-1740487614414.png new file mode 100644 index 000000000..1d103a8d4 Binary files /dev/null and b/diffs/diff-final-state-1740487614414.png differ diff --git a/diffs/diff-final-state-1740487853958.png b/diffs/diff-final-state-1740487853958.png new file mode 100644 index 000000000..1e79d9036 Binary files /dev/null and b/diffs/diff-final-state-1740487853958.png differ diff --git a/diffs/diff-final-state-1740497660535.png b/diffs/diff-final-state-1740497660535.png new file mode 100644 index 000000000..2724f87ae Binary files /dev/null and b/diffs/diff-final-state-1740497660535.png differ diff --git a/diffs/diff-final-state-1740497754481.png b/diffs/diff-final-state-1740497754481.png new file mode 100644 index 000000000..39c6d747b Binary files /dev/null and b/diffs/diff-final-state-1740497754481.png differ diff --git a/diffs/diff-initial-state-1740485959787.png b/diffs/diff-initial-state-1740485959787.png new file mode 100644 index 000000000..3fdbfce42 Binary files /dev/null and b/diffs/diff-initial-state-1740485959787.png differ diff --git a/diffs/diff-initial-state-1740486603640.png b/diffs/diff-initial-state-1740486603640.png new file mode 100644 index 000000000..89a0795a9 Binary files /dev/null and b/diffs/diff-initial-state-1740486603640.png differ diff --git a/diffs/diff-initial-state-1740487075283.png b/diffs/diff-initial-state-1740487075283.png new file mode 100644 index 000000000..b804d286d Binary files /dev/null and b/diffs/diff-initial-state-1740487075283.png differ diff --git a/diffs/diff-initial-state-1740487613319.png b/diffs/diff-initial-state-1740487613319.png new file mode 100644 index 000000000..f48cb7c56 Binary files /dev/null and b/diffs/diff-initial-state-1740487613319.png differ diff --git a/diffs/diff-initial-state-1740487852837.png b/diffs/diff-initial-state-1740487852837.png new file mode 100644 index 000000000..ec13ded38 Binary files /dev/null and b/diffs/diff-initial-state-1740487852837.png differ diff --git a/diffs/diff-initial-state-1740497659488.png b/diffs/diff-initial-state-1740497659488.png new file mode 100644 index 000000000..0bfd767ac Binary files /dev/null and b/diffs/diff-initial-state-1740497659488.png differ diff --git a/diffs/diff-initial-state-1740497753416.png b/diffs/diff-initial-state-1740497753416.png new file mode 100644 index 000000000..109394117 Binary files /dev/null and b/diffs/diff-initial-state-1740497753416.png differ diff --git a/failure-selection-indicator-to-move-to-the-second-line-1740496212623.png b/failure-selection-indicator-to-move-to-the-second-line-1740496212623.png new file mode 100644 index 000000000..1e820d9fc Binary files /dev/null and b/failure-selection-indicator-to-move-to-the-second-line-1740496212623.png differ diff --git a/failure-waiting-for-text-1740496180122.png b/failure-waiting-for-text-1740496180122.png new file mode 100644 index 000000000..0fb441a65 Binary files /dev/null and b/failure-waiting-for-text-1740496180122.png differ diff --git a/failure-waiting-for-text-1740496324569.png b/failure-waiting-for-text-1740496324569.png new file mode 100644 index 000000000..5e37677ac Binary files /dev/null and b/failure-waiting-for-text-1740496324569.png differ diff --git a/failure-waiting-for-text-1740497648570.png b/failure-waiting-for-text-1740497648570.png new file mode 100644 index 000000000..fd3812b98 Binary files /dev/null and b/failure-waiting-for-text-1740497648570.png differ diff --git a/jesty.test.js b/jesty.test.js new file mode 100644 index 000000000..0ada009f0 --- /dev/null +++ b/jesty.test.js @@ -0,0 +1,189 @@ +// @ts-check + +const fs = require('fs'); +const path = require('path'); +const { + createHtmlFile, + launchBrowser, + setupTerminal, + spawnTerminalProcess, + waitForText, + captureStableScreenshot, + navigateTUI, + verifyAgainstBaseline, +} = require('./utils'); + +describe('Nx TUI', () => { + // Setup variables we'll use in our test + let browser; + let page; + let pty; + let htmlPath; + let fullOutput = ''; + let outputChunks = []; + + // Default timeout for Jest tests is often too short for browser testing + jest.setTimeout(60000); // 60 seconds + + beforeAll(async () => { + // Create HTML file for rendering + htmlPath = createHtmlFile(); + }); + + afterAll(async () => { + // Clean up HTML file + if (fs.existsSync(htmlPath)) { + fs.unlinkSync(htmlPath); + } + }); + + afterEach(async () => { + // Kill PTY and close browser after each test + if (pty) { + pty.kill(); + } + if (browser) { + await browser.close(); + } + }); + + test('renders correctly and responds to navigation', async () => { + // Check if running in CI environment + const isCI = process.env.CI === 'true'; + + // Launch browser + const browserSetup = await launchBrowser(isCI, { + width: 1200, + height: 800, + }); + browser = browserSetup.browser; + page = browserSetup.page; + + // Setup terminal + const { dimensions } = await setupTerminal(page, htmlPath); + + // Step 1: Spawn Nx CLI using node-pty + console.log('Spawning Nx TUI...'); + pty = spawnTerminalProcess( + dimensions.cols, + dimensions.rows, + 'npx', + ['nx', 'run-many', '--target=build', '--all'], + { + env: { + NX_TUI: 'true', + FORCE_COLOR: '3', // Force color output + }, + }, + ); + + // Process data from pty and send to browser + pty.onData(async (data) => { + fullOutput += data; + outputChunks.push(data); + + // Send data to browser for rendering + await page.evaluate((text) => { + // @ts-ignore - Custom method added via browser script + window.writeToTerminal(text); + }, data); + }); + + // Wait for initial render - look for the Nx logo or header + await waitForText(page, 'NX', 15000); + + // Capture initial state + const initialState = { + screenshotPath: await captureStableScreenshot(page, 'initial-state'), + }; + + // Navigate through the TUI + const navigationScreenshots = await navigateTUI(pty, page); + + // Wait for the build to complete or reach a specific state + await waitForText(page, /Done in \d+\.\d+s|Finished running/i, 30000); + + // Capture final state + const finalState = { + screenshotPath: await captureStableScreenshot(page, 'final-state'), + }; + + // Save the full output for debugging + fs.writeFileSync( + path.join(process.cwd(), 'terminal-output.txt'), + fullOutput, + ); + fs.writeFileSync( + path.join(process.cwd(), 'terminal-chunks.json'), + JSON.stringify(outputChunks, null, 2), + ); + + console.log('Test completed successfully'); + console.log(`Initial screenshot: ${initialState.screenshotPath}`); + console.log(`Navigation screenshots:`, navigationScreenshots); + console.log(`Final screenshot: ${finalState.screenshotPath}`); + + // Verify screenshots against baselines + console.log('\n--- Comparing screenshots against baselines ---\n'); + const initialResult = await verifyAgainstBaseline( + initialState.screenshotPath, + 'initial-state', + 0.1, // 0.1% threshold + true, // Keep diff images + ); + + const beforeNavResult = await verifyAgainstBaseline( + navigationScreenshots.beforeNavPath, + 'before-navigation', + 0.1, + true, + ); + + const afterNav1Result = await verifyAgainstBaseline( + navigationScreenshots.afterNav1Path, + 'after-navigation-1', + 0.1, + true, + ); + + const afterNav2Result = await verifyAgainstBaseline( + navigationScreenshots.afterNav2Path, + 'after-navigation-2', + 0.1, + true, + ); + + const afterSelectResult = await verifyAgainstBaseline( + navigationScreenshots.afterSelectPath, + 'after-selection', + 0.1, + true, + ); + + const finalResult = await verifyAgainstBaseline( + finalState.screenshotPath, + 'final-state', + 0.1, + true, + ); + + console.log( + '\n--- All diff images are saved in the "diffs" directory ---\n', + ); + + // Assert that all comparisons pass using Jest's expect + expect(initialResult).toBe(true); + expect(beforeNavResult).toBe(true); + expect(afterNav1Result).toBe(true); + expect(afterNav2Result).toBe(true); + expect(afterSelectResult).toBe(true); + expect(finalResult).toBe(true); + }); + + // You can add more tests here to test different aspects of the TUI + test('handles error state correctly', async () => { + // This is a placeholder for another test you might want to add + // Implementation would be similar to the above test but with different inputs/expectations + expect(true).toBe(true); // Placeholder assertion + }); +}); diff --git a/nx.json b/nx.json index e56f98957..4ca657e59 100644 --- a/nx.json +++ b/nx.json @@ -1,6 +1,6 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", - "nxCloudAccessToken": "NzNkMDZiM2MtMzVlOS00YzVlLWE1MGQtNWZlYzI3MjRkOTRmfHJlYWQ=", + // "nxCloudAccessToken": "NzNkMDZiM2MtMzVlOS00YzVlLWE1MGQtNWZlYzI3MjRkOTRmfHJlYWQ=", "plugins": [ { "plugin": "@nx/eslint/plugin", diff --git a/package.json b/package.json index 6bc37ac4c..d43e4d202 100644 --- a/package.json +++ b/package.json @@ -51,14 +51,14 @@ "@angular/compiler": "19.1.5", "@commitlint/cli": "19.7.1", "@commitlint/config-conventional": "19.7.1", - "@nx/devkit": "20.3.3", - "@nx/esbuild": "20.3.3", - "@nx/eslint": "20.3.3", - "@nx/eslint-plugin": "20.3.3", - "@nx/jest": "20.3.3", - "@nx/js": "20.3.3", - "@nx/plugin": "20.3.3", - "@nx/workspace": "20.3.3", + "@nx/devkit": "0.0.0-pr-3-8473941", + "@nx/esbuild": "0.0.0-pr-3-8473941", + "@nx/eslint": "0.0.0-pr-3-8473941", + "@nx/eslint-plugin": "0.0.0-pr-3-8473941", + "@nx/jest": "0.0.0-pr-3-8473941", + "@nx/js": "0.0.0-pr-3-8473941", + "@nx/plugin": "0.0.0-pr-3-8473941", + "@nx/workspace": "0.0.0-pr-3-8473941", "@schematics/angular": "19.1.6", "@swc-node/register": "1.10.9", "@swc/cli": "0.6.0", @@ -86,9 +86,13 @@ "jsonc-eslint-parser": "^2.1.0", "lint-staged": "15.4.3", "ncp": "2.0.0", - "nx": "20.3.3", + "node-pty": "^1.0.0", + "nx": "0.0.0-pr-3-8473941", + "pixelmatch": "^7.1.0", + "pngjs": "^7.0.0", "prettier": "3.5.0", "prettier-v2-for-jest-inline-snapshots": "npm:prettier@^2", + "puppeteer": "^24.3.0", "rimraf": "5.0.10", "semver": "^7.6.2", "tree-kill": "1.2.2", @@ -98,6 +102,9 @@ "typescript": "5.7.3", "typescript-eslint": "8.23.0", "verdaccio": "6.0.5", + "xterm": "^5.3.0", + "xterm-addon-fit": "^0.8.0", + "xterm-addon-serialize": "^0.11.0", "yargs": "17.7.2" }, "pnpm": { @@ -130,6 +137,5 @@ } }, "includedScripts": [] - }, - "dependencies": {} + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 957882fb5..ef44198da 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,13 @@ patchedDependencies: importers: .: + dependencies: + pixelmatch: + specifier: ^7.1.0 + version: 7.1.0 + pngjs: + specifier: ^7.0.0 + version: 7.0.0 devDependencies: '@angular/cli': specifier: 19.1.6 @@ -31,29 +38,29 @@ importers: specifier: 19.7.1 version: 19.7.1 '@nx/devkit': - specifier: 20.3.3 - version: 20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) + specifier: 0.0.0-pr-3-8473941 + version: 0.0.0-pr-3-8473941(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) '@nx/esbuild': - specifier: 20.3.3 - version: 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(esbuild@0.25.0)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + specifier: 0.0.0-pr-3-8473941 + version: 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(esbuild@0.25.0)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/eslint': - specifier: 20.3.3 - version: 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(eslint@9.20.0(jiti@2.4.2))(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + specifier: 0.0.0-pr-3-8473941 + version: 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(eslint@9.20.0(jiti@2.4.2))(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/eslint-plugin': - specifier: 20.3.3 - version: 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@typescript-eslint/parser@8.23.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3))(eslint-config-prettier@10.0.1(eslint@9.20.0(jiti@2.4.2)))(eslint@9.20.0(jiti@2.4.2))(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + specifier: 0.0.0-pr-3-8473941 + version: 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@typescript-eslint/parser@8.23.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3))(eslint-config-prettier@10.0.1(eslint@9.20.0(jiti@2.4.2)))(eslint@9.20.0(jiti@2.4.2))(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/jest': - specifier: 20.3.3 - version: 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + specifier: 0.0.0-pr-3-8473941 + version: 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/js': - specifier: 20.3.3 - version: 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + specifier: 0.0.0-pr-3-8473941 + version: 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/plugin': - specifier: 20.3.3 - version: 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(eslint@9.20.0(jiti@2.4.2))(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + specifier: 0.0.0-pr-3-8473941 + version: 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.20.0(jiti@2.4.2))(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/workspace': - specifier: 20.3.3 - version: 20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) + specifier: 0.0.0-pr-3-8473941 + version: 0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) '@schematics/angular': specifier: 19.1.6 version: 19.1.6 @@ -119,7 +126,7 @@ importers: version: 9.1.7 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + version: 29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) json-schema-to-typescript: specifier: 15.0.4 version: 15.0.4 @@ -135,15 +142,21 @@ importers: ncp: specifier: 2.0.0 version: 2.0.0 + node-pty: + specifier: ^1.0.0 + version: 1.0.0 nx: - specifier: 20.3.3 - version: 20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) + specifier: 0.0.0-pr-3-8473941 + version: 0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) prettier: specifier: 3.5.0 version: 3.5.0 prettier-v2-for-jest-inline-snapshots: specifier: npm:prettier@^2 version: prettier@2.8.8 + puppeteer: + specifier: ^24.3.0 + version: 24.3.0(typescript@5.7.3) rimraf: specifier: 5.0.10 version: 5.0.10 @@ -155,7 +168,7 @@ importers: version: 1.2.2 ts-jest: specifier: 29.2.4 - version: 29.2.4(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.25.0)(jest@29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)))(typescript@5.7.3) + version: 29.2.4(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.25.0)(jest@29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)))(typescript@5.7.3) tslib: specifier: ^2.4.1 version: 2.8.1 @@ -171,6 +184,15 @@ importers: verdaccio: specifier: 6.0.5 version: 6.0.5(encoding@0.1.13)(typanion@3.14.0) + xterm: + specifier: ^5.3.0 + version: 5.3.0 + xterm-addon-fit: + specifier: ^0.8.0 + version: 0.8.0(xterm@5.3.0) + xterm-addon-serialize: + specifier: ^0.11.0 + version: 0.11.0(xterm@5.3.0) yargs: specifier: 17.7.2 version: 17.7.2 @@ -1911,21 +1933,21 @@ packages: resolution: {integrity: sha512-q9C0uHrb6B6cm3qXVM32UmpqTKuFGbtP23O2K5sLvPMz2hilKd0ptqGXSpuunOuOmPQb/aT5F/kCXFc1P2gO/A==} engines: {node: ^18.17.0 || >=20.5.0} - '@nx/devkit@20.3.3': - resolution: {integrity: sha512-YwVQQpyeMpQeXzu4/Yv6Ng3ZZxJ45RGbGqbb+VWQfDKkZIHcyR7iLLQDaLpyl34HkrLYdZez9BB8wnyn3IaxqA==} + '@nx/devkit@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-GPGVeNduXieaJREVed2T68VjwIItjccyV88X5Q8moZjnLAuRSdIodSEAOdvRVPfBgk71WfmbqB48UgghuNM+PQ==} peerDependencies: nx: '>= 19 <= 21' - '@nx/esbuild@20.3.3': - resolution: {integrity: sha512-t+7bSrbpFJxP2oU4IbeRqLaGwLP2AKIDURFzggN1J0f/7CsN/E2vDnVF5nO4WbhikA+tk7kMyokw12BJlFribA==} + '@nx/esbuild@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-evUqLWDEUclG0NHUZCVcsrTkJMjkaO7w8CpmU3AzddERBrbx/dXSkMA9bmbeYU487JC/E0AZ54GtRsWabqaNzA==} peerDependencies: esbuild: ~0.19.2 peerDependenciesMeta: esbuild: optional: true - '@nx/eslint-plugin@20.3.3': - resolution: {integrity: sha512-y1OLK0lCpkiDr0uAwH5+H4TdIRosu/A/+vBbNB9ZlaSQEeBpduNvMvBXnAts52SIVWJASKHxrkQuH2534dIaxA==} + '@nx/eslint-plugin@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-UU2SM1zSZXv/t/ITHFgUXec423EOrS7CbLoNDEjH3ccyIbWTCOLB7FgEIyITd+2cQZQx5LAjiHYoOIESCHY5oA==} peerDependencies: '@typescript-eslint/parser': 8.23.0 eslint-config-prettier: ^9.0.0 @@ -1933,8 +1955,8 @@ packages: eslint-config-prettier: optional: true - '@nx/eslint@20.3.3': - resolution: {integrity: sha512-yWr/GUAhlpj2CywgaKvTsHHWD/YCFmxRDjOTRUvH5CB5LqkR5+5H4Mj85mb4AwOxH1JlA0Ta20KEhRS1e8hPwA==} + '@nx/eslint@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-sNoDx4GZ2xoCf+WOpvHamrxKR6VD1bbf+06t5Xf9uNK8RBZBZZJsB2KC4Rg23EPUjkgWpx9duz2z9xJP800CBA==} peerDependencies: '@zkochan/js-yaml': 0.0.7 eslint: ^8.0.0 || ^9.0.0 @@ -1942,82 +1964,82 @@ packages: '@zkochan/js-yaml': optional: true - '@nx/jest@20.3.3': - resolution: {integrity: sha512-iRYJL3r92Kut4gg3ha0rlkOJ7ckxbQPP/HErq+eKX7hRFEqO7ToABkCXOrw2NEAgj82bPeJyop3ukcPcAz3cHA==} + '@nx/jest@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-uau7XApCyez9u4UN9LI6CyJZFe+LkpB4MwRQeNDt2JqkVIRzZ5fnHrSsECZesrXP1U15AiCKLvSooSdatdefXA==} - '@nx/js@20.3.3': - resolution: {integrity: sha512-IVECDcjUv3mzM4uIR/BhWs1IbmvGAw2EkGoISsaiXqffFlQpQBOqypZmKORTjQr7Qyn4kHzEJ7EyuQM9w/MYpA==} + '@nx/js@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-s270LG1nORHVyiW5xClEH+nTIc0rASrw3f2lEVm237j1jhiGNWHDMAeM5gXXAyQ0nSE0oIxHbroIVoXqbIPfVQ==} peerDependencies: verdaccio: ^5.0.4 peerDependenciesMeta: verdaccio: optional: true - '@nx/nx-darwin-arm64@20.3.3': - resolution: {integrity: sha512-4C7ShMrqp1vbH1ZgvSlkt0f35hJcqKtRcf8n/tCck46rnMkj4egXi3K1dE6uQcOorwiD1ttAr0DHcI1TTqcNXw==} + '@nx/nx-darwin-arm64@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-514HwrFZh4HfvUJjzGBwk08BEQxd59Wrt8HJ4B8tZKo+8hMZymnKU3wS01lktoej9k43Jhpntw89oIN5FUtpSA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@nx/nx-darwin-x64@20.3.3': - resolution: {integrity: sha512-OUtJ7gA09pJC+a+RcZf1bGbMM4T7a/IcPb97z1xOoxr5Wm2s8BGBQUW2CKJ5gCp5iI1pGo44F12u0G9gbYClow==} + '@nx/nx-darwin-x64@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-WAn5G8/iGUAbLSYi7kTmp0B88QhTzD3aR8VIz5kspdM/R5VPvW3cxgyOzE1x4p9+XtBjQmsd+0JeDzwlAeeOHw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@nx/nx-freebsd-x64@20.3.3': - resolution: {integrity: sha512-q4SABgKYWPGOcdfRZne6n8HF4CzltRL5nJ3q093jQAUO93yPXtWzhQBaKZIZr6aPoqq0/NuH6xY4gNo4w9F8Bg==} + '@nx/nx-freebsd-x64@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-7pThdB5UuIEsfPCiXK2b5KWutvkKhO9mqEaRVoitadTLUcb1mbHDSHTrN15dncFPT8MqRknMTZ0xO0HSGNeRhQ==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@nx/nx-linux-arm-gnueabihf@20.3.3': - resolution: {integrity: sha512-e07PJcVsBT/Aelo/Vj6hLplDZamGCZ3zOJpW3XVBhdG4DC4sn+jodsdrIASoEpmF70VB89lzQsm9GrAgQPaWOA==} + '@nx/nx-linux-arm-gnueabihf@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-pXQ1lybpGzmgf4qlh4Wj+Z9ehdzgRQ5KAahHbhlGPhvk1IFvr0SG+1w1k0W6xgIMYMuSxseTiPHUlt7KQj1jLg==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@nx/nx-linux-arm64-gnu@20.3.3': - resolution: {integrity: sha512-1Z9chlN0/hWzliMer7TvdLT8cb6BKpGjZ15a+rQuUbO/CyLhY21Ct+lXtnaBERnNPYJpNOJlrbBDuF/9wpZ4CQ==} + '@nx/nx-linux-arm64-gnu@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-prX9Z42uygpc5Is/JVhSwsK02MQe0S7g6JnhWcDgrsgityBoEsY1JV6kUwwcgmyu9cwCszPJi+foVuiGNH4Jmg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@nx/nx-linux-arm64-musl@20.3.3': - resolution: {integrity: sha512-RrLgujPU5NfDrsDRa7Y2isxGb8XkoQeJkTMUl1xmBK2Qnf4jAUn0PH0ULWrRMNgChi4nYUTn/Sf+2m6Uyoqcfw==} + '@nx/nx-linux-arm64-musl@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-rdZCICqOa1rScw67jaOrBrk6OX0Q4+xIlkKta0481enybssjmCqrcKfm/tMoxVKUVr6vLPz9SFZ41vMFWFD4zg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@nx/nx-linux-x64-gnu@20.3.3': - resolution: {integrity: sha512-/WmCnPxv1eR8tyYiFp4XoMbcXrJ8a/OIw1rpZZ5ceMKgH8lPaF2/KFf04JZZygrCKletEdqqIojBXz4AHoaueQ==} + '@nx/nx-linux-x64-gnu@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-QpY7txSC1FxssaUjsiOOSB1ydUAjseRG7zWYfSKdJRcTb9TnJRSJadVnh+uJxAOoh/j4emg3sdb//Pw4lAswOw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@nx/nx-linux-x64-musl@20.3.3': - resolution: {integrity: sha512-y4BJsR0fgJrXY3P7GkWfUZAeQEHMTXvaRHvzJfBSBPmnVcVZDYNTfEQYnslp8m8ahKdlJwtflxzykJ4Bwf55fw==} + '@nx/nx-linux-x64-musl@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-/PnJUMmObnjvl5QyijmOufl6IZVjw7MI1pT+uWYtmJoZb69l65g8lr2aggsC8IHIlC0Vk18oVhsgq9f6sjT8Fw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@nx/nx-win32-arm64-msvc@20.3.3': - resolution: {integrity: sha512-BHqZitBaGT9ybv386B5QKxP5N66+xpTiYlKClzQ44o6Ca8QxnkugI64exBdcQyj+DRiL6HJhN14kaPJ1KrsKRA==} + '@nx/nx-win32-arm64-msvc@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-9Y3ZUhdGlY8jk6e69ooaV8+mhRUsE+giLU6wNhpSRwcPZ/6FFrZVsvuLrGD++KjCtQzOto0tP8wS+S7X5TxLgA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@nx/nx-win32-x64-msvc@20.3.3': - resolution: {integrity: sha512-6HcbAKghEypt4aMAoDjPn2sa6FG0MyiDabpV/cVLKokK09ngyy6qQDa5vSCUSDwI542XBxqtcv0AcZi7Ez+XUQ==} + '@nx/nx-win32-x64-msvc@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-53/1g2CMFMbus7cgAjOD/stUtJB00oi+HRf7jvKrFOGu+GABxXeiBszuMeoXl4IUHEd012E909nJs49hXX4nhA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@nx/plugin@20.3.3': - resolution: {integrity: sha512-NxC8HMUr++cGtNi3eKloCVBmQZLBuuNPNWDOzYmFcn3Z9WQ4G0QQx8G3erTU+G3o2YGpnjve/mLEjrdg1Ydp0Q==} + '@nx/plugin@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-k9u9DaeH/mA2uwYPa/G8BljNFOUCUUWdspv+3s7OkI59Ofpl0qndYLteuF5tVKZMwkHdQeYtmeDmBNgsPn+Lgg==} - '@nx/workspace@20.3.3': - resolution: {integrity: sha512-eN7W9H2yLDZ4ZWegdS+pChdFETMUgjsLgvGijRpZONIguo6wR+aU2LhSfj2ww8JKNJ4rcSnOw4soaaHg2W3dTQ==} + '@nx/workspace@0.0.0-pr-3-8473941': + resolution: {integrity: sha512-lGc7qo591tLW/7rsVm/raYGKz7mGCEt7ZrjWfntVdaIQNQKFi/8nC+KuhSZidjpHPQvtqdKD0lADupmuuHxmYw==} '@oxc-resolver/binding-darwin-arm64@1.12.0': resolution: {integrity: sha512-wYe+dlF8npM7cwopOOxbdNjtmJp17e/xF5c0K2WooQXy5VOh74icydM33+Uh/SZDgwyum09/U1FVCX5GdeQk+A==} @@ -2083,6 +2105,11 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@puppeteer/browsers@2.7.1': + resolution: {integrity: sha512-MK7rtm8JjaxPN7Mf1JdZIZKPD2Z+W7osvrC1vjpvfOX1K0awDIHYbNi89f7eotp7eMUn2shWnt03HwVbriXtKQ==} + engines: {node: '>=18'} + hasBin: true + '@schematics/angular@19.1.6': resolution: {integrity: sha512-TxFp6iHBqXcuyZIW84HA4z3XkAMz3wTw46K3GNhzyfhFTFD0YD+DtaR3MfQ+vcj3YUYu9j44zrB9nchzugR9Ew==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -2239,6 +2266,9 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -2331,6 +2361,9 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@typescript-eslint/eslint-plugin@8.16.0': resolution: {integrity: sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2381,13 +2414,6 @@ packages: typescript: optional: true - '@typescript-eslint/type-utils@8.20.0': - resolution: {integrity: sha512-bPC+j71GGvA7rVNAHAtOjbVXbLN5PkwqMvy1cwGeaxUoRQXVuKCebRoLzm+IPW/NtFFpstn1ummSIasD5t60GA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/type-utils@8.23.0': resolution: {integrity: sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2399,10 +2425,6 @@ packages: resolution: {integrity: sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.20.0': - resolution: {integrity: sha512-cqaMiY72CkP+2xZRrFt3ExRBu0WmVitN/rYPZErA80mHjHx/Svgp8yfbzkJmDoQ/whcytOPO9/IZXnOc+wigRA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.23.0': resolution: {integrity: sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2416,12 +2438,6 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@8.20.0': - resolution: {integrity: sha512-Y7ncuy78bJqHI35NwzWol8E0X7XkRVS4K4P4TCyzWkOJih5NDvtoRDW4Ba9YJJoB2igm9yXDdYI/+fkiiAxPzA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/typescript-estree@8.23.0': resolution: {integrity: sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2439,10 +2455,6 @@ packages: resolution: {integrity: sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.20.0': - resolution: {integrity: sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.23.0': resolution: {integrity: sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2623,6 +2635,10 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -2714,6 +2730,10 @@ packages: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + async@3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} @@ -2766,8 +2786,9 @@ packages: resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - babel-plugin-macros@2.8.0: - resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==} + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} babel-plugin-polyfill-corejs2@0.4.12: resolution: {integrity: sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==} @@ -2810,9 +2831,35 @@ packages: bare-events@2.5.0: resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==} + bare-fs@4.0.1: + resolution: {integrity: sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==} + engines: {bare: '>=1.7.0'} + + bare-os@3.4.0: + resolution: {integrity: sha512-9Ous7UlnKbe3fMi7Y+qh0DwAup6A1JkYgPnjvMDNOlmnxNRQvQ/7Nst+OnUQKzk0iAT0m9BisbDVp9gCv8+ETA==} + engines: {bare: '>=1.6.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.6.5: + resolution: {integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==} + peerDependencies: + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + bare-events: + optional: true + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} + bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} @@ -2947,6 +2994,11 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} + chromium-bidi@2.0.0: + resolution: {integrity: sha512-8VmyVj0ewSY4pstZV0Y3rCUUwpomam8uWgHZf1XavRxJEP4vU9/dcpNuoyB+u4AQxPo96CASXz5CHPvdH+dSeQ==} + peerDependencies: + devtools-protocol: '*' + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -3130,9 +3182,9 @@ packages: cosmiconfig: '>=9' typescript: '>=5' - cosmiconfig@6.0.0: - resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==} - engines: {node: '>=8'} + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} cosmiconfig@9.0.0: resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} @@ -3167,6 +3219,10 @@ packages: resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} engines: {node: '>=0.10'} + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} @@ -3246,6 +3302,10 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -3275,6 +3335,9 @@ packages: engines: {node: '>= 4.0.0'} hasBin: true + devtools-protocol@0.0.1402036: + resolution: {integrity: sha512-JwAYQgEvm3yD45CHB+RmF5kMbWtXBaOGwuxa87sZogHcLCv8c/IqnThaoQ1y60d7pXWjSKWQphPEc+1rAScVdg==} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3405,6 +3468,11 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + eslint-config-prettier@10.0.1: resolution: {integrity: sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==} hasBin: true @@ -3542,6 +3610,11 @@ packages: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + extsprintf@1.3.0: resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} engines: {'0': node >=0.6.0} @@ -3582,6 +3655,9 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fdir@6.4.2: resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} peerDependencies: @@ -3739,6 +3815,10 @@ packages: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -3754,6 +3834,10 @@ packages: get-tsconfig@4.8.1: resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + get-uri@6.0.4: + resolution: {integrity: sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==} + engines: {node: '>= 14'} + getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} @@ -3898,6 +3982,10 @@ packages: resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} engines: {node: '>= 14'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -4678,6 +4766,9 @@ packages: resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} engines: {node: '>= 18'} + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -4708,6 +4799,9 @@ packages: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} + nan@2.22.1: + resolution: {integrity: sha512-pfRR4ZcNTSm2ZFHaztuvbICf+hyiG6ecA06SfAxoPmuHjvMu0KUIae7Y8GyVkbBqeEIidsmXeYooWIX9+qjfRQ==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -4730,6 +4824,10 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -4750,6 +4848,9 @@ packages: node-machine-id@1.1.12: resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} + node-pty@1.0.0: + resolution: {integrity: sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==} + node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} @@ -4810,8 +4911,8 @@ packages: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - nx@20.3.3: - resolution: {integrity: sha512-IUu2D8/bVa7aSr3ViRcrmpTGO2FKqzJoio6gjeq/YbyUHyjrrq5HUmHFx30Wm2vmC1BGm0MeyakTNUJzQvfAog==} + nx@0.0.0-pr-3-8473941: + resolution: {integrity: sha512-5q9W1KFjNbQ/NB8hwVRgd9UTOcVQ89A/6jlPrBMtSlDaQri4vCUfB/0CsUPyS1HMD814CXgjRYLwEPNr3cvQSA==} hasBin: true peerDependencies: '@swc-node/register': ^1.8.0 @@ -4920,6 +5021,14 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + pac-proxy-agent@7.2.0: + resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -5034,6 +5143,10 @@ packages: piscina@4.7.0: resolution: {integrity: sha512-b8hvkpp9zS0zsfa939b/jXbe64Z2gZv0Ha7FYPNUiDIB1y2AtxcOZdfP8xN8HFjUaqQiT9gRlfjAsoL8vdJ1Iw==} + pixelmatch@7.1.0: + resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} + hasBin: true + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -5042,6 +5155,10 @@ packages: resolution: {integrity: sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ==} engines: {node: '>= 0.4.0'} + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -5085,6 +5202,10 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + promise-inflight@1.0.1: resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} peerDependencies: @@ -5105,12 +5226,19 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-agent@6.5.0: + resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} + engines: {node: '>= 14'} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} pump@2.0.1: resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + pumpify@1.5.1: resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} @@ -5118,6 +5246,15 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + puppeteer-core@24.3.0: + resolution: {integrity: sha512-x8kQRP/xxtiFav6wWuLzrctO0HWRpSQy+JjaHbqIl+d5U2lmRh2pY9vh5AzDFN0EtOXW2pzngi9RrryY1vZGig==} + engines: {node: '>=18'} + + puppeteer@24.3.0: + resolution: {integrity: sha512-wYEx+NnEM1T6ncHB+IsTovUgx+JlZ0pv0sRGTb8IzoTeOILvyUcdU2h34bYEQ1iG5maz1VQA5eI4kzIyAVh90A==} + engines: {node: '>=18'} + hasBin: true + pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} @@ -5372,6 +5509,10 @@ packages: resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==} engines: {node: '>= 14'} + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + socks@2.8.3: resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} @@ -5459,6 +5600,9 @@ packages: streamx@2.20.2: resolution: {integrity: sha512-aDGDLU+j9tJcUdPGOaHmVF1u/hhI+CsGkT02V3OKlHDV7IukOI+nTWAGkiZEKCO35rWN1wIr4tS7YFr1f4qSvA==} + streamx@2.22.0: + resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -5540,6 +5684,9 @@ packages: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} + tar-fs@3.0.8: + resolution: {integrity: sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==} + tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} @@ -5629,12 +5776,6 @@ packages: peerDependencies: typescript: '>=4.2.0' - ts-api-utils@2.0.0: - resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - ts-api-utils@2.0.1: resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} engines: {node: '>=18.12'} @@ -5720,6 +5861,9 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + typed-query-selector@2.12.0: + resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==} + typescript-eslint@8.16.0: resolution: {integrity: sha512-wDkVmlY6O2do4V+lZd0GtRfbtXbeD0q9WygwXXSJnC1xorE8eqyC2L1tJimqpSeFrOzRlYtWnUp/uzgHQOgfBQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5742,11 +5886,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.6.3: - resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.7.3: resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} engines: {node: '>=14.17'} @@ -5938,10 +6077,38 @@ packages: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + ws@8.18.1: + resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + xterm-addon-fit@0.8.0: + resolution: {integrity: sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==} + deprecated: This package is now deprecated. Move to @xterm/addon-fit instead. + peerDependencies: + xterm: ^5.0.0 + + xterm-addon-serialize@0.11.0: + resolution: {integrity: sha512-2CNDnmLdLkNWfsxNFkGsI5FE9W/BbsMzeOrbu59yNqH9L6k1gmL+Ab6VXxEp2NQUJSzaiqi6t0nFR5k5EDkVIg==} + deprecated: This package is now deprecated. Move to @xterm/addon-serialize instead. + peerDependencies: + xterm: ^5.0.0 + + xterm@5.3.0: + resolution: {integrity: sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==} + deprecated: This package is now deprecated. Move to @xterm/xterm instead. + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5973,6 +6140,9 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yauzl@3.2.0: resolution: {integrity: sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w==} engines: {node: '>=12'} @@ -5993,6 +6163,9 @@ packages: resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} engines: {node: '>=18'} + zod@3.24.2: + resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} + snapshots: '@ampproject/remapping@2.3.0': @@ -6188,7 +6361,7 @@ snapshots: '@babel/helper-plugin-utils': 7.25.9 debug: 4.4.0 lodash.debounce: 4.0.8 - resolve: 1.22.8 + resolve: 1.22.10 transitivePeerDependencies: - supports-color @@ -7225,7 +7398,7 @@ snapshots: '@eslint/config-array@0.19.0': dependencies: '@eslint/object-schema': 2.1.4 - debug: 4.3.7 + debug: 4.4.0 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -7243,7 +7416,7 @@ snapshots: '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 - debug: 4.3.7 + debug: 4.4.0 espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -7435,7 +7608,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))': + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -7449,7 +7622,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + jest-config: 29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -7712,7 +7885,7 @@ snapshots: '@npmcli/agent@2.2.2': dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 lru-cache: 10.4.3 @@ -7789,22 +7962,22 @@ snapshots: - bluebird - supports-color - '@nx/devkit@20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))': + '@nx/devkit@0.0.0-pr-3-8473941(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))': dependencies: ejs: 3.1.10 enquirer: 2.3.6 ignore: 5.3.2 minimatch: 9.0.3 - nx: 20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) + nx: 0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) semver: 7.7.1 tmp: 0.2.3 tslib: 2.8.1 yargs-parser: 21.1.1 - '@nx/esbuild@20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(esbuild@0.25.0)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': + '@nx/esbuild@0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(esbuild@0.25.0)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': dependencies: - '@nx/devkit': 20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) - '@nx/js': 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + '@nx/devkit': 0.0.0-pr-3-8473941(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) + '@nx/js': 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) picocolors: 1.1.1 tinyglobby: 0.2.10 tsconfig-paths: 4.2.0 @@ -7823,12 +7996,12 @@ snapshots: - typescript - verdaccio - '@nx/eslint-plugin@20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@typescript-eslint/parser@8.23.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3))(eslint-config-prettier@10.0.1(eslint@9.20.0(jiti@2.4.2)))(eslint@9.20.0(jiti@2.4.2))(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': + '@nx/eslint-plugin@0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@typescript-eslint/parser@8.23.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3))(eslint-config-prettier@10.0.1(eslint@9.20.0(jiti@2.4.2)))(eslint@9.20.0(jiti@2.4.2))(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': dependencies: - '@nx/devkit': 20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) - '@nx/js': 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + '@nx/devkit': 0.0.0-pr-3-8473941(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) + '@nx/js': 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@typescript-eslint/parser': 8.23.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3) - '@typescript-eslint/type-utils': 8.20.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3) + '@typescript-eslint/type-utils': 8.23.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3) '@typescript-eslint/utils': 8.23.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3) chalk: 4.1.2 confusing-browser-globals: 1.0.11 @@ -7851,14 +8024,14 @@ snapshots: - typescript - verdaccio - '@nx/eslint@20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(eslint@9.20.0(jiti@2.4.2))(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': + '@nx/eslint@0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(eslint@9.20.0(jiti@2.4.2))(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': dependencies: - '@nx/devkit': 20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) - '@nx/js': 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.6.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + '@nx/devkit': 0.0.0-pr-3-8473941(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) + '@nx/js': 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) eslint: 9.20.0(jiti@2.4.2) semver: 7.7.1 tslib: 2.8.1 - typescript: 5.6.3 + typescript: 5.7.3 optionalDependencies: '@zkochan/js-yaml': 0.0.7 transitivePeerDependencies: @@ -7872,15 +8045,15 @@ snapshots: - supports-color - verdaccio - '@nx/jest@20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': + '@nx/jest@0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': dependencies: '@jest/reporters': 29.7.0 '@jest/test-result': 29.7.0 - '@nx/devkit': 20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) - '@nx/js': 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + '@nx/devkit': 0.0.0-pr-3-8473941(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) + '@nx/js': 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.7.3) identity-obj-proxy: 3.0.0 - jest-config: 29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + jest-config: 29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) jest-resolve: 29.7.0 jest-util: 29.7.0 minimatch: 9.0.3 @@ -7904,52 +8077,7 @@ snapshots: - typescript - verdaccio - '@nx/js@20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.6.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) - '@babel/preset-env': 7.26.0(@babel/core@7.26.0) - '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) - '@babel/runtime': 7.26.0 - '@nx/devkit': 20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) - '@nx/workspace': 20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) - '@zkochan/js-yaml': 0.0.7 - babel-plugin-const-enum: 1.2.0(@babel/core@7.26.0) - babel-plugin-macros: 2.8.0 - babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.26.0)(@babel/traverse@7.25.9) - chalk: 4.1.2 - columnify: 1.6.0 - detect-port: 1.6.1 - enquirer: 2.3.6 - ignore: 5.3.2 - js-tokens: 4.0.0 - jsonc-parser: 3.2.0 - minimatch: 9.0.3 - npm-package-arg: 11.0.1 - npm-run-path: 4.0.1 - ora: 5.3.0 - semver: 7.7.1 - source-map-support: 0.5.19 - tinyglobby: 0.2.10 - ts-node: 10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.6.3) - tsconfig-paths: 4.2.0 - tslib: 2.8.1 - optionalDependencies: - verdaccio: 6.0.5(encoding@0.1.13)(typanion@3.14.0) - transitivePeerDependencies: - - '@babel/traverse' - - '@swc-node/register' - - '@swc/core' - - '@swc/wasm' - - '@types/node' - - debug - - nx - - supports-color - - typescript - - '@nx/js@20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': + '@nx/js@0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0) @@ -7958,11 +8086,11 @@ snapshots: '@babel/preset-env': 7.26.0(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) '@babel/runtime': 7.26.0 - '@nx/devkit': 20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) - '@nx/workspace': 20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) + '@nx/devkit': 0.0.0-pr-3-8473941(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) + '@nx/workspace': 0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) '@zkochan/js-yaml': 0.0.7 babel-plugin-const-enum: 1.2.0(@babel/core@7.26.0) - babel-plugin-macros: 2.8.0 + babel-plugin-macros: 3.1.0 babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.26.0)(@babel/traverse@7.25.9) chalk: 4.1.2 columnify: 1.6.0 @@ -7994,42 +8122,42 @@ snapshots: - supports-color - typescript - '@nx/nx-darwin-arm64@20.3.3': + '@nx/nx-darwin-arm64@0.0.0-pr-3-8473941': optional: true - '@nx/nx-darwin-x64@20.3.3': + '@nx/nx-darwin-x64@0.0.0-pr-3-8473941': optional: true - '@nx/nx-freebsd-x64@20.3.3': + '@nx/nx-freebsd-x64@0.0.0-pr-3-8473941': optional: true - '@nx/nx-linux-arm-gnueabihf@20.3.3': + '@nx/nx-linux-arm-gnueabihf@0.0.0-pr-3-8473941': optional: true - '@nx/nx-linux-arm64-gnu@20.3.3': + '@nx/nx-linux-arm64-gnu@0.0.0-pr-3-8473941': optional: true - '@nx/nx-linux-arm64-musl@20.3.3': + '@nx/nx-linux-arm64-musl@0.0.0-pr-3-8473941': optional: true - '@nx/nx-linux-x64-gnu@20.3.3': + '@nx/nx-linux-x64-gnu@0.0.0-pr-3-8473941': optional: true - '@nx/nx-linux-x64-musl@20.3.3': + '@nx/nx-linux-x64-musl@0.0.0-pr-3-8473941': optional: true - '@nx/nx-win32-arm64-msvc@20.3.3': + '@nx/nx-win32-arm64-msvc@0.0.0-pr-3-8473941': optional: true - '@nx/nx-win32-x64-msvc@20.3.3': + '@nx/nx-win32-x64-msvc@0.0.0-pr-3-8473941': optional: true - '@nx/plugin@20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(eslint@9.20.0(jiti@2.4.2))(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': + '@nx/plugin@0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(eslint@9.20.0(jiti@2.4.2))(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))': dependencies: - '@nx/devkit': 20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) - '@nx/eslint': 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(eslint@9.20.0(jiti@2.4.2))(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) - '@nx/jest': 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) - '@nx/js': 20.3.3(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + '@nx/devkit': 0.0.0-pr-3-8473941(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) + '@nx/eslint': 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(@zkochan/js-yaml@0.0.7)(eslint@9.20.0(jiti@2.4.2))(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + '@nx/jest': 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) + '@nx/js': 0.0.0-pr-3-8473941(@babel/traverse@7.25.9)(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) tslib: 2.8.1 transitivePeerDependencies: - '@babel/traverse' @@ -8048,12 +8176,12 @@ snapshots: - typescript - verdaccio - '@nx/workspace@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))': + '@nx/workspace@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))': dependencies: - '@nx/devkit': 20.3.3(nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) + '@nx/devkit': 0.0.0-pr-3-8473941(nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15))) chalk: 4.1.2 enquirer: 2.3.6 - nx: 20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) + nx: 0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)) tslib: 2.8.1 yargs-parser: 21.1.1 transitivePeerDependencies: @@ -8104,6 +8232,19 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@puppeteer/browsers@2.7.1': + dependencies: + debug: 4.4.0 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.5.0 + semver: 7.7.1 + tar-fs: 3.0.8 + yargs: 17.7.2 + transitivePeerDependencies: + - bare-buffer + - supports-color + '@schematics/angular@19.1.6': dependencies: '@angular-devkit/core': 19.1.6 @@ -8259,6 +8400,8 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@tootallnate/quickjs-emscripten@0.23.0': {} + '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -8358,6 +8501,11 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 20.17.17 + optional: true + '@typescript-eslint/eslint-plugin@8.16.0(@typescript-eslint/parser@8.23.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -8477,17 +8625,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.20.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3)': - dependencies: - '@typescript-eslint/typescript-estree': 8.20.0(typescript@5.7.3) - '@typescript-eslint/utils': 8.23.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3) - debug: 4.4.0 - eslint: 9.20.0(jiti@2.4.2) - ts-api-utils: 2.0.0(typescript@5.7.3) - typescript: 5.7.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/type-utils@8.23.0(eslint@9.20.0(jiti@2.4.2))(typescript@5.7.3)': dependencies: '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) @@ -8501,8 +8638,6 @@ snapshots: '@typescript-eslint/types@8.16.0': {} - '@typescript-eslint/types@8.20.0': {} - '@typescript-eslint/types@8.23.0': {} '@typescript-eslint/typescript-estree@8.16.0(typescript@5.7.3)': @@ -8520,20 +8655,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.20.0(typescript@5.7.3)': - dependencies: - '@typescript-eslint/types': 8.20.0 - '@typescript-eslint/visitor-keys': 8.20.0 - debug: 4.4.0 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.1 - ts-api-utils: 2.0.0(typescript@5.7.3) - typescript: 5.7.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/typescript-estree@8.23.0(typescript@5.5.4)': dependencies: '@typescript-eslint/types': 8.23.0 @@ -8600,11 +8721,6 @@ snapshots: '@typescript-eslint/types': 8.16.0 eslint-visitor-keys: 4.2.0 - '@typescript-eslint/visitor-keys@8.20.0': - dependencies: - '@typescript-eslint/types': 8.20.0 - eslint-visitor-keys: 4.2.0 - '@typescript-eslint/visitor-keys@8.23.0': dependencies: '@typescript-eslint/types': 8.23.0 @@ -8891,6 +9007,8 @@ snapshots: transitivePeerDependencies: - supports-color + agent-base@7.1.3: {} + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -8969,6 +9087,10 @@ snapshots: assert-plus@1.0.0: {} + ast-types@0.13.4: + dependencies: + tslib: 2.8.1 + async@3.2.4: {} async@3.2.6: {} @@ -9034,11 +9156,11 @@ snapshots: '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.6 - babel-plugin-macros@2.8.0: + babel-plugin-macros@3.1.0: dependencies: '@babel/runtime': 7.26.0 - cosmiconfig: 6.0.0 - resolve: 1.22.8 + cosmiconfig: 7.1.0 + resolve: 1.22.10 babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.0): dependencies: @@ -9101,8 +9223,34 @@ snapshots: bare-events@2.5.0: optional: true + bare-fs@4.0.1: + dependencies: + bare-events: 2.5.0 + bare-path: 3.0.0 + bare-stream: 2.6.5(bare-events@2.5.0) + transitivePeerDependencies: + - bare-buffer + optional: true + + bare-os@3.4.0: + optional: true + + bare-path@3.0.0: + dependencies: + bare-os: 3.4.0 + optional: true + + bare-stream@2.6.5(bare-events@2.5.0): + dependencies: + streamx: 2.22.0 + optionalDependencies: + bare-events: 2.5.0 + optional: true + base64-js@1.5.1: {} + basic-ftp@5.0.5: {} + bcrypt-pbkdf@1.0.2: dependencies: tweetnacl: 0.14.5 @@ -9276,6 +9424,12 @@ snapshots: chownr@3.0.0: {} + chromium-bidi@2.0.0(devtools-protocol@0.0.1402036): + dependencies: + devtools-protocol: 0.0.1402036 + mitt: 3.0.1 + zod: 3.24.2 + ci-info@3.9.0: {} cjs-module-lexer@1.4.1: {} @@ -9452,7 +9606,7 @@ snapshots: jiti: 2.4.2 typescript: 5.7.3 - cosmiconfig@6.0.0: + cosmiconfig@7.1.0: dependencies: '@types/parse-json': 4.0.2 import-fresh: 3.3.0 @@ -9469,13 +9623,13 @@ snapshots: optionalDependencies: typescript: 5.7.3 - create-jest@29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)): + create-jest@29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + jest-config: 29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -9512,6 +9666,8 @@ snapshots: dependencies: assert-plus: 1.0.0 + data-uri-to-buffer@6.0.2: {} + dayjs@1.11.13: {} debug@2.6.9: @@ -9536,7 +9692,9 @@ snapshots: dedent@0.7.0: {} - dedent@1.5.3: {} + dedent@1.5.3(babel-plugin-macros@3.1.0): + optionalDependencies: + babel-plugin-macros: 3.1.0 deep-is@0.1.4: {} @@ -9558,6 +9716,12 @@ snapshots: define-lazy-prop@2.0.0: {} + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + delayed-stream@1.0.0: {} depd@2.0.0: {} @@ -9577,6 +9741,8 @@ snapshots: transitivePeerDependencies: - supports-color + devtools-protocol@0.0.1402036: {} + diff-sequences@29.6.3: {} diff@4.0.2: {} @@ -9725,6 +9891,14 @@ snapshots: escape-string-regexp@4.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + eslint-config-prettier@10.0.1(eslint@9.20.0(jiti@2.4.2)): dependencies: eslint: 9.20.0(jiti@2.4.2) @@ -9990,6 +10164,16 @@ snapshots: iconv-lite: 0.4.24 tmp: 0.0.33 + extract-zip@2.0.1: + dependencies: + debug: 4.4.0 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + extsprintf@1.3.0: {} fast-deep-equal@3.1.3: {} @@ -10030,6 +10214,10 @@ snapshots: dependencies: bser: 2.1.1 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + fdir@6.4.2(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 @@ -10183,6 +10371,10 @@ snapshots: get-package-type@0.1.0: {} + get-stream@5.2.0: + dependencies: + pump: 3.0.2 + get-stream@6.0.1: {} get-stream@8.0.1: {} @@ -10196,6 +10388,14 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-uri@6.0.4: + dependencies: + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + getpass@0.1.7: dependencies: assert-plus: 1.0.0 @@ -10340,7 +10540,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -10369,7 +10569,14 @@ snapshots: https-proxy-agent@7.0.5: dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -10595,7 +10802,7 @@ snapshots: jest-util: 29.7.0 p-limit: 3.1.0 - jest-circus@29.7.0: + jest-circus@29.7.0(babel-plugin-macros@3.1.0): dependencies: '@jest/environment': 29.7.0 '@jest/expect': 29.7.0 @@ -10604,7 +10811,7 @@ snapshots: '@types/node': 20.17.17 chalk: 4.1.2 co: 4.6.0 - dedent: 1.5.3 + dedent: 1.5.3(babel-plugin-macros@3.1.0) is-generator-fn: 2.1.0 jest-each: 29.7.0 jest-matcher-utils: 29.7.0 @@ -10621,16 +10828,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)): + jest-cli@29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + create-jest: 29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + jest-config: 29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -10640,7 +10847,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)): + jest-config@29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -10651,7 +10858,7 @@ snapshots: deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.7.0 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) jest-environment-node: 29.7.0 jest-get-type: 29.6.3 jest-regex-util: 29.6.3 @@ -10886,12 +11093,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)): + jest@29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + jest-cli: 29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -11302,6 +11509,8 @@ snapshots: minipass: 7.1.2 rimraf: 5.0.10 + mitt@3.0.1: {} + mkdirp@1.0.4: {} mkdirp@3.0.1: {} @@ -11318,6 +11527,8 @@ snapshots: mute-stream@2.0.0: {} + nan@2.22.1: {} + natural-compare@1.4.0: {} ncp@2.0.0: {} @@ -11330,6 +11541,8 @@ snapshots: neo-async@2.6.2: {} + netmask@2.0.2: {} + node-fetch@2.6.7(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 @@ -11355,6 +11568,10 @@ snapshots: node-machine-id@1.1.12: {} + node-pty@1.0.0: + dependencies: + nan: 2.22.1 + node-releases@2.0.18: {} nopt@7.2.1: @@ -11427,7 +11644,7 @@ snapshots: dependencies: path-key: 4.0.0 - nx@20.3.3(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)): + nx@0.0.0-pr-3-8473941(@swc-node/register@1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3))(@swc/core@1.10.15(@swc/helpers@0.5.15)): dependencies: '@napi-rs/wasm-runtime': 0.2.4 '@yarnpkg/lockfile': 1.1.0 @@ -11458,22 +11675,23 @@ snapshots: string-width: 4.2.3 tar-stream: 2.2.0 tmp: 0.2.3 + tree-kill: 1.2.2 tsconfig-paths: 4.2.0 tslib: 2.8.1 yaml: 2.7.0 yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@nx/nx-darwin-arm64': 20.3.3 - '@nx/nx-darwin-x64': 20.3.3 - '@nx/nx-freebsd-x64': 20.3.3 - '@nx/nx-linux-arm-gnueabihf': 20.3.3 - '@nx/nx-linux-arm64-gnu': 20.3.3 - '@nx/nx-linux-arm64-musl': 20.3.3 - '@nx/nx-linux-x64-gnu': 20.3.3 - '@nx/nx-linux-x64-musl': 20.3.3 - '@nx/nx-win32-arm64-msvc': 20.3.3 - '@nx/nx-win32-x64-msvc': 20.3.3 + '@nx/nx-darwin-arm64': 0.0.0-pr-3-8473941 + '@nx/nx-darwin-x64': 0.0.0-pr-3-8473941 + '@nx/nx-freebsd-x64': 0.0.0-pr-3-8473941 + '@nx/nx-linux-arm-gnueabihf': 0.0.0-pr-3-8473941 + '@nx/nx-linux-arm64-gnu': 0.0.0-pr-3-8473941 + '@nx/nx-linux-arm64-musl': 0.0.0-pr-3-8473941 + '@nx/nx-linux-x64-gnu': 0.0.0-pr-3-8473941 + '@nx/nx-linux-x64-musl': 0.0.0-pr-3-8473941 + '@nx/nx-win32-arm64-msvc': 0.0.0-pr-3-8473941 + '@nx/nx-win32-x64-msvc': 0.0.0-pr-3-8473941 '@swc-node/register': 1.10.9(@swc/core@1.10.15(@swc/helpers@0.5.15))(@swc/types@0.1.17)(typescript@5.7.3) '@swc/core': 1.10.15(@swc/helpers@0.5.15) transitivePeerDependencies: @@ -11595,6 +11813,24 @@ snapshots: p-try@2.2.0: {} + pac-proxy-agent@7.2.0: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.3 + debug: 4.4.0 + get-uri: 6.0.4 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + package-json-from-dist@1.0.1: {} pacote@20.0.0: @@ -11711,12 +11947,18 @@ snapshots: optionalDependencies: '@napi-rs/nice': 1.0.1 + pixelmatch@7.1.0: + dependencies: + pngjs: 7.0.0 + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 pkginfo@0.4.1: {} + pngjs@7.0.0: {} + prelude-ls@1.2.1: {} prettier@2.8.8: {} @@ -11743,6 +11985,8 @@ snapshots: process@0.11.10: {} + progress@2.0.3: {} + promise-inflight@1.0.1: {} promise-retry@2.0.1: @@ -11760,6 +12004,19 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-agent@6.5.0: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 7.18.3 + pac-proxy-agent: 7.2.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + proxy-from-env@1.1.0: {} pump@2.0.1: @@ -11767,6 +12024,11 @@ snapshots: end-of-stream: 1.4.4 once: 1.4.0 + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + pumpify@1.5.1: dependencies: duplexify: 3.7.1 @@ -11775,6 +12037,35 @@ snapshots: punycode@2.3.1: {} + puppeteer-core@24.3.0: + dependencies: + '@puppeteer/browsers': 2.7.1 + chromium-bidi: 2.0.0(devtools-protocol@0.0.1402036) + debug: 4.4.0 + devtools-protocol: 0.0.1402036 + typed-query-selector: 2.12.0 + ws: 8.18.1 + transitivePeerDependencies: + - bare-buffer + - bufferutil + - supports-color + - utf-8-validate + + puppeteer@24.3.0(typescript@5.7.3): + dependencies: + '@puppeteer/browsers': 2.7.1 + chromium-bidi: 2.0.0(devtools-protocol@0.0.1402036) + cosmiconfig: 9.0.0(typescript@5.7.3) + devtools-protocol: 0.0.1402036 + puppeteer-core: 24.3.0 + typed-query-selector: 2.12.0 + transitivePeerDependencies: + - bare-buffer + - bufferutil + - supports-color + - typescript + - utf-8-validate + pure-rand@6.1.0: {} qs@6.13.0: @@ -12034,7 +12325,15 @@ snapshots: socks-proxy-agent@8.0.4: dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 + debug: 4.4.0 + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.3 debug: 4.4.0 socks: 2.8.3 transitivePeerDependencies: @@ -12140,6 +12439,14 @@ snapshots: optionalDependencies: bare-events: 2.5.0 + streamx@2.22.0: + dependencies: + fast-fifo: 1.3.2 + text-decoder: 1.2.1 + optionalDependencies: + bare-events: 2.5.0 + optional: true + string-argv@0.3.2: {} string-length@4.0.2: @@ -12217,6 +12524,16 @@ snapshots: symbol-observable@4.0.0: {} + tar-fs@3.0.8: + dependencies: + pump: 3.0.2 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 4.0.1 + bare-path: 3.0.0 + transitivePeerDependencies: + - bare-buffer + tar-stream@2.2.0: dependencies: bl: 4.1.0 @@ -12314,10 +12631,6 @@ snapshots: dependencies: typescript: 5.7.3 - ts-api-utils@2.0.0(typescript@5.7.3): - dependencies: - typescript: 5.7.3 - ts-api-utils@2.0.1(typescript@5.5.4): dependencies: typescript: 5.5.4 @@ -12326,12 +12639,12 @@ snapshots: dependencies: typescript: 5.7.3 - ts-jest@29.2.4(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.25.0)(jest@29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)))(typescript@5.7.3): + ts-jest@29.2.4(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.25.0)(jest@29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)))(typescript@5.7.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.17)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) + jest: 29.7.0(@types/node@20.17.17)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -12346,26 +12659,6 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.26.0) esbuild: 0.25.0 - ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.6.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.17 - acorn: 8.14.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.6.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optionalDependencies: - '@swc/core': 1.10.15(@swc/helpers@0.5.15) - ts-node@10.9.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(@types/node@20.17.17)(typescript@5.7.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -12430,6 +12723,8 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + typed-query-selector@2.12.0: {} + typescript-eslint@8.16.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3): dependencies: '@typescript-eslint/eslint-plugin': 8.16.0(@typescript-eslint/parser@8.23.0(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.2))(typescript@5.7.3) @@ -12453,8 +12748,6 @@ snapshots: typescript@5.5.4: {} - typescript@5.6.3: {} - typescript@5.7.3: {} uglify-js@3.19.3: @@ -12681,8 +12974,20 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 + ws@8.18.1: {} + xtend@4.0.2: {} + xterm-addon-fit@0.8.0(xterm@5.3.0): + dependencies: + xterm: 5.3.0 + + xterm-addon-serialize@0.11.0(xterm@5.3.0): + dependencies: + xterm: 5.3.0 + + xterm@5.3.0: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -12707,6 +13012,11 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + yauzl@3.2.0: dependencies: buffer-crc32: 0.2.13 @@ -12719,3 +13029,5 @@ snapshots: yocto-queue@1.1.1: {} yoctocolors-cjs@2.1.2: {} + + zod@3.24.2: {} diff --git a/test.js b/test.js new file mode 100644 index 000000000..46d1a6e31 --- /dev/null +++ b/test.js @@ -0,0 +1,1093 @@ +// @ts-check + +const { spawn } = require('node-pty'); +const { test } = require('node:test'); +const assert = require('node:assert'); +const fs = require('fs'); +const path = require('path'); +const puppeteer = require('puppeteer'); +const { PNG } = require('pngjs'); +let pixelmatchModule; + +// Dynamically import pixelmatch at the start +(async () => { + pixelmatchModule = await import('pixelmatch'); +})(); + +/** + * @typedef {Object} Window + * @property {(data: string) => void} writeToTerminal + * @property {() => string} getTerminalState + * @property {(cols: number, rows: number) => void} resizeTerminal + * @property {() => {cols: number, rows: number}} fitTerminal + */ + +// Type declaration for window methods +/** + * @type {Window & typeof globalThis} + */ +// @ts-ignore +global.window; + +/** + * Compare two images and generate a diff image + * @param {string} img1Path - Path to the first image (baseline) + * @param {string} img2Path - Path to the second image (current) + * @param {string} diffOutputPath - Path to save the diff image + * @returns {Promise<{diffPixels: number, percentDiff: string, mismatchDetails: string}>} - Difference information + */ +const compareImages = async (img1Path, img2Path, diffOutputPath) => { + // Make sure pixelmatch is loaded + if (!pixelmatchModule) { + pixelmatchModule = await import('pixelmatch'); + } + const pixelmatch = pixelmatchModule.default; + + return new Promise((resolve, reject) => { + // Check if both images exist + if (!fs.existsSync(img1Path)) { + console.error(`Baseline image does not exist: ${img1Path}`); + return resolve({ + diffPixels: 100, + percentDiff: '100.00', + mismatchDetails: 'Baseline image missing', + }); + } + + if (!fs.existsSync(img2Path)) { + console.error(`Test image does not exist: ${img2Path}`); + return resolve({ + diffPixels: 100, + percentDiff: '100.00', + mismatchDetails: 'Test image missing', + }); + } + + const img1 = fs + .createReadStream(img1Path) + .pipe(new PNG()) + .on('parsed', () => { + const img2 = fs + .createReadStream(img2Path) + .pipe(new PNG()) + .on('parsed', () => { + const { width, height } = img1; + + // Images must have the same dimensions for pixelmatch + if (img1.width !== img2.width || img1.height !== img2.height) { + console.error( + `Image dimensions don't match: ${img1.width}x${img1.height} vs ${img2.width}x${img2.height}`, + ); + + // Create a simple diff image showing the size difference + const maxWidth = Math.max(img1.width, img2.width); + const maxHeight = Math.max(img1.height, img2.height); + const diff = new PNG({ width: maxWidth, height: maxHeight }); + + // Fill with a distinctive color to show the difference + for (let y = 0; y < maxHeight; y++) { + for (let x = 0; x < maxWidth; x++) { + const idx = (y * maxWidth + x) << 2; + // @ts-ignore - diff.data is a valid property but TypeScript doesn't recognize it + diff.data[idx] = 255; // R - make it red + // @ts-ignore - diff.data is a valid property but TypeScript doesn't recognize it + diff.data[idx + 1] = 0; // G + // @ts-ignore - diff.data is a valid property but TypeScript doesn't recognize it + diff.data[idx + 2] = 0; // B + // @ts-ignore - diff.data is a valid property but TypeScript doesn't recognize it + diff.data[idx + 3] = 255; // A + } + } + + // Write diff image + diff + .pack() + .pipe(fs.createWriteStream(diffOutputPath)) + .on('finish', () => { + return resolve({ + diffPixels: width * height, + percentDiff: '100.00', + mismatchDetails: `Size mismatch: ${img1.width}x${img1.height} vs ${img2.width}x${img2.height}`, + }); + }); + return; + } + + const diff = new PNG({ width, height }); + + // Use an extremely low threshold for pixel matching (0.01 instead of 0.05) + // This makes the comparison extremely strict + const numDiffPixels = pixelmatch( + img1.data, + img2.data, + diff.data, + width, + height, + { + threshold: 0.01, // Much lower threshold for extremely sensitive comparison + alpha: 0.1, + diffColor: [255, 0, 0], // Bright red for differences + diffColorAlt: [0, 255, 0], // Bright green for anti-aliased pixels + diffMask: false, // Draw the diff over a transparent background + includeAA: true, // Detect anti-aliased pixels + }, + ); + + // Create a side-by-side comparison image + const comparisonWidth = img1.width * 3; // baseline + current + diff + const comparisonHeight = img1.height; + const comparison = new PNG({ + width: comparisonWidth, + height: comparisonHeight, + }); + + // Fill with black background + for ( + let i = 0; + i < comparisonWidth * comparisonHeight * 4; + i += 4 + ) { + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[i] = 0; // R + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[i + 1] = 0; // G + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[i + 2] = 0; // B + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[i + 3] = 255; // A + } + + // Copy baseline image to the left side + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const srcIdx = (y * width + x) << 2; + const destIdx = (y * comparisonWidth + x) << 2; + + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx] = img1.data[srcIdx]; // R + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 1] = img1.data[srcIdx + 1]; // G + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 2] = img1.data[srcIdx + 2]; // B + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 3] = img1.data[srcIdx + 3]; // A + } + } + + // Copy current image to the middle + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const srcIdx = (y * width + x) << 2; + const destIdx = (y * comparisonWidth + width + x) << 2; + + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx] = img2.data[srcIdx]; // R + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 1] = img2.data[srcIdx + 1]; // G + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 2] = img2.data[srcIdx + 2]; // B + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 3] = img2.data[srcIdx + 3]; // A + } + } + + // Copy diff image to the right side + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const srcIdx = (y * width + x) << 2; + const destIdx = (y * comparisonWidth + width * 2 + x) << 2; + + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx] = diff.data[srcIdx]; // R + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 1] = diff.data[srcIdx + 1]; // G + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 2] = diff.data[srcIdx + 2]; // B + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 3] = diff.data[srcIdx + 3]; // A + } + } + + // Add labels to the comparison image + drawText(comparison, 10, 10, 'Baseline', [255, 255, 0]); // Yellow + drawText(comparison, img1.width + 10, 10, 'Current', [0, 255, 255]); // Cyan + drawText( + comparison, + img1.width * 2 + 10, + 10, + 'Diff', + [255, 0, 255], + ); // Magenta + + // Calculate percentage difference + const percentDiff = (numDiffPixels / (width * height)) * 100; + const percentDiffStr = percentDiff.toFixed(2); + + // Add percentage difference to the image + drawText( + comparison, + img1.width * 2 + 10, + 25, + `${percentDiffStr}% diff`, + [255, 0, 255], + ); // Magenta + + // Generate detailed mismatch information + let mismatchDetails = `${numDiffPixels} pixels differ (${percentDiffStr}% of total)`; + + // Write the side-by-side comparison image + comparison + .pack() + .pipe(fs.createWriteStream(diffOutputPath)) + .on('finish', () => { + resolve({ + diffPixels: numDiffPixels, + percentDiff: percentDiffStr, + mismatchDetails, + }); + }) + .on('error', (err) => { + console.error('Error writing comparison image:', err); + reject(err); + }); + }) + .on('error', (err) => { + console.error('Error parsing img2:', err); + reject(err); + }); + }) + .on('error', (err) => { + console.error('Error parsing img1:', err); + reject(err); + }); + }); +}; + +/** + * Verify a screenshot against a baseline image + * @param {string} screenshotPath - Path to the screenshot to verify + * @param {string} baselineName - Name of the baseline to compare against + * @param {number} threshold - Threshold percentage for acceptable difference + * @param {boolean} keepDiffs - Whether to keep diff images even when comparison passes + * @returns {Promise} - Whether the verification passed + */ +const verifyAgainstBaseline = async ( + screenshotPath, + baselineName, + threshold = 0.1, + keepDiffs = true, +) => { + // Lower default threshold from 1% to 0.1% for extremely sensitive comparison + + const baselineDir = path.join(__dirname, 'baselines'); + const baselinePath = path.join(baselineDir, `${baselineName}.png`); + const diffDir = path.join(__dirname, 'diffs'); + const diffPath = path.join(diffDir, `diff-${baselineName}-${Date.now()}.png`); + + // Create baseline directory if it doesn't exist + if (!fs.existsSync(baselineDir)) { + fs.mkdirSync(baselineDir, { recursive: true }); + } + + // Create diffs directory if it doesn't exist + if (!fs.existsSync(diffDir)) { + fs.mkdirSync(diffDir, { recursive: true }); + } + + // If baseline doesn't exist, save this screenshot as baseline + if (!fs.existsSync(baselinePath)) { + console.log( + `Baseline image doesn't exist. Saving ${screenshotPath} as baseline for ${baselineName}`, + ); + fs.copyFileSync(screenshotPath, baselinePath); + return true; + } + + // Compare the images + const diffResult = await compareImages( + baselinePath, + screenshotPath, + diffPath, + ); + + // Check if difference is within acceptable threshold + const diffPercentage = parseFloat(diffResult.percentDiff); + const passed = diffPercentage <= threshold; + + if (passed) { + console.log( + `✅ Screenshot matches baseline for ${baselineName} (${diffResult.percentDiff}% difference)`, + ); + + // Only remove diff file if keepDiffs is false + if (!keepDiffs) { + try { + fs.unlinkSync(diffPath); + } catch (error) { + console.warn( + `Warning: Could not delete diff file ${diffPath}:`, + error.message, + ); + } + } else { + console.log( + `Diff image saved to: ${diffPath} (passed but kept for reference)`, + ); + } + } else { + console.log( + `❌ Screenshot differs from baseline for ${baselineName} (${diffResult.percentDiff}% difference)`, + ); + console.log(`Details: ${diffResult.mismatchDetails}`); + console.log(`Diff image saved to: ${diffPath}`); + } + + return passed; +}; + +// Create a simple HTML file with xterm.js for rendering the terminal +const createHtmlFile = () => { + const htmlPath = path.join(__dirname, 'terminal-renderer.html'); + const html = ` + + + + + + + + + + +
+ + + + `; + + fs.writeFileSync(htmlPath, html); + return htmlPath; +}; + +/** + * Send keyboard input to the terminal process + * @param {any} pty - The pty process + * @param {string} input - The input to send + * @returns {Promise} + */ +const sendInput = async (pty, input) => { + return new Promise((resolve) => { + console.log(`Sending input: ${JSON.stringify(input)}`); + pty.write(input); + // Give some time for the terminal to process the input + setTimeout(resolve, 500); + }); +}; + +/** + * Wait for specific text to appear in the terminal + * @param {any} page - Puppeteer page + * @param {string|RegExp} text - Text or regex pattern to wait for + * @param {number} timeout - Maximum time to wait in milliseconds + * @param {number} pollInterval - How often to check for the text in milliseconds + * @returns {Promise} - Resolves to true when text is found, or false if timeout + */ +const waitForText = async (page, text, timeout = 10000, pollInterval = 100) => { + console.log( + `Waiting for text: ${text instanceof RegExp ? text.toString() : `"${text}"`}`, + ); + + const startTime = Date.now(); + let found = false; + + while (!found && Date.now() - startTime < timeout) { + found = await page.evaluate( + (searchText) => { + // Get terminal content from the serialize addon + // @ts-ignore - Custom method added via browser script + const content = window.getTerminalState(); + + // Check if the content contains the text + if (typeof searchText === 'string') { + return content.includes(searchText); + } else { + // For RegExp, we need to recreate it in the browser context + const regexParts = /\/(.*)\/([gimuy]*)/.exec(searchText); + if (regexParts) { + const [, pattern, flags] = regexParts; + const regex = new RegExp(pattern, flags); + return regex.test(content); + } + return false; + } + }, + text instanceof RegExp ? text.toString() : text, + ); + + if (found) { + console.log(`✅ Found text after ${Date.now() - startTime}ms`); + return true; + } + + // Wait for the poll interval before checking again + await new Promise((resolve) => setTimeout(resolve, pollInterval)); + } + + // Capture a failure screenshot for debugging + const failureScreenshotPath = path.join( + __dirname, + `failure-waiting-for-text-${Date.now()}.png`, + ); + await page.screenshot({ path: failureScreenshotPath }); + console.log(`📸 Failure screenshot saved to: ${failureScreenshotPath}`); + + // Get the current terminal content for debugging + const terminalContent = await page.evaluate(() => { + // @ts-ignore - Custom method added via browser script + return window.getTerminalState(); + }); + const contentPreview = + terminalContent.length > 500 + ? terminalContent.substring(0, 500) + '...' + : terminalContent; + console.log(`📄 Terminal content at failure:\n${contentPreview}`); + + // Instead of returning false, throw an error with detailed information + const errorMessage = `Timeout waiting for text: ${text instanceof RegExp ? text.toString() : `"${text}"`} after ${timeout}ms`; + console.error(`❌ ${errorMessage}`); + throw new Error( + `${errorMessage} (see screenshot at ${failureScreenshotPath})`, + ); +}; + +/** + * Wait for a condition to be true in the terminal + * @param {string} description - Description of what condition we're waiting for + * @param {any} page - Puppeteer page + * @param {Function} conditionFn - Function that evaluates in browser context and returns boolean + * @param {number} timeout - Maximum time to wait in milliseconds + * @param {number} pollInterval - How often to check the condition in milliseconds + * @returns {Promise} - Resolves to true when condition is met, or false if timeout + */ +const waitForCondition = async ( + description, + page, + conditionFn, + timeout = 10000, + pollInterval = 100, +) => { + console.log(`Waiting for: ${description}`); + + const startTime = Date.now(); + let conditionMet = false; + + while (!conditionMet && Date.now() - startTime < timeout) { + conditionMet = await page.evaluate(conditionFn); + + if (conditionMet) { + console.log( + `✅ Condition met after ${Date.now() - startTime}ms: ${description}`, + ); + return true; + } + + // Wait for the poll interval before checking again + await new Promise((resolve) => setTimeout(resolve, pollInterval)); + } + + // Capture a failure screenshot for debugging + const failureScreenshotPath = path.join( + __dirname, + `failure-${description.replace(/[^a-z0-9]/gi, '-').toLowerCase()}-${Date.now()}.png`, + ); + await page.screenshot({ path: failureScreenshotPath }); + console.log(`📸 Failure screenshot saved to: ${failureScreenshotPath}`); + + // Get the current terminal content for debugging + const terminalContent = await page.evaluate(() => { + // @ts-ignore - Custom method added via browser script + return window.getTerminalState(); + }); + const contentPreview = + terminalContent.length > 500 + ? terminalContent.substring(0, 500) + '...' + : terminalContent; + console.log(`📄 Terminal content at failure:\n${contentPreview}`); + + // Instead of returning false, throw an error with detailed information + const errorMessage = `Timeout waiting for condition: ${description} after ${timeout}ms`; + console.error(`❌ ${errorMessage}`); + throw new Error( + `${errorMessage} (see screenshot at ${failureScreenshotPath})`, + ); +}; + +/** + * Capture a screenshot and wait for the page to stabilize first + * @param {any} page - Puppeteer page + * @param {string} name - Name for the screenshot + * @param {number} stabilityTimeout - How long to wait for stability in milliseconds + * @param {number} stabilityThreshold - How many consecutive stable checks needed + * @returns {Promise} - Path to the saved screenshot + */ +const captureStableScreenshot = async ( + page, + name, + stabilityTimeout = 5000, + stabilityThreshold = 5, +) => { + console.log(`Capturing stable screenshot: ${name}`); + + // Wait for visual stability by comparing terminal content + const startTime = Date.now(); + let stableCount = 0; + let lastContent = ''; + + while ( + stableCount < stabilityThreshold && + Date.now() - startTime < stabilityTimeout + ) { + // Get current terminal content + const currentContent = await page.evaluate(() => { + // @ts-ignore - Custom method added via browser script + return window.getTerminalState(); + }); + + if (currentContent === lastContent) { + stableCount++; + } else { + stableCount = 0; + lastContent = currentContent; + } + + await new Promise((resolve) => setTimeout(resolve, 100)); + } + + if (stableCount >= stabilityThreshold) { + console.log( + `✅ Terminal content stabilized after ${Date.now() - startTime}ms`, + ); + } else { + console.log( + `⚠️ Terminal content did not fully stabilize after ${stabilityTimeout}ms`, + ); + } + + // Take the screenshot + const screenshotPath = path.join( + __dirname, + `terminal-${name}-${Date.now()}.png`, + ); + await page.screenshot({ path: screenshotPath }); + console.log(`Screenshot saved to ${screenshotPath}`); + + return screenshotPath; +}; + +/** + * Navigate through the TUI using keyboard inputs and wait for specific content + * @param {any} pty - The pty process + * @param {any} page - The puppeteer page + * @returns {Promise<{beforeNavPath: string, afterNav1Path: string, afterNav2Path: string, afterSelectPath: string}>} + */ +const navigateTUI = async (pty, page) => { + // Wait for the TUI to fully render - look for the task list header + await waitForText(page, 'run-many', 15000); + + // Take a screenshot before navigation + const beforeNavPath = await captureStableScreenshot(page, 'before-nav'); + + // Navigate down (arrow down key) + await sendInput(pty, '\x1B[B'); // ESC [ B is the escape sequence for down arrow + + // Wait for the selection indicator to move + // await waitForCondition( + // "selection indicator to move to the second line", + // page, + // () => { + // // @ts-ignore - Custom method added via browser script + // const content = window.getTerminalState(); + // // Check for the selection indicator (e.g., ">" or "❯") on the second line + // // This depends on your TUI's exact format + // const lines = content.split('\n'); + // return lines.length > 1 && (lines[1].includes('>') || lines[1].includes('❯')); + // }, + // ); + + // Take a screenshot after first navigation + const afterNav1Path = await captureStableScreenshot(page, 'after-nav1'); + + // Navigate down again + await sendInput(pty, '\x1B[B'); + + // Wait for the selection indicator to move to the third line + // await waitForCondition( + // "selection indicator to move to the third line", + // page, + // () => { + // // @ts-ignore - Custom method added via browser script + // const content = window.getTerminalState(); + // const lines = content.split('\n'); + // return lines.length > 2 && (lines[2].includes('>') || lines[2].includes('❯')); + // }, + // ); + + // Take a screenshot after second navigation + const afterNav2Path = await captureStableScreenshot(page, 'after-nav2'); + + // Press spacebar to select the item + await sendInput(pty, ' '); + + // Wait for the selection screen to disappear and build to start + // await waitForText(page, "Building", 10000); + + // Take a screenshot after selection + const afterSelectPath = await captureStableScreenshot(page, 'after-select'); + + return { + beforeNavPath, + afterNav1Path, + afterNav2Path, + afterSelectPath, + }; +}; + +/** + * Draw simple text on an image + * @param {any} png - The PNG image + * @param {number} x - X coordinate + * @param {number} y - Y coordinate + * @param {string} text - Text to draw + * @param {number[]} color - RGB color array [r, g, b] + */ +const drawText = (png, x, y, text, color = [255, 255, 255]) => { + const width = png.width; + + // Simple 5x7 pixel font for basic characters + const font = { + B: [ + [1, 1, 1, 0, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 1, 1, 0, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 1, 1, 0, 0], + ], + a: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 1, 1, 0, 0], + [0, 0, 0, 1, 0], + [0, 1, 1, 1, 0], + [1, 0, 0, 1, 0], + [0, 1, 1, 1, 0], + ], + s: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 1, 1, 1, 0], + [1, 0, 0, 0, 0], + [0, 1, 1, 0, 0], + [0, 0, 0, 1, 0], + [1, 1, 1, 0, 0], + ], + e: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 1, 1, 0, 0], + [1, 0, 0, 1, 0], + [1, 1, 1, 1, 0], + [1, 0, 0, 0, 0], + [0, 1, 1, 1, 0], + ], + l: [ + [0, 1, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 1, 1, 1, 0], + ], + i: [ + [0, 0, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + ], + n: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [1, 0, 1, 0, 0], + [1, 1, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + ], + C: [ + [0, 1, 1, 1, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [0, 1, 1, 1, 0], + ], + u: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [0, 1, 1, 1, 0], + ], + r: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [1, 0, 1, 1, 0], + [1, 1, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + ], + t: [ + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 1, 1, 1, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + ], + D: [ + [1, 1, 1, 0, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 1, 1, 0, 0], + ], + f: [ + [0, 0, 1, 1, 0], + [0, 1, 0, 0, 0], + [1, 1, 1, 0, 0], + [0, 1, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 1, 0, 0, 0], + ], + ' ': [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + ], + ':': [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 0, 0], + ], + }; + + let currentX = x; + + // Draw each character + for (let i = 0; i < text.length; i++) { + const char = text[i]; + const charPattern = font[char] || font[' ']; // Default to space if character not found + + for (let row = 0; row < charPattern.length; row++) { + for (let col = 0; col < charPattern[0].length; col++) { + if (charPattern[row][col]) { + const pixelX = currentX + col; + const pixelY = y + row; + const idx = (pixelY * width + pixelX) << 2; + + // @ts-ignore - png.data is a valid property but TypeScript doesn't recognize it + png.data[idx] = color[0]; // R + // @ts-ignore - png.data is a valid property but TypeScript doesn't recognize it + png.data[idx + 1] = color[1]; // G + // @ts-ignore - png.data is a valid property but TypeScript doesn't recognize it + png.data[idx + 2] = color[2]; // B + // @ts-ignore - png.data is a valid property but TypeScript doesn't recognize it + png.data[idx + 3] = 255; // A + } + } + } + + currentX += 6; // Character width + 1 pixel spacing + } +}; + +test('Nx TUI renders correctly and responds to navigation', async () => { + // Create HTML file for rendering + const htmlPath = createHtmlFile(); + + // Check if running in CI environment + const isCI = process.env.CI === 'true'; + + // Launch browser and open the HTML file + const browser = await puppeteer.launch({ + headless: isCI, // Use headless when in CI, non-headless for local development + defaultViewport: { + width: 1200, + height: 800, + }, + args: ['--start-maximized'], // Start with maximized window + }); + + const page = await browser.newPage(); + await page.setViewport({ width: 1200, height: 800 }); + await page.goto(`file://${htmlPath}`); + + // Wait for the page to load and terminal to initialize + // @ts-ignore - Custom method added via browser script + await page.waitForFunction(() => typeof window.fitTerminal === 'function'); + + // Fit terminal to viewport and get dimensions + const dimensions = await page.evaluate(() => { + // @ts-ignore - Custom method added via browser script + return window.fitTerminal(); + }); + + console.log(`Terminal dimensions: ${dimensions.cols}x${dimensions.rows}`); + + // Step 1: Spawn Nx CLI using node-pty + console.log('Spawning Nx TUI...'); + const pty = spawn('npx', ['nx', 'run-many', '--target=build', '--all'], { + name: 'xterm-color', + cols: dimensions.cols || 80, + rows: dimensions.rows || 24, + cwd: process.cwd(), + env: { + ...process.env, + NX_TUI: 'true', + FORCE_COLOR: '3', // Force color output + }, + }); + + let fullOutput = ''; + const outputChunks = []; + + // Create a promise to capture terminal state after a delay + const captureTerminalState = async (delay = 1000) => { + await new Promise((resolve) => setTimeout(resolve, delay)); + + // Get terminal state + const serializedState = await page.evaluate(() => { + // @ts-ignore - Custom method added via browser script + return window.getTerminalState(); + }); + + // Take a screenshot + const screenshotPath = path.join( + __dirname, + `terminal-state-${Date.now()}.png`, + ); + await page.screenshot({ path: screenshotPath }); + + console.log(`Terminal state captured and saved to ${screenshotPath}`); + return { serializedState, screenshotPath }; + }; + + // Process data from pty and send to browser + pty.onData(async (data) => { + fullOutput += data; + outputChunks.push(data); + + // Send data to browser for rendering + await page.evaluate((text) => { + // @ts-ignore - Custom method added via browser script + window.writeToTerminal(text); + }, data); + }); + + try { + // Wait for initial render - look for the Nx logo or header + await waitForText(page, 'NX', 15000); + + // Capture initial state + const initialState = { + screenshotPath: await captureStableScreenshot(page, 'initial-state'), + }; + + // Navigate through the TUI + const navigationScreenshots = await navigateTUI(pty, page); + + // Wait for the build to complete or reach a specific state + await waitForText(page, 'Completed', 30000); + + // Capture final state + const finalState = { + screenshotPath: await captureStableScreenshot(page, 'final-state'), + }; + + // Clean up + pty.kill(); + await browser.close(); + + // Save the full output for debugging + fs.writeFileSync(path.join(__dirname, 'terminal-output.txt'), fullOutput); + fs.writeFileSync( + path.join(__dirname, 'terminal-chunks.json'), + JSON.stringify(outputChunks, null, 2), + ); + + console.log('Test completed successfully'); + console.log(`Initial screenshot: ${initialState.screenshotPath}`); + console.log(`Navigation screenshots:`, navigationScreenshots); + console.log(`Final screenshot: ${finalState.screenshotPath}`); + + // Verify screenshots against baselines + console.log('\n--- Comparing screenshots against baselines ---\n'); + const initialResult = await verifyAgainstBaseline( + initialState.screenshotPath, + 'initial-state', + 0.1, // 0.1% threshold + true, // Keep diff images + ); + + const beforeNavResult = await verifyAgainstBaseline( + navigationScreenshots.beforeNavPath, + 'before-navigation', + 0.1, + true, + ); + + const afterNav1Result = await verifyAgainstBaseline( + navigationScreenshots.afterNav1Path, + 'after-navigation-1', + 0.1, + true, + ); + + const afterNav2Result = await verifyAgainstBaseline( + navigationScreenshots.afterNav2Path, + 'after-navigation-2', + 0.1, + true, + ); + + const afterSelectResult = await verifyAgainstBaseline( + navigationScreenshots.afterSelectPath, + 'after-selection', + 0.1, + true, + ); + + const finalResult = await verifyAgainstBaseline( + finalState.screenshotPath, + 'final-state', + 0.1, + true, + ); + + console.log( + '\n--- All diff images are saved in the "diffs" directory ---\n', + ); + + // Assert that all comparisons pass + assert.ok(initialResult, 'Initial state should match baseline'); + assert.ok(beforeNavResult, 'Before navigation state should match baseline'); + assert.ok( + afterNav1Result, + 'After first navigation state should match baseline', + ); + assert.ok( + afterNav2Result, + 'After second navigation state should match baseline', + ); + assert.ok(afterSelectResult, 'After selection state should match baseline'); + assert.ok(finalResult, 'Final state should match baseline'); + } catch (error) { + pty.kill(); + await browser.close(); + throw error; + } +}); diff --git a/utils.js b/utils.js new file mode 100644 index 000000000..cc0cb056e --- /dev/null +++ b/utils.js @@ -0,0 +1,978 @@ +// @ts-check + +const { spawn } = require('node-pty'); +const fs = require('fs'); +const path = require('path'); +const puppeteer = require('puppeteer'); +const { PNG } = require('pngjs'); +let pixelmatchModule; + +// Dynamically import pixelmatch at the start +(async () => { + pixelmatchModule = await import('pixelmatch'); +})(); + +/** + * Compare two images and generate a diff image + * @param {string} img1Path - Path to the first image (baseline) + * @param {string} img2Path - Path to the second image (current) + * @param {string} diffOutputPath - Path to save the diff image + * @returns {Promise<{diffPixels: number, percentDiff: string, mismatchDetails: string}>} - Difference information + */ +const compareImages = async (img1Path, img2Path, diffOutputPath) => { + // Make sure pixelmatch is loaded + if (!pixelmatchModule) { + pixelmatchModule = await import('pixelmatch'); + } + const pixelmatch = pixelmatchModule.default; + + return new Promise((resolve, reject) => { + // Check if both images exist + if (!fs.existsSync(img1Path)) { + console.error(`Baseline image does not exist: ${img1Path}`); + return resolve({ + diffPixels: 100, + percentDiff: '100.00', + mismatchDetails: 'Baseline image missing', + }); + } + + if (!fs.existsSync(img2Path)) { + console.error(`Test image does not exist: ${img2Path}`); + return resolve({ + diffPixels: 100, + percentDiff: '100.00', + mismatchDetails: 'Test image missing', + }); + } + + const img1 = fs + .createReadStream(img1Path) + .pipe(new PNG()) + .on('parsed', () => { + const img2 = fs + .createReadStream(img2Path) + .pipe(new PNG()) + .on('parsed', () => { + const { width, height } = img1; + + // Images must have the same dimensions for pixelmatch + if (img1.width !== img2.width || img1.height !== img2.height) { + console.error( + `Image dimensions don't match: ${img1.width}x${img1.height} vs ${img2.width}x${img2.height}`, + ); + + // Create a simple diff image showing the size difference + const maxWidth = Math.max(img1.width, img2.width); + const maxHeight = Math.max(img1.height, img2.height); + const diff = new PNG({ width: maxWidth, height: maxHeight }); + + // Fill with a distinctive color to show the difference + for (let y = 0; y < maxHeight; y++) { + for (let x = 0; x < maxWidth; x++) { + const idx = (y * maxWidth + x) << 2; + // @ts-ignore - diff.data is a valid property but TypeScript doesn't recognize it + diff.data[idx] = 255; // R - make it red + // @ts-ignore - diff.data is a valid property but TypeScript doesn't recognize it + diff.data[idx + 1] = 0; // G + // @ts-ignore - diff.data is a valid property but TypeScript doesn't recognize it + diff.data[idx + 2] = 0; // B + // @ts-ignore - diff.data is a valid property but TypeScript doesn't recognize it + diff.data[idx + 3] = 255; // A + } + } + + // Write diff image + diff + .pack() + .pipe(fs.createWriteStream(diffOutputPath)) + .on('finish', () => { + return resolve({ + diffPixels: width * height, + percentDiff: '100.00', + mismatchDetails: `Size mismatch: ${img1.width}x${img1.height} vs ${img2.width}x${img2.height}`, + }); + }); + return; + } + + const diff = new PNG({ width, height }); + + // Use an extremely low threshold for pixel matching (0.01 instead of 0.05) + // This makes the comparison extremely strict + const numDiffPixels = pixelmatch( + img1.data, + img2.data, + diff.data, + width, + height, + { + threshold: 0.01, // Much lower threshold for extremely sensitive comparison + alpha: 0.1, + diffColor: [255, 0, 0], // Bright red for differences + diffColorAlt: [0, 255, 0], // Bright green for anti-aliased pixels + diffMask: false, // Draw the diff over a transparent background + includeAA: true, // Detect anti-aliased pixels + }, + ); + + // Create a side-by-side comparison image + const comparisonWidth = img1.width * 3; // baseline + current + diff + const comparisonHeight = img1.height; + const comparison = new PNG({ + width: comparisonWidth, + height: comparisonHeight, + }); + + // Fill with black background + for ( + let i = 0; + i < comparisonWidth * comparisonHeight * 4; + i += 4 + ) { + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[i] = 0; // R + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[i + 1] = 0; // G + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[i + 2] = 0; // B + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[i + 3] = 255; // A + } + + // Copy baseline image to the left side + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const srcIdx = (y * width + x) << 2; + const destIdx = (y * comparisonWidth + x) << 2; + + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx] = img1.data[srcIdx]; // R + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 1] = img1.data[srcIdx + 1]; // G + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 2] = img1.data[srcIdx + 2]; // B + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 3] = img1.data[srcIdx + 3]; // A + } + } + + // Copy current image to the middle + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const srcIdx = (y * width + x) << 2; + const destIdx = (y * comparisonWidth + width + x) << 2; + + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx] = img2.data[srcIdx]; // R + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 1] = img2.data[srcIdx + 1]; // G + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 2] = img2.data[srcIdx + 2]; // B + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 3] = img2.data[srcIdx + 3]; // A + } + } + + // Copy diff image to the right side + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const srcIdx = (y * width + x) << 2; + const destIdx = (y * comparisonWidth + width * 2 + x) << 2; + + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx] = diff.data[srcIdx]; // R + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 1] = diff.data[srcIdx + 1]; // G + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 2] = diff.data[srcIdx + 2]; // B + // @ts-ignore - comparison.data is a valid property but TypeScript doesn't recognize it + comparison.data[destIdx + 3] = diff.data[srcIdx + 3]; // A + } + } + + // Add labels to the comparison image + drawText(comparison, 10, 10, 'Baseline', [255, 255, 0]); // Yellow + drawText(comparison, img1.width + 10, 10, 'Current', [0, 255, 255]); // Cyan + drawText( + comparison, + img1.width * 2 + 10, + 10, + 'Diff', + [255, 0, 255], + ); // Magenta + + // Calculate percentage difference + const percentDiff = (numDiffPixels / (width * height)) * 100; + const percentDiffStr = percentDiff.toFixed(2); + + // Add percentage difference to the image + drawText( + comparison, + img1.width * 2 + 10, + 25, + `${percentDiffStr}% diff`, + [255, 0, 255], + ); // Magenta + + // Generate detailed mismatch information + let mismatchDetails = `${numDiffPixels} pixels differ (${percentDiffStr}% of total)`; + + // Write the side-by-side comparison image + comparison + .pack() + .pipe(fs.createWriteStream(diffOutputPath)) + .on('finish', () => { + resolve({ + diffPixels: numDiffPixels, + percentDiff: percentDiffStr, + mismatchDetails, + }); + }) + .on('error', (err) => { + console.error('Error writing comparison image:', err); + reject(err); + }); + }) + .on('error', (err) => { + console.error('Error parsing img2:', err); + reject(err); + }); + }) + .on('error', (err) => { + console.error('Error parsing img1:', err); + reject(err); + }); + }); +}; + +/** + * Verify a screenshot against a baseline image + * @param {string} screenshotPath - Path to the screenshot to verify + * @param {string} baselineName - Name of the baseline to compare against + * @param {number} threshold - Threshold percentage for acceptable difference + * @param {boolean} keepDiffs - Whether to keep diff images even when comparison passes + * @returns {Promise} - Whether the verification passed + */ +const verifyAgainstBaseline = async ( + screenshotPath, + baselineName, + threshold = 0.1, + keepDiffs = true, +) => { + // Lower default threshold from 1% to 0.1% for extremely sensitive comparison + + const baselineDir = path.join(process.cwd(), 'baselines'); + const baselinePath = path.join(baselineDir, `${baselineName}.png`); + const diffDir = path.join(process.cwd(), 'diffs'); + const diffPath = path.join(diffDir, `diff-${baselineName}-${Date.now()}.png`); + + // Create baseline directory if it doesn't exist + if (!fs.existsSync(baselineDir)) { + fs.mkdirSync(baselineDir, { recursive: true }); + } + + // Create diffs directory if it doesn't exist + if (!fs.existsSync(diffDir)) { + fs.mkdirSync(diffDir, { recursive: true }); + } + + // If baseline doesn't exist, save this screenshot as baseline + if (!fs.existsSync(baselinePath)) { + console.log( + `Baseline image doesn't exist. Saving ${screenshotPath} as baseline for ${baselineName}`, + ); + fs.copyFileSync(screenshotPath, baselinePath); + return true; + } + + // Compare the images + const diffResult = await compareImages( + baselinePath, + screenshotPath, + diffPath, + ); + + // Check if difference is within acceptable threshold + const diffPercentage = parseFloat(diffResult.percentDiff); + const passed = diffPercentage <= threshold; + + if (passed) { + console.log( + `✅ Screenshot matches baseline for ${baselineName} (${diffResult.percentDiff}% difference)`, + ); + + // Only remove diff file if keepDiffs is false + if (!keepDiffs) { + try { + fs.unlinkSync(diffPath); + } catch (error) { + console.warn( + `Warning: Could not delete diff file ${diffPath}:`, + error.message, + ); + } + } else { + console.log( + `Diff image saved to: ${diffPath} (passed but kept for reference)`, + ); + } + } else { + console.log( + `❌ Screenshot differs from baseline for ${baselineName} (${diffResult.percentDiff}% difference)`, + ); + console.log(`Details: ${diffResult.mismatchDetails}`); + console.log(`Diff image saved to: ${diffPath}`); + } + + return passed; +}; + +/** + * Create a simple HTML file with xterm.js for rendering the terminal + * @returns {string} - Path to the created HTML file + */ +const createHtmlFile = () => { + const htmlPath = path.join(process.cwd(), 'terminal-renderer.html'); + const html = ` + + + + + + + + + + +
+ + + + `; + + fs.writeFileSync(htmlPath, html); + return htmlPath; +}; + +/** + * Send keyboard input to the terminal process + * @param {any} pty - The pty process + * @param {string} input - The input to send + * @returns {Promise} + */ +const sendInput = async (pty, input) => { + return new Promise((resolve) => { + console.log(`Sending input: ${JSON.stringify(input)}`); + pty.write(input); + // Give some time for the terminal to process the input + setTimeout(resolve, 500); + }); +}; + +/** + * Wait for specific text to appear in the terminal + * @param {any} page - Puppeteer page + * @param {string|RegExp} text - Text or regex pattern to wait for + * @param {number} timeout - Maximum time to wait in milliseconds + * @param {number} pollInterval - How often to check for the text in milliseconds + * @returns {Promise} - Resolves to true when text is found, or false if timeout + */ +const waitForText = async (page, text, timeout = 10000, pollInterval = 100) => { + console.log( + `Waiting for text: ${text instanceof RegExp ? text.toString() : `"${text}"`}`, + ); + + const startTime = Date.now(); + let found = false; + + while (!found && Date.now() - startTime < timeout) { + found = await page.evaluate( + (searchText) => { + // Get terminal content from the serialize addon + // @ts-ignore - Custom method added via browser script + const content = window.getTerminalState(); + + // Check if the content contains the text + if (typeof searchText === 'string') { + return content.includes(searchText); + } else { + // For RegExp, we need to recreate it in the browser context + const regexParts = /\/(.*)\/([gimuy]*)/.exec(searchText); + if (regexParts) { + const [, pattern, flags] = regexParts; + const regex = new RegExp(pattern, flags); + return regex.test(content); + } + return false; + } + }, + text instanceof RegExp ? text.toString() : text, + ); + + if (found) { + console.log(`✅ Found text after ${Date.now() - startTime}ms`); + return true; + } + + // Wait for the poll interval before checking again + await new Promise((resolve) => setTimeout(resolve, pollInterval)); + } + + // Capture a failure screenshot for debugging + const failureScreenshotPath = path.join( + process.cwd(), + `failure-waiting-for-text-${Date.now()}.png`, + ); + await page.screenshot({ path: failureScreenshotPath }); + console.log(`📸 Failure screenshot saved to: ${failureScreenshotPath}`); + + // Get the current terminal content for debugging + const terminalContent = await page.evaluate(() => { + // @ts-ignore - Custom method added via browser script + return window.getTerminalState(); + }); + const contentPreview = + terminalContent.length > 500 + ? terminalContent.substring(0, 500) + '...' + : terminalContent; + console.log(`📄 Terminal content at failure:\n${contentPreview}`); + + // Instead of returning false, throw an error with detailed information + const errorMessage = `Timeout waiting for text: ${text instanceof RegExp ? text.toString() : `"${text}"`} after ${timeout}ms`; + console.error(`❌ ${errorMessage}`); + throw new Error( + `${errorMessage} (see screenshot at ${failureScreenshotPath})`, + ); +}; + +/** + * Wait for a condition to be true in the terminal + * @param {string} description - Description of what condition we're waiting for + * @param {any} page - Puppeteer page + * @param {Function} conditionFn - Function that evaluates in browser context and returns boolean + * @param {number} timeout - Maximum time to wait in milliseconds + * @param {number} pollInterval - How often to check the condition in milliseconds + * @returns {Promise} - Resolves to true when condition is met, or false if timeout + */ +const waitForCondition = async ( + description, + page, + conditionFn, + timeout = 10000, + pollInterval = 100, +) => { + console.log(`Waiting for: ${description}`); + + const startTime = Date.now(); + let conditionMet = false; + + while (!conditionMet && Date.now() - startTime < timeout) { + conditionMet = await page.evaluate(conditionFn); + + if (conditionMet) { + console.log( + `✅ Condition met after ${Date.now() - startTime}ms: ${description}`, + ); + return true; + } + + // Wait for the poll interval before checking again + await new Promise((resolve) => setTimeout(resolve, pollInterval)); + } + + // Capture a failure screenshot for debugging + const failureScreenshotPath = path.join( + process.cwd(), + `failure-${description.replace(/[^a-z0-9]/gi, '-').toLowerCase()}-${Date.now()}.png`, + ); + await page.screenshot({ path: failureScreenshotPath }); + console.log(`📸 Failure screenshot saved to: ${failureScreenshotPath}`); + + // Get the current terminal content for debugging + const terminalContent = await page.evaluate(() => { + // @ts-ignore - Custom method added via browser script + return window.getTerminalState(); + }); + const contentPreview = + terminalContent.length > 500 + ? terminalContent.substring(0, 500) + '...' + : terminalContent; + console.log(`📄 Terminal content at failure:\n${contentPreview}`); + + // Instead of returning false, throw an error with detailed information + const errorMessage = `Timeout waiting for condition: ${description} after ${timeout}ms`; + console.error(`❌ ${errorMessage}`); + throw new Error( + `${errorMessage} (see screenshot at ${failureScreenshotPath})`, + ); +}; + +/** + * Capture a screenshot and wait for the page to stabilize first + * @param {any} page - Puppeteer page + * @param {string} name - Name for the screenshot + * @param {number} stabilityTimeout - How long to wait for stability in milliseconds + * @param {number} stabilityThreshold - How many consecutive stable checks needed + * @returns {Promise} - Path to the saved screenshot + */ +const captureStableScreenshot = async ( + page, + name, + stabilityTimeout = 5000, + stabilityThreshold = 5, +) => { + console.log(`Capturing stable screenshot: ${name}`); + + // Wait for visual stability by comparing terminal content + const startTime = Date.now(); + let stableCount = 0; + let lastContent = ''; + + while ( + stableCount < stabilityThreshold && + Date.now() - startTime < stabilityTimeout + ) { + // Get current terminal content + const currentContent = await page.evaluate(() => { + // @ts-ignore - Custom method added via browser script + return window.getTerminalState(); + }); + + if (currentContent === lastContent) { + stableCount++; + } else { + stableCount = 0; + lastContent = currentContent; + } + + await new Promise((resolve) => setTimeout(resolve, 100)); + } + + if (stableCount >= stabilityThreshold) { + console.log( + `✅ Terminal content stabilized after ${Date.now() - startTime}ms`, + ); + } else { + console.log( + `⚠️ Terminal content did not fully stabilize after ${stabilityTimeout}ms`, + ); + } + + // Take the screenshot + const screenshotPath = path.join( + process.cwd(), + `terminal-${name}-${Date.now()}.png`, + ); + await page.screenshot({ path: screenshotPath }); + console.log(`Screenshot saved to ${screenshotPath}`); + + return screenshotPath; +}; + +/** + * Navigate through the TUI using keyboard inputs and wait for specific content + * @param {any} pty - The pty process + * @param {any} page - The puppeteer page + * @returns {Promise<{beforeNavPath: string, afterNav1Path: string, afterNav2Path: string, afterSelectPath: string}>} + */ +const navigateTUI = async (pty, page) => { + // Wait for the TUI to fully render - look for the task list header + await waitForText(page, 'Select tasks to run:', 15000); + + // Take a screenshot before navigation + const beforeNavPath = await captureStableScreenshot(page, 'before-nav'); + + // Navigate down (arrow down key) + await sendInput(pty, '\x1B[B'); // ESC [ B is the escape sequence for down arrow + + // Wait for the selection indicator to move + await waitForCondition( + 'selection indicator to move to the second line', + page, + () => { + // @ts-ignore - Custom method added via browser script + const content = window.getTerminalState(); + // Check for the selection indicator (e.g., ">" or "❯") on the second line + // This depends on your TUI's exact format + const lines = content.split('\n'); + return ( + lines.length > 1 && (lines[1].includes('>') || lines[1].includes('❯')) + ); + }, + ); + + // Take a screenshot after first navigation + const afterNav1Path = await captureStableScreenshot(page, 'after-nav1'); + + // Navigate down again + await sendInput(pty, '\x1B[B'); + + // Wait for the selection indicator to move to the third line + await waitForCondition( + 'selection indicator to move to the third line', + page, + () => { + // @ts-ignore - Custom method added via browser script + const content = window.getTerminalState(); + const lines = content.split('\n'); + return ( + lines.length > 2 && (lines[2].includes('>') || lines[2].includes('❯')) + ); + }, + ); + + // Take a screenshot after second navigation + const afterNav2Path = await captureStableScreenshot(page, 'after-nav2'); + + // Press Enter to select the item + await sendInput(pty, '\r'); + + // Wait for the selection screen to disappear and build to start + await waitForText(page, 'Building', 10000); + + // Take a screenshot after selection + const afterSelectPath = await captureStableScreenshot(page, 'after-select'); + + return { + beforeNavPath, + afterNav1Path, + afterNav2Path, + afterSelectPath, + }; +}; + +/** + * Draw simple text on an image + * @param {any} png - The PNG image + * @param {number} x - X coordinate + * @param {number} y - Y coordinate + * @param {string} text - Text to draw + * @param {number[]} color - RGB color array [r, g, b] + */ +const drawText = (png, x, y, text, color = [255, 255, 255]) => { + const width = png.width; + + // Simple 5x7 pixel font for basic characters + const font = { + B: [ + [1, 1, 1, 0, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 1, 1, 0, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 1, 1, 0, 0], + ], + a: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 1, 1, 0, 0], + [0, 0, 0, 1, 0], + [0, 1, 1, 1, 0], + [1, 0, 0, 1, 0], + [0, 1, 1, 1, 0], + ], + s: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 1, 1, 1, 0], + [1, 0, 0, 0, 0], + [0, 1, 1, 0, 0], + [0, 0, 0, 1, 0], + [1, 1, 1, 0, 0], + ], + e: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 1, 1, 0, 0], + [1, 0, 0, 1, 0], + [1, 1, 1, 1, 0], + [1, 0, 0, 0, 0], + [0, 1, 1, 1, 0], + ], + l: [ + [0, 1, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 1, 1, 1, 0], + ], + i: [ + [0, 0, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + ], + n: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [1, 0, 1, 0, 0], + [1, 1, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + ], + C: [ + [0, 1, 1, 1, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [0, 1, 1, 1, 0], + ], + u: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [0, 1, 1, 1, 0], + ], + r: [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [1, 0, 1, 1, 0], + [1, 1, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + [1, 0, 0, 0, 0], + ], + t: [ + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 1, 1, 1, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + ], + D: [ + [1, 1, 1, 0, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 0, 0, 1, 0], + [1, 1, 1, 0, 0], + ], + f: [ + [0, 0, 1, 1, 0], + [0, 1, 0, 0, 0], + [1, 1, 1, 0, 0], + [0, 1, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 1, 0, 0, 0], + ], + ' ': [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + ], + ':': [ + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 0, 0], + ], + }; + + let currentX = x; + + // Draw each character + for (let i = 0; i < text.length; i++) { + const char = text[i]; + const charPattern = font[char] || font[' ']; // Default to space if character not found + + for (let row = 0; row < charPattern.length; row++) { + for (let col = 0; col < charPattern[0].length; col++) { + if (charPattern[row][col]) { + const pixelX = currentX + col; + const pixelY = y + row; + const idx = (pixelY * width + pixelX) << 2; + + // @ts-ignore - png.data is a valid property but TypeScript doesn't recognize it + png.data[idx] = color[0]; // R + // @ts-ignore - png.data is a valid property but TypeScript doesn't recognize it + png.data[idx + 1] = color[1]; // G + // @ts-ignore - png.data is a valid property but TypeScript doesn't recognize it + png.data[idx + 2] = color[2]; // B + // @ts-ignore - png.data is a valid property but TypeScript doesn't recognize it + png.data[idx + 3] = 255; // A + } + } + } + + currentX += 6; // Character width + 1 pixel spacing + } +}; + +/** + * Launch a Puppeteer browser for testing the terminal UI + * @param {boolean} headless - Whether to run the browser in headless mode + * @param {Object} viewportOptions - Options for viewport size + * @returns {Promise<{browser: any, page: any}>} - Browser and page objects + */ +const launchBrowser = async ( + headless = true, + viewportOptions = { width: 1200, height: 800 }, +) => { + const browser = await puppeteer.launch({ + headless, + defaultViewport: viewportOptions, + args: ['--start-maximized'], // Start with maximized window + }); + + const page = await browser.newPage(); + await page.setViewport(viewportOptions); + + return { browser, page }; +}; + +/** + * Set up the terminal environment for testing + * @param {any} page - Puppeteer page + * @param {string} htmlPath - Path to the HTML file + * @returns {Promise<{dimensions: {cols: number, rows: number}}>} - Terminal dimensions + */ +const setupTerminal = async (page, htmlPath) => { + await page.goto(`file://${htmlPath}`); + + // Wait for the page to load and terminal to initialize + await page.waitForFunction(() => typeof window.fitTerminal === 'function'); + + // Fit terminal to viewport and get dimensions + const dimensions = await page.evaluate(() => { + // @ts-ignore - Custom method added via browser script + return window.fitTerminal(); + }); + + console.log(`Terminal dimensions: ${dimensions.cols}x${dimensions.rows}`); + + return { dimensions }; +}; + +/** + * Spawn a terminal process for testing + * @param {number} cols - Number of columns + * @param {number} rows - Number of rows + * @param {string} command - Command to run + * @param {string[]} args - Arguments for the command + * @param {Object} options - Additional options + * @returns {any} - The spawned process + */ +const spawnTerminalProcess = (cols, rows, command, args, options = {}) => { + return spawn(command, args, { + name: 'xterm-color', + cols: cols || 80, + rows: rows || 24, + cwd: process.cwd(), + env: { + ...process.env, + ...(options.env || {}), + }, + }); +}; + +module.exports = { + compareImages, + verifyAgainstBaseline, + createHtmlFile, + sendInput, + waitForText, + waitForCondition, + captureStableScreenshot, + navigateTUI, + drawText, + launchBrowser, + setupTerminal, + spawnTerminalProcess, +};