From bb509b4318aae925a973733a5365cac442278023 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 23:07:41 +0000 Subject: [PATCH 01/14] Initial plan From f4962907efbd1d448fda00eae5e9c1ba34ba7ec1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 23:18:20 +0000 Subject: [PATCH 02/14] Add VS Code extension platform for learningmap files - Create platforms/vscode with extension, custom editor provider, and webview - Add build script for bundling extension and webview separately - Support for opening .learningmap files with visual editor - Add command for creating new learningmap files - Auto-save changes back to file - Support for empty .learningmap files Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- platforms/vscode/.vscodeignore | 8 + platforms/vscode/README.md | 42 + platforms/vscode/package.json | 58 + .../vscode/src/LearningmapEditorProvider.ts | 134 ++ platforms/vscode/src/extension.ts | 79 + platforms/vscode/src/webview.tsx | 105 ++ platforms/vscode/tsconfig.json | 15 + pnpm-lock.yaml | 1679 ++++++++++++++++- scripts/build-vscode.mjs | 102 + 9 files changed, 2219 insertions(+), 3 deletions(-) create mode 100644 platforms/vscode/.vscodeignore create mode 100644 platforms/vscode/README.md create mode 100644 platforms/vscode/package.json create mode 100644 platforms/vscode/src/LearningmapEditorProvider.ts create mode 100644 platforms/vscode/src/extension.ts create mode 100644 platforms/vscode/src/webview.tsx create mode 100644 platforms/vscode/tsconfig.json create mode 100644 scripts/build-vscode.mjs diff --git a/platforms/vscode/.vscodeignore b/platforms/vscode/.vscodeignore new file mode 100644 index 0000000..b8c8ae9 --- /dev/null +++ b/platforms/vscode/.vscodeignore @@ -0,0 +1,8 @@ +.vscode/** +.vscode-test/** +src/** +.gitignore +.prettierrc +tsconfig.json +node_modules/** +*.map diff --git a/platforms/vscode/README.md b/platforms/vscode/README.md new file mode 100644 index 0000000..c41f833 --- /dev/null +++ b/platforms/vscode/README.md @@ -0,0 +1,42 @@ +# Learningmap VS Code Extension + +Visual editor for `.learningmap` files in VS Code. + +## Features + +- **Custom Editor**: Opens `.learningmap` files with a visual editor +- **Create New**: Command to create new learningmap files +- **Auto-save**: Changes are automatically saved to the file +- **Empty File Support**: Can open and edit empty `.learningmap` files + +## Usage + +### Opening a Learningmap File + +Simply open any file with the `.learningmap` extension, and the visual editor will automatically open. + +### Creating a New Learningmap + +1. Open the Command Palette (`Ctrl+Shift+P` or `Cmd+Shift+P`) +2. Run the command `Learningmap: New Learningmap` +3. Enter a name for your learningmap +4. The editor will open automatically + +### Editing + +Use the visual editor to: +- Add nodes (topics, tasks, text, images) +- Connect nodes with edges +- Configure node properties +- Set up completion and unlock conditions +- Preview your learningmap + +Changes are automatically saved to the file. + +## Requirements + +- VS Code 1.80.0 or higher + +## License + +MIT diff --git a/platforms/vscode/package.json b/platforms/vscode/package.json new file mode 100644 index 0000000..c7c6815 --- /dev/null +++ b/platforms/vscode/package.json @@ -0,0 +1,58 @@ +{ + "name": "learningmap-vscode", + "displayName": "Learningmap Editor", + "description": "Visual editor for learningmap files", + "version": "0.1.0", + "publisher": "openpatch", + "author": "Mike Barkmin", + "license": "MIT", + "private": true, + "engines": { + "vscode": "^1.80.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [], + "main": "./dist/extension.js", + "contributes": { + "customEditors": [ + { + "viewType": "learningmap.editor", + "displayName": "Learningmap Editor", + "selector": [ + { + "filenamePattern": "*.learningmap" + } + ], + "priority": "default" + } + ], + "commands": [ + { + "command": "learningmap.new", + "title": "New Learningmap", + "category": "Learningmap" + } + ] + }, + "scripts": { + "build": "node ../../scripts/build-vscode.mjs", + "lint": "tsc --noEmit", + "watch": "node ../../scripts/build-vscode.mjs --watch", + "package": "vsce package" + }, + "dependencies": { + "@learningmap/learningmap": "workspace:*", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@types/vscode": "^1.80.0", + "@types/node": "^24.7.2", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.1", + "@vscode/vsce": "^3.2.1", + "typescript": "~5.9.3" + } +} diff --git a/platforms/vscode/src/LearningmapEditorProvider.ts b/platforms/vscode/src/LearningmapEditorProvider.ts new file mode 100644 index 0000000..5b10f8f --- /dev/null +++ b/platforms/vscode/src/LearningmapEditorProvider.ts @@ -0,0 +1,134 @@ +import * as vscode from 'vscode'; + +/** + * Provider for learningmap custom editor. + * Handles the webview that displays the LearningMapEditor component. + */ +export class LearningmapEditorProvider implements vscode.CustomTextEditorProvider { + private static readonly viewType = 'learningmap.editor'; + + constructor(private readonly context: vscode.ExtensionContext) {} + + /** + * Called when our custom editor is opened. + */ + public async resolveCustomTextEditor( + document: vscode.TextDocument, + webviewPanel: vscode.WebviewPanel, + _token: vscode.CancellationToken + ): Promise { + // Setup initial webview content + webviewPanel.webview.options = { + enableScripts: true, + }; + webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview); + + // Hook up event handlers + const updateWebview = () => { + webviewPanel.webview.postMessage({ + type: 'update', + content: document.getText(), + }); + }; + + // Send initial content + updateWebview(); + + // Listen for changes in the document + const changeDocumentSubscription = vscode.workspace.onDidChangeTextDocument(e => { + if (e.document.uri.toString() === document.uri.toString()) { + updateWebview(); + } + }); + + // Listen for messages from the webview + webviewPanel.webview.onDidReceiveMessage(e => { + switch (e.type) { + case 'save': + this.saveDocument(document, e.content); + return; + case 'ready': + // Webview is ready, send initial content + updateWebview(); + return; + } + }); + + // Clean up + webviewPanel.onDidDispose(() => { + changeDocumentSubscription.dispose(); + }); + } + + /** + * Write out the JSON to a given document. + */ + private async saveDocument(document: vscode.TextDocument, json: any): Promise { + const edit = new vscode.WorkspaceEdit(); + + // Format the JSON with 2-space indentation + const text = JSON.stringify(json, null, 2); + + // Replace the entire document + edit.replace( + document.uri, + new vscode.Range(0, 0, document.lineCount, 0), + text + ); + + await vscode.workspace.applyEdit(edit); + } + + /** + * Get the static HTML for the webview. + */ + private getHtmlForWebview(webview: vscode.Webview): string { + // Get URIs for scripts and styles + const scriptUri = webview.asWebviewUri( + vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'webview.js') + ); + const styleUri = webview.asWebviewUri( + vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'webview.css') + ); + + // Use a nonce to only allow specific scripts to be run + const nonce = getNonce(); + + return ` + + + + + + + Learningmap Editor + + + +
+ + +`; + } +} + +function getNonce() { + let text = ''; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +} diff --git a/platforms/vscode/src/extension.ts b/platforms/vscode/src/extension.ts new file mode 100644 index 0000000..a625e44 --- /dev/null +++ b/platforms/vscode/src/extension.ts @@ -0,0 +1,79 @@ +import * as vscode from 'vscode'; +import { LearningmapEditorProvider } from './LearningmapEditorProvider'; + +export function activate(context: vscode.ExtensionContext) { + // Register the custom editor provider + const provider = new LearningmapEditorProvider(context); + context.subscriptions.push( + vscode.window.registerCustomEditorProvider( + 'learningmap.editor', + provider, + { + webviewOptions: { + retainContextWhenHidden: true, + }, + supportsMultipleEditorsPerDocument: false, + } + ) + ); + + // Register command to create a new learningmap + context.subscriptions.push( + vscode.commands.registerCommand('learningmap.new', async () => { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (!workspaceFolders) { + vscode.window.showErrorMessage('Please open a folder or workspace first'); + return; + } + + // Ask for filename + const filename = await vscode.window.showInputBox({ + prompt: 'Enter the name for your new learningmap', + placeHolder: 'my-learningmap', + validateInput: (value) => { + if (!value) { + return 'Filename is required'; + } + if (!/^[a-zA-Z0-9_-]+$/.test(value)) { + return 'Filename can only contain letters, numbers, hyphens, and underscores'; + } + return null; + } + }); + + if (!filename) { + return; + } + + // Create empty learningmap file + const uri = vscode.Uri.joinPath( + workspaceFolders[0].uri, + `${filename}.learningmap` + ); + + // Initial empty learningmap structure + const emptyLearningmap = { + nodes: [], + edges: [], + settings: { + background: { color: '#ffffff' } + }, + version: 1, + type: 'learningmap', + source: 'vscode-extension' + }; + + await vscode.workspace.fs.writeFile( + uri, + Buffer.from(JSON.stringify(emptyLearningmap, null, 2), 'utf8') + ); + + // Open the file with our custom editor + await vscode.commands.executeCommand('vscode.openWith', uri, 'learningmap.editor'); + }) + ); + + console.log('Learningmap extension is now active'); +} + +export function deactivate() {} diff --git a/platforms/vscode/src/webview.tsx b/platforms/vscode/src/webview.tsx new file mode 100644 index 0000000..e664c80 --- /dev/null +++ b/platforms/vscode/src/webview.tsx @@ -0,0 +1,105 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { createRoot } from 'react-dom/client'; +import { LearningMapEditor, useEditorStore, RoadmapData } from '@learningmap/learningmap'; +import '@learningmap/learningmap/index.css'; + +// VS Code API +declare const acquireVsCodeApi: any; +const vscode = acquireVsCodeApi(); + +interface VSCodeMessage { + type: string; + content?: string; +} + +/** + * Main webview component that wraps the LearningMapEditor. + * Handles communication with the VS Code extension. + */ +function WebviewEditor() { + const [isReady, setIsReady] = useState(false); + const [initialData, setInitialData] = useState(null); + + // Get store methods + const getRoadmapData = useEditorStore(state => state.getRoadmapData); + const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); + + // Handle messages from extension + useEffect(() => { + const messageHandler = (event: MessageEvent) => { + const message = event.data; + switch (message.type) { + case 'update': + // Load the content from the file + try { + if (message.content) { + const data = JSON.parse(message.content); + loadRoadmapData(data); + } else { + // Empty file - load empty structure + loadRoadmapData({ + nodes: [], + edges: [], + settings: { background: { color: '#ffffff' } }, + version: 1, + type: 'learningmap', + } as RoadmapData); + } + } catch (e) { + console.error('Failed to parse learningmap content', e); + // If parsing fails, initialize with empty structure + loadRoadmapData({ + nodes: [], + edges: [], + settings: { background: { color: '#ffffff' } }, + version: 1, + type: 'learningmap', + } as RoadmapData); + } + break; + } + }; + + window.addEventListener('message', messageHandler); + + // Signal that webview is ready + vscode.postMessage({ type: 'ready' }); + setIsReady(true); + + return () => { + window.removeEventListener('message', messageHandler); + }; + }, [loadRoadmapData]); + + // Auto-save changes to the document + useEffect(() => { + if (!isReady) return; + + // Subscribe to store changes + const unsubscribe = useEditorStore.subscribe((state) => { + // Save the current roadmap data back to VS Code + const data = getRoadmapData(); + vscode.postMessage({ + type: 'save', + content: data, + }); + }); + + return () => { + unsubscribe(); + }; + }, [isReady, getRoadmapData]); + + if (!isReady) { + return
Loading editor...
; + } + + return ; +} + +// Mount the React component +const container = document.getElementById('root'); +if (container) { + const root = createRoot(container); + root.render(); +} diff --git a/platforms/vscode/tsconfig.json b/platforms/vscode/tsconfig.json new file mode 100644 index 0000000..2b41b83 --- /dev/null +++ b/platforms/vscode/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "target": "ES2022", + "outDir": "./dist", + "lib": ["ES2022", "DOM"], + "sourceMap": true, + "rootDir": "./src", + "strict": true, + "noImplicitAny": true, + "jsx": "react" + }, + "include": ["src/**/*"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 53c183c..512737a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,6 +152,37 @@ importers: specifier: ^7.1.9 version: 7.1.12(@types/node@24.7.2)(terser@5.44.0) + platforms/vscode: + dependencies: + '@learningmap/learningmap': + specifier: workspace:* + version: link:../../packages/learningmap + react: + specifier: ^19.2.0 + version: 19.2.0 + react-dom: + specifier: ^19.2.0 + version: 19.2.0(react@19.2.0) + devDependencies: + '@types/node': + specifier: ^24.7.2 + version: 24.7.2 + '@types/react': + specifier: ^19.2.2 + version: 19.2.2 + '@types/react-dom': + specifier: ^19.2.1 + version: 19.2.2(@types/react@19.2.2) + '@types/vscode': + specifier: ^1.80.0 + version: 1.105.0 + '@vscode/vsce': + specifier: ^3.2.1 + version: 3.6.2 + typescript: + specifier: ~5.9.3 + version: 5.9.3 + platforms/web: dependencies: '@learningmap/learningmap': @@ -221,6 +252,56 @@ packages: peerDependencies: ajv: '>=8' + '@azu/format-text@1.0.2': + resolution: {integrity: sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==} + + '@azu/style-format@1.0.1': + resolution: {integrity: sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==} + + '@azure/abort-controller@2.1.2': + resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} + engines: {node: '>=18.0.0'} + + '@azure/core-auth@1.10.1': + resolution: {integrity: sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==} + engines: {node: '>=20.0.0'} + + '@azure/core-client@1.10.1': + resolution: {integrity: sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==} + engines: {node: '>=20.0.0'} + + '@azure/core-rest-pipeline@1.22.1': + resolution: {integrity: sha512-UVZlVLfLyz6g3Hy7GNDpooMQonUygH7ghdiSASOOHy97fKj/mPLqgDX7aidOijn+sCMU+WU8NjlPlNTgnvbcGA==} + engines: {node: '>=20.0.0'} + + '@azure/core-tracing@1.3.1': + resolution: {integrity: sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==} + engines: {node: '>=20.0.0'} + + '@azure/core-util@1.13.1': + resolution: {integrity: sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==} + engines: {node: '>=20.0.0'} + + '@azure/identity@4.13.0': + resolution: {integrity: sha512-uWC0fssc+hs1TGGVkkghiaFkkS7NkTxfnCH+Hdg+yTehTpMcehpok4PgUKKdyCH+9ldu6FhiHRv84Ntqj1vVcw==} + engines: {node: '>=20.0.0'} + + '@azure/logger@1.3.0': + resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} + engines: {node: '>=20.0.0'} + + '@azure/msal-browser@4.26.0': + resolution: {integrity: sha512-Ie3SZ4IMrf9lSwWVzzJrhTPE+g9+QDUfeor1LKMBQzcblp+3J/U1G8hMpNSfLL7eA5F/DjjPXkATJ5JRUdDJLA==} + engines: {node: '>=0.8.0'} + + '@azure/msal-common@15.13.1': + resolution: {integrity: sha512-vQYQcG4J43UWgo1lj7LcmdsGUKWYo28RfEvDQAEMmQIMjSFufvb+pS0FJ3KXmrPmnWlt1vHDl3oip6mIDUQ4uA==} + engines: {node: '>=0.8.0'} + + '@azure/msal-node@3.8.1': + resolution: {integrity: sha512-HszfqoC+i2C9+BRDQfuNUGp15Re7menIhCEbFCQ49D3KaqEDrgZIgQ8zSct4T59jWeUIL9N/Dwiv4o2VueTdqQ==} + engines: {node: '>=16'} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -1255,6 +1336,55 @@ packages: cpu: [x64] os: [win32] + '@secretlint/config-creator@10.2.2': + resolution: {integrity: sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==} + engines: {node: '>=20.0.0'} + + '@secretlint/config-loader@10.2.2': + resolution: {integrity: sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==} + engines: {node: '>=20.0.0'} + + '@secretlint/core@10.2.2': + resolution: {integrity: sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==} + engines: {node: '>=20.0.0'} + + '@secretlint/formatter@10.2.2': + resolution: {integrity: sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==} + engines: {node: '>=20.0.0'} + + '@secretlint/node@10.2.2': + resolution: {integrity: sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==} + engines: {node: '>=20.0.0'} + + '@secretlint/profiler@10.2.2': + resolution: {integrity: sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==} + + '@secretlint/resolver@10.2.2': + resolution: {integrity: sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==} + + '@secretlint/secretlint-formatter-sarif@10.2.2': + resolution: {integrity: sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==} + + '@secretlint/secretlint-rule-no-dotenv@10.2.2': + resolution: {integrity: sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==} + engines: {node: '>=20.0.0'} + + '@secretlint/secretlint-rule-preset-recommend@10.2.2': + resolution: {integrity: sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==} + engines: {node: '>=20.0.0'} + + '@secretlint/source-creator@10.2.2': + resolution: {integrity: sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==} + engines: {node: '>=20.0.0'} + + '@secretlint/types@10.2.2': + resolution: {integrity: sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==} + engines: {node: '>=20.0.0'} + + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + '@surma/rollup-plugin-off-main-thread@2.2.3': resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} @@ -1264,6 +1394,21 @@ packages: react: '>=16.14.0' react-dom: '>=16.14.0' + '@textlint/ast-node-types@15.2.3': + resolution: {integrity: sha512-GEhoxfmh6TF+xC8TJmAUwOzzh0J6sVDqjKhwTTwetf7YDdhHbIv1PuUb/dTadMVIWs1H0+JD4Y27n6LWMmqn9Q==} + + '@textlint/linter-formatter@15.2.3': + resolution: {integrity: sha512-gnFGl8MejAS4rRDPKV2OYvU0Tb0iJySOPDahf+RCK30b615UqY6CjqWxXw1FvXfT3pHPoRrefVu39j1AKm2ezg==} + + '@textlint/module-interop@15.2.3': + resolution: {integrity: sha512-dV6M3ptOFJjR5bgYUMeVqc8AqFrMtCEFaZEiLAfMufX29asYonI2K8arqivOA69S2Lh6esyij6V7qpQiXeK/cA==} + + '@textlint/resolver@15.2.3': + resolution: {integrity: sha512-Qd3udqo2sWa3u0sYgDVd9M/iybBVBJLrWGaID6Yzl9GyhdGi0E6ngo3b9r+H6psbJDIaCKi54IxvC9q5didWfA==} + + '@textlint/types@15.2.3': + resolution: {integrity: sha512-i8XVmDHJwykMXcGgkSxZLjdbeqnl+voYAcIr94KIe0STwgkHIhwHJgb/tEVFawGClHo+gPczF12l1C5+TAZEzQ==} + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -1337,6 +1482,9 @@ packages: '@types/node@24.7.2': resolution: {integrity: sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==} + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/react-dom@19.2.2': resolution: {integrity: sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==} peerDependencies: @@ -1348,12 +1496,18 @@ packages: '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + '@types/sarif@2.1.7': + resolution: {integrity: sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==} + '@types/throttle-debounce@5.0.2': resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==} '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/vscode@1.105.0': + resolution: {integrity: sha512-Lotk3CTFlGZN8ray4VxJE7axIyLZZETQJVWi/lYoUVQuqfRxlQhVOfoejsD2V3dVXPSbS15ov5ZyowMAzgUqcw==} + '@typescript-eslint/eslint-plugin@8.46.2': resolution: {integrity: sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1413,6 +1567,10 @@ packages: resolution: {integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typespec/ts-http-runtime@0.3.1': + resolution: {integrity: sha512-SnbaqayTVFEA6/tYumdF0UmybY0KHyKwGPBXnyckFlrrKdhWFrL3a2HIPXHjht5ZOElKGcXfD2D63P36btb+ww==} + engines: {node: '>=20.0.0'} + '@vitejs/plugin-react@5.1.0': resolution: {integrity: sha512-4LuWrg7EKWgQaMJfnN+wcmbAW+VSsCmqGohftWjuct47bv8uE4n/nPpq4XjJPsxgq00GGG5J8dvBczp8uxScew==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1448,6 +1606,59 @@ packages: '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vscode/vsce-sign-alpine-arm64@2.0.6': + resolution: {integrity: sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==} + cpu: [arm64] + os: [alpine] + + '@vscode/vsce-sign-alpine-x64@2.0.6': + resolution: {integrity: sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==} + cpu: [x64] + os: [alpine] + + '@vscode/vsce-sign-darwin-arm64@2.0.2': + resolution: {integrity: sha512-rz8F4pMcxPj8fjKAJIfkUT8ycG9CjIp888VY/6pq6cuI2qEzQ0+b5p3xb74CJnBbSC0p2eRVoe+WgNCAxCLtzQ==} + cpu: [arm64] + os: [darwin] + + '@vscode/vsce-sign-darwin-x64@2.0.2': + resolution: {integrity: sha512-MCjPrQ5MY/QVoZ6n0D92jcRb7eYvxAujG/AH2yM6lI0BspvJQxp0o9s5oiAM9r32r9tkLpiy5s2icsbwefAQIw==} + cpu: [x64] + os: [darwin] + + '@vscode/vsce-sign-linux-arm64@2.0.6': + resolution: {integrity: sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==} + cpu: [arm64] + os: [linux] + + '@vscode/vsce-sign-linux-arm@2.0.6': + resolution: {integrity: sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==} + cpu: [arm] + os: [linux] + + '@vscode/vsce-sign-linux-x64@2.0.6': + resolution: {integrity: sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==} + cpu: [x64] + os: [linux] + + '@vscode/vsce-sign-win32-arm64@2.0.6': + resolution: {integrity: sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==} + cpu: [arm64] + os: [win32] + + '@vscode/vsce-sign-win32-x64@2.0.6': + resolution: {integrity: sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==} + cpu: [x64] + os: [win32] + + '@vscode/vsce-sign@2.0.8': + resolution: {integrity: sha512-H7p8E11cZMj6mt8xIi3QXZ7dSU/2MH3Y7c+5JfUhHAV4xfaPNc8ozwLVK282c6ah596KoIJIdPUlNHV7Qs/5JA==} + + '@vscode/vsce@3.6.2': + resolution: {integrity: sha512-gvBfarWF+Ii20ESqjA3dpnPJpQJ8fFJYtcWtjwbRADommCzGg1emtmb34E+DKKhECYvaVyAl+TF9lWS/3GSPvg==} + engines: {node: '>= 20'} + hasBin: true + '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -1528,6 +1739,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -1551,6 +1766,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@7.1.1: + resolution: {integrity: sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1592,6 +1811,10 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -1599,6 +1822,9 @@ packages: async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} @@ -1607,6 +1833,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + azure-devops-node-api@12.5.0: + resolution: {integrity: sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==} + babel-plugin-polyfill-corejs2@0.4.14: resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} peerDependencies: @@ -1625,6 +1854,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.8.23: resolution: {integrity: sha512-616V5YX4bepJFzNyOfce5Fa8fDJMfoxzOIzDCZwaGL8MKVpFrXqfNUoIpRn9YMI5pXf/VKgzjB4htFMsFKKdiQ==} hasBin: true @@ -1633,6 +1865,19 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + binaryextensions@6.11.0: + resolution: {integrity: sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==} + engines: {node: '>=4'} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + boundary@2.0.0: + resolution: {integrity: sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1648,9 +1893,22 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -1693,10 +1951,20 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.1.2: + resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} + engines: {node: '>=20.18.1'} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} @@ -1708,6 +1976,10 @@ packages: classcat@5.0.5: resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} + cockatiel@3.2.1: + resolution: {integrity: sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==} + engines: {node: '>=16'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1715,6 +1987,14 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -1751,6 +2031,13 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -1816,10 +2103,18 @@ packages: supports-color: optional: true + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1827,18 +2122,38 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + default-browser-id@5.0.0: + resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} + engines: {node: '>=18'} + + default-browser@5.2.1: + resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} + engines: {node: '>=18'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -1847,9 +2162,22 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dompurify@3.3.0: resolution: {integrity: sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==} + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dotenv@8.6.0: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} @@ -1861,6 +2189,13 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + editions@6.22.0: + resolution: {integrity: sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==} + engines: {ecmascript: '>= es5', node: '>=4'} + ejs@3.1.10: resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} @@ -1878,6 +2213,12 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + enhanced-resolve@5.18.3: resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} @@ -1886,6 +2227,18 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + es-abstract@1.24.0: resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} @@ -2005,6 +2358,10 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + expect-type@1.2.2: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} @@ -2031,6 +2388,9 @@ packages: fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2074,6 +2434,17 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@11.3.2: + resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + engines: {node: '>=14.14'} + fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -2127,6 +2498,9 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2163,6 +2537,10 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} + engines: {node: '>=18'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -2206,9 +2584,28 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + + hosted-git-info@7.0.2: + resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} + engines: {node: ^16.14.0 || >=18.0.0} + html-to-image@1.11.13: resolution: {integrity: sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==} + htmlparser2@10.0.0: + resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-id@4.1.2: resolution: {integrity: sha512-v/J+4Z/1eIJovEBdlV5TYj1IR+ZiohcYGRY+qN/oC9dAfKzVT023N/Bgw37hrKCoVRBvk3bqyzpr2PP5YeTMSg==} hasBin: true @@ -2218,6 +2615,10 @@ packages: engines: {node: '>=18'} hasBin: true + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + iconv-lite@0.7.0: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} @@ -2225,6 +2626,9 @@ packages: idb@7.1.1: resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -2241,6 +2645,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -2248,6 +2656,9 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -2284,6 +2695,11 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2304,6 +2720,11 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -2379,12 +2800,20 @@ packages: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} + is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + istextorbinary@9.5.0: + resolution: {integrity: sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==} + engines: {node: '>=4'} + jackspeak@4.1.1: resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} engines: {node: 20 || >=22} @@ -2440,6 +2869,9 @@ packages: engines: {node: '>=6'} hasBin: true + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -2450,6 +2882,19 @@ packages: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} + jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + + jwa@1.4.2: + resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} + + jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + + keytar@7.9.0: + resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -2461,6 +2906,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + loader-runner@4.3.1: resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} @@ -2476,21 +2924,48 @@ packages: lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.2.2: resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} engines: {node: 20 || >=22} @@ -2498,6 +2973,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + lucide-react@0.545.0: resolution: {integrity: sha512-7r1/yUuflQDSt4f1bpn5ZAocyIxcTyVyBBChSVtBKn5M+392cPmI5YJMWOJKk/HUWGm5wg83chlAZtCcGbEZtw==} peerDependencies: @@ -2512,6 +2991,10 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + marked@16.4.1: resolution: {integrity: sha512-ntROs7RaN3EvWfy3EZi14H4YxmT6A5YvywfhO+0pm+cH/dnSQRmdAmoFIc3B9aiwTehyk7pESH4ofyBY+V5hZg==} engines: {node: '>= 20'} @@ -2521,6 +3004,9 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -2540,6 +3026,15 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimatch@10.1.1: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} @@ -2555,10 +3050,16 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -2566,17 +3067,30 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + node-abi@3.80.0: + resolution: {integrity: sha512-LyPuZJcI9HVwzXK1GPxWNzrr+vr8Hp/3UqlmWxxh8p54U1ZbclOqbSog9lWHaCX+dBaiGi6n/hIX+mKu74GmPA==} + engines: {node: '>=10'} + + node-addon-api@4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -2589,6 +3103,17 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + node-sarif-builder@3.2.0: + resolution: {integrity: sha512-kVIOdynrF2CRodHZeP/97Rh1syTUHBNiw17hUCIVhlhEsWlfJm19MuO56s4MdKbr22xWx6mzMnNAgXzVlIYM9Q==} + engines: {node: '>=18'} + + normalize-package-data@6.0.2: + resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} + engines: {node: ^16.14.0 || >=18.0.0} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -2604,6 +3129,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -2639,6 +3168,10 @@ packages: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} engines: {node: '>=6'} + p-map@7.0.3: + resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} + engines: {node: '>=18'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -2653,6 +3186,22 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + + parse-semver@1.1.1: + resolution: {integrity: sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==} + + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2676,6 +3225,10 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -2683,6 +3236,9 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2698,6 +3254,13 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + pluralize@2.0.0: + resolution: {integrity: sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -2706,6 +3269,11 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -2741,10 +3309,21 @@ packages: peerDependencies: prettier: ^3.0.0 + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} @@ -2754,8 +3333,15 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - react-dom@19.2.0: - resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + rc-config-loader@4.1.3: + resolution: {integrity: sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-dom@19.2.0: + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} peerDependencies: react: ^19.2.0 @@ -2790,10 +3376,22 @@ packages: resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} engines: {node: '>=0.10.0'} + read-pkg@9.0.1: + resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} + engines: {node: '>=18'} + read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + read@1.0.7: + resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} + engines: {node: '>=0.8'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -2860,6 +3458,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -2881,6 +3483,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -2888,6 +3493,15 @@ packages: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} + secretlint@10.2.2: + resolution: {integrity: sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==} + engines: {node: '>=20.0.0'} + hasBin: true + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2946,10 +3560,24 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} @@ -2976,6 +3604,18 @@ packages: spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.22: + resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -3013,6 +3653,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-object@3.3.0: resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} engines: {node: '>=4'} @@ -3033,6 +3676,10 @@ packages: resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} engines: {node: '>=10'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -3040,6 +3687,9 @@ packages: strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + structured-source@4.0.0: + resolution: {integrity: sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -3048,14 +3698,29 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + temp-dir@2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} engines: {node: '>=8'} @@ -3068,6 +3733,10 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + terminal-link@4.0.0: + resolution: {integrity: sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==} + engines: {node: '>=18'} + terser-webpack-plugin@5.3.14: resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} engines: {node: '>= 10.13.0'} @@ -3089,6 +3758,13 @@ packages: engines: {node: '>=10'} hasBin: true + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + textextensions@6.11.0: + resolution: {integrity: sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==} + engines: {node: '>=4'} + throttle-debounce@5.0.2: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} @@ -3115,6 +3791,10 @@ packages: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -3148,6 +3828,13 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -3156,6 +3843,10 @@ packages: resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} engines: {node: '>=10'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -3172,6 +3863,9 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typed-rest-client@1.8.11: + resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} + typescript-eslint@8.46.2: resolution: {integrity: sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3184,13 +3878,23 @@ packages: engines: {node: '>=14.17'} hasBin: true + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + underscore@1.13.7: + resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} + undici-types@7.14.0: resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==} + undici@7.16.0: + resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} + engines: {node: '>=20.18.1'} + unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -3207,6 +3911,14 @@ packages: resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} engines: {node: '>=4'} + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + unique-string@2.0.0: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} @@ -3232,14 +3944,31 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-join@4.0.1: + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + version-range@4.15.0: + resolution: {integrity: sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==} + engines: {node: '>=4'} + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -3353,6 +4082,14 @@ packages: webpack-cli: optional: true + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -3449,9 +4186,30 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + + xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yazl@2.5.1: + resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} + yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -3516,6 +4274,95 @@ snapshots: jsonpointer: 5.0.1 leven: 3.1.0 + '@azu/format-text@1.0.2': {} + + '@azu/style-format@1.0.1': + dependencies: + '@azu/format-text': 1.0.2 + + '@azure/abort-controller@2.1.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-auth@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-client@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-rest-pipeline': 1.22.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-rest-pipeline@1.22.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@typespec/ts-http-runtime': 0.3.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-tracing@1.3.1': + dependencies: + tslib: 2.8.1 + + '@azure/core-util@1.13.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@typespec/ts-http-runtime': 0.3.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/identity@4.13.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-rest-pipeline': 1.22.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@azure/msal-browser': 4.26.0 + '@azure/msal-node': 3.8.1 + open: 10.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/logger@1.3.0': + dependencies: + '@typespec/ts-http-runtime': 0.3.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/msal-browser@4.26.0': + dependencies: + '@azure/msal-common': 15.13.1 + + '@azure/msal-common@15.13.1': {} + + '@azure/msal-node@3.8.1': + dependencies: + '@azure/msal-common': 15.13.1 + jsonwebtoken: 9.0.2 + uuid: 8.3.2 + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -4704,6 +5551,82 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.52.5': optional: true + '@secretlint/config-creator@10.2.2': + dependencies: + '@secretlint/types': 10.2.2 + + '@secretlint/config-loader@10.2.2': + dependencies: + '@secretlint/profiler': 10.2.2 + '@secretlint/resolver': 10.2.2 + '@secretlint/types': 10.2.2 + ajv: 8.17.1 + debug: 4.4.3 + rc-config-loader: 4.1.3 + transitivePeerDependencies: + - supports-color + + '@secretlint/core@10.2.2': + dependencies: + '@secretlint/profiler': 10.2.2 + '@secretlint/types': 10.2.2 + debug: 4.4.3 + structured-source: 4.0.0 + transitivePeerDependencies: + - supports-color + + '@secretlint/formatter@10.2.2': + dependencies: + '@secretlint/resolver': 10.2.2 + '@secretlint/types': 10.2.2 + '@textlint/linter-formatter': 15.2.3 + '@textlint/module-interop': 15.2.3 + '@textlint/types': 15.2.3 + chalk: 5.6.2 + debug: 4.4.3 + pluralize: 8.0.0 + strip-ansi: 7.1.2 + table: 6.9.0 + terminal-link: 4.0.0 + transitivePeerDependencies: + - supports-color + + '@secretlint/node@10.2.2': + dependencies: + '@secretlint/config-loader': 10.2.2 + '@secretlint/core': 10.2.2 + '@secretlint/formatter': 10.2.2 + '@secretlint/profiler': 10.2.2 + '@secretlint/source-creator': 10.2.2 + '@secretlint/types': 10.2.2 + debug: 4.4.3 + p-map: 7.0.3 + transitivePeerDependencies: + - supports-color + + '@secretlint/profiler@10.2.2': {} + + '@secretlint/resolver@10.2.2': {} + + '@secretlint/secretlint-formatter-sarif@10.2.2': + dependencies: + node-sarif-builder: 3.2.0 + + '@secretlint/secretlint-rule-no-dotenv@10.2.2': + dependencies: + '@secretlint/types': 10.2.2 + + '@secretlint/secretlint-rule-preset-recommend@10.2.2': {} + + '@secretlint/source-creator@10.2.2': + dependencies: + '@secretlint/types': 10.2.2 + istextorbinary: 9.5.0 + + '@secretlint/types@10.2.2': {} + + '@sindresorhus/merge-streams@2.3.0': {} + '@surma/rollup-plugin-off-main-thread@2.2.3': dependencies: ejs: 3.1.10 @@ -4717,6 +5640,35 @@ snapshots: react-dom: 19.2.0(react@19.2.0) react-transition-state: 2.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@textlint/ast-node-types@15.2.3': {} + + '@textlint/linter-formatter@15.2.3': + dependencies: + '@azu/format-text': 1.0.2 + '@azu/style-format': 1.0.1 + '@textlint/module-interop': 15.2.3 + '@textlint/resolver': 15.2.3 + '@textlint/types': 15.2.3 + chalk: 4.1.2 + debug: 4.4.3 + js-yaml: 3.14.1 + lodash: 4.17.21 + pluralize: 2.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + table: 6.9.0 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + '@textlint/module-interop@15.2.3': {} + + '@textlint/resolver@15.2.3': {} + + '@textlint/types@15.2.3': + dependencies: + '@textlint/ast-node-types': 15.2.3 + '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -4800,6 +5752,8 @@ snapshots: dependencies: undici-types: 7.14.0 + '@types/normalize-package-data@2.4.4': {} + '@types/react-dom@19.2.2(@types/react@19.2.2)': dependencies: '@types/react': 19.2.2 @@ -4810,10 +5764,14 @@ snapshots: '@types/resolve@1.20.2': {} + '@types/sarif@2.1.7': {} + '@types/throttle-debounce@5.0.2': {} '@types/trusted-types@2.0.7': {} + '@types/vscode@1.105.0': {} + '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0)(typescript@5.9.3))(eslint@9.39.0)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -4907,6 +5865,14 @@ snapshots: '@typescript-eslint/types': 8.46.2 eslint-visitor-keys: 4.2.1 + '@typespec/ts-http-runtime@0.3.1': + dependencies: + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + '@vitejs/plugin-react@5.1.0(vite@7.1.12(@types/node@24.7.2)(terser@5.44.0))': dependencies: '@babel/core': 7.28.5 @@ -4961,6 +5927,81 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 + '@vscode/vsce-sign-alpine-arm64@2.0.6': + optional: true + + '@vscode/vsce-sign-alpine-x64@2.0.6': + optional: true + + '@vscode/vsce-sign-darwin-arm64@2.0.2': + optional: true + + '@vscode/vsce-sign-darwin-x64@2.0.2': + optional: true + + '@vscode/vsce-sign-linux-arm64@2.0.6': + optional: true + + '@vscode/vsce-sign-linux-arm@2.0.6': + optional: true + + '@vscode/vsce-sign-linux-x64@2.0.6': + optional: true + + '@vscode/vsce-sign-win32-arm64@2.0.6': + optional: true + + '@vscode/vsce-sign-win32-x64@2.0.6': + optional: true + + '@vscode/vsce-sign@2.0.8': + optionalDependencies: + '@vscode/vsce-sign-alpine-arm64': 2.0.6 + '@vscode/vsce-sign-alpine-x64': 2.0.6 + '@vscode/vsce-sign-darwin-arm64': 2.0.2 + '@vscode/vsce-sign-darwin-x64': 2.0.2 + '@vscode/vsce-sign-linux-arm': 2.0.6 + '@vscode/vsce-sign-linux-arm64': 2.0.6 + '@vscode/vsce-sign-linux-x64': 2.0.6 + '@vscode/vsce-sign-win32-arm64': 2.0.6 + '@vscode/vsce-sign-win32-x64': 2.0.6 + + '@vscode/vsce@3.6.2': + dependencies: + '@azure/identity': 4.13.0 + '@secretlint/node': 10.2.2 + '@secretlint/secretlint-formatter-sarif': 10.2.2 + '@secretlint/secretlint-rule-no-dotenv': 10.2.2 + '@secretlint/secretlint-rule-preset-recommend': 10.2.2 + '@vscode/vsce-sign': 2.0.8 + azure-devops-node-api: 12.5.0 + chalk: 4.1.2 + cheerio: 1.1.2 + cockatiel: 3.2.1 + commander: 12.1.0 + form-data: 4.0.4 + glob: 11.0.3 + hosted-git-info: 4.1.0 + jsonc-parser: 3.3.1 + leven: 3.1.0 + markdown-it: 14.1.0 + mime: 1.6.0 + minimatch: 3.1.2 + parse-semver: 1.1.1 + read: 1.0.7 + secretlint: 10.2.2 + semver: 7.7.3 + tmp: 0.2.5 + typed-rest-client: 1.8.11 + url-join: 4.0.1 + xml2js: 0.5.0 + yauzl: 2.10.0 + yazl: 2.5.1 + optionalDependencies: + keytar: 7.9.0 + transitivePeerDependencies: + - supports-color + '@webassemblyjs/ast@1.14.1': dependencies: '@webassemblyjs/helper-numbers': 1.13.2 @@ -5078,6 +6119,8 @@ snapshots: acorn@8.15.0: {} + agent-base@7.1.4: {} + ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -5103,6 +6146,10 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@7.1.1: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -5140,16 +6187,25 @@ snapshots: assertion-error@2.0.1: {} + astral-regex@2.0.0: {} + async-function@1.0.0: {} async@3.2.6: {} + asynckit@0.4.0: {} + at-least-node@1.0.0: {} available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 + azure-devops-node-api@12.5.0: + dependencies: + tunnel: 0.0.6 + typed-rest-client: 1.8.11 + babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): dependencies: '@babel/compat-data': 7.28.5 @@ -5176,12 +6232,30 @@ snapshots: balanced-match@1.0.2: {} + base64-js@1.5.1: + optional: true + baseline-browser-mapping@2.8.23: {} better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 + binaryextensions@6.11.0: + dependencies: + editions: 6.22.0 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + optional: true + + boolbase@1.0.0: {} + + boundary@2.0.0: {} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -5203,8 +6277,22 @@ snapshots: node-releases: 2.0.27 update-browserslist-db: 1.1.4(browserslist@4.27.0) + buffer-crc32@0.2.13: {} + + buffer-equal-constant-time@1.0.1: {} + buffer-from@1.1.2: {} + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + optional: true + + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + cac@6.7.14: {} call-bind-apply-helpers@1.0.2: @@ -5247,22 +6335,56 @@ snapshots: check-error@2.1.1: {} + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.1.2: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.0.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.16.0 + whatwg-mimetype: 4.0.0 + chokidar@4.0.3: dependencies: readdirp: 4.1.2 + chownr@1.1.4: + optional: true + chrome-trace-event@1.0.4: {} ci-info@3.9.0: {} classcat@5.0.5: {} + cockatiel@3.2.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@12.1.0: {} + commander@2.20.3: {} common-tags@1.8.2: {} @@ -5292,6 +6414,16 @@ snapshots: crypto-random-string@2.0.0: {} + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-what@6.2.2: {} + csstype@3.1.3: {} d3-color@3.1.0: {} @@ -5354,37 +6486,77 @@ snapshots: dependencies: ms: 2.1.3 + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + optional: true + deep-eql@5.0.2: {} + deep-extend@0.6.0: + optional: true + deep-is@0.1.4: {} deepmerge@4.3.1: {} + default-browser-id@5.0.0: {} + + default-browser@5.2.1: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.0 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delayed-stream@1.0.0: {} + detect-indent@6.1.0: {} + detect-libc@2.1.2: + optional: true + diff@4.0.2: {} dir-glob@3.0.1: dependencies: path-type: 4.0.0 + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + dompurify@3.3.0: optionalDependencies: '@types/trusted-types': 2.0.7 - dotenv@8.6.0: {} + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dotenv@8.6.0: {} dunder-proto@1.0.1: dependencies: @@ -5394,6 +6566,14 @@ snapshots: eastasianwidth@0.2.0: {} + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + editions@6.22.0: + dependencies: + version-range: 4.15.0 + ejs@3.1.10: dependencies: jake: 10.9.4 @@ -5406,6 +6586,16 @@ snapshots: emoji-regex@9.2.2: {} + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + optional: true + enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 @@ -5416,6 +6606,12 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + entities@4.5.0: {} + + entities@6.0.1: {} + + environment@1.1.0: {} + es-abstract@1.24.0: dependencies: array-buffer-byte-length: 1.0.2 @@ -5629,6 +6825,9 @@ snapshots: events@3.3.0: {} + expand-template@2.0.3: + optional: true + expect-type@1.2.2: {} extendable-error@0.1.7: {} @@ -5653,6 +6852,10 @@ snapshots: dependencies: reusify: 1.1.0 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -5695,6 +6898,23 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fs-constants@1.0.0: + optional: true + + fs-extra@11.3.2: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 @@ -5762,6 +6982,9 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 + github-from-package@0.0.0: + optional: true + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -5808,6 +7031,15 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + globby@14.1.0: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + path-type: 6.0.0 + slash: 5.1.0 + unicorn-magic: 0.3.0 + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -5842,18 +7074,54 @@ snapshots: dependencies: hermes-estree: 0.25.1 + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + hosted-git-info@7.0.2: + dependencies: + lru-cache: 10.4.3 + html-to-image@1.11.13: {} + htmlparser2@10.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 6.0.1 + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + human-id@4.1.2: {} husky@9.1.7: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.7.0: dependencies: safer-buffer: 2.1.2 idb@7.1.1: {} + ieee754@1.2.1: + optional: true + ignore@5.3.2: {} ignore@7.0.5: {} @@ -5865,6 +7133,8 @@ snapshots: imurmurhash@0.1.4: {} + index-to-position@1.2.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -5872,6 +7142,9 @@ snapshots: inherits@2.0.4: {} + ini@1.3.8: + optional: true + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -5918,6 +7191,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-docker@3.0.0: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -5938,6 +7213,10 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-map@2.0.3: {} is-module@1.0.0: {} @@ -6002,10 +7281,20 @@ snapshots: is-windows@1.0.2: {} + is-wsl@3.1.0: + dependencies: + is-inside-container: 1.0.0 + isarray@2.0.5: {} isexe@2.0.0: {} + istextorbinary@9.5.0: + dependencies: + binaryextensions: 6.11.0 + editions: 6.22.0 + textextensions: 6.11.0 + jackspeak@4.1.1: dependencies: '@isaacs/cliui': 8.0.2 @@ -6051,6 +7340,8 @@ snapshots: json5@2.2.3: {} + jsonc-parser@3.3.1: {} + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -6063,6 +7354,36 @@ snapshots: jsonpointer@5.0.1: {} + jsonwebtoken@9.0.2: + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.7.3 + + jwa@1.4.2: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@3.2.2: + dependencies: + jwa: 1.4.2 + safe-buffer: 5.2.1 + + keytar@7.9.0: + dependencies: + node-addon-api: 4.3.0 + prebuild-install: 7.1.3 + optional: true + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -6074,6 +7395,10 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + loader-runner@4.3.1: {} locate-path@5.0.0: @@ -6086,22 +7411,44 @@ snapshots: lodash.debounce@4.0.8: {} + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.merge@4.6.2: {} + lodash.once@4.1.1: {} + lodash.sortby@4.7.0: {} lodash.startcase@4.4.0: {} + lodash.truncate@4.4.2: {} + lodash@4.17.21: {} loupe@3.2.1: {} + lru-cache@10.4.3: {} + lru-cache@11.2.2: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + lucide-react@0.545.0(react@19.2.0): dependencies: react: 19.2.0 @@ -6116,10 +7463,21 @@ snapshots: make-error@1.3.6: {} + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + marked@16.4.1: {} math-intrinsics@1.1.0: {} + mdurl@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -6135,6 +7493,11 @@ snapshots: dependencies: mime-db: 1.52.0 + mime@1.6.0: {} + + mimic-response@3.1.0: + optional: true + minimatch@10.1.1: dependencies: '@isaacs/brace-expansion': 5.0.0 @@ -6151,24 +7514,58 @@ snapshots: dependencies: brace-expansion: 2.0.2 + minimist@1.2.8: + optional: true + minipass@7.1.2: {} + mkdirp-classic@0.5.3: + optional: true + mri@1.2.0: {} ms@2.1.3: {} + mute-stream@0.0.8: {} + nanoid@3.3.11: {} + napi-build-utils@2.0.0: + optional: true + natural-compare@1.4.0: {} neo-async@2.6.2: {} + node-abi@3.80.0: + dependencies: + semver: 7.7.3 + optional: true + + node-addon-api@4.3.0: + optional: true + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 node-releases@2.0.27: {} + node-sarif-builder@3.2.0: + dependencies: + '@types/sarif': 2.1.7 + fs-extra: 11.3.2 + + normalize-package-data@6.0.2: + dependencies: + hosted-git-info: 7.0.2 + semver: 7.7.3 + validate-npm-package-license: 3.0.4 + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + object-inspect@1.13.4: {} object-keys@1.1.1: {} @@ -6186,6 +7583,13 @@ snapshots: dependencies: wrappy: 1.0.2 + open@10.2.0: + dependencies: + default-browser: 5.2.1 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -6225,6 +7629,8 @@ snapshots: p-map@2.1.0: {} + p-map@7.0.3: {} + p-try@2.2.0: {} package-json-from-dist@1.0.1: {} @@ -6237,6 +7643,29 @@ snapshots: dependencies: callsites: 3.1.0 + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.27.1 + index-to-position: 1.2.0 + type-fest: 4.41.0 + + parse-semver@1.1.1: + dependencies: + semver: 5.7.2 + + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -6252,10 +7681,14 @@ snapshots: path-type@4.0.0: {} + path-type@6.0.0: {} + pathe@2.0.3: {} pathval@2.0.1: {} + pend@1.2.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -6264,6 +7697,10 @@ snapshots: pify@4.0.1: {} + pluralize@2.0.0: {} + + pluralize@8.0.0: {} + possible-typed-array-names@1.1.0: {} postcss@8.5.6: @@ -6272,6 +7709,22 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.80.0 + pump: 3.0.3 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + optional: true + prelude-ls@1.2.1: {} prettier-plugin-sort-json@4.1.1(prettier@3.6.2): @@ -6297,8 +7750,20 @@ snapshots: tinyexec: 0.3.2 tslib: 2.8.1 + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + optional: true + + punycode.js@2.3.1: {} + punycode@2.3.1: {} + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + quansync@0.2.11: {} queue-microtask@1.2.3: {} @@ -6307,6 +7772,23 @@ snapshots: dependencies: safe-buffer: 5.2.1 + rc-config-loader@4.1.3: + dependencies: + debug: 4.4.3 + js-yaml: 4.1.0 + json5: 2.2.3 + require-from-string: 2.0.2 + transitivePeerDependencies: + - supports-color + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + optional: true + react-dom@19.2.0(react@19.2.0): dependencies: react: 19.2.0 @@ -6335,6 +7817,14 @@ snapshots: react@19.2.0: {} + read-pkg@9.0.1: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 6.0.2 + parse-json: 8.3.0 + type-fest: 4.41.0 + unicorn-magic: 0.1.0 + read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 @@ -6342,6 +7832,17 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 + read@1.0.7: + dependencies: + mute-stream: 0.0.8 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + optional: true + readdirp@4.1.2: {} reflect.getprototypeof@1.0.10: @@ -6436,6 +7937,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.52.5 fsevents: 2.3.3 + run-applescript@7.1.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -6463,6 +7966,8 @@ snapshots: safer-buffer@2.1.2: {} + sax@1.4.1: {} + scheduler@0.27.0: {} schema-utils@4.3.3: @@ -6472,6 +7977,20 @@ snapshots: ajv-formats: 2.1.1(ajv@8.17.1) ajv-keywords: 5.1.0(ajv@8.17.1) + secretlint@10.2.2: + dependencies: + '@secretlint/config-creator': 10.2.2 + '@secretlint/formatter': 10.2.2 + '@secretlint/node': 10.2.2 + '@secretlint/profiler': 10.2.2 + debug: 4.4.3 + globby: 14.1.0 + read-pkg: 9.0.1 + transitivePeerDependencies: + - supports-color + + semver@5.7.2: {} + semver@6.3.1: {} semver@7.7.3: {} @@ -6542,8 +8061,26 @@ snapshots: signal-exit@4.1.0: {} + simple-concat@1.0.1: + optional: true + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + optional: true + slash@3.0.0: {} + slash@5.1.0: {} + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + smob@1.5.0: {} source-map-js@1.2.1: {} @@ -6566,6 +8103,20 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.22 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.22 + + spdx-license-ids@3.0.22: {} + sprintf-js@1.0.3: {} stackback@0.0.2: {} @@ -6628,6 +8179,11 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + optional: true + stringify-object@3.3.0: dependencies: get-own-enumerable-property-symbols: 3.0.2 @@ -6646,12 +8202,19 @@ snapshots: strip-comments@2.0.1: {} + strip-json-comments@2.0.1: + optional: true + strip-json-comments@3.1.1: {} strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 + structured-source@4.0.0: + dependencies: + boundary: 2.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -6660,10 +8223,40 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-preserve-symlinks-flag@1.0.0: {} + table@6.9.0: + dependencies: + ajv: 8.17.1 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + tapable@2.3.0: {} + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.3 + tar-stream: 2.2.0 + optional: true + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + optional: true + temp-dir@2.0.0: {} tempy@0.6.0: @@ -6675,6 +8268,11 @@ snapshots: term-size@2.2.1: {} + terminal-link@4.0.0: + dependencies: + ansi-escapes: 7.1.1 + supports-hyperlinks: 3.2.0 + terser-webpack-plugin@5.3.14(esbuild@0.25.10)(webpack@5.102.1(esbuild@0.25.10)): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -6693,6 +8291,12 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 + text-table@0.2.0: {} + + textextensions@6.11.0: + dependencies: + editions: 6.22.0 + throttle-debounce@5.0.2: {} tinybench@2.9.0: {} @@ -6710,6 +8314,8 @@ snapshots: tinyspy@4.0.4: {} + tmp@0.2.5: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -6744,12 +8350,21 @@ snapshots: tslib@2.8.1: {} + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + optional: true + + tunnel@0.0.6: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 type-fest@0.16.0: {} + type-fest@4.41.0: {} + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -6783,6 +8398,12 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typed-rest-client@1.8.11: + dependencies: + qs: 6.14.0 + tunnel: 0.0.6 + underscore: 1.13.7 + typescript-eslint@8.46.2(eslint@9.39.0)(typescript@5.9.3): dependencies: '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0)(typescript@5.9.3))(eslint@9.39.0)(typescript@5.9.3) @@ -6796,6 +8417,8 @@ snapshots: typescript@5.9.3: {} + uc.micro@2.1.0: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -6803,8 +8426,12 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + underscore@1.13.7: {} + undici-types@7.14.0: {} + undici@7.16.0: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: @@ -6816,6 +8443,10 @@ snapshots: unicode-property-aliases-ecmascript@2.2.0: {} + unicorn-magic@0.1.0: {} + + unicorn-magic@0.3.0: {} + unique-string@2.0.0: dependencies: crypto-random-string: 2.0.0 @@ -6836,12 +8467,26 @@ snapshots: dependencies: punycode: 2.3.1 + url-join@4.0.1: {} + use-sync-external-store@1.6.0(react@19.2.0): dependencies: react: 19.2.0 + util-deprecate@1.0.2: + optional: true + + uuid@8.3.2: {} + v8-compile-cache-lib@3.0.1: {} + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + version-range@4.15.0: {} + vite-node@3.2.4(@types/node@24.7.2)(terser@5.44.0): dependencies: cac: 6.7.14 @@ -6973,6 +8618,12 @@ snapshots: - esbuild - uglify-js + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -7163,8 +8814,30 @@ snapshots: wrappy@1.0.2: {} + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.0 + + xml2js@0.5.0: + dependencies: + sax: 1.4.1 + xmlbuilder: 11.0.1 + + xmlbuilder@11.0.1: {} + yallist@3.1.1: {} + yallist@4.0.0: {} + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yazl@2.5.1: + dependencies: + buffer-crc32: 0.2.13 + yn@3.1.1: {} yocto-queue@0.1.0: {} diff --git a/scripts/build-vscode.mjs b/scripts/build-vscode.mjs new file mode 100644 index 0000000..aed96de --- /dev/null +++ b/scripts/build-vscode.mjs @@ -0,0 +1,102 @@ +#!/usr/bin/env node + +import esbuild from "esbuild"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const isWatch = process.argv.includes("--watch"); + +// Common options +const commonOptions = { + bundle: true, + sourcemap: true, + minify: !isWatch, + logLevel: "info", +}; + +// Build extension (Node.js environment) +const extensionOptions = { + ...commonOptions, + entryPoints: [ + path.join(__dirname, "../platforms/vscode/src/extension.ts"), + ], + outfile: path.join(__dirname, "../platforms/vscode/dist/extension.js"), + format: "cjs", + platform: "node", + external: ["vscode"], + target: "node16", +}; + +// Build webview (Browser environment) +const webviewOptions = { + ...commonOptions, + entryPoints: [ + path.join(__dirname, "../platforms/vscode/src/webview.tsx"), + ], + outfile: path.join(__dirname, "../platforms/vscode/dist/webview.js"), + format: "iife", + platform: "browser", + target: ["es2020", "chrome90", "firefox90"], + loader: { + ".svg": "dataurl", + ".png": "dataurl", + ".jpg": "dataurl", + ".jpeg": "dataurl", + ".woff": "dataurl", + ".woff2": "dataurl", + ".ttf": "dataurl", + ".eot": "dataurl", + }, + define: { + "process.env.NODE_ENV": '"production"', + }, +}; + +// Build CSS separately +const cssOptions = { + ...commonOptions, + entryPoints: [ + path.join(__dirname, "../packages/learningmap/dist/index.css"), + ], + outfile: path.join(__dirname, "../platforms/vscode/dist/webview.css"), + loader: { + ".css": "copy", + }, +}; + +async function build() { + try { + if (isWatch) { + const ctxExtension = await esbuild.context(extensionOptions); + const ctxWebview = await esbuild.context(webviewOptions); + + await Promise.all([ + ctxExtension.watch(), + ctxWebview.watch(), + ]); + + console.log("Watching for changes..."); + } else { + await Promise.all([ + esbuild.build(extensionOptions), + esbuild.build(webviewOptions), + ]); + + // Copy CSS file + const fs = await import("fs/promises"); + const cssSource = path.join(__dirname, "../packages/learningmap/dist/index.css"); + const cssTarget = path.join(__dirname, "../platforms/vscode/dist/webview.css"); + await fs.copyFile(cssSource, cssTarget); + + console.log("Build complete!"); + } + } catch (error) { + console.error("Build failed:", error); + process.exit(1); + } +} + +build(); From 1e8bd4955f97197845c9b1b1884eadbd97687604 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 23:22:15 +0000 Subject: [PATCH 03/14] Improve VS Code extension with debouncing and documentation - Add debounced saving to prevent race conditions - Prevent save loops by tracking loading state - Add icon, keywords, and repository info to package.json - Create DEVELOPMENT.md with architecture documentation - Add VS Code launch configuration for debugging - Document known limitations (share feature, URL hash loading) Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- platforms/vscode/.vscode/launch.json | 17 ++ platforms/vscode/DEVELOPMENT.md | 82 +++++++++ platforms/vscode/icon.svg | 159 ++++++++++++++++++ platforms/vscode/package.json | 13 ++ .../vscode/src/LearningmapEditorProvider.ts | 23 ++- platforms/vscode/src/webview.tsx | 46 +++-- 6 files changed, 325 insertions(+), 15 deletions(-) create mode 100644 platforms/vscode/.vscode/launch.json create mode 100644 platforms/vscode/DEVELOPMENT.md create mode 100644 platforms/vscode/icon.svg diff --git a/platforms/vscode/.vscode/launch.json b/platforms/vscode/.vscode/launch.json new file mode 100644 index 0000000..34a59d0 --- /dev/null +++ b/platforms/vscode/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}" + ], + "outFiles": [ + "${workspaceFolder}/dist/**/*.js" + ], + "preLaunchTask": "${defaultBuildTask}" + } + ] +} diff --git a/platforms/vscode/DEVELOPMENT.md b/platforms/vscode/DEVELOPMENT.md new file mode 100644 index 0000000..682fb0a --- /dev/null +++ b/platforms/vscode/DEVELOPMENT.md @@ -0,0 +1,82 @@ +# Learningmap VS Code Extension Development + +This directory contains the VS Code extension for editing `.learningmap` files. + +## Architecture + +The extension consists of two main parts: + +1. **Extension Host** (`src/extension.ts`, `src/LearningmapEditorProvider.ts`): Runs in Node.js and manages the VS Code integration +2. **Webview** (`src/webview.tsx`): Runs in a browser context and hosts the React-based LearningMapEditor + +### Extension Host + +- Registers a custom editor for `.learningmap` files +- Provides a command to create new learningmap files +- Manages file I/O and document synchronization +- Communicates with the webview via message passing + +### Webview + +- Renders the LearningMapEditor React component +- Syncs state with the editor store (Zustand) +- Sends save messages to the extension host on changes (debounced) +- Receives update messages when the file changes externally + +## Building + +```bash +# From the root of the repository +pnpm build + +# Or build just the vscode extension +pnpm --filter learningmap-vscode build +``` + +The build process: +1. Compiles TypeScript and bundles extension code with esbuild (target: Node.js) +2. Bundles webview code with esbuild (target: Browser) +3. Copies CSS from the learningmap package + +## Development + +```bash +# Watch mode for development +pnpm --filter learningmap-vscode watch +``` + +To test the extension: +1. Open VS Code +2. Press F5 to launch Extension Development Host +3. Open or create a `.learningmap` file +4. The visual editor should appear + +## File Format + +Learningmap files are JSON files with the `.learningmap` extension. The structure includes: + +- `nodes`: Array of nodes (topics, tasks, text, images) +- `edges`: Array of connections between nodes +- `settings`: Map settings (background color, title, etc.) +- `version`: Schema version +- `type`: Always "learningmap" + +## Limitations + +Some features from the web platform may not work in the VS Code webview: + +- **Share functionality**: Uses `window.location` which doesn't work in webviews +- **External JSON store**: Loading from external IDs via URL hash won't work + +These are optional features and don't affect core editing capabilities. + +## Packaging + +To create a `.vsix` package for distribution: + +```bash +cd platforms/vscode +pnpm package +``` + +This requires the extension to be built first. diff --git a/platforms/vscode/icon.svg b/platforms/vscode/icon.svg new file mode 100644 index 0000000..a1c2ef5 --- /dev/null +++ b/platforms/vscode/icon.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platforms/vscode/package.json b/platforms/vscode/package.json index c7c6815..96de473 100644 --- a/platforms/vscode/package.json +++ b/platforms/vscode/package.json @@ -7,6 +7,19 @@ "author": "Mike Barkmin", "license": "MIT", "private": true, + "icon": "icon.svg", + "repository": { + "type": "git", + "url": "https://github.com/openpatch/learningmap.git", + "directory": "platforms/vscode" + }, + "keywords": [ + "learningmap", + "education", + "learning", + "roadmap", + "visual-editor" + ], "engines": { "vscode": "^1.80.0" }, diff --git a/platforms/vscode/src/LearningmapEditorProvider.ts b/platforms/vscode/src/LearningmapEditorProvider.ts index 5b10f8f..21015d8 100644 --- a/platforms/vscode/src/LearningmapEditorProvider.ts +++ b/platforms/vscode/src/LearningmapEditorProvider.ts @@ -23,29 +23,42 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide }; webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview); + // Track if we're currently updating from external changes + let isUpdatingFromDocument = false; + // Hook up event handlers const updateWebview = () => { + isUpdatingFromDocument = true; webviewPanel.webview.postMessage({ type: 'update', content: document.getText(), }); + // Reset flag after a short delay + setTimeout(() => { + isUpdatingFromDocument = false; + }, 100); }; // Send initial content updateWebview(); - // Listen for changes in the document + // Listen for changes in the document (from external sources) const changeDocumentSubscription = vscode.workspace.onDidChangeTextDocument(e => { - if (e.document.uri.toString() === document.uri.toString()) { - updateWebview(); + if (e.document.uri.toString() === document.uri.toString() && e.contentChanges.length > 0) { + // Only update if change was from external source (not from us) + if (!isUpdatingFromDocument) { + updateWebview(); + } } }); // Listen for messages from the webview - webviewPanel.webview.onDidReceiveMessage(e => { + webviewPanel.webview.onDidReceiveMessage(async e => { switch (e.type) { case 'save': - this.saveDocument(document, e.content); + if (!isUpdatingFromDocument) { + await this.saveDocument(document, e.content); + } return; case 'ready': // Webview is ready, send initial content diff --git a/platforms/vscode/src/webview.tsx b/platforms/vscode/src/webview.tsx index e664c80..d43bd4e 100644 --- a/platforms/vscode/src/webview.tsx +++ b/platforms/vscode/src/webview.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useCallback } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import { createRoot } from 'react-dom/client'; import { LearningMapEditor, useEditorStore, RoadmapData } from '@learningmap/learningmap'; import '@learningmap/learningmap/index.css'; @@ -18,7 +18,8 @@ interface VSCodeMessage { */ function WebviewEditor() { const [isReady, setIsReady] = useState(false); - const [initialData, setInitialData] = useState(null); + const isLoadingFromFile = useRef(false); + const saveTimeoutRef = useRef(null); // Get store methods const getRoadmapData = useEditorStore(state => state.getRoadmapData); @@ -30,6 +31,9 @@ function WebviewEditor() { const message = event.data; switch (message.type) { case 'update': + // Set flag to prevent saving during load + isLoadingFromFile.current = true; + // Load the content from the file try { if (message.content) { @@ -56,6 +60,11 @@ function WebviewEditor() { type: 'learningmap', } as RoadmapData); } + + // Clear the flag after a short delay to allow store to settle + setTimeout(() => { + isLoadingFromFile.current = false; + }, 100); break; } }; @@ -68,25 +77,42 @@ function WebviewEditor() { return () => { window.removeEventListener('message', messageHandler); + if (saveTimeoutRef.current) { + clearTimeout(saveTimeoutRef.current); + } }; }, [loadRoadmapData]); - // Auto-save changes to the document + // Auto-save changes to the document (debounced) useEffect(() => { if (!isReady) return; // Subscribe to store changes - const unsubscribe = useEditorStore.subscribe((state) => { - // Save the current roadmap data back to VS Code - const data = getRoadmapData(); - vscode.postMessage({ - type: 'save', - content: data, - }); + const unsubscribe = useEditorStore.subscribe(() => { + // Don't save if we're loading from file + if (isLoadingFromFile.current) { + return; + } + + // Debounce saves to avoid too many updates + if (saveTimeoutRef.current) { + clearTimeout(saveTimeoutRef.current); + } + + saveTimeoutRef.current = setTimeout(() => { + const data = getRoadmapData(); + vscode.postMessage({ + type: 'save', + content: data, + }); + }, 500); // Wait 500ms after last change before saving }); return () => { unsubscribe(); + if (saveTimeoutRef.current) { + clearTimeout(saveTimeoutRef.current); + } }; }, [isReady, getRoadmapData]); From feff4fd80c1e69eebedce2e5e01ff91bf73b4217 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 23:26:20 +0000 Subject: [PATCH 04/14] Address code review feedback - Remove unused CSS options from build script - Add proper type definition for VS Code API instead of using 'any' - Use crypto.randomBytes() for secure nonce generation instead of Math.random() - Add example.learningmap file for testing Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- platforms/vscode/.vscodeignore | 2 + platforms/vscode/example.learningmap | 46 +++++++++++++++++++ .../vscode/src/LearningmapEditorProvider.ts | 8 +--- platforms/vscode/src/webview.tsx | 11 ++++- scripts/build-vscode.mjs | 12 ----- 5 files changed, 59 insertions(+), 20 deletions(-) create mode 100644 platforms/vscode/example.learningmap diff --git a/platforms/vscode/.vscodeignore b/platforms/vscode/.vscodeignore index b8c8ae9..374e0f4 100644 --- a/platforms/vscode/.vscodeignore +++ b/platforms/vscode/.vscodeignore @@ -6,3 +6,5 @@ src/** tsconfig.json node_modules/** *.map +example.learningmap +DEVELOPMENT.md diff --git a/platforms/vscode/example.learningmap b/platforms/vscode/example.learningmap new file mode 100644 index 0000000..ae12421 --- /dev/null +++ b/platforms/vscode/example.learningmap @@ -0,0 +1,46 @@ +{ + "nodes": [ + { + "id": "1", + "type": "topic", + "position": { + "x": 250, + "y": 100 + }, + "data": { + "state": "unlocked", + "label": "Getting Started", + "description": "Learn the basics of creating learningmaps" + } + }, + { + "id": "2", + "type": "topic", + "position": { + "x": 250, + "y": 250 + }, + "data": { + "state": "locked", + "label": "Advanced Topics", + "description": "Deep dive into advanced features" + } + } + ], + "edges": [ + { + "id": "e1-2", + "source": "1", + "target": "2" + } + ], + "settings": { + "title": "Sample Learningmap", + "background": { + "color": "#ffffff" + } + }, + "version": 1, + "type": "learningmap", + "source": "vscode-extension" +} diff --git a/platforms/vscode/src/LearningmapEditorProvider.ts b/platforms/vscode/src/LearningmapEditorProvider.ts index 21015d8..6e985f0 100644 --- a/platforms/vscode/src/LearningmapEditorProvider.ts +++ b/platforms/vscode/src/LearningmapEditorProvider.ts @@ -1,4 +1,5 @@ import * as vscode from 'vscode'; +import * as crypto from 'crypto'; /** * Provider for learningmap custom editor. @@ -138,10 +139,5 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide } function getNonce() { - let text = ''; - const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (let i = 0; i < 32; i++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)); - } - return text; + return crypto.randomBytes(16).toString('hex'); } diff --git a/platforms/vscode/src/webview.tsx b/platforms/vscode/src/webview.tsx index d43bd4e..656d2be 100644 --- a/platforms/vscode/src/webview.tsx +++ b/platforms/vscode/src/webview.tsx @@ -3,8 +3,15 @@ import { createRoot } from 'react-dom/client'; import { LearningMapEditor, useEditorStore, RoadmapData } from '@learningmap/learningmap'; import '@learningmap/learningmap/index.css'; -// VS Code API -declare const acquireVsCodeApi: any; +// VS Code API type +interface VSCodeApi { + postMessage(message: any): void; + setState(state: any): void; + getState(): any; +} + +// VS Code API - this is provided by VS Code in webview context +declare function acquireVsCodeApi(): VSCodeApi; const vscode = acquireVsCodeApi(); interface VSCodeMessage { diff --git a/scripts/build-vscode.mjs b/scripts/build-vscode.mjs index aed96de..3cfe3b9 100644 --- a/scripts/build-vscode.mjs +++ b/scripts/build-vscode.mjs @@ -55,18 +55,6 @@ const webviewOptions = { }, }; -// Build CSS separately -const cssOptions = { - ...commonOptions, - entryPoints: [ - path.join(__dirname, "../packages/learningmap/dist/index.css"), - ], - outfile: path.join(__dirname, "../platforms/vscode/dist/webview.css"), - loader: { - ".css": "copy", - }, -}; - async function build() { try { if (isWatch) { From 29b2023fa9ffa3c3ff11d25b0aec3b4e7105197b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 23:28:34 +0000 Subject: [PATCH 05/14] Update documentation to include VS Code extension - Add VS Code platform to repository structure in development docs - Add section on developing the VS Code extension - Update main README with platforms section - Link to platform-specific documentation Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- README.md | 7 +++++++ docs/book/development.md | 20 +++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 804d225..bc354b3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,13 @@ explore learning pathways. It is developed by - **Repository:** https://github.com/openpath/learningmap - **Community**: https://matrix.to/#/#openpatch:matrix.org +## Platforms + +- **Web App**: Create and share learningmaps at [learningmap.app](https://learningmap.app) +- **VS Code Extension**: Edit `.learningmap` files locally in VS Code (see [platforms/vscode](platforms/vscode)) +- **React Component**: Integrate learningmap into your own React app (see [packages/learningmap](packages/learningmap)) +- **Web Component**: Use learningmap in any web application (see [packages/web-component](packages/web-component)) + ## Documentation If you want to work on the documentation, run the diff --git a/docs/book/development.md b/docs/book/development.md index e72bc99..ecd129f 100644 --- a/docs/book/development.md +++ b/docs/book/development.md @@ -40,7 +40,8 @@ learningmap/ │ ├── learningmap/ # Core React component library │ └── web-component/ # Web component wrapper ├── platforms/ -│ └── web/ # Web application (learningmap.app) +│ ├── web/ # Web application (learningmap.app) +│ └── vscode/ # VS Code extension ├── docs/ # Documentation (Hyperbook) └── scripts/ # Build and development scripts ``` @@ -88,6 +89,23 @@ pnpm docs:dev The documentation is built with [Hyperbook](https://hyperbook.openpatch.org) and is located in the `docs/` directory. +### VS Code Extension + +To develop the VS Code extension: + +1. Build the extension: + ```bash + pnpm --filter learningmap-vscode build + ``` + +2. Open the `platforms/vscode` directory in VS Code + +3. Press F5 to launch the Extension Development Host + +4. Open or create a `.learningmap` file to test the editor + +See [platforms/vscode/DEVELOPMENT.md](../../platforms/vscode/DEVELOPMENT.md) for more details. + ## Testing Your Changes 1. **Type-check**: `pnpm lint` From ccd6d828f183d16bcbc4a84ed10e145dfd498ef9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 2 Nov 2025 07:37:20 +0000 Subject: [PATCH 06/14] Remove sharing functionality and add browser support for VS Code extension - Add disableSharing prop to LearningMapEditor and EditorToolbar components - Conditionally hide share button when disableSharing is true - Enable disableSharing in VS Code webview - Replace Node.js crypto module with Web Crypto API for browser compatibility - Add "browser" field to package.json for github.dev support - Use crypto.getRandomValues() which works in both Node.js and browser environments Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/src/EditorToolbar.tsx | 10 +++++++--- packages/learningmap/src/LearningMapEditor.tsx | 4 +++- platforms/vscode/package.json | 1 + platforms/vscode/src/LearningmapEditorProvider.ts | 15 +++++++++++++-- platforms/vscode/src/webview.tsx | 2 +- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/learningmap/src/EditorToolbar.tsx b/packages/learningmap/src/EditorToolbar.tsx index b073798..eb19e6e 100644 --- a/packages/learningmap/src/EditorToolbar.tsx +++ b/packages/learningmap/src/EditorToolbar.tsx @@ -13,10 +13,12 @@ import { getZIndexForNodeType } from "./zIndexHelper"; interface EditorToolbarProps { defaultLanguage?: string; + disableSharing?: boolean; } export const EditorToolbar: React.FC = ({ defaultLanguage = "en", + disableSharing = false, }) => { const { screenToFlowPosition } = useReactFlow(); @@ -118,9 +120,11 @@ export const EditorToolbar: React.FC = ({ {t.download} - - {t.share} - + {!disableSharing && ( + + {t.share} + + )} {t.reset} diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index 334cee8..f281de8 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -15,12 +15,14 @@ export interface LearningMapEditorProps { roadmapData?: string | RoadmapData; language?: string; jsonStore?: string; + disableSharing?: boolean; } export function LearningMapEditor({ roadmapData, language = "en", jsonStore = "https://json.openpatch.org", + disableSharing = false, }: LearningMapEditorProps) { // Only get minimal state needed in this component const nodes = useEditorStore(state => state.nodes); @@ -64,7 +66,7 @@ export function LearningMapEditor({ {/* Toolbar */} - + {/* Preview or Edit mode */} {previewMode && } diff --git a/platforms/vscode/package.json b/platforms/vscode/package.json index 96de473..3cdbe47 100644 --- a/platforms/vscode/package.json +++ b/platforms/vscode/package.json @@ -28,6 +28,7 @@ ], "activationEvents": [], "main": "./dist/extension.js", + "browser": "./dist/extension.js", "contributes": { "customEditors": [ { diff --git a/platforms/vscode/src/LearningmapEditorProvider.ts b/platforms/vscode/src/LearningmapEditorProvider.ts index 6e985f0..fb8dfcf 100644 --- a/platforms/vscode/src/LearningmapEditorProvider.ts +++ b/platforms/vscode/src/LearningmapEditorProvider.ts @@ -1,5 +1,4 @@ import * as vscode from 'vscode'; -import * as crypto from 'crypto'; /** * Provider for learningmap custom editor. @@ -139,5 +138,17 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide } function getNonce() { - return crypto.randomBytes(16).toString('hex'); + // Generate a cryptographically secure random string + // This works in both Node.js and browser environments + const array = new Uint32Array(8); + if (typeof crypto !== 'undefined' && crypto.getRandomValues) { + // Browser or modern Node.js with Web Crypto API + crypto.getRandomValues(array); + } else { + // Fallback for older environments + for (let i = 0; i < array.length; i++) { + array[i] = Math.floor(Math.random() * 0xffffffff); + } + } + return Array.from(array, num => num.toString(16).padStart(8, '0')).join(''); } diff --git a/platforms/vscode/src/webview.tsx b/platforms/vscode/src/webview.tsx index 656d2be..51d2000 100644 --- a/platforms/vscode/src/webview.tsx +++ b/platforms/vscode/src/webview.tsx @@ -127,7 +127,7 @@ function WebviewEditor() { return
Loading editor...
; } - return ; + return ; } // Mount the React component From dc9404d8d48f7959a2b167e2624eec703459c0e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 2 Nov 2025 07:45:45 +0000 Subject: [PATCH 07/14] Hide open/download buttons and add show source command - Add disableFileOperations prop to LearningMapEditor and EditorToolbar - Conditionally hide open and download buttons when disableFileOperations is true - Enable disableFileOperations in VS Code webview - Add "Learningmap: Show Source" command to view JSON source - Visual editor is now the default view (custom editors always open in custom view) - Users can use the new command to switch to source view when needed Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- packages/learningmap/src/EditorToolbar.tsx | 18 +++++++++++------ .../learningmap/src/LearningMapEditor.tsx | 4 +++- platforms/vscode/package.json | 5 +++++ platforms/vscode/src/extension.ts | 20 +++++++++++++++++++ platforms/vscode/src/webview.tsx | 2 +- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/learningmap/src/EditorToolbar.tsx b/packages/learningmap/src/EditorToolbar.tsx index eb19e6e..992f54e 100644 --- a/packages/learningmap/src/EditorToolbar.tsx +++ b/packages/learningmap/src/EditorToolbar.tsx @@ -14,11 +14,13 @@ import { getZIndexForNodeType } from "./zIndexHelper"; interface EditorToolbarProps { defaultLanguage?: string; disableSharing?: boolean; + disableFileOperations?: boolean; } export const EditorToolbar: React.FC = ({ defaultLanguage = "en", disableSharing = false, + disableFileOperations = false, }) => { const { screenToFlowPosition } = useReactFlow(); @@ -114,12 +116,16 @@ export const EditorToolbar: React.FC = ({
}> - - {t.open} - - - {t.download} - + {!disableFileOperations && ( + + {t.open} + + )} + {!disableFileOperations && ( + + {t.download} + + )} {!disableSharing && ( {t.share} diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index f281de8..8f83fd4 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -16,6 +16,7 @@ export interface LearningMapEditorProps { language?: string; jsonStore?: string; disableSharing?: boolean; + disableFileOperations?: boolean; } export function LearningMapEditor({ @@ -23,6 +24,7 @@ export function LearningMapEditor({ language = "en", jsonStore = "https://json.openpatch.org", disableSharing = false, + disableFileOperations = false, }: LearningMapEditorProps) { // Only get minimal state needed in this component const nodes = useEditorStore(state => state.nodes); @@ -66,7 +68,7 @@ export function LearningMapEditor({ {/* Toolbar */} - + {/* Preview or Edit mode */} {previewMode && } diff --git a/platforms/vscode/package.json b/platforms/vscode/package.json index 3cdbe47..5aa69ec 100644 --- a/platforms/vscode/package.json +++ b/platforms/vscode/package.json @@ -47,6 +47,11 @@ "command": "learningmap.new", "title": "New Learningmap", "category": "Learningmap" + }, + { + "command": "learningmap.showSource", + "title": "Show Source", + "category": "Learningmap" } ] }, diff --git a/platforms/vscode/src/extension.ts b/platforms/vscode/src/extension.ts index a625e44..6cbb954 100644 --- a/platforms/vscode/src/extension.ts +++ b/platforms/vscode/src/extension.ts @@ -73,6 +73,26 @@ export function activate(context: vscode.ExtensionContext) { }) ); + // Register command to show source + context.subscriptions.push( + vscode.commands.registerCommand('learningmap.showSource', async () => { + const activeEditor = vscode.window.activeTextEditor; + if (!activeEditor) { + vscode.window.showErrorMessage('No active learningmap file'); + return; + } + + const uri = activeEditor.document.uri; + if (!uri.path.endsWith('.learningmap')) { + vscode.window.showErrorMessage('Active file is not a learningmap file'); + return; + } + + // Open the file with the default text editor + await vscode.commands.executeCommand('vscode.openWith', uri, 'default'); + }) + ); + console.log('Learningmap extension is now active'); } diff --git a/platforms/vscode/src/webview.tsx b/platforms/vscode/src/webview.tsx index 51d2000..624ee0c 100644 --- a/platforms/vscode/src/webview.tsx +++ b/platforms/vscode/src/webview.tsx @@ -127,7 +127,7 @@ function WebviewEditor() { return
Loading editor...
; } - return ; + return ; } // Mount the React component From 9d466eda0ad4a54e5691b51c7c698edb53854846 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 2 Nov 2025 07:56:16 +0000 Subject: [PATCH 08/14] Update web-component and documentation with new props - Add disableSharing and disableFileOperations props to web-component wrapper - Add jsonStore prop to web-component wrapper (was missing) - Update React package documentation with new props descriptions - Update web-component documentation with new attributes - Document use cases for each prop (VS Code, embedded environments, etc.) Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- docs/book/react/index.md | 2 ++ docs/book/web-component/index.md | 3 +++ packages/web-component/src/index.ts | 3 +++ 3 files changed, 8 insertions(+) diff --git a/docs/book/react/index.md b/docs/book/react/index.md index 3788633..ce429e2 100644 --- a/docs/book/react/index.md +++ b/docs/book/react/index.md @@ -46,6 +46,8 @@ function App() { | `roadmapData` | `string \| RoadmapData` | `undefined` | Initial roadmap data (JSON string or object) | | `language` | `string` | `"en"` | UI language (`"en"` or `"de"`) | | `jsonStore` | `string` | `"https://json.openpatch.org"` | URL for JSON storage service | +| `disableSharing` | `boolean` | `false` | Hide the share button (useful in environments without external sharing) | +| `disableFileOperations` | `boolean` | `false` | Hide open and download buttons (useful when file operations are handled externally) | #### Features diff --git a/docs/book/web-component/index.md b/docs/book/web-component/index.md index 4140c4a..436fa51 100644 --- a/docs/book/web-component/index.md +++ b/docs/book/web-component/index.md @@ -96,6 +96,9 @@ Interactive editor for creating and editing learning maps. |-----------|------|---------|-------------| | `roadmap-data` | `string` | `undefined` | JSON string of roadmap data | | `language` | `string` | `"en"` | UI language (`"en"` or `"de"`) | +| `json-store` | `string` | `"https://json.openpatch.org"` | URL for JSON storage service | +| `disable-sharing` | `boolean` | `false` | Hide the share button (useful in environments without external sharing) | +| `disable-file-operations` | `boolean` | `false` | Hide open and download buttons (useful when file operations are handled externally) | #### Events diff --git a/packages/web-component/src/index.ts b/packages/web-component/src/index.ts index 80a9c50..b21451b 100644 --- a/packages/web-component/src/index.ts +++ b/packages/web-component/src/index.ts @@ -20,6 +20,9 @@ const LearningmapEditorWC = r2wc(LearningMapEditor, { props: { roadmapData: "string", language: "string", + jsonStore: "string", + disableSharing: "boolean", + disableFileOperations: "boolean", onChange: "function", }, events: { From 26ba86a6b085595daeff0451d1786dfc264ec768 Mon Sep 17 00:00:00 2001 From: Mike Barkmin Date: Sun, 2 Nov 2025 13:43:39 +0100 Subject: [PATCH 09/14] fix css and logo --- packages/learningmap/src/EditorToolbar.tsx | 2 - packages/learningmap/src/index.css | 15 +- packages/learningmap/src/index.ts | 2 - platforms/vscode/.gitignore | 7 + platforms/vscode/LICENSE.md | 22 +++ platforms/vscode/example.learningmap | 27 +++- platforms/vscode/icon.png | Bin 0 -> 37510 bytes platforms/vscode/icon.svg | 159 --------------------- platforms/vscode/package.json | 10 +- scripts/buildPackage.mjs | 14 ++ 10 files changed, 83 insertions(+), 175 deletions(-) create mode 100644 platforms/vscode/.gitignore create mode 100644 platforms/vscode/LICENSE.md create mode 100644 platforms/vscode/icon.png delete mode 100644 platforms/vscode/icon.svg diff --git a/packages/learningmap/src/EditorToolbar.tsx b/packages/learningmap/src/EditorToolbar.tsx index 992f54e..df7c57e 100644 --- a/packages/learningmap/src/EditorToolbar.tsx +++ b/packages/learningmap/src/EditorToolbar.tsx @@ -1,7 +1,5 @@ import React from "react"; import { Menu, MenuButton, MenuDivider, MenuItem, SubMenu } from "@szhsin/react-menu"; -import "@szhsin/react-menu/dist/index.css"; -import '@szhsin/react-menu/dist/transitions/zoom.css'; import { Plus, Bug, Settings, Eye, Menu as MenuI, FolderOpen, Download, ImageDown, ExternalLink, Share2, RotateCcw } from "lucide-react"; import { getTranslations } from "./translations"; import { useEditorStore } from "./editorStore"; diff --git a/packages/learningmap/src/index.css b/packages/learningmap/src/index.css index 0d832be..6ce6c16 100644 --- a/packages/learningmap/src/index.css +++ b/packages/learningmap/src/index.css @@ -1,3 +1,4 @@ +@import "@szhsin/react-menu/dist/index.css"; @import "@xyflow/react/dist/style.css"; :root { @@ -254,9 +255,17 @@ header.drawer-header { line-height: 1.25; } -.drawer-description h1 { font-size: 1.5em; } -.drawer-description h2 { font-size: 1.25em; } -.drawer-description h3 { font-size: 1.1em; } +.drawer-description h1 { + font-size: 1.5em; +} + +.drawer-description h2 { + font-size: 1.25em; +} + +.drawer-description h3 { + font-size: 1.1em; +} .drawer-description p { margin-bottom: 1em; diff --git a/packages/learningmap/src/index.ts b/packages/learningmap/src/index.ts index 394b1a4..62b6b56 100644 --- a/packages/learningmap/src/index.ts +++ b/packages/learningmap/src/index.ts @@ -1,5 +1,3 @@ -import "./index.css"; - import LearningMap from "./LearningMap"; import LearningMapEditor from "./LearningMapEditor"; diff --git a/platforms/vscode/.gitignore b/platforms/vscode/.gitignore new file mode 100644 index 0000000..7a26d5d --- /dev/null +++ b/platforms/vscode/.gitignore @@ -0,0 +1,7 @@ +index.css +out +node_modules +.vscode-test/ +*.vsix +.DS_Store +.history diff --git a/platforms/vscode/LICENSE.md b/platforms/vscode/LICENSE.md new file mode 100644 index 0000000..ad03040 --- /dev/null +++ b/platforms/vscode/LICENSE.md @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2025 Mike Barkmin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/platforms/vscode/example.learningmap b/platforms/vscode/example.learningmap index ae12421..4af11c4 100644 --- a/platforms/vscode/example.learningmap +++ b/platforms/vscode/example.learningmap @@ -4,9 +4,10 @@ "id": "1", "type": "topic", "position": { - "x": 250, - "y": 100 + "x": 192, + "y": 271 }, + "zIndex": 30, "data": { "state": "unlocked", "label": "Getting Started", @@ -17,14 +18,28 @@ "id": "2", "type": "topic", "position": { - "x": 250, - "y": 250 + "x": 599, + "y": 217 }, + "zIndex": 30, "data": { "state": "locked", "label": "Advanced Topics", "description": "Deep dive into advanced features" } + }, + { + "id": "node-1762086584942", + "type": "task", + "position": { + "x": 189, + "y": 176 + }, + "zIndex": 30, + "data": { + "label": "New task", + "state": "unlocked" + } } ], "edges": [ @@ -42,5 +57,5 @@ }, "version": 1, "type": "learningmap", - "source": "vscode-extension" -} + "source": "https://learningmap.app" +} \ No newline at end of file diff --git a/platforms/vscode/icon.png b/platforms/vscode/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3c9c6803cfa8c24d833b35329d7ae5a8b2183cd1 GIT binary patch literal 37510 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 literal 0 HcmV?d00001 diff --git a/platforms/vscode/icon.svg b/platforms/vscode/icon.svg deleted file mode 100644 index a1c2ef5..0000000 --- a/platforms/vscode/icon.svg +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/platforms/vscode/package.json b/platforms/vscode/package.json index 5aa69ec..62f3496 100644 --- a/platforms/vscode/package.json +++ b/platforms/vscode/package.json @@ -1,13 +1,13 @@ { - "name": "learningmap-vscode", - "displayName": "Learningmap Editor", + "name": "learningmap-studio", + "displayName": "Learningmap Studio", "description": "Visual editor for learningmap files", "version": "0.1.0", "publisher": "openpatch", "author": "Mike Barkmin", "license": "MIT", "private": true, - "icon": "icon.svg", + "icon": "icon.png", "repository": { "type": "git", "url": "https://github.com/openpatch/learningmap.git", @@ -73,5 +73,9 @@ "@types/react-dom": "^19.2.1", "@vscode/vsce": "^3.2.1", "typescript": "~5.9.3" + }, + "vsce": { + "dependencies": false, + "skipDuplicate": true } } diff --git a/scripts/buildPackage.mjs b/scripts/buildPackage.mjs index 3b7dcec..88a9ebf 100644 --- a/scripts/buildPackage.mjs +++ b/scripts/buildPackage.mjs @@ -86,5 +86,19 @@ export const buildPackage = async (path) => { throw new Error(`ESM Build failed for ${packageName} \n ${e}`); }); + // bundle index.css + await build({ + entryPoints: [`${path}/src/index.css`], + outfile: `${path}/dist/index.css`, + minify: true, + bundle: true, + loader: { + ".svg": "dataurl", + ".woff2": "dataurl", + }, + }).catch((e) => { + throw new Error(`ESM Build failed for ${packageName} \n ${e}`); + }); + console.log(`build ${chalk.green("success")} - ${packageName}`); }; From 112970854be266eb2ddefd7dc7218eec15c703a2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 2 Nov 2025 12:49:00 +0000 Subject: [PATCH 10/14] Fix show source command to work with custom editors - Check workspace.textDocuments for open .learningmap files when no active text editor - Fall back to visible text editors if available - Properly handle the case when custom editor is active (no activeTextEditor) - Improved error message clarity Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- platforms/vscode/src/extension.ts | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/platforms/vscode/src/extension.ts b/platforms/vscode/src/extension.ts index 6cbb954..1256afd 100644 --- a/platforms/vscode/src/extension.ts +++ b/platforms/vscode/src/extension.ts @@ -76,13 +76,31 @@ export function activate(context: vscode.ExtensionContext) { // Register command to show source context.subscriptions.push( vscode.commands.registerCommand('learningmap.showSource', async () => { - const activeEditor = vscode.window.activeTextEditor; - if (!activeEditor) { - vscode.window.showErrorMessage('No active learningmap file'); + // Try to get the active text editor first + let uri = vscode.window.activeTextEditor?.document.uri; + + // If no active text editor, check visible text editors + if (!uri && vscode.window.visibleTextEditors.length > 0) { + uri = vscode.window.visibleTextEditors[0].document.uri; + } + + // If still no URI, try to find an open learningmap document + if (!uri) { + const learningmapDocs = vscode.workspace.textDocuments.filter( + doc => doc.uri.path.endsWith('.learningmap') + ); + if (learningmapDocs.length > 0) { + uri = learningmapDocs[0].uri; + } + } + + // If we still don't have a URI, show an error + if (!uri) { + vscode.window.showErrorMessage('No learningmap file is currently open'); return; } - - const uri = activeEditor.document.uri; + + // Verify it's a learningmap file if (!uri.path.endsWith('.learningmap')) { vscode.window.showErrorMessage('Active file is not a learningmap file'); return; From cd2261bfcb57efb02d0b8694645872d3e2dd8920 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 2 Nov 2025 12:55:12 +0000 Subject: [PATCH 11/14] Make keyboard shortcuts configurable in VS Code - Add keybindings contribution to package.json for Show Source command - Default shortcut: Ctrl+K Ctrl+S (Windows/Linux) or Cmd+K Cmd+S (Mac) - Users can customize shortcuts via VS Code keyboard shortcuts editor - Update README with keyboard shortcuts documentation - Document how to customize shortcuts in VS Code Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- platforms/vscode/README.md | 23 +++++++++++++++++++++++ platforms/vscode/package.json | 8 ++++++++ 2 files changed, 31 insertions(+) diff --git a/platforms/vscode/README.md b/platforms/vscode/README.md index c41f833..6f1a0f6 100644 --- a/platforms/vscode/README.md +++ b/platforms/vscode/README.md @@ -33,6 +33,29 @@ Use the visual editor to: Changes are automatically saved to the file. +### Viewing Source + +To view or edit the JSON source of a learningmap: + +1. Open the Command Palette (`Ctrl+Shift+P` or `Cmd+Shift+P`) +2. Run the command `Learningmap: Show Source` +3. Or use the keyboard shortcut: `Ctrl+K Ctrl+S` (Windows/Linux) or `Cmd+K Cmd+S` (Mac) + +### Keyboard Shortcuts + +The extension provides a configurable keyboard shortcut: + +| Command | Default Shortcut | Description | +|---------|-----------------|-------------| +| Show Source | `Ctrl+K Ctrl+S` (Windows/Linux)
`Cmd+K Cmd+S` (Mac) | Switch to JSON source view | + +**Note:** All keyboard shortcuts within the editor (like adding nodes, undo/redo, etc.) work as documented in the learningmap editor and are handled by the visual editor itself. + +To customize keyboard shortcuts: +1. Open VS Code Keyboard Shortcuts editor (`Ctrl+K Ctrl+S` or `Cmd+K Cmd+S`) +2. Search for "Learningmap" +3. Click on the pencil icon next to the command to change the shortcut + ## Requirements - VS Code 1.80.0 or higher diff --git a/platforms/vscode/package.json b/platforms/vscode/package.json index 62f3496..b16024a 100644 --- a/platforms/vscode/package.json +++ b/platforms/vscode/package.json @@ -53,6 +53,14 @@ "title": "Show Source", "category": "Learningmap" } + ], + "keybindings": [ + { + "command": "learningmap.showSource", + "key": "ctrl+k ctrl+s", + "mac": "cmd+k cmd+s", + "when": "resourceExtname == .learningmap" + } ] }, "scripts": { From 761eb36a0ea293dc1416a61292c4578cc218e0da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 2 Nov 2025 13:06:07 +0000 Subject: [PATCH 12/14] Add configurable keybindings prop to LearningMapEditor - Add KeyBinding and KeyBindings types to define custom keyboard shortcuts - Update KeyboardShortcuts component to accept and use custom keybindings - Add keyBindings prop to LearningMapEditor component - VS Code extension now disables Ctrl+S (save) since VS Code handles saving - Export KeyBinding and KeyBindings types from package - Update web-component to support key-bindings attribute - Document keyboard shortcuts and customization in React docs - Document key-bindings attribute in web-component docs Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- docs/book/react/index.md | 57 ++++++ docs/book/web-component/index.md | 13 ++ .../learningmap/src/KeyboardShortcuts.tsx | 184 +++++++++++------- .../learningmap/src/LearningMapEditor.tsx | 6 +- packages/learningmap/src/index.ts | 2 +- packages/learningmap/src/types.ts | 33 ++++ packages/web-component/src/index.ts | 1 + platforms/vscode/src/webview.tsx | 13 +- 8 files changed, 233 insertions(+), 76 deletions(-) diff --git a/docs/book/react/index.md b/docs/book/react/index.md index ce429e2..ece2861 100644 --- a/docs/book/react/index.md +++ b/docs/book/react/index.md @@ -48,6 +48,63 @@ function App() { | `jsonStore` | `string` | `"https://json.openpatch.org"` | URL for JSON storage service | | `disableSharing` | `boolean` | `false` | Hide the share button (useful in environments without external sharing) | | `disableFileOperations` | `boolean` | `false` | Hide open and download buttons (useful when file operations are handled externally) | +| `keyBindings` | `Partial` | `undefined` | Custom keyboard shortcuts (see [Keyboard Shortcuts](#keyboard-shortcuts)) | + +#### Keyboard Shortcuts + +The editor includes many keyboard shortcuts for efficient editing. You can customize these shortcuts by providing a `keyBindings` prop: + +```tsx +import { LearningMapEditor, KeyBindings } from '@learningmap/learningmap'; + +const customKeyBindings: Partial = { + save: undefined, // Disable save shortcut + addTaskNode: { key: 't', ctrl: true }, // Change from Ctrl+1 to Ctrl+T +}; + + +``` + +**Default Keyboard Shortcuts:** + +| Action | Default Shortcut | KeyBinding Property | +|--------|-----------------|-------------------| +| Add Task Node | `Ctrl+1` | `addTaskNode` | +| Add Topic Node | `Ctrl+2` | `addTopicNode` | +| Add Image Node | `Ctrl+3` | `addImageNode` | +| Add Text Node | `Ctrl+4` | `addTextNode` | +| Save | `Ctrl+S` | `save` | +| Undo | `Ctrl+Z` | `undo` | +| Redo | `Ctrl+Y` | `redo` | +| Toggle Preview | `Ctrl+P` | `togglePreview` | +| Toggle Debug | `Ctrl+D` | `toggleDebug` | +| Zoom In | `Ctrl++` | `zoomIn` | +| Zoom Out | `Ctrl+-` | `zoomOut` | +| Reset Zoom | `Ctrl+0` | `resetZoom` | +| Toggle Grid | `Ctrl+'` | `toggleGrid` | +| Reset Map | `Ctrl+Delete` | `resetMap` | +| Cut | `Ctrl+X` | `cut` | +| Copy | `Ctrl+C` | `copy` | +| Paste | `Ctrl+V` | `paste` | +| Select All | `Ctrl+A` | `selectAll` | +| Fit View | `Shift+!` | `fitView` | +| Zoom to Selection | `Shift+@` | `zoomToSelection` | +| Delete Selected | `Delete` | `deleteSelected` | +| Help | `Ctrl+?` | `help` | + +**KeyBinding Type:** + +```typescript +interface KeyBinding { + key: string; + ctrl?: boolean; + shift?: boolean; + alt?: boolean; + meta?: boolean; +} +``` + +To disable a shortcut, set it to `undefined`. To customize, provide a `KeyBinding` object with the desired key combination. #### Features diff --git a/docs/book/web-component/index.md b/docs/book/web-component/index.md index 436fa51..bb107c6 100644 --- a/docs/book/web-component/index.md +++ b/docs/book/web-component/index.md @@ -99,6 +99,19 @@ Interactive editor for creating and editing learning maps. | `json-store` | `string` | `"https://json.openpatch.org"` | URL for JSON storage service | | `disable-sharing` | `boolean` | `false` | Hide the share button (useful in environments without external sharing) | | `disable-file-operations` | `boolean` | `false` | Hide open and download buttons (useful when file operations are handled externally) | +| `key-bindings` | `string` | `undefined` | JSON string of custom keyboard shortcuts (see React docs for KeyBindings type) | + +#### Customizing Keyboard Shortcuts + +You can customize keyboard shortcuts by passing a JSON string to the `key-bindings` attribute: + +```html + +``` + +This example disables the save shortcut and changes the "add task" shortcut from `Ctrl+1` to `Ctrl+T`. See the React package documentation for a complete list of available shortcuts and the KeyBindings type definition. #### Events diff --git a/packages/learningmap/src/KeyboardShortcuts.tsx b/packages/learningmap/src/KeyboardShortcuts.tsx index 9a7d41e..c560cbe 100644 --- a/packages/learningmap/src/KeyboardShortcuts.tsx +++ b/packages/learningmap/src/KeyboardShortcuts.tsx @@ -2,14 +2,58 @@ import { useEffect } from "react"; import { useReactFlow } from "@xyflow/react"; import { useEditorStore, useTemporalStore } from "./editorStore"; import { Node } from "@xyflow/react"; -import { NodeData } from "./types"; +import { NodeData, KeyBindings, KeyBinding } from "./types"; import { getTranslations } from "./translations"; interface KeyboardShortcutsProps { jsonStore?: string; + keyBindings?: Partial; } -export const KeyboardShortcuts = ({ jsonStore = "https://json.openpatch.org" }: KeyboardShortcutsProps) => { +// Default keybindings +const defaultKeyBindings: KeyBindings = { + addTaskNode: { key: '1', ctrl: true }, + addTopicNode: { key: '2', ctrl: true }, + addImageNode: { key: '3', ctrl: true }, + addTextNode: { key: '4', ctrl: true }, + save: { key: 's', ctrl: true }, + undo: { key: 'z', ctrl: true }, + redo: { key: 'y', ctrl: true }, + help: { key: '?', ctrl: true }, + togglePreview: { key: 'p', ctrl: true }, + toggleDebug: { key: 'd', ctrl: true }, + zoomIn: { key: '+', ctrl: true }, + zoomOut: { key: '-', ctrl: true }, + resetZoom: { key: '0', ctrl: true }, + toggleGrid: { key: "'", ctrl: true }, + resetMap: { key: 'Delete', ctrl: true }, + cut: { key: 'x', ctrl: true }, + copy: { key: 'c', ctrl: true }, + paste: { key: 'v', ctrl: true }, + selectAll: { key: 'a', ctrl: true }, + fitView: { key: '!', shift: true }, + zoomToSelection: { key: '@', shift: true }, + deleteSelected: { key: 'Delete' }, +}; + +const matchesKeyBinding = (e: KeyboardEvent, binding: KeyBinding | undefined): boolean => { + if (!binding) return false; + + const keyMatches = e.key.toLowerCase() === binding.key.toLowerCase(); + const ctrlMatches = binding.ctrl ? (e.ctrlKey || e.metaKey) : !(e.ctrlKey || e.metaKey); + const shiftMatches = binding.shift ? e.shiftKey : !e.shiftKey; + const altMatches = binding.alt ? e.altKey : !e.altKey; + + return keyMatches && ctrlMatches && shiftMatches && altMatches; +}; + +export const KeyboardShortcuts = ({ + jsonStore = "https://json.openpatch.org", + keyBindings: customKeyBindings = {} +}: KeyboardShortcutsProps) => { + // Merge custom keybindings with defaults + const keyBindings = { ...defaultKeyBindings, ...customKeyBindings }; + const { zoomIn, zoomOut, setCenter, fitView, screenToFlowPosition } = useReactFlow(); // Get store state @@ -167,74 +211,72 @@ export const KeyboardShortcuts = ({ jsonStore = "https://json.openpatch.org" }: if (drawerOpen || edgeDrawerOpen || settingsDrawerOpen) { return; // Ignore shortcuts when any drawer is open } - if (e.ctrlKey || e.metaKey) { - if (e.key === '1') { - e.preventDefault(); - onAddNode("task"); - } else if (e.key === '2') { - e.preventDefault(); - onAddNode("topic"); - } else if (e.key === '3') { - e.preventDefault(); - onAddNode("image"); - } else if (e.key === '4') { - e.preventDefault(); - onAddNode("text"); - } else if (e.key === 's') { - e.preventDefault(); - onSave(); - } else if (e.key === 'z' && !e.shiftKey) { - e.preventDefault(); - undo(); - } else if ((e.key === 'y') || (e.key === 'z' && e.shiftKey)) { - e.preventDefault(); - redo(); - } else if ((e.key === '?' || (e.shiftKey && e.key === '/'))) { - e.preventDefault(); - setHelpOpen(!helpOpen); - } else if (e.key.toLowerCase() === 'p' && !e.shiftKey) { - e.preventDefault(); - onTogglePreview(); - } else if (e.key.toLowerCase() === 'd' && !e.shiftKey) { - e.preventDefault(); - onToggleDebug(); - } else if (e.key === '+' || e.key === '=') { - e.preventDefault(); - onZoomIn(); - } else if (e.key === '-') { - e.preventDefault(); - onZoomOut(); - } else if (e.key === '0') { - e.preventDefault(); - onResetZoom(); - } else if (e.key === "'") { - e.preventDefault(); - onToggleGrid(); - } else if (e.key === 'Delete') { - e.preventDefault(); - onResetMap(); - } else if (e.key.toLowerCase() === 'x') { - e.preventDefault(); - onCut(); - } else if (e.key.toLowerCase() === 'c') { - e.preventDefault(); - onCopy(); - } else if (e.key.toLowerCase() === 'v') { - e.preventDefault(); - onPaste(); - } else if (e.key.toLowerCase() === 'a') { - e.preventDefault(); - onSelectAll(); - } - } else if (e.shiftKey) { - if (e.key === '!') { - e.preventDefault(); - onFitView(); - } else if (e.key === '@') { - e.preventDefault(); - onZoomToSelection(); - } - } else if (e.key === 'Delete') { + + // Check each keybinding + if (matchesKeyBinding(e, keyBindings.addTaskNode)) { + e.preventDefault(); + onAddNode("task"); + } else if (matchesKeyBinding(e, keyBindings.addTopicNode)) { + e.preventDefault(); + onAddNode("topic"); + } else if (matchesKeyBinding(e, keyBindings.addImageNode)) { + e.preventDefault(); + onAddNode("image"); + } else if (matchesKeyBinding(e, keyBindings.addTextNode)) { + e.preventDefault(); + onAddNode("text"); + } else if (matchesKeyBinding(e, keyBindings.save)) { + e.preventDefault(); + onSave(); + } else if (matchesKeyBinding(e, keyBindings.undo)) { + e.preventDefault(); + undo(); + } else if (matchesKeyBinding(e, keyBindings.redo)) { + e.preventDefault(); + redo(); + } else if (matchesKeyBinding(e, keyBindings.help)) { + e.preventDefault(); + setHelpOpen(!helpOpen); + } else if (matchesKeyBinding(e, keyBindings.togglePreview)) { + e.preventDefault(); + onTogglePreview(); + } else if (matchesKeyBinding(e, keyBindings.toggleDebug)) { + e.preventDefault(); + onToggleDebug(); + } else if (matchesKeyBinding(e, keyBindings.zoomIn)) { + e.preventDefault(); + onZoomIn(); + } else if (matchesKeyBinding(e, keyBindings.zoomOut)) { + e.preventDefault(); + onZoomOut(); + } else if (matchesKeyBinding(e, keyBindings.resetZoom)) { + e.preventDefault(); + onResetZoom(); + } else if (matchesKeyBinding(e, keyBindings.toggleGrid)) { + e.preventDefault(); + onToggleGrid(); + } else if (matchesKeyBinding(e, keyBindings.resetMap)) { + e.preventDefault(); + onResetMap(); + } else if (matchesKeyBinding(e, keyBindings.cut)) { + e.preventDefault(); + onCut(); + } else if (matchesKeyBinding(e, keyBindings.copy)) { + e.preventDefault(); + onCopy(); + } else if (matchesKeyBinding(e, keyBindings.paste)) { + e.preventDefault(); + onPaste(); + } else if (matchesKeyBinding(e, keyBindings.selectAll)) { + e.preventDefault(); + onSelectAll(); + } else if (matchesKeyBinding(e, keyBindings.fitView)) { + e.preventDefault(); + onFitView(); + } else if (matchesKeyBinding(e, keyBindings.zoomToSelection)) { + e.preventDefault(); + onZoomToSelection(); + } else if (matchesKeyBinding(e, keyBindings.deleteSelected)) { e.preventDefault(); onDeleteSelected(); } @@ -246,7 +288,7 @@ export const KeyboardShortcuts = ({ jsonStore = "https://json.openpatch.org" }: }; }, [onAddNode, onDeleteSelected, onSave, undo, redo, helpOpen, setHelpOpen, onTogglePreview, onToggleDebug, onZoomIn, onZoomOut, onResetZoom, onFitView, onZoomToSelection, onToggleGrid, - onResetMap, onCut, onCopy, onPaste, onSelectAll, drawerOpen, edgeDrawerOpen, settingsDrawerOpen]); + onResetMap, onCut, onCopy, onPaste, onSelectAll, drawerOpen, edgeDrawerOpen, settingsDrawerOpen, keyBindings]); return null; }; diff --git a/packages/learningmap/src/LearningMapEditor.tsx b/packages/learningmap/src/LearningMapEditor.tsx index 8f83fd4..92421b3 100644 --- a/packages/learningmap/src/LearningMapEditor.tsx +++ b/packages/learningmap/src/LearningMapEditor.tsx @@ -1,7 +1,7 @@ import { ReactFlowProvider, } from "@xyflow/react"; -import { RoadmapData } from "./types"; +import { RoadmapData, KeyBindings } from "./types"; import { EditorToolbar } from "./EditorToolbar"; import { LearningMap } from "./LearningMap"; import { useEditorStore } from "./editorStore"; @@ -17,6 +17,7 @@ export interface LearningMapEditorProps { jsonStore?: string; disableSharing?: boolean; disableFileOperations?: boolean; + keyBindings?: Partial; } export function LearningMapEditor({ @@ -25,6 +26,7 @@ export function LearningMapEditor({ jsonStore = "https://json.openpatch.org", disableSharing = false, disableFileOperations = false, + keyBindings, }: LearningMapEditorProps) { // Only get minimal state needed in this component const nodes = useEditorStore(state => state.nodes); @@ -65,7 +67,7 @@ export function LearningMapEditor({ return ( <> {/* Keyboard shortcuts handler */} - + {/* Toolbar */} diff --git a/packages/learningmap/src/index.ts b/packages/learningmap/src/index.ts index 62b6b56..05ab743 100644 --- a/packages/learningmap/src/index.ts +++ b/packages/learningmap/src/index.ts @@ -1,7 +1,7 @@ import LearningMap from "./LearningMap"; import LearningMapEditor from "./LearningMapEditor"; -export type { RoadmapData, RoadmapState } from "./types"; +export type { RoadmapData, RoadmapState, KeyBindings, KeyBinding } from "./types"; export type { LearningMapProps } from "./LearningMap"; export type { LearningMapEditorProps } from "./LearningMapEditor"; export { LearningMap, LearningMapEditor }; diff --git a/packages/learningmap/src/types.ts b/packages/learningmap/src/types.ts index 92df46f..54010ab 100644 --- a/packages/learningmap/src/types.ts +++ b/packages/learningmap/src/types.ts @@ -110,3 +110,36 @@ export type HelperLine = { color?: string; anchorName: string; }; + +export interface KeyBinding { + key: string; + ctrl?: boolean; + shift?: boolean; + alt?: boolean; + meta?: boolean; +} + +export interface KeyBindings { + addTaskNode?: KeyBinding; + addTopicNode?: KeyBinding; + addImageNode?: KeyBinding; + addTextNode?: KeyBinding; + save?: KeyBinding; + undo?: KeyBinding; + redo?: KeyBinding; + help?: KeyBinding; + togglePreview?: KeyBinding; + toggleDebug?: KeyBinding; + zoomIn?: KeyBinding; + zoomOut?: KeyBinding; + resetZoom?: KeyBinding; + toggleGrid?: KeyBinding; + resetMap?: KeyBinding; + cut?: KeyBinding; + copy?: KeyBinding; + paste?: KeyBinding; + selectAll?: KeyBinding; + fitView?: KeyBinding; + zoomToSelection?: KeyBinding; + deleteSelected?: KeyBinding; +} diff --git a/packages/web-component/src/index.ts b/packages/web-component/src/index.ts index b21451b..0f5f00a 100644 --- a/packages/web-component/src/index.ts +++ b/packages/web-component/src/index.ts @@ -23,6 +23,7 @@ const LearningmapEditorWC = r2wc(LearningMapEditor, { jsonStore: "string", disableSharing: "boolean", disableFileOperations: "boolean", + keyBindings: "json", onChange: "function", }, events: { diff --git a/platforms/vscode/src/webview.tsx b/platforms/vscode/src/webview.tsx index 624ee0c..002b0fc 100644 --- a/platforms/vscode/src/webview.tsx +++ b/platforms/vscode/src/webview.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState, useRef } from 'react'; import { createRoot } from 'react-dom/client'; -import { LearningMapEditor, useEditorStore, RoadmapData } from '@learningmap/learningmap'; +import { LearningMapEditor, useEditorStore, RoadmapData, KeyBindings } from '@learningmap/learningmap'; import '@learningmap/learningmap/index.css'; // VS Code API type @@ -127,7 +127,16 @@ function WebviewEditor() { return
Loading editor...
; } - return ; + // Custom keybindings for VS Code - disable Ctrl+S since VS Code handles save + const vscodeKeyBindings: Partial = { + save: undefined, // Disable save shortcut - VS Code handles this + }; + + return ; } // Mount the React component From 718895dca3214e932edab5308f5be13fd3a6482c Mon Sep 17 00:00:00 2001 From: Mike Barkmin Date: Sun, 2 Nov 2025 19:34:30 +0100 Subject: [PATCH 13/14] update name --- platforms/vscode/DEVELOPMENT.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platforms/vscode/DEVELOPMENT.md b/platforms/vscode/DEVELOPMENT.md index 682fb0a..18b0abe 100644 --- a/platforms/vscode/DEVELOPMENT.md +++ b/platforms/vscode/DEVELOPMENT.md @@ -30,7 +30,7 @@ The extension consists of two main parts: pnpm build # Or build just the vscode extension -pnpm --filter learningmap-vscode build +pnpm --filter learningmap-studio build ``` The build process: @@ -42,7 +42,7 @@ The build process: ```bash # Watch mode for development -pnpm --filter learningmap-vscode watch +pnpm --filter learningmap-studio watch ``` To test the extension: From 24dde25f3ef331c4237c851cfb9dc9cf0c917168 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 2 Nov 2025 18:40:31 +0000 Subject: [PATCH 14/14] Make all editor keybindings configurable in VS Code - Add VS Code commands for all 21 editor actions (add nodes, undo/redo, zoom, etc.) - Register keybindings for all commands in package.json with proper when clauses - Update LearningmapEditorProvider to track active webview and send commands - Update webview to handle command messages and simulate keyboard events - All shortcuts scoped to learningmap editor using 'activeCustomEditorId' context - Users can customize any shortcut through VS Code keyboard shortcuts editor - Update README with complete keyboard shortcuts table and customization instructions Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com> --- platforms/vscode/README.md | 49 +++- platforms/vscode/package.json | 231 ++++++++++++++++++ .../vscode/src/LearningmapEditorProvider.ts | 30 +++ platforms/vscode/src/extension.ts | 33 +++ platforms/vscode/src/webview.tsx | 66 ++++- 5 files changed, 396 insertions(+), 13 deletions(-) diff --git a/platforms/vscode/README.md b/platforms/vscode/README.md index 6f1a0f6..a26c1d2 100644 --- a/platforms/vscode/README.md +++ b/platforms/vscode/README.md @@ -43,18 +43,43 @@ To view or edit the JSON source of a learningmap: ### Keyboard Shortcuts -The extension provides a configurable keyboard shortcut: - -| Command | Default Shortcut | Description | -|---------|-----------------|-------------| -| Show Source | `Ctrl+K Ctrl+S` (Windows/Linux)
`Cmd+K Cmd+S` (Mac) | Switch to JSON source view | - -**Note:** All keyboard shortcuts within the editor (like adding nodes, undo/redo, etc.) work as documented in the learningmap editor and are handled by the visual editor itself. - -To customize keyboard shortcuts: -1. Open VS Code Keyboard Shortcuts editor (`Ctrl+K Ctrl+S` or `Cmd+K Cmd+S`) -2. Search for "Learningmap" -3. Click on the pencil icon next to the command to change the shortcut +The extension provides configurable keyboard shortcuts for all editor commands: + +| Command | Default Shortcut (Win/Linux) | Default Shortcut (Mac) | Description | +|---------|------------------------------|------------------------|-------------| +| Show Source | `Ctrl+K Ctrl+S` | `Cmd+K Cmd+S` | Switch to JSON source view | +| Add Task Node | `Ctrl+1` | `Cmd+1` | Add a task node | +| Add Topic Node | `Ctrl+2` | `Cmd+2` | Add a topic node | +| Add Image Node | `Ctrl+3` | `Cmd+3` | Add an image node | +| Add Text Node | `Ctrl+4` | `Cmd+4` | Add a text node | +| Undo | `Ctrl+Z` | `Cmd+Z` | Undo last action | +| Redo | `Ctrl+Y` | `Cmd+Y` | Redo last action | +| Toggle Preview | `Ctrl+P` | `Cmd+P` | Toggle preview mode | +| Toggle Debug | `Ctrl+D` | `Cmd+D` | Toggle debug mode | +| Zoom In | `Ctrl+=` | `Cmd+=` | Zoom in | +| Zoom Out | `Ctrl+-` | `Cmd+-` | Zoom out | +| Reset Zoom | `Ctrl+0` | `Cmd+0` | Reset zoom to 100% | +| Toggle Grid | `Ctrl+'` | `Cmd+'` | Toggle grid visibility | +| Reset Map | `Ctrl+Delete` | `Cmd+Delete` | Reset entire map (with confirmation) | +| Cut | `Ctrl+X` | `Cmd+X` | Cut selected nodes | +| Copy | `Ctrl+C` | `Cmd+C` | Copy selected nodes | +| Paste | `Ctrl+V` | `Cmd+V` | Paste nodes | +| Select All | `Ctrl+A` | `Cmd+A` | Select all nodes | +| Fit View | `Shift+1` | `Shift+1` | Fit all nodes in view | +| Zoom to Selection | `Shift+2` | `Shift+2` | Zoom to selected nodes | +| Delete Selected | `Delete` | `Delete` | Delete selected nodes or edge | +| Show Help | `Ctrl+Shift+/` | `Cmd+Shift+/` | Show keyboard shortcuts help | + +**Customizing Shortcuts:** + +All keyboard shortcuts are fully customizable through VS Code's keyboard shortcuts editor: + +1. Open VS Code Keyboard Shortcuts editor: `Ctrl+K Ctrl+S` (Windows/Linux) or `Cmd+K Cmd+S` (Mac) +2. Search for "Learningmap" to see all available commands +3. Click on the pencil icon next to any command to change its shortcut +4. Or right-click on a command to add additional keybindings + +**Note:** The shortcuts work through VS Code's command system, allowing you to customize them per your preferences or resolve conflicts with other extensions. ## Requirements diff --git a/platforms/vscode/package.json b/platforms/vscode/package.json index b16024a..64704c8 100644 --- a/platforms/vscode/package.json +++ b/platforms/vscode/package.json @@ -52,6 +52,111 @@ "command": "learningmap.showSource", "title": "Show Source", "category": "Learningmap" + }, + { + "command": "learningmap.addTaskNode", + "title": "Add Task Node", + "category": "Learningmap" + }, + { + "command": "learningmap.addTopicNode", + "title": "Add Topic Node", + "category": "Learningmap" + }, + { + "command": "learningmap.addImageNode", + "title": "Add Image Node", + "category": "Learningmap" + }, + { + "command": "learningmap.addTextNode", + "title": "Add Text Node", + "category": "Learningmap" + }, + { + "command": "learningmap.undo", + "title": "Undo", + "category": "Learningmap" + }, + { + "command": "learningmap.redo", + "title": "Redo", + "category": "Learningmap" + }, + { + "command": "learningmap.togglePreview", + "title": "Toggle Preview Mode", + "category": "Learningmap" + }, + { + "command": "learningmap.toggleDebug", + "title": "Toggle Debug Mode", + "category": "Learningmap" + }, + { + "command": "learningmap.zoomIn", + "title": "Zoom In", + "category": "Learningmap" + }, + { + "command": "learningmap.zoomOut", + "title": "Zoom Out", + "category": "Learningmap" + }, + { + "command": "learningmap.resetZoom", + "title": "Reset Zoom", + "category": "Learningmap" + }, + { + "command": "learningmap.toggleGrid", + "title": "Toggle Grid", + "category": "Learningmap" + }, + { + "command": "learningmap.resetMap", + "title": "Reset Map", + "category": "Learningmap" + }, + { + "command": "learningmap.cut", + "title": "Cut", + "category": "Learningmap" + }, + { + "command": "learningmap.copy", + "title": "Copy", + "category": "Learningmap" + }, + { + "command": "learningmap.paste", + "title": "Paste", + "category": "Learningmap" + }, + { + "command": "learningmap.selectAll", + "title": "Select All", + "category": "Learningmap" + }, + { + "command": "learningmap.fitView", + "title": "Fit View", + "category": "Learningmap" + }, + { + "command": "learningmap.zoomToSelection", + "title": "Zoom to Selection", + "category": "Learningmap" + }, + { + "command": "learningmap.deleteSelected", + "title": "Delete Selected", + "category": "Learningmap" + }, + { + "command": "learningmap.help", + "title": "Show Help", + "category": "Learningmap" } ], "keybindings": [ @@ -60,6 +165,132 @@ "key": "ctrl+k ctrl+s", "mac": "cmd+k cmd+s", "when": "resourceExtname == .learningmap" + }, + { + "command": "learningmap.addTaskNode", + "key": "ctrl+1", + "mac": "cmd+1", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.addTopicNode", + "key": "ctrl+2", + "mac": "cmd+2", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.addImageNode", + "key": "ctrl+3", + "mac": "cmd+3", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.addTextNode", + "key": "ctrl+4", + "mac": "cmd+4", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.undo", + "key": "ctrl+z", + "mac": "cmd+z", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.redo", + "key": "ctrl+y", + "mac": "cmd+y", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.togglePreview", + "key": "ctrl+p", + "mac": "cmd+p", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.toggleDebug", + "key": "ctrl+d", + "mac": "cmd+d", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.zoomIn", + "key": "ctrl+=", + "mac": "cmd+=", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.zoomOut", + "key": "ctrl+-", + "mac": "cmd+-", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.resetZoom", + "key": "ctrl+0", + "mac": "cmd+0", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.toggleGrid", + "key": "ctrl+'", + "mac": "cmd+'", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.resetMap", + "key": "ctrl+delete", + "mac": "cmd+delete", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.cut", + "key": "ctrl+x", + "mac": "cmd+x", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.copy", + "key": "ctrl+c", + "mac": "cmd+c", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.paste", + "key": "ctrl+v", + "mac": "cmd+v", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.selectAll", + "key": "ctrl+a", + "mac": "cmd+a", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.fitView", + "key": "shift+1", + "mac": "shift+1", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.zoomToSelection", + "key": "shift+2", + "mac": "shift+2", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.deleteSelected", + "key": "delete", + "mac": "delete", + "when": "activeCustomEditorId == learningmap.editor" + }, + { + "command": "learningmap.help", + "key": "ctrl+shift+/", + "mac": "cmd+shift+/", + "when": "activeCustomEditorId == learningmap.editor" } ] }, diff --git a/platforms/vscode/src/LearningmapEditorProvider.ts b/platforms/vscode/src/LearningmapEditorProvider.ts index fb8dfcf..3df5677 100644 --- a/platforms/vscode/src/LearningmapEditorProvider.ts +++ b/platforms/vscode/src/LearningmapEditorProvider.ts @@ -6,9 +6,22 @@ import * as vscode from 'vscode'; */ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvider { private static readonly viewType = 'learningmap.editor'; + private activeWebviewPanel: vscode.WebviewPanel | undefined; constructor(private readonly context: vscode.ExtensionContext) {} + /** + * Send a command to the active editor webview + */ + public sendCommandToActiveEditor(command: string): void { + if (this.activeWebviewPanel) { + this.activeWebviewPanel.webview.postMessage({ + type: 'command', + command: command, + }); + } + } + /** * Called when our custom editor is opened. */ @@ -17,6 +30,23 @@ export class LearningmapEditorProvider implements vscode.CustomTextEditorProvide webviewPanel: vscode.WebviewPanel, _token: vscode.CancellationToken ): Promise { + // Track this as the active webview panel + this.activeWebviewPanel = webviewPanel; + + // Clear active panel when disposed + webviewPanel.onDidDispose(() => { + if (this.activeWebviewPanel === webviewPanel) { + this.activeWebviewPanel = undefined; + } + }); + + // Update active panel on focus + webviewPanel.onDidChangeViewState(() => { + if (webviewPanel.active) { + this.activeWebviewPanel = webviewPanel; + } + }); + // Setup initial webview content webviewPanel.webview.options = { enableScripts: true, diff --git a/platforms/vscode/src/extension.ts b/platforms/vscode/src/extension.ts index 1256afd..85d6851 100644 --- a/platforms/vscode/src/extension.ts +++ b/platforms/vscode/src/extension.ts @@ -111,6 +111,39 @@ export function activate(context: vscode.ExtensionContext) { }) ); + // Register editor commands that send messages to the webview + const editorCommands = [ + 'addTaskNode', + 'addTopicNode', + 'addImageNode', + 'addTextNode', + 'undo', + 'redo', + 'togglePreview', + 'toggleDebug', + 'zoomIn', + 'zoomOut', + 'resetZoom', + 'toggleGrid', + 'resetMap', + 'cut', + 'copy', + 'paste', + 'selectAll', + 'fitView', + 'zoomToSelection', + 'deleteSelected', + 'help', + ]; + + editorCommands.forEach(command => { + context.subscriptions.push( + vscode.commands.registerCommand(`learningmap.${command}`, () => { + provider.sendCommandToActiveEditor(command); + }) + ); + }); + console.log('Learningmap extension is now active'); } diff --git a/platforms/vscode/src/webview.tsx b/platforms/vscode/src/webview.tsx index 002b0fc..3550d46 100644 --- a/platforms/vscode/src/webview.tsx +++ b/platforms/vscode/src/webview.tsx @@ -17,6 +17,7 @@ const vscode = acquireVsCodeApi(); interface VSCodeMessage { type: string; content?: string; + command?: string; } /** @@ -27,16 +28,79 @@ function WebviewEditor() { const [isReady, setIsReady] = useState(false); const isLoadingFromFile = useRef(false); const saveTimeoutRef = useRef(null); + const commandTriggerRef = useRef(null); // Get store methods const getRoadmapData = useEditorStore(state => state.getRoadmapData); const loadRoadmapData = useEditorStore(state => state.loadRoadmapData); + // Handle commands from VS Code extension + const handleVSCodeCommand = (command: string) => { + // Simulate keyboard event to trigger the corresponding action + const event = new KeyboardEvent('keydown', { + key: getKeyForCommand(command), + ctrlKey: needsCtrl(command), + shiftKey: needsShift(command), + metaKey: needsCtrl(command), + bubbles: true, + cancelable: true, + }); + window.dispatchEvent(event); + }; + + const getKeyForCommand = (command: string): string => { + const keyMap: Record = { + addTaskNode: '1', + addTopicNode: '2', + addImageNode: '3', + addTextNode: '4', + undo: 'z', + redo: 'y', + togglePreview: 'p', + toggleDebug: 'd', + zoomIn: '+', + zoomOut: '-', + resetZoom: '0', + toggleGrid: "'", + resetMap: 'Delete', + cut: 'x', + copy: 'c', + paste: 'v', + selectAll: 'a', + fitView: '!', + zoomToSelection: '@', + deleteSelected: 'Delete', + help: '?', + }; + return keyMap[command] || ''; + }; + + const needsCtrl = (command: string): boolean => { + const ctrlCommands = [ + 'addTaskNode', 'addTopicNode', 'addImageNode', 'addTextNode', + 'undo', 'redo', 'togglePreview', 'toggleDebug', + 'zoomIn', 'zoomOut', 'resetZoom', 'toggleGrid', 'resetMap', + 'cut', 'copy', 'paste', 'selectAll', 'help', + ]; + return ctrlCommands.includes(command); + }; + + const needsShift = (command: string): boolean => { + const shiftCommands = ['fitView', 'zoomToSelection']; + return shiftCommands.includes(command); + }; + // Handle messages from extension useEffect(() => { const messageHandler = (event: MessageEvent) => { const message = event.data; switch (message.type) { + case 'command': + // Handle command from VS Code + if (message.command) { + handleVSCodeCommand(message.command); + } + break; case 'update': // Set flag to prevent saving during load isLoadingFromFile.current = true; @@ -127,7 +191,7 @@ function WebviewEditor() { return
Loading editor...
; } - // Custom keybindings for VS Code - disable Ctrl+S since VS Code handles save + // Custom keybindings for VS Code - only disable save since VS Code handles it const vscodeKeyBindings: Partial = { save: undefined, // Disable save shortcut - VS Code handles this };