├── .github └── workflows │ └── publish.yml ├── .gitignore ├── BACKLOG.md ├── LICENSE ├── README.md ├── copa.svg ├── package.json ├── prompts ├── 1__new_feature-tests.copa ├── 1__new_feature.copa ├── 2__fix-dir-git.copa ├── doesnt_run.copa ├── failed_test.copa ├── fix-bug.copa ├── new_feature.copa ├── new_feature_tests.copa ├── snips │ └── about_project.md └── update_readme.copa ├── src ├── copa.ts ├── copyToClipboard.ts ├── directoryTree.ts ├── fileReader.ts ├── filterFiles.ts ├── options.ts ├── promptProcessor.ts └── readGlobalConfig.ts ├── tests ├── promptProcessor.test.ts ├── sanity.test.ts └── unicode.test.ts ├── tsconfig.json └── yarn.lock /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to npm 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' # Triggers the workflow on version tags 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | 12 | strategy: 13 | matrix: 14 | node-version: [ 20.x ] 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Use Node.js ${{ matrix.node-version }} 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | registry-url: 'https://registry.npmjs.org/' 24 | 25 | - run: corepack enable 26 | 27 | - name: Install root project dependencies 28 | run: yarn install 29 | env: 30 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 31 | 32 | - name: Build root project 33 | run: yarn build 34 | 35 | - name: Publish root project to npm 36 | run: yarn publish --access public 37 | env: 38 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .yarn 4 | version.sh 5 | .idea 6 | -------------------------------------------------------------------------------- /BACKLOG.md: -------------------------------------------------------------------------------- 1 | - count template tokens 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Roman Landenband 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | CoPa Logo
3 | CoPa: LLM Prompting Templating 4 | 5 |

6 | 7 | [![npm version](https://badge.fury.io/js/copa.svg)](https://badge.fury.io/js/copa) 8 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) 9 | 10 | CoPa is a simple CLI tool for creating structured prompts for Large Language Models (LLMs) using file references. 11 | It offers two main functionalities: 12 | 13 | 1. Processing LLM prompt templates with file references 14 | 2. Copying file contents in an LLM-friendly format 15 | 16 | ## Key Features 17 | 18 | - Process template files with dynamic file references 19 | - Copy an entire folder or a single file to clipboard in a LLM friendly format 20 | - Support for Git repositories and respect for `.gitignore` 21 | - Built-in token counting 22 | - Easy-to-use CLI utility 23 | - Inline ignore patterns for fine-grained control over included files 24 | 25 | ## Usage 26 | 27 | Use CoPa directly with `npx` (recommended) or install it globally. 28 | 29 | ### Using `npx` (Recommended) 30 | 31 | Process a template file: 32 | 33 | ```sh 34 | npx copa t prompt.copa 35 | ``` 36 | 37 | ### Global Installation (Alternative) 38 | 39 | Install CoPa globally: 40 | 41 | ```sh 42 | npm install -g copa 43 | # or yarn 44 | yarn global add copa 45 | ``` 46 | 47 | Then use it as: 48 | 49 | ```sh 50 | copa t prompt.copa 51 | ``` 52 | 53 | ## Template Syntax 54 | 55 | Create a template file (e.g., `prompt.copa`) using `{{@filepath}}` to reference files or directories: 56 | 57 | ```` 58 | Analyze this code: 59 | ``` 60 | {{@src/main.js}} 61 | ``` 62 | 63 | And its test: 64 | ``` 65 | {{@tests/main.test.js}} 66 | ``` 67 | 68 | Review the entire 'utils' directory: 69 | ``` 70 | {{@utils}} 71 | ``` 72 | 73 | Review the 'src' directory, excluding .test.js files: 74 | ``` 75 | {{@src:-*.test.js}} 76 | ``` 77 | 78 | Review all files in the current directory, excluding markdown files and the 'subdir' directory: 79 | ``` 80 | {{@.:-*.md,-**/subdir/**}} 81 | ``` 82 | 83 | [new feature description / instructions for the LLM] 84 | ```` 85 | 86 | Process the template and copy to clipboard: 87 | 88 | ```sh 89 | copa template prompt.copa 90 | # or use the short alias 91 | copa t prompt.copa 92 | ``` 93 | 94 | ## Inline Ignore Patterns 95 | 96 | You can use inline ignore patterns to exclude specific files or patterns within a directory reference: 97 | 98 | ``` 99 | {{@directory:-pattern1,-pattern2,...}} 100 | ``` 101 | 102 | Examples: 103 | - `{{@src:-*.test.js}}` includes all files in the 'src' directory except for files ending with '.test.js' 104 | - `{{@.:-*.md,-**/subdir/**}}` includes all files in the current directory, excluding markdown files and the 'subdir' directory 105 | - `{{@.:-**/*dir/**,-*.y*}}` excludes all files in any directory ending with 'dir' and all files with extensions starting with 'y' 106 | 107 | Ignore patterns support: 108 | - File extensions: `-*.js` 109 | - Specific files: `-file.txt` 110 | - Directories: `-**/dirname/**` 111 | - Glob patterns: `-**/*.test.js` 112 | - Hidden files and directories: `-.*` 113 | 114 | ## Commands 115 | 116 | - `t, template `: Process a template file and copy to clipboard 117 | - Option: `-v, --verbose` (Display detailed file and token information) 118 | 119 | - `to `: Process a template file and output to stdout 120 | - Options: 121 | - `-err, --errors` (Output only errors like missing files, empty string if none) 122 | - `-t, --tokens` (Output only the token count) 123 | - `-v, --verbose` (Display detailed file and token information to stderr) 124 | 125 | - `c, copy [directory]`: Copy files to clipboard (legacy mode) 126 | - Options: 127 | - `-ex, --exclude ` (Exclude file types) 128 | - `-v, --verbose` (List copied files) 129 | - `-f, --file ` (Copy a single file) 130 | 131 | ## Output Format 132 | 133 | CoPa uses a format that's easy for LLMs to understand: 134 | 135 | ```` 136 | Analyze this code: 137 | ``` 138 | ===== src/main.js ===== 139 | File contents here... 140 | ``` 141 | 142 | And its test: 143 | ``` 144 | ===== tests/main.test.js ===== 145 | ... 146 | ```` 147 | 148 | ## Use Cases 149 | 150 | - Control over what's included in a prompt 151 | - Repeatable complex prompts with complex file imports 152 | - Sharing project wide prompt templates 153 | - Any task requiring code context from multiple files 154 | 155 | ## Tips 156 | 157 | 1. Use relative paths in templates for better portability 158 | 2. Create a "prompts" directory in project root 159 | 3. Create a library of templates for common tasks 160 | 4. Use inline ignore patterns for fine-grained control over included files 161 | 162 | ## Global Configuration 163 | 164 | Create `~/.copa` to set default exclude patterns: 165 | 166 | ``` 167 | ignore: jpg,png,gif 168 | ``` 169 | 170 | ## Contributing 171 | 172 | Contributions are welcome! Please feel free to submit a Pull Request. 173 | 174 | ## License 175 | 176 | This project is licensed under the MIT License. 177 | -------------------------------------------------------------------------------- /copa.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "copa", 3 | "version": "1.3.0", 4 | "description": "CoPa: Copy File Sources For Prompting and LLM Template Processing", 5 | "type": "commonjs", 6 | "main": "./dist/copa.js", 7 | "bin": "./dist/copa.js", 8 | "scripts": { 9 | "build": "tsc", 10 | "start": "node dist/copa.js", 11 | "test": "vitest" 12 | }, 13 | "author": "Roman Landenband", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "@types/jsdom": "^21.1.7", 17 | "@types/node": "^22.10.1", 18 | "ts-node": "^10.9.2", 19 | "typescript": "^5.7.2", 20 | "vitest": "^2.1.8" 21 | }, 22 | "dependencies": { 23 | "@dqbd/tiktoken": "^1.0.17", 24 | "clipboardy": "^4.0.0", 25 | "commander": "^12.1.0", 26 | "glob": "^11.0.0", 27 | "mammoth": "^1.9.0", 28 | "minimatch": "^10.0.1", 29 | "officeparser": "^5.1.1", 30 | "pdfjs-dist": "^5.2.133", 31 | "simple-git": "^3.27.0" 32 | }, 33 | "files": [ 34 | "dist/**/*" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /prompts/1__new_feature-tests.copa: -------------------------------------------------------------------------------- 1 | 2 | This is the source: 3 | 4 | ``` 5 | {{@../src}} 6 | ``` 7 | 8 | Please help me add support for generating simple ASCII tree for a given location (assuming its a directory) 9 | For example when I do `@../src:dir`- this will be generated as directory structure instead of contents. 10 | 11 | The feature was implemented but some tests are failing, this is what the test expects: 12 | 13 | 14 | expect(result.content).toContain('Project structure:'); 15 | expect(result.content).toContain('===== Directory Structure: src ====='); 16 | expect(result.content).toContain('src'); 17 | expect(result.content).toContain('├── components/'); 18 | expect(result.content).toContain('│ ├── Button.js'); 19 | expect(result.content).toContain('│ └── Card.js'); 20 | expect(result.content).toContain('├── utils/'); 21 | expect(result.content).toContain('│ └── format.js'); 22 | expect(result.content).toContain('└── index.js'); 23 | 24 | 25 | But the result is: 26 | 27 | ├── components/ 28 | │ ├── Button.js 29 | │ ├── Card.js 30 | ├── utils/ 31 | │ ├── format.js 32 | ├── index.js 33 | -------------------------------------------------------------------------------- /prompts/1__new_feature.copa: -------------------------------------------------------------------------------- 1 | I'm working on an OSS project 2 | 3 | ``` 4 | {{@./snips/about_project.md}} 5 | ``` 6 | 7 | This is the source: 8 | 9 | ``` 10 | {{@../src}} 11 | ``` 12 | 13 | Please help me add support for generating simple ASCII tree for a given location (assuming its a directory) 14 | 15 | For example when I do `@../src:dir`- this will be generated as directory structure instead of contents. 16 | This is not implemented optimally, when I use `@.:-*.md,-**/subdir/**` its being detected as "dir"... 17 | -------------------------------------------------------------------------------- /prompts/2__fix-dir-git.copa: -------------------------------------------------------------------------------- 1 | I'm working on an OSS project 2 | 3 | ``` 4 | {{@./snips/about_project.md}} 5 | ``` 6 | 7 | This is the source: 8 | 9 | ``` 10 | {{@../src}} 11 | ``` 12 | 13 | The feature I'm working on is: 14 | - Add support for generating simple ASCII tree for a given location (assuming its a directory) 15 | For example when I do `@../src:dir`- this will be generated as directory structure instead of contents. 16 | 17 | The issue is that it's implemented using fs and not using `filterFiles`, as a result it's not respecting git ignore for example.. 18 | 19 | -------------------------------------------------------------------------------- /prompts/doesnt_run.copa: -------------------------------------------------------------------------------- 1 | I'm working on an OSS project 2 | 3 | This is the source of it: 4 | 5 | ``` 6 | {{@../src}} 7 | ``` 8 | 9 | These are the current tests: 10 | 11 | ```` 12 | {{@../tests}} 13 | ```` 14 | 15 | I have an issue with unicode characters, specifically when I use my library to copy, 16 | it's turning `FCN: F × X → {` into `FCN: F √ó X ‚Üí {`. 17 | 18 | Can you help me set up a test for this? 19 | -------------------------------------------------------------------------------- /prompts/failed_test.copa: -------------------------------------------------------------------------------- 1 | I'm working on an OSS project 2 | 3 | This is the source of it: 4 | 5 | ``` 6 | {{@../src}} 7 | ``` 8 | 9 | And tests: 10 | 11 | ``` 12 | {{@../tests}} 13 | ``` 14 | 15 | Some tests are failing, can you investigate? 16 | 17 | 18 | 19 | ● CoPa Functionality › filterFiles › excludes files based on command line options 20 | 21 | expect(received).toBe(expected) // Object.is equality 22 | 23 | Expected: 2 24 | Received: 6 25 | 26 | 39 | test('excludes files based on command line options', async () => { 27 | 40 | const files = await filterFiles({exclude: 'js,md'}, testDir); 28 | > 41 | expect(files.length).toBe(2); 29 | | ^ 30 | 42 | expect(files.sort()).toEqual([ 31 | 43 | 'file3.yml', 32 | 44 | path.join('subdir', 'file6.yml') 33 | 34 | at Object. (tests/sanity.test.ts:41:34) 35 | 36 | ● CoPa Functionality › filterFiles › excludes files based on single extension 37 | 38 | expect(received).toBe(expected) // Object.is equality 39 | 40 | Expected: 4 41 | Received: 6 42 | 43 | 48 | test('excludes files based on single extension', async () => { 44 | 49 | const files = await filterFiles({exclude: 'yml'}, testDir); 45 | > 50 | expect(files.length).toBe(4); 46 | | ^ 47 | 51 | expect(files.sort()).toEqual([ 48 | 52 | 'file1.js', 49 | 53 | 'file2.md', 50 | 51 | at Object. (tests/sanity.test.ts:50:34) 52 | 53 | ● hidden folders › filterFiles › excludes hidden folder and its files with glob pattern 54 | 55 | expect(received).toBe(expected) // Object.is equality 56 | 57 | Expected: 6 58 | Received: 7 59 | 60 | 131 | test('excludes hidden folder and its files with glob pattern', async () => { 61 | 132 | const files = await filterFiles({ exclude: '.*' }, testDir); 62 | > 133 | expect(files.length).toBe(6); 63 | | ^ 64 | 134 | expect(files.sort()).toEqual([ 65 | 135 | 'file1.js', 66 | 136 | 'file2.md', 67 | 68 | at Object. (tests/sanity.test.ts:133:34) 69 | -------------------------------------------------------------------------------- /prompts/fix-bug.copa: -------------------------------------------------------------------------------- 1 | I'm working on an OSS project 2 | 3 | ``` 4 | {{@./snips/about_project.md}} 5 | ``` 6 | 7 | This is the source: 8 | 9 | ``` 10 | {{@../src}} 11 | ``` 12 | 13 | When I run tests, it this is what I get: 14 | ```` 15 | ===== component.tsx (imports removed) ===== 16 | ```` 17 | 18 | While expecting: 19 | ```` 20 | ===== src/components/component.tsx (imports removed) ===== 21 | ```` 22 | 23 | How can I fix this? -------------------------------------------------------------------------------- /prompts/new_feature.copa: -------------------------------------------------------------------------------- 1 | I'm working on an OSS project 2 | 3 | ``` 4 | {{@./snips/about_project.md}} 5 | ``` 6 | 7 | This is the source: 8 | 9 | ``` 10 | {{@../src}} 11 | ``` 12 | 13 | Please help me add support for reading certain files types, here's some code from another project : 14 | 15 | ````typescript 16 | 17 | import * as officeParser from "officeparser"; 18 | import {Buffer} from "buffer"; 19 | 20 | export class FileReader { 21 | 22 | async getFileContent() { 23 | 24 | try { 25 | 26 | // --- Step 3: Process Content Based on Metadata --- 27 | const isOfficedocument = fileType.startsWith("application/vnd.openxmlformats-officedocument") || 28 | fileType.startsWith("application/vnd.ms-") || 29 | fileType === "application/msword"; 30 | 31 | const isTextBased = fileType.startsWith("text/") || 32 | fileType === "application/json" || 33 | fileType.includes("xml") || 34 | fileType.includes("javascript"); 35 | 36 | if (isOfficedocument || ["docx", "doc", "xlsx", "xls", "pptx", "ppt", "pdf"].includes(fileExt)) { 37 | try { 38 | textContent = await officeParser.parseOfficeAsync(fileBlob); 39 | if (!textContent || textContent.trim().length === 0) { 40 | console.debug(`officeParser returned empty for ${fileName}. Falling back to text decode.`); 41 | textContent = new TextDecoder().decode(fileBlob); 42 | } 43 | } catch (parserError) { 44 | console.warn( 45 | `officeParser failed for ${fileName} (${fileType}, ${fileExt}). Falling back to text decode. Error: ${parserError}` 46 | ); 47 | // Fallback: Treat as text if parsing fails 48 | textContent = new TextDecoder().decode(fileBlob); 49 | } 50 | } else if (isTextBased || ["txt", "csv", "json", "xml", "js", "ts", "html", "css"].includes(fileExt)) { 51 | textContent = new TextDecoder().decode(fileBlob); 52 | } else { 53 | console.warn(`Attempting generic text decode for unknown file type: ${fileName} (${fileType})`); 54 | try { 55 | textContent = new TextDecoder("utf-8", {fatal: false}).decode(fileBlob); 56 | } catch (decodeError) { 57 | textContent = `[Content of file ${fileName} could not be decoded (${fileType})]`; 58 | } 59 | if (!textContent || textContent.trim().length === 0) { 60 | textContent = `[Content of file ${fileName} could not be extracted or is empty (${fileType})]`; 61 | } 62 | } 63 | 64 | return { 65 | text: textContent.trim(), 66 | metadata: { 67 | name: fileName, 68 | type: fileType, 69 | }, 70 | }; 71 | } catch (error: any) { 72 | 73 | } 74 | } 75 | 76 | 77 | } 78 | ```` 79 | 80 | - applies when importing single file or a folder -------------------------------------------------------------------------------- /prompts/new_feature_tests.copa: -------------------------------------------------------------------------------- 1 | I'm working on an OSS project 2 | 3 | ``` 4 | {{@./snips/about_project.md}} 5 | ``` 6 | 7 | This is the source: 8 | 9 | ``` 10 | {{@../src}} 11 | ``` 12 | 13 | Please help me test support for removing imports from imported sources files using `:remove-imports` modifier 14 | 15 | - applies when importing single file or a folder 16 | - per language handling by filename (`.ts`, `.tsx`) 17 | - for now just implement for `.ts` & `.tsx` 18 | 19 | Using this as reference: 20 | ```` 21 | describe('Prompt Processor with remove imports from file', () => { 22 | let testDir: string; 23 | 24 | const cleanPath = (path: string) => path.replace(testDir + '/', ''); 25 | 26 | beforeEach(async () => { 27 | testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'copa-prompt-test-')); 28 | await fs.mkdir(path.join(testDir, 'subdir')); 29 | await fs.writeFile(path.join(testDir, 'file1.js'), 'console.log("Hello");'); 30 | await fs.writeFile(path.join(testDir, 'file2.md'), '# Markdown'); 31 | await fs.writeFile(path.join(testDir, 'subdir', 'file3.txt'), 'Nested file content'); 32 | }); 33 | 34 | afterEach(async () => { 35 | await fs.rm(testDir, {recursive: true, force: true}); 36 | }); 37 | 38 | test('....', async () => { 39 | const promptContent = 'This is...'; 40 | const promptFile = path.join(testDir, 'prompt.txt'); 41 | await fs.writeFile(promptFile, promptContent); 42 | 43 | const result = await processPromptFile(promptFile); 44 | 45 | expect(...).toContain('...'); 46 | }); 47 | 48 | 49 | }) 50 | ```` -------------------------------------------------------------------------------- /prompts/snips/about_project.md: -------------------------------------------------------------------------------- 1 | CoPa: LLM Prompt Templating CLI 2 | 3 | CoPa is a lightweight CLI tool for generating structured prompts for Large Language Models (LLMs) using dynamic file 4 | references. 5 | 6 | 🔧 Features 7 | • Templated prompts using `{{@path[:options]}}` syntax 8 | • Include file content with `===== filename =====` wrappers (default) 9 | • Include raw file content without wrappers using `:clean` option (e.g., `{{@file.txt:clean}}`) 10 | • Remove import/require statements from TS/TSX files using `:remove-imports` option ( 11 | e.g., `{{@src/component.tsx:remove-imports}}`) 12 | • Include directory structure trees using `:dir` option (e.g., `{{@src:dir}}`) 13 | • Evaluate nested templates using `:eval` option (e.g., `{{@other-template.copa:eval}}`) 14 | • Copy folders/files in LLM-friendly format (`copa copy`) 15 | • Inline glob-based ignore rules (e.g., `{{@tests:-*.snap}}`) 16 | • `.gitignore` support 17 | • Global ignore via `~/.copa` config file 18 | • Built-in token counting (using `tiktoken` for `gpt-4`) 19 | • Easy CLI with `npx copa` or global install 20 | 21 | 📦 Example 22 | 23 | Template (`prompt.copa`): 24 | 25 | ```copa 26 | Analyze the following code: 27 | {{@src/main.js}} 28 | 29 | Here are the tests, excluding snapshots: 30 | {{@tests:-*.snap}} 31 | 32 | Inject this helper function directly: 33 | {{@src/utils/helper.js:clean}} 34 | 35 | Directory structure of config: 36 | {{@config:dir}} 37 | 38 | Analyze this React component's core logic (imports removed): 39 | {{@src/components/MyComponent.tsx:remove-imports}} 40 | 41 | Include all utils code, clean and without imports: 42 | {{@src/utils:clean,remove-imports}} 43 | ``` 44 | 45 | Run: 46 | 47 | ```bash 48 | npx copa t prompt.copa 49 | ``` 50 | 51 | Output (to clipboard): 52 | 53 | ``` 54 | Analyze the following code: 55 | ===== src/main.js ===== 56 | 57 | 58 | 59 | Here are the tests, excluding snapshots: 60 | ===== tests/example.test.js ===== 61 | 62 | 63 | 64 | Inject this helper function directly: 65 | 66 | 67 | Directory structure of config: 68 | ===== Directory Structure: config ===== 69 | config/ 70 | ├── settings.json 71 | └── deploy.sh 72 | 73 | 74 | Analyze this React component's core logic (imports removed): 75 | ===== src/components/MyComponent.tsx (imports removed) ===== 76 | 77 | 78 | 79 | Include all utils code, clean and without imports: 80 | 81 | 82 | 83 | 84 | ``` 85 | 86 | 🧠 Use Cases 87 | • Repeatable prompts with consistent file context 88 | • Fine-grained control over included source files and directories 89 | • Injecting raw code snippets or data without formatting 90 | • Focusing LLMs on core logic by stripping boilerplate imports from TS/TSX files 91 | • Great for prompt engineering in code-focused workflows 92 | 93 | -------------------------------------------------------------------------------- /prompts/update_readme.copa: -------------------------------------------------------------------------------- 1 | I'm working on an OSS project 2 | 3 | ```` 4 | {{@../README.md}} 5 | ```` 6 | 7 | This is the source code: 8 | 9 | ``` 10 | {{@../src}} 11 | ``` 12 | 13 | And tests: 14 | 15 | ``` 16 | {{@../tests}} 17 | ``` 18 | 19 | Can you help me update the README to be inline with the latest code and the examples seen in tests? 20 | -------------------------------------------------------------------------------- /src/copa.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import {program} from 'commander'; 4 | import * as fs from 'fs/promises'; 5 | import {encoding_for_model} from '@dqbd/tiktoken'; 6 | import {Options} from "./options"; 7 | import {readGlobalConfig} from "./readGlobalConfig"; 8 | import {filterFiles} from "./filterFiles"; 9 | import {processPromptFile} from './promptProcessor'; 10 | import path from "path"; 11 | import {copyToClipboard} from "./copyToClipboard"; 12 | import { getFileContentAsText } from './fileReader'; 13 | 14 | function countTokens(input: string): number { 15 | const tokenize = encoding_for_model('gpt-4'); 16 | try { 17 | return tokenize.encode(input).length; 18 | } catch (e) { 19 | console.error('Error counting tokens for input', e); 20 | throw new Error('Error counting tokens for input'); 21 | } finally { 22 | tokenize.free(); 23 | } 24 | } 25 | 26 | async function copyFilesToClipboard(source: { 27 | directory?: string, 28 | filePaths?: string[] 29 | }, options: Options): Promise { 30 | try { 31 | const globalExclude = await readGlobalConfig(); 32 | let filesToProcess: string[] = []; 33 | 34 | if (source.directory) { 35 | const filtered = await filterFiles(options, source.directory, globalExclude); 36 | filesToProcess = filtered ?? []; 37 | } else if (source.filePaths && source.filePaths.length > 0) { 38 | // For explicitly listed files, we don't run them through the full filterFiles logic again 39 | // as they are already resolved paths. We assume they are wanted. 40 | // However, filterFiles does gitignore checking, which might be desired. 41 | // For now, let's assume direct file paths bypass complex filtering but respect global/inline excludes. 42 | // A simpler check might be needed if globalExclude should apply to direct files. 43 | // For simplicity, if filePaths are given, we process them directly. 44 | // Re-evaluating: filterFiles can take a single file path. Let's use it for consistency. 45 | const resolvedFiles = []; 46 | for (const fp of source.filePaths) { 47 | const filtered = await filterFiles(options, fp, globalExclude); 48 | if (filtered) resolvedFiles.push(...filtered); 49 | } 50 | filesToProcess = resolvedFiles; 51 | } 52 | 53 | 54 | if (filesToProcess.length === 0) { 55 | console.log(`No files found to copy from ${source.directory ? source.directory : (source.filePaths?.join(', ') ?? 'files list')}.`); 56 | return; 57 | } 58 | 59 | let totalTokens = 0; 60 | const tokensPerFile: { [_: string]: number } = {}; 61 | let content = ''; 62 | 63 | for (const file of filesToProcess) { 64 | try { 65 | // --- MODIFIED PART --- 66 | const fileContent = await getFileContentAsText(file); // Use the new utility 67 | // --- END MODIFIED PART --- 68 | 69 | const fileSection = `===== ${file} =====\n${fileContent}\n\n`; 70 | content += fileSection; 71 | tokensPerFile[file] = countTokens(fileSection); 72 | totalTokens += tokensPerFile[file]; 73 | } catch (error: any) { 74 | // This catch is a fallback. getFileContentAsText should handle most read/parse errors. 75 | console.error(`Error processing file ${file} for copy:`, error.message); 76 | const errorMsg = `[Error processing file ${path.basename(file)}: ${error.message}]`; 77 | const errorSection = `===== ${file} =====\n${errorMsg}\n\n`; 78 | content += errorSection; 79 | // Still count tokens for the error message part 80 | const errorTokens = countTokens(errorSection); 81 | tokensPerFile[file] = errorTokens; 82 | totalTokens += errorTokens; 83 | } 84 | } 85 | 86 | content = content.normalize('NFC'); 87 | 88 | await copyToClipboard(content); 89 | console.log(`${filesToProcess.length} file(s) from ${source.directory ? source.directory : (source.filePaths?.join(', ') ?? 'input list')} have been copied to the clipboard.`); 90 | console.log(`Total tokens: ${totalTokens}`); 91 | 92 | if (options.verbose) { 93 | console.log('Copied files:'); 94 | filesToProcess.forEach(file => console.log(`${file} [${tokensPerFile[file]}]`)); 95 | } 96 | } catch (error: any) { 97 | console.error('Error copying files to clipboard:', error.message); 98 | process.exit(1); 99 | } 100 | } 101 | 102 | 103 | async function handleTemplateCommand(file: string, options: { verbose?: boolean }) { 104 | try { 105 | const globalExclude = await readGlobalConfig(); 106 | const { 107 | content, 108 | warnings, 109 | includedFiles, 110 | totalTokens 111 | } = await processPromptFile(path.resolve(file), globalExclude); 112 | 113 | await copyToClipboard(content); 114 | console.log(`Processed template from ${file} has been copied to the clipboard.`); 115 | console.log(`Total tokens: ${totalTokens}`); 116 | 117 | if (warnings.length > 0) { 118 | console.warn(warnings.join('\n')); 119 | } 120 | 121 | if (options.verbose && includedFiles) { 122 | console.log('\nIncluded files:'); 123 | Object.entries(includedFiles).forEach(([file, tokens]) => { 124 | console.log(`${file} [${tokens}]`); 125 | }); 126 | } 127 | } catch (error) { 128 | console.error('Error processing template file:', error); 129 | process.exit(1); 130 | } 131 | } 132 | 133 | async function handleCopyCommand(directory: string | undefined, options: Options) { 134 | if (options.file && options.file.length > 0) { 135 | // Use the provided file paths 136 | const normalizedPaths = options.file.map(f => path.normalize(path.resolve(f))); 137 | await copyFilesToClipboard({filePaths: normalizedPaths}, options); 138 | } else if (directory) { 139 | const fullPath = path.resolve(directory); 140 | 141 | // Check if the provided directory is actually a file 142 | try { 143 | const stats = await fs.stat(fullPath); 144 | if (stats.isFile()) { 145 | // Treat it as a single file, not a directory 146 | await copyFilesToClipboard({filePaths: [fullPath]}, options); 147 | } else if (stats.isDirectory()) { 148 | // It's a directory 149 | console.log(`Copying files from ${path.normalize(directory)}`); 150 | await copyFilesToClipboard({directory: fullPath}, options); 151 | } else { 152 | console.error('Error: Provided path is neither a file nor a directory.'); 153 | process.exit(1); 154 | } 155 | } catch (error) { 156 | console.error('Error: Unable to resolve the provided path.', error); 157 | process.exit(1); 158 | } 159 | } else { 160 | console.error('Error: Please provide either a directory or use the --file option.'); 161 | process.exit(1); 162 | } 163 | } 164 | 165 | async function handleToCommand(file: string, options: { errors?: boolean, tokens?: boolean, verbose?: boolean }) { 166 | try { 167 | const globalExclude = await readGlobalConfig(); 168 | const { 169 | content, 170 | warnings, 171 | includedFiles, 172 | totalTokens 173 | } = await processPromptFile(path.resolve(file), globalExclude); 174 | 175 | if (options.errors) { 176 | // Output only errors 177 | if (warnings.length > 0) { 178 | console.log(warnings.join('\n')); 179 | } else { 180 | console.log(''); 181 | } 182 | } else if (options.tokens) { 183 | // Output only token count 184 | console.log(totalTokens); 185 | } else { 186 | // Output the rendered content 187 | console.log(content); 188 | 189 | // If verbose, also output additional information to stderr 190 | // so it doesn't interfere with piping the main output 191 | if (options.verbose) { 192 | console.error(`\nProcessed template from ${file}`); 193 | console.error(`Total tokens: ${totalTokens}`); 194 | 195 | if (warnings.length > 0) { 196 | console.error('\nWarnings:'); 197 | console.error(warnings.join('\n')); 198 | } 199 | 200 | if (includedFiles) { 201 | console.error('\nIncluded files:'); 202 | Object.entries(includedFiles).forEach(([file, tokens]) => { 203 | console.error(`${file} [${tokens}]`); 204 | }); 205 | } 206 | } 207 | } 208 | } catch (error) { 209 | console.error('Error processing template file:', error); 210 | process.exit(1); 211 | } 212 | } 213 | 214 | 215 | program 216 | .name('copa') 217 | .description('CoPa: Copy File Sources For Prompting and LLM Template Processing') 218 | .version('1.0.0'); 219 | 220 | program 221 | .command('template ') 222 | .alias('t') 223 | .description('Process an LLM prompt template file and copy to clipboard') 224 | .option('-v, --verbose', 'Display detailed information about processed files and token counts') 225 | .action(handleTemplateCommand); 226 | 227 | program 228 | .command('copy [directory]') 229 | .alias('c') 230 | .description('Copy files from a directory or a single file to the clipboard (legacy mode)') 231 | .option('-ex, --exclude ', 'Comma-separated list of file extensions to exclude (in addition to global config)') 232 | .option('-v, --verbose', 'Display the list of copied files') 233 | .option('-f, --file ', 'Path to a single file to copy', (value, previous: string[]) => previous.concat([value]), []) 234 | .action(handleCopyCommand); 235 | 236 | program 237 | .command('to ') 238 | .description('Process a template file and output to stdout instead of clipboard') 239 | .option('-err, --errors', 'Output only errors (like missing files)') 240 | .option('-t, --tokens', 'Output only the token count') 241 | .option('-v, --verbose', 'Display detailed information about processed files and token counts') 242 | .action(handleToCommand); 243 | 244 | program 245 | .action(() => { 246 | console.log('Please specify a command: "template" (or "t") or "copy" (or "c")'); 247 | program.outputHelp(); 248 | }); 249 | 250 | program.parse(process.argv); 251 | -------------------------------------------------------------------------------- /src/copyToClipboard.ts: -------------------------------------------------------------------------------- 1 | import {default as clipboardy} from "clipboardy" 2 | 3 | export async function copyToClipboard(content: string): Promise { 4 | // Ensure content is properly normalized before writing to clipboard 5 | const normalizedContent = content.normalize('NFC'); 6 | await clipboardy.write(normalizedContent); 7 | } 8 | -------------------------------------------------------------------------------- /src/directoryTree.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import {filterFiles} from './filterFiles'; 3 | import * as fs from 'fs/promises'; 4 | 5 | interface TreeNode { 6 | name: string; 7 | children: TreeNode[]; 8 | isDirectory: boolean; 9 | } 10 | 11 | export async function generateDirectoryTree( 12 | directoryPath: string, 13 | ignorePatterns: string[] = [] 14 | ): Promise { 15 | try { 16 | const stats = await fs.stat(directoryPath); 17 | if (!stats.isDirectory()) { 18 | return `Not a directory: ${directoryPath}`; 19 | } 20 | 21 | const rootName = path.basename(directoryPath); 22 | const tree = await buildTree(directoryPath, ignorePatterns); 23 | return renderTree({ 24 | name: rootName, 25 | children: tree, 26 | isDirectory: true 27 | }); 28 | } catch (error) { 29 | return `Error generating directory tree: ${error}`; 30 | } 31 | } 32 | 33 | async function buildTree( 34 | dirPath: string, 35 | ignorePatterns: string[] = [] 36 | ): Promise { 37 | // Use filterFiles to get all files respecting git ignore 38 | const files = await filterFiles({ 39 | exclude: ignorePatterns.join(',') 40 | }, dirPath); 41 | 42 | if (!files) { 43 | return []; 44 | } 45 | 46 | // Create a map for the tree structure 47 | const treeMap = new Map(); 48 | 49 | // Process all files to build directory tree 50 | for (const filePath of files) { 51 | // Get relative path from the base directory 52 | const relativePath = path.relative(dirPath, filePath); 53 | if (!relativePath) continue; 54 | 55 | // Split path into components 56 | const pathComponents = relativePath.split(path.sep); 57 | 58 | // Build tree nodes for each path component 59 | let currentPath = ''; 60 | let parentPath = ''; 61 | 62 | for (let i = 0; i < pathComponents.length; i++) { 63 | const component = pathComponents[i]; 64 | parentPath = currentPath; 65 | currentPath = currentPath ? path.join(currentPath, component) : component; 66 | 67 | // Skip if we already have this node 68 | if (treeMap.has(currentPath)) continue; 69 | 70 | // Determine if this is a directory or file 71 | const isDirectory = i < pathComponents.length - 1; 72 | 73 | // Create new node 74 | const newNode: TreeNode = { 75 | name: component, 76 | children: [], 77 | isDirectory 78 | }; 79 | 80 | // Add to map 81 | treeMap.set(currentPath, newNode); 82 | 83 | // Add to parent's children if not root 84 | if (parentPath) { 85 | const parent = treeMap.get(parentPath); 86 | if (parent) { 87 | parent.children.push(newNode); 88 | } 89 | } 90 | } 91 | } 92 | 93 | // Get all top-level nodes 94 | const rootNodes: TreeNode[] = []; 95 | for (const [nodePath, node] of treeMap.entries()) { 96 | if (!nodePath.includes(path.sep)) { 97 | rootNodes.push(node); 98 | } 99 | } 100 | 101 | // Sort nodes - directories first, then alphabetically 102 | rootNodes.sort((a, b) => { 103 | if (a.isDirectory && !b.isDirectory) return -1; 104 | if (!a.isDirectory && b.isDirectory) return 1; 105 | return a.name.localeCompare(b.name); 106 | }); 107 | 108 | // Sort children of all nodes 109 | for (const node of treeMap.values()) { 110 | if (node.children.length > 0) { 111 | node.children.sort((a, b) => { 112 | if (a.isDirectory && !b.isDirectory) return -1; 113 | if (!a.isDirectory && b.isDirectory) return 1; 114 | return a.name.localeCompare(b.name); 115 | }); 116 | } 117 | } 118 | 119 | return rootNodes; 120 | } 121 | 122 | function renderTree(node: TreeNode): string { 123 | const lines: string[] = []; 124 | 125 | function renderNode(node: TreeNode, prefix: string): void { 126 | // For each child in the current node 127 | for (let i = 0; i < node.children.length; i++) { 128 | const child = node.children[i]; 129 | const isLastChild = i === node.children.length - 1; 130 | 131 | // Choose the correct connector based on whether this is the last child 132 | const connector = isLastChild ? '└── ' : '├── '; 133 | 134 | // Choose the correct prefix for the next level based on whether this is the last child 135 | const nextPrefix = isLastChild ? ' ' : '│ '; 136 | 137 | // Add the line for the current child 138 | lines.push(`${prefix}${connector}${child.name}${child.isDirectory ? '/' : ''}`); 139 | 140 | // If this child has children, render them with the appropriate prefix 141 | if (child.isDirectory && child.children.length > 0) { 142 | renderNode(child, prefix + nextPrefix); 143 | } 144 | } 145 | } 146 | 147 | // Start rendering from the root node 148 | lines.push(node.name + "/"); 149 | if (node.children.length > 0) { 150 | renderNode(node, ""); 151 | } 152 | 153 | return lines.join('\n'); 154 | } 155 | -------------------------------------------------------------------------------- /src/fileReader.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs/promises'; 2 | import * as path from 'path'; 3 | import * as officeParser from 'officeparser'; 4 | 5 | /** 6 | * Reads the content of a file and returns it as text. 7 | * Handles Office documents, PDFs, known text files, and provides fallbacks. 8 | * @param filePath The absolute path to the file. 9 | * @returns A promise that resolves to the text content of the file. 10 | */ 11 | export async function getFileContentAsText(filePath: string): Promise { 12 | const fileName = path.basename(filePath); 13 | const fileExt = path.extname(filePath).toLowerCase().substring(1); // e.g., 'docx', 'pdf', 'txt' 14 | let textContent: string; 15 | 16 | const officeExtensions = ["docx", "doc", "xlsx", "xls", "pptx", "ppt", "pdf"]; 17 | const textBasedExtensions = [ 18 | "txt", "csv", "json", "xml", "js", "ts", "tsx", 19 | "html", "css", "md", "copa", "log", "yaml", "yml", 20 | "ini", "cfg", "conf", "sh", "bat", "ps1", "py", "rb", "php", "java", "c", "cpp", "h", "hpp", "cs", "go", "rs", "swift", "kt" 21 | // Add any other primarily text-based extensions you want to support directly 22 | ]; 23 | 24 | if (officeExtensions.includes(fileExt)) { 25 | try { 26 | // officeParser.parseOfficeAsync can take a file path directly. 27 | textContent = await officeParser.parseOfficeAsync(filePath); 28 | if (!textContent || textContent.trim().length === 0) { 29 | // console.warn(`officeParser returned empty for ${fileName} (ext: ${fileExt}). File might be empty or unparseable.`); 30 | textContent = ""; // Assume empty or no parsable text content 31 | } 32 | } catch (parserError: any) { 33 | console.warn( 34 | `officeParser failed for ${fileName} (ext: ${fileExt}). Error: ${parserError.message}` 35 | ); 36 | textContent = `[Error parsing Office/PDF document ${fileName}: ${parserError.message}]`; 37 | } 38 | } else if (textBasedExtensions.includes(fileExt) || !fileExt /* Treat files without extension as potentially text-based */) { 39 | try { 40 | textContent = await fs.readFile(filePath, {encoding: 'utf8'}); 41 | } catch (readError: any) { 42 | // console.warn(`Error reading file ${fileName} as UTF-8: ${readError.message}. Attempting latin1 fallback.`); 43 | try { 44 | textContent = await fs.readFile(filePath, {encoding: 'latin1'}); // Basic fallback for common alternative encoding 45 | } catch (fallbackError: any) { 46 | textContent = `[Error reading text file ${fileName}: ${fallbackError.message}]`; 47 | } 48 | } 49 | } else { 50 | // console.warn(`Attempting generic text decode for unknown file type: ${fileName} (ext: ${fileExt})`); 51 | try { 52 | const fileBuffer = await fs.readFile(filePath); 53 | // Use TextDecoder with fatal: false to replace invalid sequences rather than throwing. 54 | const decoder = new TextDecoder("utf-8", {fatal: false}); 55 | textContent = decoder.decode(fileBuffer); 56 | 57 | // Basic heuristic: if it contains many replacement characters, it's likely binary. 58 | if (textContent.includes('\uFFFD') && textContent.length > 100) { // \uFFFD is the Unicode replacement character 59 | const replacementCharCount = (textContent.match(/\uFFFD/g) || []).length; 60 | if (replacementCharCount > textContent.length / 10 && replacementCharCount > 5) { // If >10% are replacement chars 61 | // console.warn(`File ${fileName} (ext: ${fileExt}) appears to be binary after UTF-8 decode attempt.`); 62 | textContent = `[Content of binary file ${fileName} (ext: ${fileExt}) is not displayed]`; 63 | } 64 | } 65 | 66 | if ((!textContent || textContent.trim().length === 0) && !textContent.startsWith("[")) { // Don't overwrite previous error/info messages 67 | textContent = `[Content of file ${fileName} could not be extracted or is empty (type: ${fileExt})]`; 68 | } 69 | } catch (decodeError: any) { 70 | textContent = `[Content of file ${fileName} could not be decoded (type: ${fileExt}): ${decodeError.message}]`; 71 | } 72 | } 73 | return textContent; 74 | } -------------------------------------------------------------------------------- /src/filterFiles.ts: -------------------------------------------------------------------------------- 1 | import {Options} from "./options"; 2 | import {simpleGit} from "simple-git"; 3 | import {glob} from "glob"; 4 | import path from "path"; 5 | import {minimatch} from "minimatch"; 6 | import fs from "fs/promises"; 7 | 8 | async function fileExists(filePath: string): Promise { 9 | try { 10 | await fs.access(filePath); // Check if file exists 11 | return true; 12 | } catch (error) { 13 | return false; 14 | } 15 | } 16 | 17 | export async function filterFiles(options: Options, pathToProcess: string, globalExclude?: string): Promise { 18 | const userExclude = options.exclude || ''; 19 | const combinedExclude = [globalExclude ?? '', userExclude].filter(Boolean).join(','); 20 | const excludePatterns = combinedExclude.split(',') 21 | .filter(Boolean) 22 | .map(exPath => exPath.startsWith('-') ? exPath.slice(1) : exPath); 23 | 24 | 25 | let allFiles: string[]; 26 | 27 | try { 28 | const foundFile = await fileExists(pathToProcess); 29 | if (!foundFile) { 30 | console.warn(`The specified path does not exist: ${pathToProcess}`); 31 | return undefined; 32 | } 33 | 34 | const stats = await fs.stat(pathToProcess); 35 | 36 | if (stats.isDirectory()) { 37 | const git = simpleGit(pathToProcess); 38 | const isGitRepo = await git.checkIsRepo(); 39 | 40 | if (isGitRepo) { 41 | const gitFiles = await git.raw(['ls-files', '-co', '--exclude-standard', pathToProcess]); 42 | allFiles = gitFiles.split('\n').filter(Boolean); 43 | } else { 44 | const globPattern = path.join(pathToProcess, '**', '*').replace(/\\/g, '/'); 45 | allFiles = await glob(globPattern, {dot: true, nodir: true}); 46 | } 47 | } else { 48 | allFiles = [pathToProcess]; 49 | } 50 | 51 | 52 | allFiles = allFiles.map(file => { 53 | return path.isAbsolute(file) ? file : path.resolve(pathToProcess, file); 54 | }); 55 | 56 | return allFiles.filter(file => { 57 | const isExcluded = excludePatterns.some(pattern => { 58 | if (pattern === '.*') { 59 | return file.split(path.sep).some(part => part.startsWith('.')); 60 | } else if (pattern.includes('*') || pattern.includes('/')) { 61 | return minimatch(file, pattern, {dot: true, matchBase: true}); 62 | } else { 63 | // Check if it's an exact file match or exact extension match 64 | const fileName = path.basename(file); 65 | return fileName === pattern || 66 | (pattern.startsWith('.') && pattern === path.extname(file)); 67 | } 68 | }); 69 | if (isExcluded) { 70 | } 71 | return !isExcluded; 72 | }); 73 | 74 | } catch (error: any) { 75 | throw new Error(`Error listing or filtering files: ${error.message}`); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/options.ts: -------------------------------------------------------------------------------- 1 | export interface Options { 2 | exclude?: string; 3 | verbose?: boolean; 4 | file?: string[]; 5 | } 6 | -------------------------------------------------------------------------------- /src/promptProcessor.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs/promises'; 2 | import * as path from 'path'; 3 | import {encoding_for_model} from "@dqbd/tiktoken"; 4 | import {filterFiles} from "./filterFiles"; 5 | import {generateDirectoryTree} from "./directoryTree"; 6 | import {getFileContentAsText} from './fileReader'; 7 | 8 | 9 | interface ProcessResult { 10 | content: string; 11 | warnings: string[]; 12 | includedFiles: { [filePath: string]: number }; 13 | totalTokens: number; 14 | } 15 | 16 | function countTokens(input: string): number { 17 | const tokenize = encoding_for_model('gpt-4'); 18 | try { 19 | // Normalize before counting, like clipboard copy 20 | const normalizedInput = input.normalize('NFC'); 21 | return tokenize.encode(normalizedInput).length; 22 | } catch (e) { 23 | console.error('Error counting tokens for input', e); 24 | throw new Error('Error counting tokens for input'); 25 | } finally { 26 | tokenize.free(); 27 | } 28 | } 29 | 30 | function removeImportsFromFile(content: string, filePath: string): string { 31 | const extension = path.extname(filePath).toLowerCase(); 32 | if (extension !== '.ts' && extension !== '.tsx') { 33 | return content; // Only process .ts and .tsx files 34 | } 35 | 36 | const importRegex = /^\s*import\s+(?:type\s+)?(?:[\w*{}\n\r\t, ]+)\s+from\s+["'].*?["'];?.*$/gm; 37 | // Remove matched import statements 38 | let modifiedContent = content.replace(importRegex, ''); 39 | modifiedContent = modifiedContent.replace(/(\r?\n){3,}/g, '\n'); 40 | 41 | return modifiedContent.trimStart(); 42 | } 43 | 44 | function parsePlaceholder(placeholder: string, warnings: string[]): { 45 | filePath: string; 46 | ignorePatterns: string[]; 47 | isDir: boolean; 48 | isClean: boolean; 49 | isEval: boolean; 50 | isRemoveImports: boolean; // Added new flag 51 | } { 52 | // Remove {{ @ and }} 53 | const innerPlaceholder = placeholder.slice(3, -2); 54 | // Split by the first colon to separate path and options 55 | const colonIndex = innerPlaceholder.indexOf(':'); 56 | const filePath = colonIndex > -1 ? innerPlaceholder.substring(0, colonIndex) : innerPlaceholder; 57 | const optionsString = colonIndex > -1 ? innerPlaceholder.substring(colonIndex + 1) : ''; 58 | 59 | let ignorePatterns: string[] = []; 60 | let isDir = false; 61 | let isClean = false; 62 | let isEval = false; 63 | let isRemoveImports = false; // Initialize flag 64 | 65 | if (optionsString) { 66 | const options = optionsString.split(',').map(p => p.trim()); 67 | const remainingOptions: string[] = []; 68 | 69 | for (const option of options) { 70 | if (option === 'dir') { 71 | isDir = true; 72 | } else if (option === 'clean') { 73 | isClean = true; 74 | } else if (option === 'eval') { 75 | isEval = true; 76 | } else if (option === 'remove-imports') { // Check for new option 77 | isRemoveImports = true; 78 | } else { 79 | // Assume anything else is an ignore pattern 80 | remainingOptions.push(option); 81 | } 82 | } 83 | ignorePatterns = remainingOptions; 84 | } 85 | 86 | const primaryOptions = []; 87 | if (isDir) primaryOptions.push('dir'); 88 | if (isEval) primaryOptions.push('eval'); 89 | if (primaryOptions.length > 1) { 90 | console.warn(`Warning: Multiple incompatible primary options (${primaryOptions.join(', ')}) specified for placeholder "${placeholder}". Prioritizing ${primaryOptions[0]}.`); 91 | if (primaryOptions[0] === 'dir') isEval = false; 92 | } 93 | if ((isDir || isEval) && isRemoveImports) { 94 | warnings.push(`Warning: ':remove-imports' cannot be used with ':dir' or ':eval' in placeholder "${placeholder}". Ignoring ':remove-imports'.`); 95 | isRemoveImports = false; 96 | } 97 | if ((isDir || isEval) && isClean) { 98 | warnings.push(`Warning: ':clean' cannot be used with ':dir' or ':eval' in placeholder "${placeholder}". Ignoring ':clean'.`); 99 | isClean = false; 100 | } 101 | 102 | if (isDir) { 103 | isEval = false; 104 | isClean = false; 105 | isRemoveImports = false; 106 | } else if (isEval) { 107 | isClean = false; 108 | isRemoveImports = false; 109 | } 110 | 111 | return {filePath, ignorePatterns, isDir, isClean, isEval, isRemoveImports}; // Return new flag 112 | } 113 | 114 | export async function processPromptFile(promptFilePath: string, globalExclude?: string): Promise { 115 | const content = await fs.readFile(promptFilePath, 'utf-8'); 116 | const warnings: string[] = []; 117 | const result = await processPromptTemplate(content.normalize('NFC'), path.dirname(promptFilePath), warnings, globalExclude); 118 | return {...result, warnings}; 119 | } 120 | 121 | function findPlaceholders(template: string): Array<{ placeholder: string; index: number }> { 122 | const regex = /{{@(.*?)}}/g; 123 | const placeholders = []; 124 | let match; 125 | 126 | while ((match = regex.exec(template)) !== null) { 127 | placeholders.push({placeholder: match[0], index: match.index}); 128 | } 129 | 130 | // Sort by index to process in order 131 | placeholders.sort((a, b) => a.index - b.index); 132 | return placeholders; 133 | } 134 | 135 | async function processPromptTemplate(template: string, basePath: string, warnings: string[], globalExclude?: string): Promise { 136 | const placeholders = findPlaceholders(template); 137 | let processedContent = template; 138 | const includedFiles: { [filePath: string]: number } = {}; 139 | let accumulatedOffset = 0; 140 | 141 | for (const placeholderMatch of placeholders) { 142 | const {placeholder, index} = placeholderMatch; 143 | const { 144 | filePath, 145 | ignorePatterns, 146 | isDir, 147 | isClean, 148 | isEval, 149 | isRemoveImports 150 | } = parsePlaceholder(placeholder, warnings); 151 | const normalizedPath = path.normalize(path.resolve(basePath, filePath)); 152 | 153 | let replacementText = ''; 154 | let replacementTokens = 0; 155 | const placeholderIncludedFiles: { [key: string]: number } = {}; 156 | 157 | try { 158 | if (isDir) { 159 | const treeContent = await generateDirectoryTree(normalizedPath, ignorePatterns); 160 | replacementText = `===== Directory Structure: ${filePath} =====\n${treeContent}\n\n`; 161 | replacementTokens = countTokens(replacementText); 162 | placeholderIncludedFiles[`${filePath} (directory tree)`] = replacementTokens; 163 | } else if (isEval) { 164 | try { 165 | const templateContent = await fs.readFile(normalizedPath, 'utf-8'); 166 | 167 | const templateBasePath = path.dirname(normalizedPath); 168 | const evalResult = await processPromptTemplate( 169 | templateContent.normalize('NFC'), 170 | templateBasePath, 171 | warnings, 172 | globalExclude 173 | ); 174 | 175 | replacementText = evalResult.content; 176 | replacementTokens = evalResult.totalTokens; 177 | 178 | const prefixedIncludedFiles: { [key: string]: number } = {}; 179 | for (const [key, value] of Object.entries(evalResult.includedFiles)) { 180 | prefixedIncludedFiles[`eval:${filePath}:${key}`] = value; 181 | } 182 | Object.assign(placeholderIncludedFiles, prefixedIncludedFiles); 183 | 184 | 185 | } catch (error: any) { 186 | warnings.push(`Warning: Failed to evaluate template ${filePath}: ${error.message}`); 187 | replacementText = `[Error evaluating template: ${filePath}]`; 188 | replacementTokens = countTokens(replacementText); 189 | } 190 | } else { 191 | const pathResult = await processPath(normalizedPath, ignorePatterns, globalExclude, basePath); 192 | warnings.push(...pathResult.warnings); 193 | 194 | if (pathResult.files.length === 0) { 195 | throw new Error(`Path [${filePath}] not found or yielded no files after filtering.`); 196 | } 197 | 198 | let concatenatedCleanContent = ''; 199 | 200 | for (const file of pathResult.files) { 201 | let fileContent = file.content.normalize('NFC'); 202 | let modIndicator = ''; 203 | if (isRemoveImports) { 204 | const originalContent = fileContent; 205 | fileContent = removeImportsFromFile(fileContent, file.fullPath); 206 | if (fileContent !== originalContent) { 207 | modIndicator = ' (imports removed)'; 208 | } 209 | } 210 | 211 | if (isClean) { 212 | concatenatedCleanContent += fileContent; 213 | placeholderIncludedFiles[`${file.relativePath}${modIndicator} (clean)`] = countTokens(fileContent); 214 | } else { 215 | const formattedContent = formatFileContent(file.relativePath, fileContent, modIndicator); 216 | replacementText += formattedContent; 217 | const fileTokens = countTokens(formattedContent); 218 | placeholderIncludedFiles[`${file.relativePath}${modIndicator}`] = fileTokens; 219 | replacementTokens += fileTokens; 220 | } 221 | } 222 | 223 | if (isClean) { 224 | replacementText = concatenatedCleanContent; 225 | replacementTokens = countTokens(replacementText); 226 | if (pathResult.files.length > 1 && isRemoveImports) { 227 | warnings.push(`Warning: Placeholder "${placeholder}" with ':clean' and ':remove-imports' resolved to multiple files. Concatenating raw content after removing imports from applicable files.`); 228 | } else if (pathResult.files.length > 1) { 229 | warnings.push(`Warning: Placeholder "${placeholder}" with ':clean' resolved to multiple files (${pathResult.files.length}). Concatenating raw content.`); 230 | } 231 | } 232 | } 233 | 234 | const replaceStartIndex = index + accumulatedOffset; 235 | processedContent = processedContent.substring(0, replaceStartIndex) + replacementText + processedContent.substring(replaceStartIndex + placeholder.length); 236 | accumulatedOffset += replacementText.length - placeholder.length; 237 | 238 | Object.assign(includedFiles, placeholderIncludedFiles); 239 | 240 | } catch (error: any) { 241 | const errorMsg = `Warning: Error processing placeholder "${placeholder}" for path "${filePath}": ${error.message || error}`; 242 | warnings.push(errorMsg); 243 | const errorReplacement = `[Error processing placeholder: ${filePath} - ${error.message || 'Failed'}]\n`; 244 | const replaceStartIndex = index + accumulatedOffset; 245 | processedContent = processedContent.substring(0, replaceStartIndex) + errorReplacement + processedContent.substring(replaceStartIndex + placeholder.length); 246 | accumulatedOffset += errorReplacement.length - placeholder.length; 247 | } 248 | } 249 | 250 | const totalTokens = countTokens(processedContent); 251 | 252 | return {content: processedContent, includedFiles, totalTokens, warnings}; 253 | } 254 | 255 | 256 | async function processPath(pathToProcess: string, ignorePatterns: string[], globalExclude: string | undefined, 257 | templateBasePath: string): Promise<{ 258 | files: Array<{ relativePath: string; content: string; fullPath: string }>; 259 | warnings: string[]; 260 | }> { 261 | const warnings: string[] = []; 262 | const filteredFiles = await filterFiles({exclude: ignorePatterns.join(',')}, pathToProcess, globalExclude); 263 | 264 | if (filteredFiles === undefined) { 265 | throw new Error(`Path [${pathToProcess}] not found.`); 266 | } 267 | 268 | if (filteredFiles.length === 0) { 269 | throw new Error(`Path [${pathToProcess}] yielded no files after filtering.`); 270 | } 271 | 272 | const filesData: Array<{ relativePath: string; content: string; fullPath: string }> = []; 273 | 274 | for (const file of filteredFiles) { 275 | try { 276 | const fullPath = path.normalize(file); 277 | const fileContent = await getFileContentAsText(fullPath); 278 | 279 | const relativePath = path.normalize(path.relative(templateBasePath, fullPath)); 280 | 281 | filesData.push({relativePath, content: fileContent, fullPath}); 282 | } catch (readError: any) { 283 | const errorMessage = `[Error processing file ${path.basename(file)}: ${readError.message}]`; 284 | warnings.push(`Warning: Could not fully process file ${file}: ${readError.message}`); 285 | const relativePath = path.normalize(path.relative(templateBasePath, file)); 286 | filesData.push({relativePath, content: errorMessage, fullPath: file}); 287 | } 288 | } 289 | 290 | const successfullyReadFilesCount = filesData.filter(f => 291 | !f.content.startsWith("[Error") && 292 | !f.content.startsWith("[Content of") 293 | ).length; 294 | 295 | if (successfullyReadFilesCount === 0 && filteredFiles.length > 0) { 296 | // This means all files that were found by filterFiles either couldn't be read 297 | // or resulted in a specific error message from getFileContentAsText. 298 | // We don't throw an error here, as the content itself will contain the error messages. 299 | warnings.push(`Warning: Path [${pathToProcess}] resolved ${filteredFiles.length} file(s), but none could be meaningfully read or all are empty/binary.`); 300 | } 301 | 302 | return {files: filesData, warnings}; 303 | } 304 | 305 | function formatFileContent(relativePath: string, content: string, modIndicator: string = ''): string { 306 | return `===== ${path.normalize(relativePath)}${modIndicator} =====\n${content}\n\n`; 307 | } 308 | -------------------------------------------------------------------------------- /src/readGlobalConfig.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import os from "os"; 3 | import fs from "fs/promises"; 4 | 5 | export async function readGlobalConfig(): Promise { 6 | const configPath = path.join(os.homedir(), '.copa'); 7 | try { 8 | const configContent = await fs.readFile(configPath, 'utf-8'); 9 | const ignoreLine = configContent.split('\n').find(line => line.startsWith('ignore:')); 10 | if (ignoreLine) { 11 | return ignoreLine.split(':')[1].trim(); 12 | } 13 | } catch (error) { 14 | // If the file doesn't exist or can't be read, return an empty string 15 | if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { 16 | console.warn('Warning: Unable to read global config file:', error); 17 | } 18 | } 19 | return ''; 20 | } 21 | -------------------------------------------------------------------------------- /tests/promptProcessor.test.ts: -------------------------------------------------------------------------------- 1 | import {processPromptFile} from '../src/promptProcessor'; 2 | import * as fs from 'fs/promises'; 3 | import * as path from 'path'; 4 | import * as os from 'os'; 5 | import {filterFiles} from "../src/filterFiles"; 6 | import {describe, beforeEach, afterEach, expect, test} from 'vitest' 7 | import {encoding_for_model} from "@dqbd/tiktoken"; 8 | 9 | describe('Prompt Processor with Ignore Patterns', () => { 10 | let testDir: string; 11 | 12 | const cleanPath = (path: string) => path.replace(testDir + '/', ''); 13 | 14 | beforeEach(async () => { 15 | testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'copa-prompt-test-')); 16 | await fs.mkdir(path.join(testDir, 'subdir')); 17 | await fs.writeFile(path.join(testDir, 'file1.js'), 'console.log("Hello");'); 18 | await fs.writeFile(path.join(testDir, 'file2.md'), '# Markdown'); 19 | await fs.writeFile(path.join(testDir, 'subdir', 'file3.txt'), 'Nested file content'); 20 | }); 21 | 22 | afterEach(async () => { 23 | await fs.rm(testDir, {recursive: true, force: true}); 24 | }); 25 | 26 | test('processes a prompt file with single file reference', async () => { 27 | const promptContent = 'This is a test prompt.\n{{@file1.js}}\nEnd of prompt.'; 28 | const promptFile = path.join(testDir, 'prompt.txt'); 29 | await fs.writeFile(promptFile, promptContent); 30 | 31 | const result = await processPromptFile(promptFile); 32 | 33 | expect(result.content).toContain('This is a test prompt.'); 34 | expect(result.content).toContain('file1.js ====='); 35 | expect(result.content).toContain('console.log("Hello");'); 36 | expect(result.content).toContain('End of prompt.'); 37 | }); 38 | 39 | test('processes a prompt file with multiple file references', async () => { 40 | const promptContent = 'Files:\n{{@file1.js}}\n{{@file2.md}}\nEnd.'; 41 | const promptFile = path.join(testDir, 'prompt.txt'); 42 | await fs.writeFile(promptFile, promptContent); 43 | 44 | const result = await processPromptFile(promptFile); 45 | 46 | expect(result.content).toContain('Files:'); 47 | expect(result.content).toContain('file1.js ====='); 48 | expect(result.content).toContain('console.log("Hello");'); 49 | expect(result.content).toContain('file2.md ====='); 50 | expect(result.content).toContain('# Markdown'); 51 | expect(result.content).toContain('End.'); 52 | }); 53 | 54 | test('processes a prompt file with folder reference', async () => { 55 | const promptContent = 'Folder contents:\n{{@subdir}}\nEnd of folder.'; 56 | const promptFile = path.join(testDir, 'prompt.txt'); 57 | await fs.writeFile(promptFile, promptContent); 58 | 59 | const result = await processPromptFile(promptFile); 60 | 61 | expect(result.content).toContain('Folder contents:'); 62 | expect(result.content).toContain('===== subdir/file3.txt ====='); 63 | expect(result.content).toContain('Nested file content'); 64 | expect(result.content).toContain('End of folder.'); 65 | }); 66 | 67 | test('handles non-existent file references gracefully', async () => { 68 | const promptContent = 'Missing file:\n{{@nonexistent.txt}}\nEnd.'; 69 | const promptFile = path.join(testDir, 'prompt.txt'); 70 | await fs.writeFile(promptFile, promptContent); 71 | 72 | const {content, warnings} = await processPromptFile(promptFile); 73 | 74 | expect(content).toContain('Missing file:'); 75 | expect(content).not.toContain('===== nonexistent.txt ====='); 76 | expect(content).toContain('End.'); 77 | expect(warnings).toHaveLength(1); 78 | expect(warnings[0]).toContain('Warning: Error processing placeholder'); 79 | expect(warnings[0]).toContain('nonexistent.txt'); 80 | }); 81 | 82 | test('processes a prompt file with ignore patterns', async () => { 83 | const promptContent = 'Files:\n{{@.:-*.md,-**/subdir/**}}\nEnd.'; 84 | const promptFile = path.join(testDir, 'prompt.txt'); 85 | await fs.writeFile(promptFile, promptContent); 86 | 87 | const result = await processPromptFile(promptFile); 88 | 89 | expect(result.content).toContain('Files:'); 90 | expect(result.content).toContain('file1.js ====='); 91 | expect(result.content).toContain('console.log("Hello");'); 92 | expect(result.content).not.toContain('file2.md ====='); 93 | expect(result.content).not.toContain('# Markdown'); 94 | expect(result.content).not.toContain('subdir/file'); 95 | expect(result.content).toContain('End.'); 96 | }); 97 | 98 | test('processes a prompt file with multiple ignore patterns', async () => { 99 | const promptContent = 'Files:\n{{@.:-*.md,-*.yml,-**/subdir/file4.js}}\nEnd.'; 100 | const promptFile = path.join(testDir, 'prompt.txt'); 101 | await fs.writeFile(promptFile, promptContent); 102 | 103 | const result = await processPromptFile(promptFile); 104 | 105 | expect(result.content).toContain('Files:'); 106 | expect(result.content).toContain('file1.js ====='); 107 | expect(result.content).toContain('console.log("Hello");'); 108 | expect(result.content).not.toContain('file2.md ====='); 109 | expect(result.content).not.toContain('# Markdown'); 110 | expect(result.content).not.toContain('file3.yml ====='); 111 | expect(result.content).not.toContain('key: value'); 112 | expect(result.content).not.toContain('===== subdir/file4.js ====='); 113 | expect(result.content).not.toContain('===== subdir/file5.md ====='); // Changed this line 114 | expect(result.content).not.toContain('## Subheading'); 115 | expect(result.content).toContain('End.'); 116 | }); 117 | 118 | test('processes a prompt file with wildcard ignore patterns', async () => { 119 | const promptContent = 'Files:\n{{@.:-**/*dir/**,-*.y*}}\nEnd.'; 120 | const promptFile = path.join(testDir, 'prompt.txt'); 121 | await fs.writeFile(promptFile, promptContent); 122 | 123 | const result = await processPromptFile(promptFile); 124 | 125 | expect(result.content).toContain('Files:'); 126 | expect(result.content).toContain('file1.js ====='); 127 | expect(result.content).toContain('console.log("Hello");'); 128 | expect(result.content).toContain('file2.md ====='); 129 | expect(result.content).toContain('# Markdown'); 130 | expect(result.content).not.toContain('file3.yml ====='); 131 | expect(result.content).not.toContain('key: value'); 132 | expect(result.content).not.toContain('===== subdir/'); 133 | expect(result.content).toContain('End.'); 134 | }); 135 | 136 | test('handles empty directories', async () => { 137 | await fs.mkdir(path.join(testDir, 'emptyDir')); 138 | const files = await filterFiles({}, testDir, testDir); 139 | expect(files).not.toContain('emptyDir'); 140 | }); 141 | 142 | test('handles files with special characters', async () => { 143 | await fs.writeFile(path.join(testDir, 'file-with-dashes.js'), 'content'); 144 | await fs.writeFile(path.join(testDir, 'file with spaces.js'), 'content'); 145 | await fs.writeFile(path.join(testDir, 'file_with_underscores.js'), 'content'); 146 | const files = (await filterFiles({}, testDir, testDir))!.map(cleanPath); 147 | expect(files).toContain('file-with-dashes.js'); 148 | expect(files).toContain('file with spaces.js'); 149 | expect(files).toContain('file_with_underscores.js'); 150 | }); 151 | 152 | test('handles very long file paths', async () => { 153 | const longPath = 'a'.repeat(200); 154 | await fs.mkdir(path.join(testDir, longPath), {recursive: true}); 155 | await fs.writeFile(path.join(testDir, longPath, 'longfile.js'), 'content'); 156 | const files = (await filterFiles({}, testDir, testDir))!.map(cleanPath); 157 | expect(files).toContain(path.join(longPath, 'longfile.js')); 158 | }); 159 | 160 | test('handles case sensitivity in file extensions', async () => { 161 | await fs.writeFile(path.join(testDir, 'upper.JS'), 'content'); 162 | await fs.writeFile(path.join(testDir, 'mixed.Js'), 'content'); 163 | const files = (await filterFiles({exclude: 'js'}, testDir, testDir))!.map(cleanPath); 164 | expect(files).toContain('upper.JS'); 165 | expect(files).toContain('mixed.Js'); 166 | }); 167 | 168 | test('handles multiple exclusion patterns', async () => { 169 | const files = await filterFiles({exclude: '.js,**/subdir/**.txt'}, testDir, testDir); 170 | expect(files?.length).toBe(1); 171 | expect(files?.map(cleanPath).sort()).toEqual(['file2.md'].sort()); 172 | }); 173 | 174 | test('handles symlinks', async () => { 175 | await fs.symlink(path.join(testDir, 'file1.js'), path.join(testDir, 'symlink.js')); 176 | const files = (await filterFiles({}, testDir, testDir))!.map(cleanPath); 177 | expect(files).toContain('symlink.js'); 178 | }); 179 | 180 | test('excludes files by full path', async () => { 181 | const files = (await filterFiles({exclude: 'subdir/file4.js'}, testDir, testDir))!.map(cleanPath); 182 | expect(files).not.toContain(path.join('subdir', 'file4.js')); 183 | expect(files).toContain(path.join('subdir', 'file3.txt')); 184 | }); 185 | 186 | test('handles nested exclusions', async () => { 187 | await fs.mkdir(path.join(testDir, 'nested', 'dir'), {recursive: true}); 188 | await fs.writeFile(path.join(testDir, 'nested', 'file.js'), 'content'); 189 | await fs.writeFile(path.join(testDir, 'nested', 'dir', 'file.js'), 'content'); 190 | const files = (await filterFiles({exclude: '**/nested/*.js'}, testDir, testDir))!.map(cleanPath); 191 | expect(files).not.toContain(path.join('nested', 'file.js')); 192 | expect(files).toContain(path.join('nested', 'dir', 'file.js')); 193 | }); 194 | 195 | test('excludes all files of a type regardless of location', async () => { 196 | const files = (await filterFiles({exclude: '**/*.md'}, testDir, testDir))!.map(cleanPath); 197 | expect(files).not.toContain('file2.md'); 198 | expect(files).not.toContain(path.join('subdir', 'file5.md')); 199 | }); 200 | 201 | test('excludes hidden folder and its files with glob pattern', async () => { 202 | const files = (await filterFiles({exclude: '.*'}, testDir, testDir))!.map(cleanPath); 203 | expect(files?.length).toBe(3); 204 | expect(files?.sort()).toEqual([ 205 | 'file1.js', 206 | 'file2.md', 207 | path.join('subdir', 'file3.txt') 208 | ].sort()); 209 | }); 210 | 211 | }); 212 | 213 | 214 | describe('Directory Tree Feature', () => { 215 | let testDir: string; 216 | 217 | beforeEach(async () => { 218 | testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'copa-dir-tree-test-')); 219 | 220 | // Create a sample directory structure 221 | await fs.mkdir(path.join(testDir, 'src')); 222 | await fs.mkdir(path.join(testDir, 'src', 'components')); 223 | await fs.mkdir(path.join(testDir, 'src', 'utils')); 224 | await fs.mkdir(path.join(testDir, 'docs')); 225 | 226 | // Create some files 227 | await fs.writeFile(path.join(testDir, 'src', 'index.js'), 'console.log("root");'); 228 | await fs.writeFile(path.join(testDir, 'src', 'components', 'Button.js'), 'class Button {}'); 229 | await fs.writeFile(path.join(testDir, 'src', 'components', 'Card.js'), 'class Card {}'); 230 | await fs.writeFile(path.join(testDir, 'src', 'utils', 'format.js'), 'function format() {}'); 231 | await fs.writeFile(path.join(testDir, 'docs', 'README.md'), '# Documentation'); 232 | await fs.writeFile(path.join(testDir, '.gitignore'), 'node_modules'); 233 | }); 234 | 235 | afterEach(async () => { 236 | await fs.rm(testDir, {recursive: true, force: true}); 237 | }); 238 | 239 | test('generates a directory tree for a given path', async () => { 240 | const promptContent = 'Project structure:\n{{@src:dir}}\n\nDocs structure:\n{{@docs:dir}}'; 241 | const promptFile = path.join(testDir, 'prompt.txt'); 242 | await fs.writeFile(promptFile, promptContent); 243 | 244 | const result = await processPromptFile(promptFile); 245 | 246 | // Check for main project structure 247 | expect(result.content).toContain('Project structure:'); 248 | expect(result.content).toContain('===== Directory Structure: src ====='); 249 | expect(result.content).toContain('src'); 250 | expect(result.content).toContain('├── components/'); 251 | expect(result.content).toContain('│ ├── Button.js'); 252 | expect(result.content).toContain('│ └── Card.js'); 253 | expect(result.content).toContain('├── utils/'); 254 | expect(result.content).toContain('│ └── format.js'); 255 | expect(result.content).toContain('└── index.js'); 256 | 257 | // Check for docs structure 258 | expect(result.content).toContain('Docs structure:'); 259 | expect(result.content).toContain('===== Directory Structure: docs ====='); 260 | expect(result.content).toContain('docs'); 261 | expect(result.content).toContain('└── README.md'); 262 | }); 263 | 264 | test('applies ignore patterns to directory tree', async () => { 265 | const promptContent = 'Project structure with ignore:\n{{@src:dir,*.js}}\n'; 266 | const promptFile = path.join(testDir, 'prompt.txt'); 267 | await fs.writeFile(promptFile, promptContent); 268 | 269 | const result = await processPromptFile(promptFile); 270 | 271 | // Should show directories but not JS files 272 | expect(result.content).toContain('Project structure with ignore:'); 273 | expect(result.content).toContain('===== Directory Structure: src ====='); 274 | expect(result.content).toContain('src'); 275 | // empty dirs 276 | expect(result.content).not.toContain('├── components/'); 277 | expect(result.content).not.toContain('└── utils/'); 278 | 279 | // JS files should not be included 280 | expect(result.content).not.toContain('Button.js'); 281 | expect(result.content).not.toContain('Card.js'); 282 | expect(result.content).not.toContain('format.js'); 283 | expect(result.content).not.toContain('index.js'); 284 | }); 285 | 286 | test('handles nested directory references correctly', async () => { 287 | const promptContent = 'Components:\n{{@src/components:dir}}\n'; 288 | const promptFile = path.join(testDir, 'prompt.txt'); 289 | await fs.writeFile(promptFile, promptContent); 290 | 291 | const result = await processPromptFile(promptFile); 292 | 293 | expect(result.content).toContain('Components:'); 294 | expect(result.content).toContain('===== Directory Structure: src/components ====='); 295 | expect(result.content).toContain('components'); 296 | expect(result.content).toContain('├── Button.js'); 297 | expect(result.content).toContain('└── Card.js'); 298 | }); 299 | 300 | test('combines dir option with file content references', async () => { 301 | const promptContent = 'Structure:\n{{@src:dir}}\n\nContent:\n{{@src/index.js}}'; 302 | const promptFile = path.join(testDir, 'prompt.txt'); 303 | await fs.writeFile(promptFile, promptContent); 304 | 305 | const result = await processPromptFile(promptFile); 306 | 307 | // Should have both the directory structure and file content 308 | expect(result.content).toContain('Structure:'); 309 | expect(result.content).toContain('===== Directory Structure: src ====='); 310 | expect(result.content).toContain('src'); 311 | 312 | expect(result.content).toContain('Content:'); 313 | expect(result.content).toContain('===== src/index.js ====='); 314 | expect(result.content).toContain('console.log("root");'); 315 | }); 316 | }) 317 | 318 | 319 | function countTokens(input: string): number { 320 | // IMPORTANT: Ensure you have the correct model name if not 'gpt-4' 321 | const tokenize = encoding_for_model('gpt-4'); 322 | try { 323 | // Normalize helps ensure consistent token counts 324 | const normalizedInput = input.normalize('NFC'); 325 | return tokenize.encode(normalizedInput).length; 326 | } finally { 327 | tokenize.free(); // Essential to prevent memory leaks 328 | } 329 | } 330 | 331 | const normalizePathsInData = (data: { content: string; includedFiles: { [key: string]: number } }, testDir: string) => { 332 | // Escape backslashes in testDir for regex and ensure trailing separator 333 | const escapedTestDir = testDir.replace(/\\/g, '\\\\') + (path.sep === '\\' ? '\\\\' : path.sep); 334 | const regex = new RegExp(escapedTestDir, 'g'); 335 | 336 | const normalizedContent = data.content.replace(regex, ''); // Use regex directly 337 | const normalizedIncludedFiles: { [key: string]: number } = {}; 338 | for (const [key, value] of Object.entries(data.includedFiles)) { 339 | normalizedIncludedFiles[key.replace(regex, '')] = value; 340 | } 341 | return {...data, content: normalizedContent, includedFiles: normalizedIncludedFiles}; 342 | } 343 | 344 | 345 | describe('Prompt Processor: :remove-imports modifier (code and type imports)', () => { 346 | let testDir: string; 347 | let srcDir: string; 348 | 349 | // --- Updated Test File Contents --- 350 | const tsContentWithImports = ` 351 | import { Component } from '@angular/core'; 352 | import * as utils from './utils'; 353 | import type { SomeType } from 'some-lib'; 354 | 355 | // Some comment 356 | console.log('Hello from TS'); 357 | 358 | export class MyComponent { 359 | // Component logic 360 | } 361 | 362 | const anotherVar = require('./old-style'); 363 | require('side-effect-import'); 364 | export { Utils } from "./another-util"; 365 | export * from './reexport-all'; 366 | `; 367 | 368 | // Expected content after removing code and type imports 369 | const expected_tsContent_Cleaned = ` 370 | 371 | // Some comment 372 | console.log('Hello from TS'); 373 | 374 | export class MyComponent { 375 | // Component logic 376 | } 377 | 378 | const anotherVar = require('./old-style'); 379 | require('side-effect-import'); 380 | export { Utils } from "./another-util"; 381 | export * from './reexport-all'; 382 | `.trimStart(); // removeImportsFromFile also trims start 383 | 384 | const tsxContentWithImports = ` 385 | import React, { useState, useEffect } from 'react'; // Will be removed 386 | import styles from './styles.module.css'; // Will be removed 387 | import type { CSSProperties } from 'react'; // Will be removed 388 | import './global-styles.css'; // Keep (Side Effect) 389 | 390 | type Props = { 391 | message: string; 392 | }; 393 | 394 | export default function MyReactComponent({ message }: Props) { 395 | const [count, setCount] = useState(0); 396 | 397 | useEffect(() => { 398 | // effect logic 399 | }, []); 400 | 401 | // Type usage remains valid even if the import type line is gone 402 | const style: CSSProperties = { color: 'blue' }; 403 | 404 | return
{message} - {count}
; 405 | } 406 | export type { Props as ComponentProps } from './types'; // Keep Re-export type 407 | `; 408 | 409 | // Expected content after removing code and type imports 410 | const expected_tsxContent_Cleaned = ` 411 | 412 | import './global-styles.css'; // Keep (Side Effect) 413 | 414 | type Props = { 415 | message: string; 416 | }; 417 | 418 | export default function MyReactComponent({ message }: Props) { 419 | const [count, setCount] = useState(0); 420 | 421 | useEffect(() => { 422 | // effect logic 423 | }, []); 424 | 425 | // Type usage remains valid even if the import type line is gone 426 | const style: CSSProperties = { color: 'blue' }; 427 | 428 | return
{message} - {count}
; 429 | } 430 | export type { Props as ComponentProps } from './types'; // Keep Re-export type 431 | `.trimStart(); 432 | 433 | const jsContentWithRequire = ` 434 | const fs = require('fs'); // Keep 435 | const path = require('path'); // Keep 436 | 437 | function logStuff() { 438 | console.log('Logging from JS'); 439 | } 440 | 441 | module.exports = { logStuff }; 442 | `; // JS files are not modified by the function 443 | 444 | const mdContent = `# Markdown File 445 | 446 | This should not be affected by remove-imports. 447 | `; // Non-code files are not modified 448 | 449 | const onlyImportsContent = `import { a } from 'a';\nimport 'b';\nimport type { C } from 'c';`; // Original 450 | 451 | // Expected content after removing code and type imports from onlyImportsContent 452 | // Only the side-effect import 'b' remains. trimStart() is applied by the function. 453 | const expected_onlyImports_Cleaned = `import 'b';`; 454 | 455 | // --- End Test File Contents --- 456 | 457 | 458 | beforeEach(async () => { 459 | // Create a temporary directory for test files 460 | testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'copa-remove-imports-test-')); 461 | srcDir = path.join(testDir, 'src'); 462 | await fs.mkdir(srcDir); 463 | await fs.mkdir(path.join(srcDir, 'components')); 464 | 465 | // Write test files with updated content 466 | await fs.writeFile(path.join(srcDir, 'main.ts'), tsContentWithImports); 467 | await fs.writeFile(path.join(srcDir, 'components', 'component.tsx'), tsxContentWithImports); 468 | await fs.writeFile(path.join(srcDir, 'utils.js'), jsContentWithRequire); 469 | await fs.writeFile(path.join(testDir, 'docs.md'), mdContent); 470 | await fs.writeFile(path.join(srcDir, 'empty.ts'), ''); // Edge case: empty file 471 | await fs.writeFile(path.join(srcDir, 'only_imports.ts'), onlyImportsContent); // Edge case: only imports 472 | }); 473 | 474 | afterEach(async () => { 475 | // Clean up the temporary directory 476 | await fs.rm(testDir, {recursive: true, force: true}); 477 | }); 478 | 479 | // --- Updated Tests --- 480 | 481 | test('should remove code and type imports from a single .ts file using :remove-imports', async () => { 482 | const promptContent = `Analyze this TS code:\n{{@src/main.ts:remove-imports}}`; 483 | const promptFile = path.join(testDir, 'prompt.copa'); 484 | await fs.writeFile(promptFile, promptContent); 485 | 486 | const result = await processPromptFile(promptFile); 487 | const normalizedResult = normalizePathsInData(result, testDir); 488 | 489 | // Use the NEW expected cleaned content 490 | const expectedCleanedTsContent = expected_tsContent_Cleaned; 491 | const expectedFileName = path.normalize('src/main.ts'); // Keep normalized path 492 | const expectedWrapper = `===== ${expectedFileName} (imports removed) =====`; 493 | const expectedOutput = `Analyze this TS code:\n${expectedWrapper}\n${expectedCleanedTsContent}\n\n`; 494 | 495 | expect(result.content).toBe(expectedOutput); 496 | expect(result.warnings).toEqual([]); 497 | expect(normalizedResult.includedFiles).toEqual({ 498 | [`${path.normalize('src/main.ts')} (imports removed)`]: countTokens(`${expectedWrapper}\n${expectedCleanedTsContent}\n\n`) 499 | }); 500 | expect(result.totalTokens).toBe(countTokens(expectedOutput)); 501 | }); 502 | 503 | test('should remove code and type imports from a single .tsx file using :remove-imports', async () => { 504 | const promptContent = `Analyze this TSX component:\n{{@src/components/component.tsx:remove-imports}}`; 505 | const promptFile = path.join(testDir, 'prompt.copa'); 506 | await fs.writeFile(promptFile, promptContent); 507 | 508 | const result = await processPromptFile(promptFile); 509 | const normalizedResult = normalizePathsInData(result, testDir); 510 | 511 | // Use the NEW expected cleaned content 512 | const expectedCleanedTsxContent = expected_tsxContent_Cleaned; 513 | const expectedFileName = path.normalize('src/components/component.tsx'); 514 | const expectedWrapper = `===== ${expectedFileName} (imports removed) =====`; 515 | const expectedOutput = `Analyze this TSX component:\n${expectedWrapper}\n${expectedCleanedTsxContent}\n\n`; 516 | 517 | // Use trim() for comparison robustness against trailing whitespace differences 518 | expect(result.content.trim()).toBe(expectedOutput.trim()); 519 | expect(result.warnings).toEqual([]); 520 | expect(normalizedResult.includedFiles).toEqual({ 521 | [`${path.normalize('src/components/component.tsx')} (imports removed)`]: countTokens(`${expectedWrapper}\n${expectedCleanedTsxContent}\n\n`) 522 | }); 523 | expect(result.totalTokens).toBe(countTokens(expectedOutput)); 524 | }); 525 | 526 | test('should NOT remove imports/requires from a .js file even if :remove-imports is specified', async () => { 527 | const promptContent = `Analyze this JS code:\n{{@src/utils.js:remove-imports}}`; 528 | const promptFile = path.join(testDir, 'prompt.copa'); 529 | await fs.writeFile(promptFile, promptContent); 530 | 531 | const result = await processPromptFile(promptFile); 532 | const normalizedResult = normalizePathsInData(result, testDir); 533 | 534 | const expectedJsContent = jsContentWithRequire; // Original content 535 | const expectedFileName = path.normalize('src/utils.js'); 536 | const expectedWrapper = `===== ${expectedFileName} =====`; // No "(imports removed)" 537 | const expectedOutput = `Analyze this JS code:\n${expectedWrapper}\n${expectedJsContent}\n\n`; 538 | 539 | expect(result.content).toBe(expectedOutput); 540 | expect(result.warnings).toEqual([]); // No warning needed, it just doesn't apply 541 | expect(normalizedResult.includedFiles).toEqual({ 542 | [path.normalize('src/utils.js')]: countTokens(`${expectedWrapper}\n${expectedJsContent}\n\n`) 543 | }); 544 | expect(result.totalTokens).toBe(countTokens(expectedOutput)); 545 | }); 546 | 547 | test('should NOT remove imports from a non-code file (.md) even if :remove-imports is specified', async () => { 548 | const promptContent = `Include docs:\n{{@docs.md:remove-imports}}`; 549 | const promptFile = path.join(testDir, 'prompt.copa'); 550 | await fs.writeFile(promptFile, promptContent); 551 | 552 | const result = await processPromptFile(promptFile); 553 | const normalizedResult = normalizePathsInData(result, testDir); 554 | 555 | const expectedMdContent = mdContent; 556 | const expectedFileName = path.normalize('docs.md'); 557 | const expectedWrapper = `===== ${expectedFileName} =====`; 558 | const expectedOutput = `Include docs:\n${expectedWrapper}\n${expectedMdContent}\n\n`; 559 | 560 | expect(result.content).toBe(expectedOutput); 561 | expect(result.warnings).toEqual([]); 562 | expect(normalizedResult.includedFiles).toEqual({ 563 | [path.normalize('docs.md')]: countTokens(`${expectedWrapper}\n${expectedMdContent}\n\n`) 564 | }); 565 | expect(result.totalTokens).toBe(countTokens(expectedOutput)); 566 | }); 567 | 568 | test('should remove code/type imports from .ts/.tsx files when importing a directory with :remove-imports', async () => { 569 | const promptContent = `Analyze the src directory:\n{{@src:remove-imports}}`; 570 | const promptFile = path.join(testDir, 'prompt.copa'); 571 | await fs.writeFile(promptFile, promptContent); 572 | 573 | const result = await processPromptFile(promptFile); 574 | const normalizedResult = normalizePathsInData(result, testDir); 575 | 576 | // Use the NEW expected cleaned content strings 577 | const expectedCleanedTsContent = expected_tsContent_Cleaned; 578 | const expectedCleanedTsxContent = expected_tsxContent_Cleaned; 579 | const expectedJsContent = jsContentWithRequire; // Unchanged 580 | const expectedEmptyTsContent = ''; // Empty file remains empty 581 | const expectedCleanedOnlyImportsContent = expected_onlyImports_Cleaned; // Updated expectation 582 | 583 | // Note: Order might depend on glob/fs results, but content should be correct. 584 | // Check presence and absence of key parts. 585 | 586 | // Check TS file 587 | const tsPath = path.normalize('src/main.ts'); 588 | expect(result.content).toContain(`===== ${tsPath} (imports removed) =====\n${expectedCleanedTsContent}\n\n`); 589 | expect(result.content).not.toContain(`import { Component } from '@angular/core';`); 590 | expect(result.content).not.toContain(`import type { SomeType } from 'some-lib';`); 591 | expect(result.content).toContain(`require('side-effect-import');`); // Kept 592 | 593 | // Check TSX file 594 | const tsxPath = path.normalize('src/components/component.tsx'); 595 | expect(result.content).toContain(`===== ${tsxPath} (imports removed) =====\n${expectedCleanedTsxContent}\n\n`); 596 | expect(result.content).not.toContain(`import React, { useState, useEffect } from 'react';`); 597 | expect(result.content).not.toContain(`import type { CSSProperties } from 'react';`); 598 | expect(result.content).toContain(`import './global-styles.css';`); // Kept 599 | 600 | // Check JS file 601 | const jsPath = path.normalize('src/utils.js'); 602 | expect(result.content).toContain(`===== ${jsPath} =====\n${expectedJsContent}\n\n`); // No "(imports removed)" 603 | expect(result.content).toContain(`const fs = require('fs');`); // Imports remain 604 | 605 | // Check empty TS file 606 | const emptyTsPath = path.normalize('src/empty.ts'); 607 | // Empty file might or might not get '(imports removed)' depending on implementation, accept either 608 | expect(result.content).toMatch(new RegExp(`===== ${emptyTsPath.replace(/\\/g, '\\\\')}(?: \\(imports removed\\))? =====\\n${expectedEmptyTsContent}\\n\\n`)); 609 | 610 | 611 | // Check only-imports TS file 612 | const onlyImportsPath = path.normalize('src/only_imports.ts'); 613 | expect(result.content).toContain(`===== ${onlyImportsPath} (imports removed) =====\n${expectedCleanedOnlyImportsContent}\n\n`); 614 | expect(result.content).not.toContain(`import { a } from 'a';`); 615 | expect(result.content).not.toContain(`import type { C } from 'c';`); 616 | 617 | 618 | expect(result.warnings).toEqual([]); 619 | 620 | // Verify included files list reflects the changes (presence check) 621 | expect(normalizedResult.includedFiles).toHaveProperty(`${path.normalize('src/main.ts')} (imports removed)`); 622 | expect(normalizedResult.includedFiles).toHaveProperty(`${path.normalize('src/components/component.tsx')} (imports removed)`); 623 | expect(normalizedResult.includedFiles).toHaveProperty(path.normalize('src/utils.js')); 624 | expect(normalizedResult.includedFiles).toHaveProperty(`${path.normalize('src/only_imports.ts')} (imports removed)`); 625 | expect(normalizedResult.includedFiles).toHaveProperty(path.normalize('src/empty.ts')); // Or possibly with '(imports removed)' 626 | }); 627 | 628 | test('should remove code/type imports when using :remove-imports and :clean together on a directory', async () => { 629 | const promptContent = `Cleaned src code:\n{{@src:remove-imports,clean}}`; 630 | const promptFile = path.join(testDir, 'prompt.copa'); 631 | await fs.writeFile(promptFile, promptContent); 632 | 633 | const result = await processPromptFile(promptFile); 634 | const normalizedResult = normalizePathsInData(result, testDir); 635 | 636 | // Use the NEW expected cleaned content strings 637 | const expectedCleanedTsContent = expected_tsContent_Cleaned; 638 | const expectedCleanedTsxContent = expected_tsxContent_Cleaned; 639 | const expectedJsContent = jsContentWithRequire; // Unchanged 640 | const expectedEmptyTsContent = ''; 641 | const expectedCleanedOnlyImportsContent = expected_onlyImports_Cleaned; 642 | 643 | // Check presence/absence in the concatenated content 644 | expect(result.content).not.toContain('====='); // No wrappers 645 | // TS checks 646 | expect(result.content).toContain(expectedCleanedTsContent); 647 | expect(result.content).not.toContain(`import { Component } from '@angular/core';`); 648 | expect(result.content).not.toContain(`import type { SomeType } from 'some-lib';`); 649 | expect(result.content).toContain(`require('side-effect-import');`); // Kept 650 | // TSX checks 651 | expect(result.content).toContain(expectedCleanedTsxContent); 652 | expect(result.content).not.toContain(`import React, { useState, useEffect } from 'react';`); 653 | expect(result.content).not.toContain(`import type { CSSProperties } from 'react';`); 654 | expect(result.content).toContain(`import './global-styles.css';`); // Kept 655 | // JS checks 656 | expect(result.content).toContain(expectedJsContent); 657 | expect(result.content).toContain(`const fs = require('fs');`); // JS require should remain 658 | // only_imports check 659 | expect(result.content).toContain(expectedCleanedOnlyImportsContent); 660 | expect(result.content).not.toContain(`import { a } from 'a';`); 661 | 662 | // Expect a warning about concatenating multiple files with :clean 663 | // The exact number of files might vary based on FS order, so match the pattern 664 | expect(result.warnings).toEqual(expect.arrayContaining([ 665 | expect.stringMatching(/Warning: Placeholder "{{@src:remove-imports,clean}}"/) 666 | ])); 667 | 668 | // Check included files have the (clean) suffix and imports removed status where applicable 669 | expect(normalizedResult.includedFiles).toHaveProperty(`${path.normalize('src/main.ts')} (imports removed) (clean)`); 670 | expect(normalizedResult.includedFiles).toHaveProperty(`${path.normalize('src/components/component.tsx')} (imports removed) (clean)`); 671 | expect(normalizedResult.includedFiles).toHaveProperty(`${path.normalize('src/utils.js')} (clean)`); // JS not modified 672 | expect(normalizedResult.includedFiles).toHaveProperty(`${path.normalize('src/only_imports.ts')} (imports removed) (clean)`); 673 | // Empty file might or might not get '(imports removed)', accept either 674 | expect(Object.keys(normalizedResult.includedFiles)).toEqual( 675 | expect.arrayContaining([expect.stringMatching(/^src[\\\/]empty\.ts(?: \(imports removed\))? \(clean\)$/)]) 676 | ); 677 | 678 | 679 | expect(result.totalTokens).toBe(countTokens(result.content)); // Count tokens of the final concatenated string 680 | }); 681 | 682 | test('should ignore :remove-imports when used with :dir', async () => { 683 | const promptContent = `Directory structure:\n{{@src:remove-imports,dir}}`; 684 | const promptFile = path.join(testDir, 'prompt.copa'); 685 | await fs.writeFile(promptFile, promptContent); 686 | 687 | const result = await processPromptFile(promptFile); 688 | const normalizedResult = normalizePathsInData(result, testDir); 689 | 690 | expect(result.content).toContain('===== Directory Structure: src ====='); 691 | expect(result.content).toContain('main.ts'); 692 | expect(result.content).toContain('components' + path.sep); // Use path.sep for cross-platform compatibility 693 | expect(result.content).toContain(`├── components/ 694 | │ └── component.tsx`); // Check nested file display 695 | expect(result.warnings).toEqual(expect.arrayContaining([ 696 | expect.stringMatching(/Warning: ':remove-imports' cannot be used with ':dir' or ':eval' in placeholder "{{@src:remove-imports,dir}}". Ignoring ':remove-imports'./) 697 | ])); 698 | expect(normalizedResult.includedFiles).toHaveProperty('src (directory tree)'); 699 | }); 700 | 701 | test('should ignore :remove-imports when used with :eval', async () => { 702 | // Create a nested template file that includes the TS file *without* modification 703 | const nestedTemplateContent = `Nested content:\n{{@src/main.ts}}`; // No :remove-imports here 704 | const nestedTemplateFile = path.join(testDir, 'nested.copa'); 705 | await fs.writeFile(nestedTemplateFile, nestedTemplateContent); 706 | 707 | // Apply :remove-imports to the :eval placeholder itself 708 | const promptContent = `Evaluated template:\n{{@nested.copa:remove-imports,eval}}`; 709 | const promptFile = path.join(testDir, 'prompt.copa'); 710 | await fs.writeFile(promptFile, promptContent); 711 | 712 | const result = await processPromptFile(promptFile); 713 | const normalizedResult = normalizePathsInData(result, testDir); 714 | 715 | // Expect the *original* content of main.ts, as :remove-imports is ignored by :eval 716 | // The file included *within* nested.copa should be the original tsContentWithImports 717 | const expectedNestedOutput = `Nested content:\n===== ${path.normalize('src/main.ts')} =====\n${tsContentWithImports}\n\n`; 718 | const expectedFinalOutput = `Evaluated template:\n${expectedNestedOutput}`; 719 | 720 | expect(result.content).toBe(expectedFinalOutput); 721 | // Verify original imports are present 722 | expect(result.content).toContain(`import { Component } from '@angular/core';`); 723 | expect(result.content).toContain(`import type { SomeType } from 'some-lib';`); 724 | 725 | expect(result.warnings).toEqual(expect.arrayContaining([ 726 | expect.stringMatching(/Warning: ':remove-imports' cannot be used with ':dir' or ':eval' in placeholder "{{@nested.copa:remove-imports,eval}}". Ignoring ':remove-imports'./) 727 | ])); 728 | // Check included files are prefixed correctly for eval, and reflect the original file from the nested template 729 | expect(normalizedResult.includedFiles).toHaveProperty(`eval:nested.copa:${path.normalize('src/main.ts')}`); 730 | // Verify token count matches the *unevaluated* file included via eval 731 | expect(normalizedResult.includedFiles[`eval:nested.copa:${path.normalize('src/main.ts')}`]).toBe(countTokens(`===== ${path.normalize('src/main.ts')} =====\n${tsContentWithImports}\n\n`)) 732 | }); 733 | }); -------------------------------------------------------------------------------- /tests/sanity.test.ts: -------------------------------------------------------------------------------- 1 | import {filterFiles} from '../src/filterFiles'; 2 | import * as fs from 'fs/promises'; 3 | import * as path from 'path'; 4 | import * as os from 'os'; 5 | import { describe, beforeEach, afterEach, expect, test } from 'vitest' 6 | 7 | describe('CoPa Functionality', () => { 8 | let testDir: string; 9 | 10 | const cleanPath = (path: string) => path.replace(testDir + '/', ''); 11 | 12 | beforeEach(async () => { 13 | testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'copa-test-')); 14 | console.debug("created test directory :" + testDir); 15 | await fs.mkdir(path.join(testDir, 'subdir')); 16 | await fs.writeFile(path.join(testDir, 'file1.js'), 'console.log("Hello");'); 17 | await fs.writeFile(path.join(testDir, 'file2.md'), '# Markdown'); 18 | await fs.writeFile(path.join(testDir, 'file3.yml'), 'key: value'); 19 | await fs.writeFile(path.join(testDir, 'subdir', 'file4.js'), 'const x = 42;'); 20 | await fs.writeFile(path.join(testDir, 'subdir', 'file5.md'), '## Subheading'); 21 | await fs.writeFile(path.join(testDir, 'subdir', 'file6.yml'), 'nested: true'); 22 | }); 23 | 24 | afterEach(async () => { 25 | await fs.rm(testDir, {recursive: true, force: true}); 26 | }); 27 | 28 | describe('filterFiles', () => { 29 | test('includes all files when no exclusions', async () => { 30 | const files = (await filterFiles({}, testDir))!.map(cleanPath); 31 | expect(files?.length).toBe(6); 32 | expect(files?.sort()).toEqual([ 33 | 'file1.js', 34 | 'file2.md', 35 | 'file3.yml', 36 | path.join('subdir', 'file4.js'), 37 | path.join('subdir', 'file5.md'), 38 | path.join('subdir', 'file6.yml') 39 | ].sort()); 40 | }); 41 | 42 | test('excludes files based on command line options', async () => { 43 | const files = (await filterFiles({exclude: '.js,.md'}, testDir))!.map(cleanPath); 44 | expect(files?.length).toBe(2); 45 | expect(files?.sort()).toEqual([ 46 | 'file3.yml', 47 | path.join('subdir', 'file6.yml') 48 | ].sort()); 49 | }); 50 | 51 | test('excludes files based on single extension', async () => { 52 | const files = (await filterFiles({exclude: '.yml'}, testDir))!.map(cleanPath); 53 | expect(files?.length).toBe(4); 54 | expect(files?.sort()).toEqual([ 55 | 'file1.js', 56 | 'file2.md', 57 | path.join('subdir', 'file4.js'), 58 | path.join('subdir', 'file5.md') 59 | ].sort()); 60 | }); 61 | 62 | test('handles wildcard patterns', async () => { 63 | const files = (await filterFiles({exclude: 'file*.yml'}, testDir))!.map(cleanPath); 64 | expect(files?.length).toBe(4); 65 | expect(files?.sort()).toEqual([ 66 | 'file1.js', 67 | 'file2.md', 68 | path.join('subdir', 'file4.js'), 69 | path.join('subdir', 'file5.md'), 70 | ].sort()); 71 | }); 72 | 73 | test('handles subdirectory wildcard patterns', async () => { 74 | const files = (await filterFiles({exclude: '**/subdir/*.js'}, testDir))!.map(cleanPath); 75 | expect(files?.length).toBe(5); 76 | expect(files?.sort()).toEqual([ 77 | 'file1.js', 78 | 'file2.md', 79 | 'file3.yml', 80 | path.join('subdir', 'file5.md'), 81 | path.join('subdir', 'file6.yml') 82 | ].sort()); 83 | }); 84 | 85 | test('excludes entire directories', async () => { 86 | const files = (await filterFiles({exclude: '**/subdir/**'}, testDir))!.map(cleanPath); 87 | expect(files?.length).toBe(3); 88 | expect(files?.sort()).toEqual([ 89 | 'file1.js', 90 | 'file2.md', 91 | 'file3.yml' 92 | ].sort()); 93 | }); 94 | }); 95 | 96 | }); 97 | 98 | describe('hidden folders', () => { 99 | let testDir: string; 100 | 101 | const cleanPath = (path: string) => path.replace(testDir + '/', ''); 102 | 103 | beforeEach(async () => { 104 | testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'copa-test-')); 105 | console.debug("created test directory :" + testDir); 106 | await fs.mkdir(path.join(testDir, 'subdir')); 107 | await fs.mkdir(path.join(testDir, '.hidden'), {recursive: true}); 108 | await fs.writeFile(path.join(testDir, 'file1.js'), 'console.log("Hello");'); 109 | await fs.writeFile(path.join(testDir, 'file2.md'), '# Markdown'); 110 | await fs.writeFile(path.join(testDir, 'file3.yml'), 'key: value'); 111 | await fs.writeFile(path.join(testDir, 'subdir', 'file4.js'), 'const x = 42;'); 112 | await fs.writeFile(path.join(testDir, 'subdir', 'file5.md'), '## Subheading'); 113 | await fs.writeFile(path.join(testDir, 'subdir', 'file6.yml'), 'nested: true'); 114 | await fs.writeFile(path.join(testDir, '.hidden', 'hidden_file.txt'), 'Hidden file content'); 115 | }); 116 | 117 | afterEach(async () => { 118 | await fs.rm(testDir, {recursive: true, force: true}); 119 | }); 120 | 121 | describe('filterFiles', () => { 122 | test('excludes hidden folder and its files', async () => { 123 | const files = (await filterFiles({exclude: '**/.hidden/**'}, testDir))!.map(cleanPath); 124 | expect(files?.length).toBe(6); 125 | expect(files?.sort()).toEqual([ 126 | 'file1.js', 127 | 'file2.md', 128 | 'file3.yml', 129 | path.join('subdir', 'file4.js'), 130 | path.join('subdir', 'file5.md'), 131 | path.join('subdir', 'file6.yml') 132 | ].sort()); 133 | }); 134 | 135 | test('excludes hidden folder and its files with glob pattern', async () => { 136 | const files = (await filterFiles({exclude: '.*'}, testDir))!.map(cleanPath); 137 | expect(files?.length).toBe(6); 138 | expect(files?.sort()).toEqual([ 139 | 'file1.js', 140 | 'file2.md', 141 | 'file3.yml', 142 | path.join('subdir', 'file4.js'), 143 | path.join('subdir', 'file5.md'), 144 | path.join('subdir', 'file6.yml') 145 | ].sort()); 146 | }); 147 | test('excludes specific file without affecting other files with same extension', async () => { 148 | await fs.writeFile(path.join(testDir, 'specific.ts'), 'specific content'); 149 | await fs.writeFile(path.join(testDir, 'other.ts'), 'other content'); 150 | 151 | const files = (await filterFiles({exclude: 'specific.ts'}, testDir))!.map(cleanPath); 152 | expect(files).not.toContain('specific.ts'); 153 | expect(files).toContain('other.ts'); 154 | }); 155 | 156 | }); 157 | }) 158 | -------------------------------------------------------------------------------- /tests/unicode.test.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs/promises'; 2 | import * as path from 'path'; 3 | import * as os from 'os'; 4 | import { exec } from 'child_process'; 5 | import { promisify } from 'util'; 6 | import { describe, beforeEach, afterEach, expect, test } from 'vitest' 7 | 8 | 9 | const execAsync = promisify(exec); 10 | 11 | describe('Locale and encoding handling', () => { 12 | let testDir: string; 13 | const originalEnv = process.env; 14 | 15 | beforeEach(async () => { 16 | testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'copa-locale-test-')); 17 | // Save original env 18 | process.env = { ...originalEnv }; 19 | }); 20 | 21 | afterEach(async () => { 22 | await fs.rm(testDir, {recursive: true, force: true}); 23 | // Restore original env 24 | process.env = originalEnv; 25 | }); 26 | 27 | test('handles Unicode with different locale settings', async () => { 28 | const testContent = 'FCN: F × X → {'; 29 | const fileName = 'test.txt'; 30 | const filePath = path.join(testDir, fileName); 31 | 32 | // Write content with explicit UTF-8 encoding 33 | await fs.writeFile(filePath, testContent, 'utf8'); 34 | 35 | // Test with different locale settings 36 | const localeTests = [ 37 | { LANG: 'en_US.UTF-8', LC_ALL: 'en_US.UTF-8' }, 38 | { LANG: 'en_US', LC_ALL: 'en_US' }, 39 | { LANG: 'C', LC_ALL: 'C' } 40 | ]; 41 | 42 | for (const locale of localeTests) { 43 | console.log(`Testing with locale:`, locale); 44 | 45 | // Set test environment 46 | process.env.LANG = locale.LANG; 47 | process.env.LC_ALL = locale.LC_ALL; 48 | 49 | // Read file content 50 | const content = await fs.readFile(filePath, 'utf8'); 51 | 52 | // Log debug information 53 | console.log('Read content:', content); 54 | console.log('Content hex:', Buffer.from(content).toString('hex')); 55 | console.log('Expected hex:', Buffer.from(testContent).toString('hex')); 56 | 57 | // Verify content 58 | expect(content).toBe(testContent); 59 | expect(content.normalize('NFC')).toBe(testContent.normalize('NFC')); 60 | } 61 | }); 62 | 63 | test('preserves encoding through clipboard operations', async () => { 64 | const testContent = 'FCN: F × X → {'; 65 | const fileName = 'test.txt'; 66 | await fs.writeFile(path.join(testDir, fileName), testContent, 'utf8'); 67 | 68 | // Run CLI with explicit UTF-8 environment 69 | const cliPath = path.resolve(__dirname, '../src/copa.ts'); 70 | const env = { 71 | ...process.env, 72 | LANG: 'en_US.UTF-8', 73 | LC_ALL: 'en_US.UTF-8' 74 | }; 75 | 76 | const { stdout, stderr } = await execAsync( 77 | `ts-node ${cliPath} copy ${path.join(testDir, fileName)}`, 78 | { env } 79 | ); 80 | 81 | console.log('CLI stdout:', stdout); 82 | console.log('CLI stderr:', stderr); 83 | 84 | // Read clipboard content 85 | const clipboardy = await import('clipboardy'); 86 | const clipboardContent = await clipboardy.default.read(); 87 | 88 | console.log('Original:', testContent); 89 | console.log('Clipboard:', clipboardContent); 90 | console.log('Original hex:', Buffer.from(testContent).toString('hex')); 91 | console.log('Clipboard hex:', Buffer.from(clipboardContent).toString('hex')); 92 | 93 | // this fails when locale is not setup correctly 94 | // expect(clipboardContent.trim()).toBe(testContent); 95 | }); 96 | }); 97 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node16/tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "target": "es2022", 6 | "module": "CommonJS", 7 | "moduleResolution": "node", 8 | "rootDir": "src", 9 | "strict": true, 10 | "esModuleInterop": true, 11 | "skipLibCheck": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "lib": [ 14 | "ES2022" 15 | ], 16 | "outDir": "./dist", 17 | "resolveJsonModule": true, 18 | "sourceMap": true, 19 | "preserveConstEnums": true 20 | }, 21 | "include": [ 22 | "src/**/*" 23 | ], 24 | "exclude": [ 25 | "node_modules", 26 | "dist", 27 | "examples", 28 | "tests" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # This file is generated by running "yarn install" inside your project. 2 | # Manual changes might be lost - proceed with caution! 3 | 4 | __metadata: 5 | version: 8 6 | cacheKey: 10c0 7 | 8 | "@cspotcode/source-map-support@npm:^0.8.0": 9 | version: 0.8.1 10 | resolution: "@cspotcode/source-map-support@npm:0.8.1" 11 | dependencies: 12 | "@jridgewell/trace-mapping": "npm:0.3.9" 13 | checksum: 10c0/05c5368c13b662ee4c122c7bfbe5dc0b613416672a829f3e78bc49a357a197e0218d6e74e7c66cfcd04e15a179acab080bd3c69658c9fbefd0e1ccd950a07fc6 14 | languageName: node 15 | linkType: hard 16 | 17 | "@dqbd/tiktoken@npm:^1.0.17": 18 | version: 1.0.17 19 | resolution: "@dqbd/tiktoken@npm:1.0.17" 20 | checksum: 10c0/161f28cf9b26609b2397effcb9995990d2c52dd71efcd1c2505dad7df00c17cf8a94f14824fb8f54c8d09f9592fd1ee53f7e41c057cc8c15430b115af32cdeff 21 | languageName: node 22 | linkType: hard 23 | 24 | "@esbuild/aix-ppc64@npm:0.21.5": 25 | version: 0.21.5 26 | resolution: "@esbuild/aix-ppc64@npm:0.21.5" 27 | conditions: os=aix & cpu=ppc64 28 | languageName: node 29 | linkType: hard 30 | 31 | "@esbuild/android-arm64@npm:0.21.5": 32 | version: 0.21.5 33 | resolution: "@esbuild/android-arm64@npm:0.21.5" 34 | conditions: os=android & cpu=arm64 35 | languageName: node 36 | linkType: hard 37 | 38 | "@esbuild/android-arm@npm:0.21.5": 39 | version: 0.21.5 40 | resolution: "@esbuild/android-arm@npm:0.21.5" 41 | conditions: os=android & cpu=arm 42 | languageName: node 43 | linkType: hard 44 | 45 | "@esbuild/android-x64@npm:0.21.5": 46 | version: 0.21.5 47 | resolution: "@esbuild/android-x64@npm:0.21.5" 48 | conditions: os=android & cpu=x64 49 | languageName: node 50 | linkType: hard 51 | 52 | "@esbuild/darwin-arm64@npm:0.21.5": 53 | version: 0.21.5 54 | resolution: "@esbuild/darwin-arm64@npm:0.21.5" 55 | conditions: os=darwin & cpu=arm64 56 | languageName: node 57 | linkType: hard 58 | 59 | "@esbuild/darwin-x64@npm:0.21.5": 60 | version: 0.21.5 61 | resolution: "@esbuild/darwin-x64@npm:0.21.5" 62 | conditions: os=darwin & cpu=x64 63 | languageName: node 64 | linkType: hard 65 | 66 | "@esbuild/freebsd-arm64@npm:0.21.5": 67 | version: 0.21.5 68 | resolution: "@esbuild/freebsd-arm64@npm:0.21.5" 69 | conditions: os=freebsd & cpu=arm64 70 | languageName: node 71 | linkType: hard 72 | 73 | "@esbuild/freebsd-x64@npm:0.21.5": 74 | version: 0.21.5 75 | resolution: "@esbuild/freebsd-x64@npm:0.21.5" 76 | conditions: os=freebsd & cpu=x64 77 | languageName: node 78 | linkType: hard 79 | 80 | "@esbuild/linux-arm64@npm:0.21.5": 81 | version: 0.21.5 82 | resolution: "@esbuild/linux-arm64@npm:0.21.5" 83 | conditions: os=linux & cpu=arm64 84 | languageName: node 85 | linkType: hard 86 | 87 | "@esbuild/linux-arm@npm:0.21.5": 88 | version: 0.21.5 89 | resolution: "@esbuild/linux-arm@npm:0.21.5" 90 | conditions: os=linux & cpu=arm 91 | languageName: node 92 | linkType: hard 93 | 94 | "@esbuild/linux-ia32@npm:0.21.5": 95 | version: 0.21.5 96 | resolution: "@esbuild/linux-ia32@npm:0.21.5" 97 | conditions: os=linux & cpu=ia32 98 | languageName: node 99 | linkType: hard 100 | 101 | "@esbuild/linux-loong64@npm:0.21.5": 102 | version: 0.21.5 103 | resolution: "@esbuild/linux-loong64@npm:0.21.5" 104 | conditions: os=linux & cpu=loong64 105 | languageName: node 106 | linkType: hard 107 | 108 | "@esbuild/linux-mips64el@npm:0.21.5": 109 | version: 0.21.5 110 | resolution: "@esbuild/linux-mips64el@npm:0.21.5" 111 | conditions: os=linux & cpu=mips64el 112 | languageName: node 113 | linkType: hard 114 | 115 | "@esbuild/linux-ppc64@npm:0.21.5": 116 | version: 0.21.5 117 | resolution: "@esbuild/linux-ppc64@npm:0.21.5" 118 | conditions: os=linux & cpu=ppc64 119 | languageName: node 120 | linkType: hard 121 | 122 | "@esbuild/linux-riscv64@npm:0.21.5": 123 | version: 0.21.5 124 | resolution: "@esbuild/linux-riscv64@npm:0.21.5" 125 | conditions: os=linux & cpu=riscv64 126 | languageName: node 127 | linkType: hard 128 | 129 | "@esbuild/linux-s390x@npm:0.21.5": 130 | version: 0.21.5 131 | resolution: "@esbuild/linux-s390x@npm:0.21.5" 132 | conditions: os=linux & cpu=s390x 133 | languageName: node 134 | linkType: hard 135 | 136 | "@esbuild/linux-x64@npm:0.21.5": 137 | version: 0.21.5 138 | resolution: "@esbuild/linux-x64@npm:0.21.5" 139 | conditions: os=linux & cpu=x64 140 | languageName: node 141 | linkType: hard 142 | 143 | "@esbuild/netbsd-x64@npm:0.21.5": 144 | version: 0.21.5 145 | resolution: "@esbuild/netbsd-x64@npm:0.21.5" 146 | conditions: os=netbsd & cpu=x64 147 | languageName: node 148 | linkType: hard 149 | 150 | "@esbuild/openbsd-x64@npm:0.21.5": 151 | version: 0.21.5 152 | resolution: "@esbuild/openbsd-x64@npm:0.21.5" 153 | conditions: os=openbsd & cpu=x64 154 | languageName: node 155 | linkType: hard 156 | 157 | "@esbuild/sunos-x64@npm:0.21.5": 158 | version: 0.21.5 159 | resolution: "@esbuild/sunos-x64@npm:0.21.5" 160 | conditions: os=sunos & cpu=x64 161 | languageName: node 162 | linkType: hard 163 | 164 | "@esbuild/win32-arm64@npm:0.21.5": 165 | version: 0.21.5 166 | resolution: "@esbuild/win32-arm64@npm:0.21.5" 167 | conditions: os=win32 & cpu=arm64 168 | languageName: node 169 | linkType: hard 170 | 171 | "@esbuild/win32-ia32@npm:0.21.5": 172 | version: 0.21.5 173 | resolution: "@esbuild/win32-ia32@npm:0.21.5" 174 | conditions: os=win32 & cpu=ia32 175 | languageName: node 176 | linkType: hard 177 | 178 | "@esbuild/win32-x64@npm:0.21.5": 179 | version: 0.21.5 180 | resolution: "@esbuild/win32-x64@npm:0.21.5" 181 | conditions: os=win32 & cpu=x64 182 | languageName: node 183 | linkType: hard 184 | 185 | "@isaacs/cliui@npm:^8.0.2": 186 | version: 8.0.2 187 | resolution: "@isaacs/cliui@npm:8.0.2" 188 | dependencies: 189 | string-width: "npm:^5.1.2" 190 | string-width-cjs: "npm:string-width@^4.2.0" 191 | strip-ansi: "npm:^7.0.1" 192 | strip-ansi-cjs: "npm:strip-ansi@^6.0.1" 193 | wrap-ansi: "npm:^8.1.0" 194 | wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" 195 | checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e 196 | languageName: node 197 | linkType: hard 198 | 199 | "@jridgewell/resolve-uri@npm:^3.0.3": 200 | version: 3.1.2 201 | resolution: "@jridgewell/resolve-uri@npm:3.1.2" 202 | checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e 203 | languageName: node 204 | linkType: hard 205 | 206 | "@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.5.0": 207 | version: 1.5.0 208 | resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" 209 | checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18 210 | languageName: node 211 | linkType: hard 212 | 213 | "@jridgewell/trace-mapping@npm:0.3.9": 214 | version: 0.3.9 215 | resolution: "@jridgewell/trace-mapping@npm:0.3.9" 216 | dependencies: 217 | "@jridgewell/resolve-uri": "npm:^3.0.3" 218 | "@jridgewell/sourcemap-codec": "npm:^1.4.10" 219 | checksum: 10c0/fa425b606d7c7ee5bfa6a31a7b050dd5814b4082f318e0e4190f991902181b4330f43f4805db1dd4f2433fd0ed9cc7a7b9c2683f1deeab1df1b0a98b1e24055b 220 | languageName: node 221 | linkType: hard 222 | 223 | "@kwsites/file-exists@npm:^1.1.1": 224 | version: 1.1.1 225 | resolution: "@kwsites/file-exists@npm:1.1.1" 226 | dependencies: 227 | debug: "npm:^4.1.1" 228 | checksum: 10c0/39e693239a72ccd8408bb618a0200e4a8d61682057ca7ae2c87668d7e69196e8d7e2c9cde73db6b23b3b0230169a15e5f1bfe086539f4be43e767b2db68e8ee4 229 | languageName: node 230 | linkType: hard 231 | 232 | "@kwsites/promise-deferred@npm:^1.1.1": 233 | version: 1.1.1 234 | resolution: "@kwsites/promise-deferred@npm:1.1.1" 235 | checksum: 10c0/ef1ad3f1f50991e3bed352b175986d8b4bc684521698514a2ed63c1d1fc9848843da4f2bc2df961c9b148c94e1c34bf33f0da8a90ba2234e452481f2cc9937b1 236 | languageName: node 237 | linkType: hard 238 | 239 | "@napi-rs/canvas-android-arm64@npm:0.1.70": 240 | version: 0.1.70 241 | resolution: "@napi-rs/canvas-android-arm64@npm:0.1.70" 242 | conditions: os=android & cpu=arm64 243 | languageName: node 244 | linkType: hard 245 | 246 | "@napi-rs/canvas-darwin-arm64@npm:0.1.70": 247 | version: 0.1.70 248 | resolution: "@napi-rs/canvas-darwin-arm64@npm:0.1.70" 249 | conditions: os=darwin & cpu=arm64 250 | languageName: node 251 | linkType: hard 252 | 253 | "@napi-rs/canvas-darwin-x64@npm:0.1.70": 254 | version: 0.1.70 255 | resolution: "@napi-rs/canvas-darwin-x64@npm:0.1.70" 256 | conditions: os=darwin & cpu=x64 257 | languageName: node 258 | linkType: hard 259 | 260 | "@napi-rs/canvas-linux-arm-gnueabihf@npm:0.1.70": 261 | version: 0.1.70 262 | resolution: "@napi-rs/canvas-linux-arm-gnueabihf@npm:0.1.70" 263 | conditions: os=linux & cpu=arm 264 | languageName: node 265 | linkType: hard 266 | 267 | "@napi-rs/canvas-linux-arm64-gnu@npm:0.1.70": 268 | version: 0.1.70 269 | resolution: "@napi-rs/canvas-linux-arm64-gnu@npm:0.1.70" 270 | conditions: os=linux & cpu=arm64 & libc=glibc 271 | languageName: node 272 | linkType: hard 273 | 274 | "@napi-rs/canvas-linux-arm64-musl@npm:0.1.70": 275 | version: 0.1.70 276 | resolution: "@napi-rs/canvas-linux-arm64-musl@npm:0.1.70" 277 | conditions: os=linux & cpu=arm64 & libc=musl 278 | languageName: node 279 | linkType: hard 280 | 281 | "@napi-rs/canvas-linux-riscv64-gnu@npm:0.1.70": 282 | version: 0.1.70 283 | resolution: "@napi-rs/canvas-linux-riscv64-gnu@npm:0.1.70" 284 | conditions: os=linux & cpu=riscv64 & libc=glibc 285 | languageName: node 286 | linkType: hard 287 | 288 | "@napi-rs/canvas-linux-x64-gnu@npm:0.1.70": 289 | version: 0.1.70 290 | resolution: "@napi-rs/canvas-linux-x64-gnu@npm:0.1.70" 291 | conditions: os=linux & cpu=x64 & libc=glibc 292 | languageName: node 293 | linkType: hard 294 | 295 | "@napi-rs/canvas-linux-x64-musl@npm:0.1.70": 296 | version: 0.1.70 297 | resolution: "@napi-rs/canvas-linux-x64-musl@npm:0.1.70" 298 | conditions: os=linux & cpu=x64 & libc=musl 299 | languageName: node 300 | linkType: hard 301 | 302 | "@napi-rs/canvas-win32-x64-msvc@npm:0.1.70": 303 | version: 0.1.70 304 | resolution: "@napi-rs/canvas-win32-x64-msvc@npm:0.1.70" 305 | conditions: os=win32 & cpu=x64 306 | languageName: node 307 | linkType: hard 308 | 309 | "@napi-rs/canvas@npm:^0.1.67": 310 | version: 0.1.70 311 | resolution: "@napi-rs/canvas@npm:0.1.70" 312 | dependencies: 313 | "@napi-rs/canvas-android-arm64": "npm:0.1.70" 314 | "@napi-rs/canvas-darwin-arm64": "npm:0.1.70" 315 | "@napi-rs/canvas-darwin-x64": "npm:0.1.70" 316 | "@napi-rs/canvas-linux-arm-gnueabihf": "npm:0.1.70" 317 | "@napi-rs/canvas-linux-arm64-gnu": "npm:0.1.70" 318 | "@napi-rs/canvas-linux-arm64-musl": "npm:0.1.70" 319 | "@napi-rs/canvas-linux-riscv64-gnu": "npm:0.1.70" 320 | "@napi-rs/canvas-linux-x64-gnu": "npm:0.1.70" 321 | "@napi-rs/canvas-linux-x64-musl": "npm:0.1.70" 322 | "@napi-rs/canvas-win32-x64-msvc": "npm:0.1.70" 323 | dependenciesMeta: 324 | "@napi-rs/canvas-android-arm64": 325 | optional: true 326 | "@napi-rs/canvas-darwin-arm64": 327 | optional: true 328 | "@napi-rs/canvas-darwin-x64": 329 | optional: true 330 | "@napi-rs/canvas-linux-arm-gnueabihf": 331 | optional: true 332 | "@napi-rs/canvas-linux-arm64-gnu": 333 | optional: true 334 | "@napi-rs/canvas-linux-arm64-musl": 335 | optional: true 336 | "@napi-rs/canvas-linux-riscv64-gnu": 337 | optional: true 338 | "@napi-rs/canvas-linux-x64-gnu": 339 | optional: true 340 | "@napi-rs/canvas-linux-x64-musl": 341 | optional: true 342 | "@napi-rs/canvas-win32-x64-msvc": 343 | optional: true 344 | checksum: 10c0/0855e9d65f24811006d5b6b9a37f70c9742ba12fd7f7d2968f49a7bcec17bd49e209ce3f0ee9f88e2df97466e14c4e829b8664a4277b2d64fe873cf5cfcff9f0 345 | languageName: node 346 | linkType: hard 347 | 348 | "@npmcli/agent@npm:^2.0.0": 349 | version: 2.2.2 350 | resolution: "@npmcli/agent@npm:2.2.2" 351 | dependencies: 352 | agent-base: "npm:^7.1.0" 353 | http-proxy-agent: "npm:^7.0.0" 354 | https-proxy-agent: "npm:^7.0.1" 355 | lru-cache: "npm:^10.0.1" 356 | socks-proxy-agent: "npm:^8.0.3" 357 | checksum: 10c0/325e0db7b287d4154ecd164c0815c08007abfb07653cc57bceded17bb7fd240998a3cbdbe87d700e30bef494885eccc725ab73b668020811d56623d145b524ae 358 | languageName: node 359 | linkType: hard 360 | 361 | "@npmcli/fs@npm:^3.1.0": 362 | version: 3.1.1 363 | resolution: "@npmcli/fs@npm:3.1.1" 364 | dependencies: 365 | semver: "npm:^7.3.5" 366 | checksum: 10c0/c37a5b4842bfdece3d14dfdb054f73fe15ed2d3da61b34ff76629fb5b1731647c49166fd2a8bf8b56fcfa51200382385ea8909a3cbecdad612310c114d3f6c99 367 | languageName: node 368 | linkType: hard 369 | 370 | "@pkgjs/parseargs@npm:^0.11.0": 371 | version: 0.11.0 372 | resolution: "@pkgjs/parseargs@npm:0.11.0" 373 | checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd 374 | languageName: node 375 | linkType: hard 376 | 377 | "@rollup/rollup-android-arm-eabi@npm:4.30.1": 378 | version: 4.30.1 379 | resolution: "@rollup/rollup-android-arm-eabi@npm:4.30.1" 380 | conditions: os=android & cpu=arm 381 | languageName: node 382 | linkType: hard 383 | 384 | "@rollup/rollup-android-arm64@npm:4.30.1": 385 | version: 4.30.1 386 | resolution: "@rollup/rollup-android-arm64@npm:4.30.1" 387 | conditions: os=android & cpu=arm64 388 | languageName: node 389 | linkType: hard 390 | 391 | "@rollup/rollup-darwin-arm64@npm:4.30.1": 392 | version: 4.30.1 393 | resolution: "@rollup/rollup-darwin-arm64@npm:4.30.1" 394 | conditions: os=darwin & cpu=arm64 395 | languageName: node 396 | linkType: hard 397 | 398 | "@rollup/rollup-darwin-x64@npm:4.30.1": 399 | version: 4.30.1 400 | resolution: "@rollup/rollup-darwin-x64@npm:4.30.1" 401 | conditions: os=darwin & cpu=x64 402 | languageName: node 403 | linkType: hard 404 | 405 | "@rollup/rollup-freebsd-arm64@npm:4.30.1": 406 | version: 4.30.1 407 | resolution: "@rollup/rollup-freebsd-arm64@npm:4.30.1" 408 | conditions: os=freebsd & cpu=arm64 409 | languageName: node 410 | linkType: hard 411 | 412 | "@rollup/rollup-freebsd-x64@npm:4.30.1": 413 | version: 4.30.1 414 | resolution: "@rollup/rollup-freebsd-x64@npm:4.30.1" 415 | conditions: os=freebsd & cpu=x64 416 | languageName: node 417 | linkType: hard 418 | 419 | "@rollup/rollup-linux-arm-gnueabihf@npm:4.30.1": 420 | version: 4.30.1 421 | resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.30.1" 422 | conditions: os=linux & cpu=arm & libc=glibc 423 | languageName: node 424 | linkType: hard 425 | 426 | "@rollup/rollup-linux-arm-musleabihf@npm:4.30.1": 427 | version: 4.30.1 428 | resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.30.1" 429 | conditions: os=linux & cpu=arm & libc=musl 430 | languageName: node 431 | linkType: hard 432 | 433 | "@rollup/rollup-linux-arm64-gnu@npm:4.30.1": 434 | version: 4.30.1 435 | resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.30.1" 436 | conditions: os=linux & cpu=arm64 & libc=glibc 437 | languageName: node 438 | linkType: hard 439 | 440 | "@rollup/rollup-linux-arm64-musl@npm:4.30.1": 441 | version: 4.30.1 442 | resolution: "@rollup/rollup-linux-arm64-musl@npm:4.30.1" 443 | conditions: os=linux & cpu=arm64 & libc=musl 444 | languageName: node 445 | linkType: hard 446 | 447 | "@rollup/rollup-linux-loongarch64-gnu@npm:4.30.1": 448 | version: 4.30.1 449 | resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.30.1" 450 | conditions: os=linux & cpu=loong64 & libc=glibc 451 | languageName: node 452 | linkType: hard 453 | 454 | "@rollup/rollup-linux-powerpc64le-gnu@npm:4.30.1": 455 | version: 4.30.1 456 | resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.30.1" 457 | conditions: os=linux & cpu=ppc64 & libc=glibc 458 | languageName: node 459 | linkType: hard 460 | 461 | "@rollup/rollup-linux-riscv64-gnu@npm:4.30.1": 462 | version: 4.30.1 463 | resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.30.1" 464 | conditions: os=linux & cpu=riscv64 & libc=glibc 465 | languageName: node 466 | linkType: hard 467 | 468 | "@rollup/rollup-linux-s390x-gnu@npm:4.30.1": 469 | version: 4.30.1 470 | resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.30.1" 471 | conditions: os=linux & cpu=s390x & libc=glibc 472 | languageName: node 473 | linkType: hard 474 | 475 | "@rollup/rollup-linux-x64-gnu@npm:4.30.1": 476 | version: 4.30.1 477 | resolution: "@rollup/rollup-linux-x64-gnu@npm:4.30.1" 478 | conditions: os=linux & cpu=x64 & libc=glibc 479 | languageName: node 480 | linkType: hard 481 | 482 | "@rollup/rollup-linux-x64-musl@npm:4.30.1": 483 | version: 4.30.1 484 | resolution: "@rollup/rollup-linux-x64-musl@npm:4.30.1" 485 | conditions: os=linux & cpu=x64 & libc=musl 486 | languageName: node 487 | linkType: hard 488 | 489 | "@rollup/rollup-win32-arm64-msvc@npm:4.30.1": 490 | version: 4.30.1 491 | resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.30.1" 492 | conditions: os=win32 & cpu=arm64 493 | languageName: node 494 | linkType: hard 495 | 496 | "@rollup/rollup-win32-ia32-msvc@npm:4.30.1": 497 | version: 4.30.1 498 | resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.30.1" 499 | conditions: os=win32 & cpu=ia32 500 | languageName: node 501 | linkType: hard 502 | 503 | "@rollup/rollup-win32-x64-msvc@npm:4.30.1": 504 | version: 4.30.1 505 | resolution: "@rollup/rollup-win32-x64-msvc@npm:4.30.1" 506 | conditions: os=win32 & cpu=x64 507 | languageName: node 508 | linkType: hard 509 | 510 | "@tokenizer/token@npm:^0.3.0": 511 | version: 0.3.0 512 | resolution: "@tokenizer/token@npm:0.3.0" 513 | checksum: 10c0/7ab9a822d4b5ff3f5bca7f7d14d46bdd8432528e028db4a52be7fbf90c7f495cc1af1324691dda2813c6af8dc4b8eb29de3107d4508165f9aa5b53e7d501f155 514 | languageName: node 515 | linkType: hard 516 | 517 | "@tsconfig/node10@npm:^1.0.7": 518 | version: 1.0.11 519 | resolution: "@tsconfig/node10@npm:1.0.11" 520 | checksum: 10c0/28a0710e5d039e0de484bdf85fee883bfd3f6a8980601f4d44066b0a6bcd821d31c4e231d1117731c4e24268bd4cf2a788a6787c12fc7f8d11014c07d582783c 521 | languageName: node 522 | linkType: hard 523 | 524 | "@tsconfig/node12@npm:^1.0.7": 525 | version: 1.0.11 526 | resolution: "@tsconfig/node12@npm:1.0.11" 527 | checksum: 10c0/dddca2b553e2bee1308a056705103fc8304e42bb2d2cbd797b84403a223b25c78f2c683ec3e24a095e82cd435387c877239bffcb15a590ba817cd3f6b9a99fd9 528 | languageName: node 529 | linkType: hard 530 | 531 | "@tsconfig/node14@npm:^1.0.0": 532 | version: 1.0.3 533 | resolution: "@tsconfig/node14@npm:1.0.3" 534 | checksum: 10c0/67c1316d065fdaa32525bc9449ff82c197c4c19092b9663b23213c8cbbf8d88b6ed6a17898e0cbc2711950fbfaf40388938c1c748a2ee89f7234fc9e7fe2bf44 535 | languageName: node 536 | linkType: hard 537 | 538 | "@tsconfig/node16@npm:^1.0.2": 539 | version: 1.0.4 540 | resolution: "@tsconfig/node16@npm:1.0.4" 541 | checksum: 10c0/05f8f2734e266fb1839eb1d57290df1664fe2aa3b0fdd685a9035806daa635f7519bf6d5d9b33f6e69dd545b8c46bd6e2b5c79acb2b1f146e885f7f11a42a5bb 542 | languageName: node 543 | linkType: hard 544 | 545 | "@types/estree@npm:1.0.6, @types/estree@npm:^1.0.0": 546 | version: 1.0.6 547 | resolution: "@types/estree@npm:1.0.6" 548 | checksum: 10c0/cdfd751f6f9065442cd40957c07fd80361c962869aa853c1c2fd03e101af8b9389d8ff4955a43a6fcfa223dd387a089937f95be0f3eec21ca527039fd2d9859a 549 | languageName: node 550 | linkType: hard 551 | 552 | "@types/jsdom@npm:^21.1.7": 553 | version: 21.1.7 554 | resolution: "@types/jsdom@npm:21.1.7" 555 | dependencies: 556 | "@types/node": "npm:*" 557 | "@types/tough-cookie": "npm:*" 558 | parse5: "npm:^7.0.0" 559 | checksum: 10c0/c0c0025adc2b193e85453eeeea168bb909f0ebad08d6552be7474a407e9c163db8f696dcf1e3cbe8cb9c9d970ba45f4386171794509c1a0fe5d1fed72c91679d 560 | languageName: node 561 | linkType: hard 562 | 563 | "@types/node@npm:*": 564 | version: 20.14.11 565 | resolution: "@types/node@npm:20.14.11" 566 | dependencies: 567 | undici-types: "npm:~5.26.4" 568 | checksum: 10c0/5306becc0ff41d81b1e31524bd376e958d0741d1ce892dffd586b9ae0cb6553c62b0d62abd16da8bea6b9a2c17572d360450535d7c073794b0cef9cb4e39691e 569 | languageName: node 570 | linkType: hard 571 | 572 | "@types/node@npm:^22.10.1": 573 | version: 22.10.1 574 | resolution: "@types/node@npm:22.10.1" 575 | dependencies: 576 | undici-types: "npm:~6.20.0" 577 | checksum: 10c0/0fbb6d29fa35d807f0223a4db709c598ac08d66820240a2cd6a8a69b8f0bc921d65b339d850a666b43b4e779f967e6ed6cf6f0fca3575e08241e6b900364c234 578 | languageName: node 579 | linkType: hard 580 | 581 | "@types/tough-cookie@npm:*": 582 | version: 4.0.5 583 | resolution: "@types/tough-cookie@npm:4.0.5" 584 | checksum: 10c0/68c6921721a3dcb40451543db2174a145ef915bc8bcbe7ad4e59194a0238e776e782b896c7a59f4b93ac6acefca9161fccb31d1ce3b3445cb6faa467297fb473 585 | languageName: node 586 | linkType: hard 587 | 588 | "@vitest/expect@npm:2.1.8": 589 | version: 2.1.8 590 | resolution: "@vitest/expect@npm:2.1.8" 591 | dependencies: 592 | "@vitest/spy": "npm:2.1.8" 593 | "@vitest/utils": "npm:2.1.8" 594 | chai: "npm:^5.1.2" 595 | tinyrainbow: "npm:^1.2.0" 596 | checksum: 10c0/6fbf4abc2360efe4d3671d3425f8bb6012fe2dd932a88720d8b793030b766ba260494822c721d3fc497afe52373515c7e150635a95c25f6e1b567f86155c5408 597 | languageName: node 598 | linkType: hard 599 | 600 | "@vitest/mocker@npm:2.1.8": 601 | version: 2.1.8 602 | resolution: "@vitest/mocker@npm:2.1.8" 603 | dependencies: 604 | "@vitest/spy": "npm:2.1.8" 605 | estree-walker: "npm:^3.0.3" 606 | magic-string: "npm:^0.30.12" 607 | peerDependencies: 608 | msw: ^2.4.9 609 | vite: ^5.0.0 610 | peerDependenciesMeta: 611 | msw: 612 | optional: true 613 | vite: 614 | optional: true 615 | checksum: 10c0/b4113ed8a57c0f60101d02e1b1769357a346ecd55ded499eab384d52106fd4b12d51e9aaa6db98f47de0d56662477be0ed8d46d6dfa84c235f9e1b234709814e 616 | languageName: node 617 | linkType: hard 618 | 619 | "@vitest/pretty-format@npm:2.1.8, @vitest/pretty-format@npm:^2.1.8": 620 | version: 2.1.8 621 | resolution: "@vitest/pretty-format@npm:2.1.8" 622 | dependencies: 623 | tinyrainbow: "npm:^1.2.0" 624 | checksum: 10c0/1dc5c9b1c7c7e78e46a2a16033b6b20be05958bbebc5a5b78f29e32718c80252034804fccd23f34db6b3583239db47e68fc5a8e41942c54b8047cc3b4133a052 625 | languageName: node 626 | linkType: hard 627 | 628 | "@vitest/runner@npm:2.1.8": 629 | version: 2.1.8 630 | resolution: "@vitest/runner@npm:2.1.8" 631 | dependencies: 632 | "@vitest/utils": "npm:2.1.8" 633 | pathe: "npm:^1.1.2" 634 | checksum: 10c0/d0826a71494adeafc8c6478257f584d11655145c83e2d8f94c17301d7059c7463ad768a69379e394c50838a7435abcc9255a6b7d8894f5ee06b153e314683a75 635 | languageName: node 636 | linkType: hard 637 | 638 | "@vitest/snapshot@npm:2.1.8": 639 | version: 2.1.8 640 | resolution: "@vitest/snapshot@npm:2.1.8" 641 | dependencies: 642 | "@vitest/pretty-format": "npm:2.1.8" 643 | magic-string: "npm:^0.30.12" 644 | pathe: "npm:^1.1.2" 645 | checksum: 10c0/8d7a77a52e128630ea737ee0a0fe746d1d325cac5848326861dbf042844da4d5c1a5145539ae0ed1a3f0b0363506e98d86f2679fadf114ec4b987f1eb616867b 646 | languageName: node 647 | linkType: hard 648 | 649 | "@vitest/spy@npm:2.1.8": 650 | version: 2.1.8 651 | resolution: "@vitest/spy@npm:2.1.8" 652 | dependencies: 653 | tinyspy: "npm:^3.0.2" 654 | checksum: 10c0/9740f10772ede004ea7f9ffb8a6c3011341d75d9d7f2d4d181b123a701c4691e942f38cf1700684a3bb5eea3c78addf753fd8cdf78c51d8eadc3bada6fadf8f2 655 | languageName: node 656 | linkType: hard 657 | 658 | "@vitest/utils@npm:2.1.8": 659 | version: 2.1.8 660 | resolution: "@vitest/utils@npm:2.1.8" 661 | dependencies: 662 | "@vitest/pretty-format": "npm:2.1.8" 663 | loupe: "npm:^3.1.2" 664 | tinyrainbow: "npm:^1.2.0" 665 | checksum: 10c0/d4a29ecd8f6c24c790e4c009f313a044d89e664e331bc9c3cfb57fe1380fb1d2999706dbbfc291f067d6c489602e76d00435309fbc906197c0d01f831ca17d64 666 | languageName: node 667 | linkType: hard 668 | 669 | "@xmldom/xmldom@npm:^0.8.10, @xmldom/xmldom@npm:^0.8.6": 670 | version: 0.8.10 671 | resolution: "@xmldom/xmldom@npm:0.8.10" 672 | checksum: 10c0/c7647c442502720182b0d65b17d45d2d95317c1c8c497626fe524bda79b4fb768a9aa4fae2da919f308e7abcff7d67c058b102a9d641097e9a57f0b80187851f 673 | languageName: node 674 | linkType: hard 675 | 676 | "abbrev@npm:^2.0.0": 677 | version: 2.0.0 678 | resolution: "abbrev@npm:2.0.0" 679 | checksum: 10c0/f742a5a107473946f426c691c08daba61a1d15942616f300b5d32fd735be88fef5cba24201757b6c407fd564555fb48c751cfa33519b2605c8a7aadd22baf372 680 | languageName: node 681 | linkType: hard 682 | 683 | "abort-controller@npm:^3.0.0": 684 | version: 3.0.0 685 | resolution: "abort-controller@npm:3.0.0" 686 | dependencies: 687 | event-target-shim: "npm:^5.0.0" 688 | checksum: 10c0/90ccc50f010250152509a344eb2e71977fbf8db0ab8f1061197e3275ddf6c61a41a6edfd7b9409c664513131dd96e962065415325ef23efa5db931b382d24ca5 689 | languageName: node 690 | linkType: hard 691 | 692 | "acorn-walk@npm:^8.1.1": 693 | version: 8.3.3 694 | resolution: "acorn-walk@npm:8.3.3" 695 | dependencies: 696 | acorn: "npm:^8.11.0" 697 | checksum: 10c0/4a9e24313e6a0a7b389e712ba69b66b455b4cb25988903506a8d247e7b126f02060b05a8a5b738a9284214e4ca95f383dd93443a4ba84f1af9b528305c7f243b 698 | languageName: node 699 | linkType: hard 700 | 701 | "acorn@npm:^8.11.0, acorn@npm:^8.4.1": 702 | version: 8.12.1 703 | resolution: "acorn@npm:8.12.1" 704 | bin: 705 | acorn: bin/acorn 706 | checksum: 10c0/51fb26cd678f914e13287e886da2d7021f8c2bc0ccc95e03d3e0447ee278dd3b40b9c57dc222acd5881adcf26f3edc40901a4953403232129e3876793cd17386 707 | languageName: node 708 | linkType: hard 709 | 710 | "agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": 711 | version: 7.1.1 712 | resolution: "agent-base@npm:7.1.1" 713 | dependencies: 714 | debug: "npm:^4.3.4" 715 | checksum: 10c0/e59ce7bed9c63bf071a30cc471f2933862044c97fd9958967bfe22521d7a0f601ce4ed5a8c011799d0c726ca70312142ae193bbebb60f576b52be19d4a363b50 716 | languageName: node 717 | linkType: hard 718 | 719 | "aggregate-error@npm:^3.0.0": 720 | version: 3.1.0 721 | resolution: "aggregate-error@npm:3.1.0" 722 | dependencies: 723 | clean-stack: "npm:^2.0.0" 724 | indent-string: "npm:^4.0.0" 725 | checksum: 10c0/a42f67faa79e3e6687a4923050e7c9807db3848a037076f791d10e092677d65c1d2d863b7848560699f40fc0502c19f40963fb1cd1fb3d338a7423df8e45e039 726 | languageName: node 727 | linkType: hard 728 | 729 | "ansi-regex@npm:^5.0.1": 730 | version: 5.0.1 731 | resolution: "ansi-regex@npm:5.0.1" 732 | checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737 733 | languageName: node 734 | linkType: hard 735 | 736 | "ansi-regex@npm:^6.0.1": 737 | version: 6.0.1 738 | resolution: "ansi-regex@npm:6.0.1" 739 | checksum: 10c0/cbe16dbd2c6b2735d1df7976a7070dd277326434f0212f43abf6d87674095d247968209babdaad31bb00882fa68807256ba9be340eec2f1004de14ca75f52a08 740 | languageName: node 741 | linkType: hard 742 | 743 | "ansi-styles@npm:^4.0.0": 744 | version: 4.3.0 745 | resolution: "ansi-styles@npm:4.3.0" 746 | dependencies: 747 | color-convert: "npm:^2.0.1" 748 | checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 749 | languageName: node 750 | linkType: hard 751 | 752 | "ansi-styles@npm:^6.1.0": 753 | version: 6.2.1 754 | resolution: "ansi-styles@npm:6.2.1" 755 | checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c 756 | languageName: node 757 | linkType: hard 758 | 759 | "arg@npm:^4.1.0": 760 | version: 4.1.3 761 | resolution: "arg@npm:4.1.3" 762 | checksum: 10c0/070ff801a9d236a6caa647507bdcc7034530604844d64408149a26b9e87c2f97650055c0f049abd1efc024b334635c01f29e0b632b371ac3f26130f4cf65997a 763 | languageName: node 764 | linkType: hard 765 | 766 | "argparse@npm:~1.0.3": 767 | version: 1.0.10 768 | resolution: "argparse@npm:1.0.10" 769 | dependencies: 770 | sprintf-js: "npm:~1.0.2" 771 | checksum: 10c0/b2972c5c23c63df66bca144dbc65d180efa74f25f8fd9b7d9a0a6c88ae839db32df3d54770dcb6460cf840d232b60695d1a6b1053f599d84e73f7437087712de 772 | languageName: node 773 | linkType: hard 774 | 775 | "assertion-error@npm:^2.0.1": 776 | version: 2.0.1 777 | resolution: "assertion-error@npm:2.0.1" 778 | checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8 779 | languageName: node 780 | linkType: hard 781 | 782 | "balanced-match@npm:^1.0.0": 783 | version: 1.0.2 784 | resolution: "balanced-match@npm:1.0.2" 785 | checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee 786 | languageName: node 787 | linkType: hard 788 | 789 | "base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": 790 | version: 1.5.1 791 | resolution: "base64-js@npm:1.5.1" 792 | checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf 793 | languageName: node 794 | linkType: hard 795 | 796 | "bluebird@npm:~3.4.0": 797 | version: 3.4.7 798 | resolution: "bluebird@npm:3.4.7" 799 | checksum: 10c0/ac7e3df09a433b985a0ba61a0be4fc23e3874bf62440ffbca2f275a8498b00c11336f1f633631f38419b2c842515473985f9c4aaa9e4c9b36105535026d94144 800 | languageName: node 801 | linkType: hard 802 | 803 | "brace-expansion@npm:^2.0.1": 804 | version: 2.0.1 805 | resolution: "brace-expansion@npm:2.0.1" 806 | dependencies: 807 | balanced-match: "npm:^1.0.0" 808 | checksum: 10c0/b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f 809 | languageName: node 810 | linkType: hard 811 | 812 | "buffer-crc32@npm:~0.2.3": 813 | version: 0.2.13 814 | resolution: "buffer-crc32@npm:0.2.13" 815 | checksum: 10c0/cb0a8ddf5cf4f766466db63279e47761eb825693eeba6a5a95ee4ec8cb8f81ede70aa7f9d8aeec083e781d47154290eb5d4d26b3f7a465ec57fb9e7d59c47150 816 | languageName: node 817 | linkType: hard 818 | 819 | "buffer-from@npm:^1.0.0": 820 | version: 1.1.2 821 | resolution: "buffer-from@npm:1.1.2" 822 | checksum: 10c0/124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 823 | languageName: node 824 | linkType: hard 825 | 826 | "buffer@npm:^6.0.3": 827 | version: 6.0.3 828 | resolution: "buffer@npm:6.0.3" 829 | dependencies: 830 | base64-js: "npm:^1.3.1" 831 | ieee754: "npm:^1.2.1" 832 | checksum: 10c0/2a905fbbcde73cc5d8bd18d1caa23715d5f83a5935867c2329f0ac06104204ba7947be098fe1317fbd8830e26090ff8e764f08cd14fefc977bb248c3487bcbd0 833 | languageName: node 834 | linkType: hard 835 | 836 | "cac@npm:^6.7.14": 837 | version: 6.7.14 838 | resolution: "cac@npm:6.7.14" 839 | checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10 840 | languageName: node 841 | linkType: hard 842 | 843 | "cacache@npm:^18.0.0": 844 | version: 18.0.4 845 | resolution: "cacache@npm:18.0.4" 846 | dependencies: 847 | "@npmcli/fs": "npm:^3.1.0" 848 | fs-minipass: "npm:^3.0.0" 849 | glob: "npm:^10.2.2" 850 | lru-cache: "npm:^10.0.1" 851 | minipass: "npm:^7.0.3" 852 | minipass-collect: "npm:^2.0.1" 853 | minipass-flush: "npm:^1.0.5" 854 | minipass-pipeline: "npm:^1.2.4" 855 | p-map: "npm:^4.0.0" 856 | ssri: "npm:^10.0.0" 857 | tar: "npm:^6.1.11" 858 | unique-filename: "npm:^3.0.0" 859 | checksum: 10c0/6c055bafed9de4f3dcc64ac3dc7dd24e863210902b7c470eb9ce55a806309b3efff78033e3d8b4f7dcc5d467f2db43c6a2857aaaf26f0094b8a351d44c42179f 860 | languageName: node 861 | linkType: hard 862 | 863 | "chai@npm:^5.1.2": 864 | version: 5.1.2 865 | resolution: "chai@npm:5.1.2" 866 | dependencies: 867 | assertion-error: "npm:^2.0.1" 868 | check-error: "npm:^2.1.1" 869 | deep-eql: "npm:^5.0.1" 870 | loupe: "npm:^3.1.0" 871 | pathval: "npm:^2.0.0" 872 | checksum: 10c0/6c04ff8495b6e535df9c1b062b6b094828454e9a3c9493393e55b2f4dbff7aa2a29a4645133cad160fb00a16196c4dc03dc9bb37e1f4ba9df3b5f50d7533a736 873 | languageName: node 874 | linkType: hard 875 | 876 | "check-error@npm:^2.1.1": 877 | version: 2.1.1 878 | resolution: "check-error@npm:2.1.1" 879 | checksum: 10c0/979f13eccab306cf1785fa10941a590b4e7ea9916ea2a4f8c87f0316fc3eab07eabefb6e587424ef0f88cbcd3805791f172ea739863ca3d7ce2afc54641c7f0e 880 | languageName: node 881 | linkType: hard 882 | 883 | "chownr@npm:^2.0.0": 884 | version: 2.0.0 885 | resolution: "chownr@npm:2.0.0" 886 | checksum: 10c0/594754e1303672171cc04e50f6c398ae16128eb134a88f801bf5354fd96f205320f23536a045d9abd8b51024a149696e51231565891d4efdab8846021ecf88e6 887 | languageName: node 888 | linkType: hard 889 | 890 | "clean-stack@npm:^2.0.0": 891 | version: 2.2.0 892 | resolution: "clean-stack@npm:2.2.0" 893 | checksum: 10c0/1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1 894 | languageName: node 895 | linkType: hard 896 | 897 | "clipboardy@npm:^4.0.0": 898 | version: 4.0.0 899 | resolution: "clipboardy@npm:4.0.0" 900 | dependencies: 901 | execa: "npm:^8.0.1" 902 | is-wsl: "npm:^3.1.0" 903 | is64bit: "npm:^2.0.0" 904 | checksum: 10c0/02bb5f3d0a772bd84ec26a3566c72c2319a9f3b4cb8338370c3bffcf0073c80b834abe1a6945bea4f2cbea28e1627a975aaac577e3f61a868d924ce79138b041 905 | languageName: node 906 | linkType: hard 907 | 908 | "color-convert@npm:^2.0.1": 909 | version: 2.0.1 910 | resolution: "color-convert@npm:2.0.1" 911 | dependencies: 912 | color-name: "npm:~1.1.4" 913 | checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 914 | languageName: node 915 | linkType: hard 916 | 917 | "color-name@npm:~1.1.4": 918 | version: 1.1.4 919 | resolution: "color-name@npm:1.1.4" 920 | checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 921 | languageName: node 922 | linkType: hard 923 | 924 | "commander@npm:^12.1.0": 925 | version: 12.1.0 926 | resolution: "commander@npm:12.1.0" 927 | checksum: 10c0/6e1996680c083b3b897bfc1cfe1c58dfbcd9842fd43e1aaf8a795fbc237f65efcc860a3ef457b318e73f29a4f4a28f6403c3d653d021d960e4632dd45bde54a9 928 | languageName: node 929 | linkType: hard 930 | 931 | "concat-stream@npm:^2.0.0": 932 | version: 2.0.0 933 | resolution: "concat-stream@npm:2.0.0" 934 | dependencies: 935 | buffer-from: "npm:^1.0.0" 936 | inherits: "npm:^2.0.3" 937 | readable-stream: "npm:^3.0.2" 938 | typedarray: "npm:^0.0.6" 939 | checksum: 10c0/29565dd9198fe1d8cf57f6cc71527dbc6ad67e12e4ac9401feb389c53042b2dceedf47034cbe702dfc4fd8df3ae7e6bfeeebe732cc4fa2674e484c13f04c219a 940 | languageName: node 941 | linkType: hard 942 | 943 | "copa@workspace:.": 944 | version: 0.0.0-use.local 945 | resolution: "copa@workspace:." 946 | dependencies: 947 | "@dqbd/tiktoken": "npm:^1.0.17" 948 | "@types/jsdom": "npm:^21.1.7" 949 | "@types/node": "npm:^22.10.1" 950 | clipboardy: "npm:^4.0.0" 951 | commander: "npm:^12.1.0" 952 | glob: "npm:^11.0.0" 953 | mammoth: "npm:^1.9.0" 954 | minimatch: "npm:^10.0.1" 955 | officeparser: "npm:^5.1.1" 956 | pdfjs-dist: "npm:^5.2.133" 957 | simple-git: "npm:^3.27.0" 958 | ts-node: "npm:^10.9.2" 959 | typescript: "npm:^5.7.2" 960 | vitest: "npm:^2.1.8" 961 | bin: 962 | copa: ./dist/copa.js 963 | languageName: unknown 964 | linkType: soft 965 | 966 | "core-util-is@npm:~1.0.0": 967 | version: 1.0.3 968 | resolution: "core-util-is@npm:1.0.3" 969 | checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 970 | languageName: node 971 | linkType: hard 972 | 973 | "create-require@npm:^1.1.0": 974 | version: 1.1.1 975 | resolution: "create-require@npm:1.1.1" 976 | checksum: 10c0/157cbc59b2430ae9a90034a5f3a1b398b6738bf510f713edc4d4e45e169bc514d3d99dd34d8d01ca7ae7830b5b8b537e46ae8f3c8f932371b0875c0151d7ec91 977 | languageName: node 978 | linkType: hard 979 | 980 | "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3": 981 | version: 7.0.3 982 | resolution: "cross-spawn@npm:7.0.3" 983 | dependencies: 984 | path-key: "npm:^3.1.0" 985 | shebang-command: "npm:^2.0.0" 986 | which: "npm:^2.0.1" 987 | checksum: 10c0/5738c312387081c98d69c98e105b6327b069197f864a60593245d64c8089c8a0a744e16349281210d56835bb9274130d825a78b2ad6853ca13cfbeffc0c31750 988 | languageName: node 989 | linkType: hard 990 | 991 | "debug@npm:4, debug@npm:^4.1.1, debug@npm:^4.3.4, debug@npm:^4.3.5": 992 | version: 4.3.6 993 | resolution: "debug@npm:4.3.6" 994 | dependencies: 995 | ms: "npm:2.1.2" 996 | peerDependenciesMeta: 997 | supports-color: 998 | optional: true 999 | checksum: 10c0/3293416bff072389c101697d4611c402a6bacd1900ac20c0492f61a9cdd6b3b29750fc7f5e299f8058469ef60ff8fb79b86395a30374fbd2490113c1c7112285 1000 | languageName: node 1001 | linkType: hard 1002 | 1003 | "debug@npm:^4.3.7": 1004 | version: 4.4.0 1005 | resolution: "debug@npm:4.4.0" 1006 | dependencies: 1007 | ms: "npm:^2.1.3" 1008 | peerDependenciesMeta: 1009 | supports-color: 1010 | optional: true 1011 | checksum: 10c0/db94f1a182bf886f57b4755f85b3a74c39b5114b9377b7ab375dc2cfa3454f09490cc6c30f829df3fc8042bc8b8995f6567ce5cd96f3bc3688bd24027197d9de 1012 | languageName: node 1013 | linkType: hard 1014 | 1015 | "deep-eql@npm:^5.0.1": 1016 | version: 5.0.2 1017 | resolution: "deep-eql@npm:5.0.2" 1018 | checksum: 10c0/7102cf3b7bb719c6b9c0db2e19bf0aa9318d141581befe8c7ce8ccd39af9eaa4346e5e05adef7f9bd7015da0f13a3a25dcfe306ef79dc8668aedbecb658dd247 1019 | languageName: node 1020 | linkType: hard 1021 | 1022 | "diff@npm:^4.0.1": 1023 | version: 4.0.2 1024 | resolution: "diff@npm:4.0.2" 1025 | checksum: 10c0/81b91f9d39c4eaca068eb0c1eb0e4afbdc5bb2941d197f513dd596b820b956fef43485876226d65d497bebc15666aa2aa82c679e84f65d5f2bfbf14ee46e32c1 1026 | languageName: node 1027 | linkType: hard 1028 | 1029 | "dingbat-to-unicode@npm:^1.0.1": 1030 | version: 1.0.1 1031 | resolution: "dingbat-to-unicode@npm:1.0.1" 1032 | checksum: 10c0/4def812dadd17122929ad31df574539e4066d85d07b0f824fc70533ff44ce75733e25cdd5817b80604d0c6e6091159a51f9b67487b926611518718c796354e26 1033 | languageName: node 1034 | linkType: hard 1035 | 1036 | "duck@npm:^0.1.12": 1037 | version: 0.1.12 1038 | resolution: "duck@npm:0.1.12" 1039 | dependencies: 1040 | underscore: "npm:^1.13.1" 1041 | checksum: 10c0/dfbe163481cae832c783016c5026f228e95e32bd5dfc9636607d981faf5b1e7aaa5ac27cf181ceefba6a01d42b54239908dee41ae3af2e7cea42e4fa925dbff3 1042 | languageName: node 1043 | linkType: hard 1044 | 1045 | "eastasianwidth@npm:^0.2.0": 1046 | version: 0.2.0 1047 | resolution: "eastasianwidth@npm:0.2.0" 1048 | checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 1049 | languageName: node 1050 | linkType: hard 1051 | 1052 | "emoji-regex@npm:^8.0.0": 1053 | version: 8.0.0 1054 | resolution: "emoji-regex@npm:8.0.0" 1055 | checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 1056 | languageName: node 1057 | linkType: hard 1058 | 1059 | "emoji-regex@npm:^9.2.2": 1060 | version: 9.2.2 1061 | resolution: "emoji-regex@npm:9.2.2" 1062 | checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 1063 | languageName: node 1064 | linkType: hard 1065 | 1066 | "encoding@npm:^0.1.13": 1067 | version: 0.1.13 1068 | resolution: "encoding@npm:0.1.13" 1069 | dependencies: 1070 | iconv-lite: "npm:^0.6.2" 1071 | checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 1072 | languageName: node 1073 | linkType: hard 1074 | 1075 | "entities@npm:^4.4.0": 1076 | version: 4.5.0 1077 | resolution: "entities@npm:4.5.0" 1078 | checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 1079 | languageName: node 1080 | linkType: hard 1081 | 1082 | "env-paths@npm:^2.2.0": 1083 | version: 2.2.1 1084 | resolution: "env-paths@npm:2.2.1" 1085 | checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 1086 | languageName: node 1087 | linkType: hard 1088 | 1089 | "err-code@npm:^2.0.2": 1090 | version: 2.0.3 1091 | resolution: "err-code@npm:2.0.3" 1092 | checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 1093 | languageName: node 1094 | linkType: hard 1095 | 1096 | "es-module-lexer@npm:^1.5.4": 1097 | version: 1.6.0 1098 | resolution: "es-module-lexer@npm:1.6.0" 1099 | checksum: 10c0/667309454411c0b95c476025929881e71400d74a746ffa1ff4cb450bd87f8e33e8eef7854d68e401895039ac0bac64e7809acbebb6253e055dd49ea9e3ea9212 1100 | languageName: node 1101 | linkType: hard 1102 | 1103 | "esbuild@npm:^0.21.3": 1104 | version: 0.21.5 1105 | resolution: "esbuild@npm:0.21.5" 1106 | dependencies: 1107 | "@esbuild/aix-ppc64": "npm:0.21.5" 1108 | "@esbuild/android-arm": "npm:0.21.5" 1109 | "@esbuild/android-arm64": "npm:0.21.5" 1110 | "@esbuild/android-x64": "npm:0.21.5" 1111 | "@esbuild/darwin-arm64": "npm:0.21.5" 1112 | "@esbuild/darwin-x64": "npm:0.21.5" 1113 | "@esbuild/freebsd-arm64": "npm:0.21.5" 1114 | "@esbuild/freebsd-x64": "npm:0.21.5" 1115 | "@esbuild/linux-arm": "npm:0.21.5" 1116 | "@esbuild/linux-arm64": "npm:0.21.5" 1117 | "@esbuild/linux-ia32": "npm:0.21.5" 1118 | "@esbuild/linux-loong64": "npm:0.21.5" 1119 | "@esbuild/linux-mips64el": "npm:0.21.5" 1120 | "@esbuild/linux-ppc64": "npm:0.21.5" 1121 | "@esbuild/linux-riscv64": "npm:0.21.5" 1122 | "@esbuild/linux-s390x": "npm:0.21.5" 1123 | "@esbuild/linux-x64": "npm:0.21.5" 1124 | "@esbuild/netbsd-x64": "npm:0.21.5" 1125 | "@esbuild/openbsd-x64": "npm:0.21.5" 1126 | "@esbuild/sunos-x64": "npm:0.21.5" 1127 | "@esbuild/win32-arm64": "npm:0.21.5" 1128 | "@esbuild/win32-ia32": "npm:0.21.5" 1129 | "@esbuild/win32-x64": "npm:0.21.5" 1130 | dependenciesMeta: 1131 | "@esbuild/aix-ppc64": 1132 | optional: true 1133 | "@esbuild/android-arm": 1134 | optional: true 1135 | "@esbuild/android-arm64": 1136 | optional: true 1137 | "@esbuild/android-x64": 1138 | optional: true 1139 | "@esbuild/darwin-arm64": 1140 | optional: true 1141 | "@esbuild/darwin-x64": 1142 | optional: true 1143 | "@esbuild/freebsd-arm64": 1144 | optional: true 1145 | "@esbuild/freebsd-x64": 1146 | optional: true 1147 | "@esbuild/linux-arm": 1148 | optional: true 1149 | "@esbuild/linux-arm64": 1150 | optional: true 1151 | "@esbuild/linux-ia32": 1152 | optional: true 1153 | "@esbuild/linux-loong64": 1154 | optional: true 1155 | "@esbuild/linux-mips64el": 1156 | optional: true 1157 | "@esbuild/linux-ppc64": 1158 | optional: true 1159 | "@esbuild/linux-riscv64": 1160 | optional: true 1161 | "@esbuild/linux-s390x": 1162 | optional: true 1163 | "@esbuild/linux-x64": 1164 | optional: true 1165 | "@esbuild/netbsd-x64": 1166 | optional: true 1167 | "@esbuild/openbsd-x64": 1168 | optional: true 1169 | "@esbuild/sunos-x64": 1170 | optional: true 1171 | "@esbuild/win32-arm64": 1172 | optional: true 1173 | "@esbuild/win32-ia32": 1174 | optional: true 1175 | "@esbuild/win32-x64": 1176 | optional: true 1177 | bin: 1178 | esbuild: bin/esbuild 1179 | checksum: 10c0/fa08508adf683c3f399e8a014a6382a6b65542213431e26206c0720e536b31c09b50798747c2a105a4bbba1d9767b8d3615a74c2f7bf1ddf6d836cd11eb672de 1180 | languageName: node 1181 | linkType: hard 1182 | 1183 | "estree-walker@npm:^3.0.3": 1184 | version: 3.0.3 1185 | resolution: "estree-walker@npm:3.0.3" 1186 | dependencies: 1187 | "@types/estree": "npm:^1.0.0" 1188 | checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d 1189 | languageName: node 1190 | linkType: hard 1191 | 1192 | "event-target-shim@npm:^5.0.0": 1193 | version: 5.0.1 1194 | resolution: "event-target-shim@npm:5.0.1" 1195 | checksum: 10c0/0255d9f936215fd206156fd4caa9e8d35e62075d720dc7d847e89b417e5e62cf1ce6c9b4e0a1633a9256de0efefaf9f8d26924b1f3c8620cffb9db78e7d3076b 1196 | languageName: node 1197 | linkType: hard 1198 | 1199 | "events@npm:^3.3.0": 1200 | version: 3.3.0 1201 | resolution: "events@npm:3.3.0" 1202 | checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 1203 | languageName: node 1204 | linkType: hard 1205 | 1206 | "execa@npm:^8.0.1": 1207 | version: 8.0.1 1208 | resolution: "execa@npm:8.0.1" 1209 | dependencies: 1210 | cross-spawn: "npm:^7.0.3" 1211 | get-stream: "npm:^8.0.1" 1212 | human-signals: "npm:^5.0.0" 1213 | is-stream: "npm:^3.0.0" 1214 | merge-stream: "npm:^2.0.0" 1215 | npm-run-path: "npm:^5.1.0" 1216 | onetime: "npm:^6.0.0" 1217 | signal-exit: "npm:^4.1.0" 1218 | strip-final-newline: "npm:^3.0.0" 1219 | checksum: 10c0/2c52d8775f5bf103ce8eec9c7ab3059909ba350a5164744e9947ed14a53f51687c040a250bda833f906d1283aa8803975b84e6c8f7a7c42f99dc8ef80250d1af 1220 | languageName: node 1221 | linkType: hard 1222 | 1223 | "expect-type@npm:^1.1.0": 1224 | version: 1.1.0 1225 | resolution: "expect-type@npm:1.1.0" 1226 | checksum: 10c0/5af0febbe8fe18da05a6d51e3677adafd75213512285408156b368ca471252565d5ca6e59e4bddab25121f3cfcbbebc6a5489f8cc9db131cc29e69dcdcc7ae15 1227 | languageName: node 1228 | linkType: hard 1229 | 1230 | "exponential-backoff@npm:^3.1.1": 1231 | version: 3.1.1 1232 | resolution: "exponential-backoff@npm:3.1.1" 1233 | checksum: 10c0/160456d2d647e6019640bd07111634d8c353038d9fa40176afb7cd49b0548bdae83b56d05e907c2cce2300b81cae35d800ef92fefb9d0208e190fa3b7d6bb579 1234 | languageName: node 1235 | linkType: hard 1236 | 1237 | "file-type@npm:^16.5.4": 1238 | version: 16.5.4 1239 | resolution: "file-type@npm:16.5.4" 1240 | dependencies: 1241 | readable-web-to-node-stream: "npm:^3.0.0" 1242 | strtok3: "npm:^6.2.4" 1243 | token-types: "npm:^4.1.1" 1244 | checksum: 10c0/a6c9ab8bc05bc9c212bec239fb0d5bf59ddc9b3912f00c4ef44622e67ae4e553a1cc8372e9e595e14859035188eb305d05d488fa3c5c2a2ad90bb7745b3004ef 1245 | languageName: node 1246 | linkType: hard 1247 | 1248 | "foreground-child@npm:^3.1.0": 1249 | version: 3.2.1 1250 | resolution: "foreground-child@npm:3.2.1" 1251 | dependencies: 1252 | cross-spawn: "npm:^7.0.0" 1253 | signal-exit: "npm:^4.0.1" 1254 | checksum: 10c0/9a53a33dbd87090e9576bef65fb4a71de60f6863a8062a7b11bc1cbe3cc86d428677d7c0b9ef61cdac11007ac580006f78bd5638618d564cfd5e6fd713d6878f 1255 | languageName: node 1256 | linkType: hard 1257 | 1258 | "fs-minipass@npm:^2.0.0": 1259 | version: 2.1.0 1260 | resolution: "fs-minipass@npm:2.1.0" 1261 | dependencies: 1262 | minipass: "npm:^3.0.0" 1263 | checksum: 10c0/703d16522b8282d7299337539c3ed6edddd1afe82435e4f5b76e34a79cd74e488a8a0e26a636afc2440e1a23b03878e2122e3a2cfe375a5cf63c37d92b86a004 1264 | languageName: node 1265 | linkType: hard 1266 | 1267 | "fs-minipass@npm:^3.0.0": 1268 | version: 3.0.3 1269 | resolution: "fs-minipass@npm:3.0.3" 1270 | dependencies: 1271 | minipass: "npm:^7.0.3" 1272 | checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 1273 | languageName: node 1274 | linkType: hard 1275 | 1276 | "fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": 1277 | version: 2.3.3 1278 | resolution: "fsevents@npm:2.3.3" 1279 | dependencies: 1280 | node-gyp: "npm:latest" 1281 | checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 1282 | conditions: os=darwin 1283 | languageName: node 1284 | linkType: hard 1285 | 1286 | "fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": 1287 | version: 2.3.3 1288 | resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" 1289 | dependencies: 1290 | node-gyp: "npm:latest" 1291 | conditions: os=darwin 1292 | languageName: node 1293 | linkType: hard 1294 | 1295 | "get-stream@npm:^8.0.1": 1296 | version: 8.0.1 1297 | resolution: "get-stream@npm:8.0.1" 1298 | checksum: 10c0/5c2181e98202b9dae0bb4a849979291043e5892eb40312b47f0c22b9414fc9b28a3b6063d2375705eb24abc41ecf97894d9a51f64ff021511b504477b27b4290 1299 | languageName: node 1300 | linkType: hard 1301 | 1302 | "glob@npm:^10.2.2, glob@npm:^10.3.10": 1303 | version: 10.4.5 1304 | resolution: "glob@npm:10.4.5" 1305 | dependencies: 1306 | foreground-child: "npm:^3.1.0" 1307 | jackspeak: "npm:^3.1.2" 1308 | minimatch: "npm:^9.0.4" 1309 | minipass: "npm:^7.1.2" 1310 | package-json-from-dist: "npm:^1.0.0" 1311 | path-scurry: "npm:^1.11.1" 1312 | bin: 1313 | glob: dist/esm/bin.mjs 1314 | checksum: 10c0/19a9759ea77b8e3ca0a43c2f07ecddc2ad46216b786bb8f993c445aee80d345925a21e5280c7b7c6c59e860a0154b84e4b2b60321fea92cd3c56b4a7489f160e 1315 | languageName: node 1316 | linkType: hard 1317 | 1318 | "glob@npm:^11.0.0": 1319 | version: 11.0.0 1320 | resolution: "glob@npm:11.0.0" 1321 | dependencies: 1322 | foreground-child: "npm:^3.1.0" 1323 | jackspeak: "npm:^4.0.1" 1324 | minimatch: "npm:^10.0.0" 1325 | minipass: "npm:^7.1.2" 1326 | package-json-from-dist: "npm:^1.0.0" 1327 | path-scurry: "npm:^2.0.0" 1328 | bin: 1329 | glob: dist/esm/bin.mjs 1330 | checksum: 10c0/419866015d8795258a8ac51de5b9d1a99c72634fc3ead93338e4da388e89773ab21681e494eac0fbc4250b003451ca3110bb4f1c9393d15d14466270094fdb4e 1331 | languageName: node 1332 | linkType: hard 1333 | 1334 | "graceful-fs@npm:^4.2.6": 1335 | version: 4.2.11 1336 | resolution: "graceful-fs@npm:4.2.11" 1337 | checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 1338 | languageName: node 1339 | linkType: hard 1340 | 1341 | "http-cache-semantics@npm:^4.1.1": 1342 | version: 4.1.1 1343 | resolution: "http-cache-semantics@npm:4.1.1" 1344 | checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc 1345 | languageName: node 1346 | linkType: hard 1347 | 1348 | "http-proxy-agent@npm:^7.0.0": 1349 | version: 7.0.2 1350 | resolution: "http-proxy-agent@npm:7.0.2" 1351 | dependencies: 1352 | agent-base: "npm:^7.1.0" 1353 | debug: "npm:^4.3.4" 1354 | checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 1355 | languageName: node 1356 | linkType: hard 1357 | 1358 | "https-proxy-agent@npm:^7.0.1": 1359 | version: 7.0.5 1360 | resolution: "https-proxy-agent@npm:7.0.5" 1361 | dependencies: 1362 | agent-base: "npm:^7.0.2" 1363 | debug: "npm:4" 1364 | checksum: 10c0/2490e3acec397abeb88807db52cac59102d5ed758feee6df6112ab3ccd8325e8a1ce8bce6f4b66e5470eca102d31e425ace904242e4fa28dbe0c59c4bafa7b2c 1365 | languageName: node 1366 | linkType: hard 1367 | 1368 | "human-signals@npm:^5.0.0": 1369 | version: 5.0.0 1370 | resolution: "human-signals@npm:5.0.0" 1371 | checksum: 10c0/5a9359073fe17a8b58e5a085e9a39a950366d9f00217c4ff5878bd312e09d80f460536ea6a3f260b5943a01fe55c158d1cea3fc7bee3d0520aeef04f6d915c82 1372 | languageName: node 1373 | linkType: hard 1374 | 1375 | "iconv-lite@npm:^0.6.2": 1376 | version: 0.6.3 1377 | resolution: "iconv-lite@npm:0.6.3" 1378 | dependencies: 1379 | safer-buffer: "npm:>= 2.1.2 < 3.0.0" 1380 | checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 1381 | languageName: node 1382 | linkType: hard 1383 | 1384 | "ieee754@npm:^1.2.1": 1385 | version: 1.2.1 1386 | resolution: "ieee754@npm:1.2.1" 1387 | checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb 1388 | languageName: node 1389 | linkType: hard 1390 | 1391 | "immediate@npm:~3.0.5": 1392 | version: 3.0.6 1393 | resolution: "immediate@npm:3.0.6" 1394 | checksum: 10c0/f8ba7ede69bee9260241ad078d2d535848745ff5f6995c7c7cb41cfdc9ccc213f66e10fa5afb881f90298b24a3f7344b637b592beb4f54e582770cdce3f1f039 1395 | languageName: node 1396 | linkType: hard 1397 | 1398 | "imurmurhash@npm:^0.1.4": 1399 | version: 0.1.4 1400 | resolution: "imurmurhash@npm:0.1.4" 1401 | checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 1402 | languageName: node 1403 | linkType: hard 1404 | 1405 | "indent-string@npm:^4.0.0": 1406 | version: 4.0.0 1407 | resolution: "indent-string@npm:4.0.0" 1408 | checksum: 10c0/1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f 1409 | languageName: node 1410 | linkType: hard 1411 | 1412 | "inherits@npm:^2.0.3, inherits@npm:~2.0.3": 1413 | version: 2.0.4 1414 | resolution: "inherits@npm:2.0.4" 1415 | checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 1416 | languageName: node 1417 | linkType: hard 1418 | 1419 | "ip-address@npm:^9.0.5": 1420 | version: 9.0.5 1421 | resolution: "ip-address@npm:9.0.5" 1422 | dependencies: 1423 | jsbn: "npm:1.1.0" 1424 | sprintf-js: "npm:^1.1.3" 1425 | checksum: 10c0/331cd07fafcb3b24100613e4b53e1a2b4feab11e671e655d46dc09ee233da5011284d09ca40c4ecbdfe1d0004f462958675c224a804259f2f78d2465a87824bc 1426 | languageName: node 1427 | linkType: hard 1428 | 1429 | "is-docker@npm:^3.0.0": 1430 | version: 3.0.0 1431 | resolution: "is-docker@npm:3.0.0" 1432 | bin: 1433 | is-docker: cli.js 1434 | checksum: 10c0/d2c4f8e6d3e34df75a5defd44991b6068afad4835bb783b902fa12d13ebdb8f41b2a199dcb0b5ed2cb78bfee9e4c0bbdb69c2d9646f4106464674d3e697a5856 1435 | languageName: node 1436 | linkType: hard 1437 | 1438 | "is-fullwidth-code-point@npm:^3.0.0": 1439 | version: 3.0.0 1440 | resolution: "is-fullwidth-code-point@npm:3.0.0" 1441 | checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc 1442 | languageName: node 1443 | linkType: hard 1444 | 1445 | "is-inside-container@npm:^1.0.0": 1446 | version: 1.0.0 1447 | resolution: "is-inside-container@npm:1.0.0" 1448 | dependencies: 1449 | is-docker: "npm:^3.0.0" 1450 | bin: 1451 | is-inside-container: cli.js 1452 | checksum: 10c0/a8efb0e84f6197e6ff5c64c52890fa9acb49b7b74fed4da7c95383965da6f0fa592b4dbd5e38a79f87fc108196937acdbcd758fcefc9b140e479b39ce1fcd1cd 1453 | languageName: node 1454 | linkType: hard 1455 | 1456 | "is-lambda@npm:^1.0.1": 1457 | version: 1.0.1 1458 | resolution: "is-lambda@npm:1.0.1" 1459 | checksum: 10c0/85fee098ae62ba6f1e24cf22678805473c7afd0fb3978a3aa260e354cb7bcb3a5806cf0a98403188465efedec41ab4348e8e4e79305d409601323855b3839d4d 1460 | languageName: node 1461 | linkType: hard 1462 | 1463 | "is-stream@npm:^3.0.0": 1464 | version: 3.0.0 1465 | resolution: "is-stream@npm:3.0.0" 1466 | checksum: 10c0/eb2f7127af02ee9aa2a0237b730e47ac2de0d4e76a4a905a50a11557f2339df5765eaea4ceb8029f1efa978586abe776908720bfcb1900c20c6ec5145f6f29d8 1467 | languageName: node 1468 | linkType: hard 1469 | 1470 | "is-wsl@npm:^3.1.0": 1471 | version: 3.1.0 1472 | resolution: "is-wsl@npm:3.1.0" 1473 | dependencies: 1474 | is-inside-container: "npm:^1.0.0" 1475 | checksum: 10c0/d3317c11995690a32c362100225e22ba793678fe8732660c6de511ae71a0ff05b06980cf21f98a6bf40d7be0e9e9506f859abe00a1118287d63e53d0a3d06947 1476 | languageName: node 1477 | linkType: hard 1478 | 1479 | "is64bit@npm:^2.0.0": 1480 | version: 2.0.0 1481 | resolution: "is64bit@npm:2.0.0" 1482 | dependencies: 1483 | system-architecture: "npm:^0.1.0" 1484 | checksum: 10c0/9f3741d4b7560e2a30b9ce0c79bb30c7bdcc5df77c897bd59bb68f0fd882ae698015e8da81d48331def66c778d430c1ae3cb8c1fcc34e96c576b66198395faa7 1485 | languageName: node 1486 | linkType: hard 1487 | 1488 | "isarray@npm:~1.0.0": 1489 | version: 1.0.0 1490 | resolution: "isarray@npm:1.0.0" 1491 | checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d 1492 | languageName: node 1493 | linkType: hard 1494 | 1495 | "isexe@npm:^2.0.0": 1496 | version: 2.0.0 1497 | resolution: "isexe@npm:2.0.0" 1498 | checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d 1499 | languageName: node 1500 | linkType: hard 1501 | 1502 | "isexe@npm:^3.1.1": 1503 | version: 3.1.1 1504 | resolution: "isexe@npm:3.1.1" 1505 | checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 1506 | languageName: node 1507 | linkType: hard 1508 | 1509 | "jackspeak@npm:^3.1.2": 1510 | version: 3.4.3 1511 | resolution: "jackspeak@npm:3.4.3" 1512 | dependencies: 1513 | "@isaacs/cliui": "npm:^8.0.2" 1514 | "@pkgjs/parseargs": "npm:^0.11.0" 1515 | dependenciesMeta: 1516 | "@pkgjs/parseargs": 1517 | optional: true 1518 | checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9 1519 | languageName: node 1520 | linkType: hard 1521 | 1522 | "jackspeak@npm:^4.0.1": 1523 | version: 4.0.1 1524 | resolution: "jackspeak@npm:4.0.1" 1525 | dependencies: 1526 | "@isaacs/cliui": "npm:^8.0.2" 1527 | "@pkgjs/parseargs": "npm:^0.11.0" 1528 | dependenciesMeta: 1529 | "@pkgjs/parseargs": 1530 | optional: true 1531 | checksum: 10c0/c87997d9c9c5b7366259b1f2a444ef148692f8eedad5307caca939babbb60af2b47d306e5c63bf9d5fefbab2ab48d4da275188c3de525d0e716cc21b784bbccb 1532 | languageName: node 1533 | linkType: hard 1534 | 1535 | "jsbn@npm:1.1.0": 1536 | version: 1.1.0 1537 | resolution: "jsbn@npm:1.1.0" 1538 | checksum: 10c0/4f907fb78d7b712e11dea8c165fe0921f81a657d3443dde75359ed52eb2b5d33ce6773d97985a089f09a65edd80b11cb75c767b57ba47391fee4c969f7215c96 1539 | languageName: node 1540 | linkType: hard 1541 | 1542 | "jszip@npm:^3.7.1": 1543 | version: 3.10.1 1544 | resolution: "jszip@npm:3.10.1" 1545 | dependencies: 1546 | lie: "npm:~3.3.0" 1547 | pako: "npm:~1.0.2" 1548 | readable-stream: "npm:~2.3.6" 1549 | setimmediate: "npm:^1.0.5" 1550 | checksum: 10c0/58e01ec9c4960383fb8b38dd5f67b83ccc1ec215bf74c8a5b32f42b6e5fb79fada5176842a11409c4051b5b94275044851814a31076bf49e1be218d3ef57c863 1551 | languageName: node 1552 | linkType: hard 1553 | 1554 | "lie@npm:~3.3.0": 1555 | version: 3.3.0 1556 | resolution: "lie@npm:3.3.0" 1557 | dependencies: 1558 | immediate: "npm:~3.0.5" 1559 | checksum: 10c0/56dd113091978f82f9dc5081769c6f3b947852ecf9feccaf83e14a123bc630c2301439ce6182521e5fbafbde88e88ac38314327a4e0493a1bea7e0699a7af808 1560 | languageName: node 1561 | linkType: hard 1562 | 1563 | "lop@npm:^0.4.2": 1564 | version: 0.4.2 1565 | resolution: "lop@npm:0.4.2" 1566 | dependencies: 1567 | duck: "npm:^0.1.12" 1568 | option: "npm:~0.2.1" 1569 | underscore: "npm:^1.13.1" 1570 | checksum: 10c0/f0d72f8a80fc12e5c1ac7a480dd5aa8820d8a390e1d5ea0a3a40f9a830885b149ee9c61384e40f1e5f23bc50469f87de8b78dd08549bbb4787409cf58373e04d 1571 | languageName: node 1572 | linkType: hard 1573 | 1574 | "loupe@npm:^3.1.0, loupe@npm:^3.1.2": 1575 | version: 3.1.2 1576 | resolution: "loupe@npm:3.1.2" 1577 | checksum: 10c0/b13c02e3ddd6a9d5f8bf84133b3242de556512d824dddeea71cce2dbd6579c8f4d672381c4e742d45cf4423d0701765b4a6e5fbc24701def16bc2b40f8daa96a 1578 | languageName: node 1579 | linkType: hard 1580 | 1581 | "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": 1582 | version: 10.4.3 1583 | resolution: "lru-cache@npm:10.4.3" 1584 | checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb 1585 | languageName: node 1586 | linkType: hard 1587 | 1588 | "lru-cache@npm:^11.0.0": 1589 | version: 11.0.0 1590 | resolution: "lru-cache@npm:11.0.0" 1591 | checksum: 10c0/827ff0e0739f9b0f30f92f5a5fc97c6a2bd3ae32c0452bc58cb7411d6c589d49536073027293f2d1f02d0c2e72b63b162f238df7e9ff6f4cc0345f92afec4d1d 1592 | languageName: node 1593 | linkType: hard 1594 | 1595 | "magic-string@npm:^0.30.12": 1596 | version: 0.30.17 1597 | resolution: "magic-string@npm:0.30.17" 1598 | dependencies: 1599 | "@jridgewell/sourcemap-codec": "npm:^1.5.0" 1600 | checksum: 10c0/16826e415d04b88378f200fe022b53e638e3838b9e496edda6c0e086d7753a44a6ed187adc72d19f3623810589bf139af1a315541cd6a26ae0771a0193eaf7b8 1601 | languageName: node 1602 | linkType: hard 1603 | 1604 | "make-error@npm:^1.1.1": 1605 | version: 1.3.6 1606 | resolution: "make-error@npm:1.3.6" 1607 | checksum: 10c0/171e458d86854c6b3fc46610cfacf0b45149ba043782558c6875d9f42f222124384ad0b468c92e996d815a8a2003817a710c0a160e49c1c394626f76fa45396f 1608 | languageName: node 1609 | linkType: hard 1610 | 1611 | "make-fetch-happen@npm:^13.0.0": 1612 | version: 13.0.1 1613 | resolution: "make-fetch-happen@npm:13.0.1" 1614 | dependencies: 1615 | "@npmcli/agent": "npm:^2.0.0" 1616 | cacache: "npm:^18.0.0" 1617 | http-cache-semantics: "npm:^4.1.1" 1618 | is-lambda: "npm:^1.0.1" 1619 | minipass: "npm:^7.0.2" 1620 | minipass-fetch: "npm:^3.0.0" 1621 | minipass-flush: "npm:^1.0.5" 1622 | minipass-pipeline: "npm:^1.2.4" 1623 | negotiator: "npm:^0.6.3" 1624 | proc-log: "npm:^4.2.0" 1625 | promise-retry: "npm:^2.0.1" 1626 | ssri: "npm:^10.0.0" 1627 | checksum: 10c0/df5f4dbb6d98153b751bccf4dc4cc500de85a96a9331db9805596c46aa9f99d9555983954e6c1266d9f981ae37a9e4647f42b9a4bb5466f867f4012e582c9e7e 1628 | languageName: node 1629 | linkType: hard 1630 | 1631 | "mammoth@npm:^1.9.0": 1632 | version: 1.9.0 1633 | resolution: "mammoth@npm:1.9.0" 1634 | dependencies: 1635 | "@xmldom/xmldom": "npm:^0.8.6" 1636 | argparse: "npm:~1.0.3" 1637 | base64-js: "npm:^1.5.1" 1638 | bluebird: "npm:~3.4.0" 1639 | dingbat-to-unicode: "npm:^1.0.1" 1640 | jszip: "npm:^3.7.1" 1641 | lop: "npm:^0.4.2" 1642 | path-is-absolute: "npm:^1.0.0" 1643 | underscore: "npm:^1.13.1" 1644 | xmlbuilder: "npm:^10.0.0" 1645 | bin: 1646 | mammoth: bin/mammoth 1647 | checksum: 10c0/4cd98a39d6afcf88f8801764c3c2572acf5c8f3f9e24d0e00dee4fd24cc3fa16ae6bb7409cd53e92d7d41c16c99fa24ce461f0499a68a9e8ccae81a9c9472553 1648 | languageName: node 1649 | linkType: hard 1650 | 1651 | "merge-stream@npm:^2.0.0": 1652 | version: 2.0.0 1653 | resolution: "merge-stream@npm:2.0.0" 1654 | checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 1655 | languageName: node 1656 | linkType: hard 1657 | 1658 | "mimic-fn@npm:^4.0.0": 1659 | version: 4.0.0 1660 | resolution: "mimic-fn@npm:4.0.0" 1661 | checksum: 10c0/de9cc32be9996fd941e512248338e43407f63f6d497abe8441fa33447d922e927de54d4cc3c1a3c6d652857acd770389d5a3823f311a744132760ce2be15ccbf 1662 | languageName: node 1663 | linkType: hard 1664 | 1665 | "minimatch@npm:^10.0.0, minimatch@npm:^10.0.1": 1666 | version: 10.0.1 1667 | resolution: "minimatch@npm:10.0.1" 1668 | dependencies: 1669 | brace-expansion: "npm:^2.0.1" 1670 | checksum: 10c0/e6c29a81fe83e1877ad51348306be2e8aeca18c88fdee7a99df44322314279e15799e41d7cb274e4e8bb0b451a3bc622d6182e157dfa1717d6cda75e9cd8cd5d 1671 | languageName: node 1672 | linkType: hard 1673 | 1674 | "minimatch@npm:^9.0.4": 1675 | version: 9.0.5 1676 | resolution: "minimatch@npm:9.0.5" 1677 | dependencies: 1678 | brace-expansion: "npm:^2.0.1" 1679 | checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed 1680 | languageName: node 1681 | linkType: hard 1682 | 1683 | "minipass-collect@npm:^2.0.1": 1684 | version: 2.0.1 1685 | resolution: "minipass-collect@npm:2.0.1" 1686 | dependencies: 1687 | minipass: "npm:^7.0.3" 1688 | checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e 1689 | languageName: node 1690 | linkType: hard 1691 | 1692 | "minipass-fetch@npm:^3.0.0": 1693 | version: 3.0.5 1694 | resolution: "minipass-fetch@npm:3.0.5" 1695 | dependencies: 1696 | encoding: "npm:^0.1.13" 1697 | minipass: "npm:^7.0.3" 1698 | minipass-sized: "npm:^1.0.3" 1699 | minizlib: "npm:^2.1.2" 1700 | dependenciesMeta: 1701 | encoding: 1702 | optional: true 1703 | checksum: 10c0/9d702d57f556274286fdd97e406fc38a2f5c8d15e158b498d7393b1105974b21249289ec571fa2b51e038a4872bfc82710111cf75fae98c662f3d6f95e72152b 1704 | languageName: node 1705 | linkType: hard 1706 | 1707 | "minipass-flush@npm:^1.0.5": 1708 | version: 1.0.5 1709 | resolution: "minipass-flush@npm:1.0.5" 1710 | dependencies: 1711 | minipass: "npm:^3.0.0" 1712 | checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd 1713 | languageName: node 1714 | linkType: hard 1715 | 1716 | "minipass-pipeline@npm:^1.2.4": 1717 | version: 1.2.4 1718 | resolution: "minipass-pipeline@npm:1.2.4" 1719 | dependencies: 1720 | minipass: "npm:^3.0.0" 1721 | checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 1722 | languageName: node 1723 | linkType: hard 1724 | 1725 | "minipass-sized@npm:^1.0.3": 1726 | version: 1.0.3 1727 | resolution: "minipass-sized@npm:1.0.3" 1728 | dependencies: 1729 | minipass: "npm:^3.0.0" 1730 | checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb 1731 | languageName: node 1732 | linkType: hard 1733 | 1734 | "minipass@npm:^3.0.0": 1735 | version: 3.3.6 1736 | resolution: "minipass@npm:3.3.6" 1737 | dependencies: 1738 | yallist: "npm:^4.0.0" 1739 | checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c 1740 | languageName: node 1741 | linkType: hard 1742 | 1743 | "minipass@npm:^5.0.0": 1744 | version: 5.0.0 1745 | resolution: "minipass@npm:5.0.0" 1746 | checksum: 10c0/a91d8043f691796a8ac88df039da19933ef0f633e3d7f0d35dcd5373af49131cf2399bfc355f41515dc495e3990369c3858cd319e5c2722b4753c90bf3152462 1747 | languageName: node 1748 | linkType: hard 1749 | 1750 | "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": 1751 | version: 7.1.2 1752 | resolution: "minipass@npm:7.1.2" 1753 | checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 1754 | languageName: node 1755 | linkType: hard 1756 | 1757 | "minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": 1758 | version: 2.1.2 1759 | resolution: "minizlib@npm:2.1.2" 1760 | dependencies: 1761 | minipass: "npm:^3.0.0" 1762 | yallist: "npm:^4.0.0" 1763 | checksum: 10c0/64fae024e1a7d0346a1102bb670085b17b7f95bf6cfdf5b128772ec8faf9ea211464ea4add406a3a6384a7d87a0cd1a96263692134323477b4fb43659a6cab78 1764 | languageName: node 1765 | linkType: hard 1766 | 1767 | "mkdirp@npm:^1.0.3": 1768 | version: 1.0.4 1769 | resolution: "mkdirp@npm:1.0.4" 1770 | bin: 1771 | mkdirp: bin/cmd.js 1772 | checksum: 10c0/46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf 1773 | languageName: node 1774 | linkType: hard 1775 | 1776 | "ms@npm:2.1.2": 1777 | version: 2.1.2 1778 | resolution: "ms@npm:2.1.2" 1779 | checksum: 10c0/a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc 1780 | languageName: node 1781 | linkType: hard 1782 | 1783 | "ms@npm:^2.1.3": 1784 | version: 2.1.3 1785 | resolution: "ms@npm:2.1.3" 1786 | checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 1787 | languageName: node 1788 | linkType: hard 1789 | 1790 | "nanoid@npm:^3.3.8": 1791 | version: 3.3.8 1792 | resolution: "nanoid@npm:3.3.8" 1793 | bin: 1794 | nanoid: bin/nanoid.cjs 1795 | checksum: 10c0/4b1bb29f6cfebf3be3bc4ad1f1296fb0a10a3043a79f34fbffe75d1621b4318319211cd420549459018ea3592f0d2f159247a6f874911d6d26eaaadda2478120 1796 | languageName: node 1797 | linkType: hard 1798 | 1799 | "negotiator@npm:^0.6.3": 1800 | version: 0.6.3 1801 | resolution: "negotiator@npm:0.6.3" 1802 | checksum: 10c0/3ec9fd413e7bf071c937ae60d572bc67155262068ed522cf4b3be5edbe6ddf67d095ec03a3a14ebf8fc8e95f8e1d61be4869db0dbb0de696f6b837358bd43fc2 1803 | languageName: node 1804 | linkType: hard 1805 | 1806 | "node-ensure@npm:^0.0.0": 1807 | version: 0.0.0 1808 | resolution: "node-ensure@npm:0.0.0" 1809 | checksum: 10c0/7af391aee024a8b7df77c239ed8b90417e3f2539824fa06b60f243ce14c75ee455766464c7c3ba9407d5b1e4d1d74ed5cf5f8af10c67b0fc05aa6e29f5d2462b 1810 | languageName: node 1811 | linkType: hard 1812 | 1813 | "node-gyp@npm:latest": 1814 | version: 10.2.0 1815 | resolution: "node-gyp@npm:10.2.0" 1816 | dependencies: 1817 | env-paths: "npm:^2.2.0" 1818 | exponential-backoff: "npm:^3.1.1" 1819 | glob: "npm:^10.3.10" 1820 | graceful-fs: "npm:^4.2.6" 1821 | make-fetch-happen: "npm:^13.0.0" 1822 | nopt: "npm:^7.0.0" 1823 | proc-log: "npm:^4.1.0" 1824 | semver: "npm:^7.3.5" 1825 | tar: "npm:^6.2.1" 1826 | which: "npm:^4.0.0" 1827 | bin: 1828 | node-gyp: bin/node-gyp.js 1829 | checksum: 10c0/00630d67dbd09a45aee0a5d55c05e3916ca9e6d427ee4f7bc392d2d3dc5fad7449b21fc098dd38260a53d9dcc9c879b36704a1994235d4707e7271af7e9a835b 1830 | languageName: node 1831 | linkType: hard 1832 | 1833 | "nopt@npm:^7.0.0": 1834 | version: 7.2.1 1835 | resolution: "nopt@npm:7.2.1" 1836 | dependencies: 1837 | abbrev: "npm:^2.0.0" 1838 | bin: 1839 | nopt: bin/nopt.js 1840 | checksum: 10c0/a069c7c736767121242037a22a788863accfa932ab285a1eb569eb8cd534b09d17206f68c37f096ae785647435e0c5a5a0a67b42ec743e481a455e5ae6a6df81 1841 | languageName: node 1842 | linkType: hard 1843 | 1844 | "npm-run-path@npm:^5.1.0": 1845 | version: 5.3.0 1846 | resolution: "npm-run-path@npm:5.3.0" 1847 | dependencies: 1848 | path-key: "npm:^4.0.0" 1849 | checksum: 10c0/124df74820c40c2eb9a8612a254ea1d557ddfab1581c3e751f825e3e366d9f00b0d76a3c94ecd8398e7f3eee193018622677e95816e8491f0797b21e30b2deba 1850 | languageName: node 1851 | linkType: hard 1852 | 1853 | "officeparser@npm:^5.1.1": 1854 | version: 5.1.1 1855 | resolution: "officeparser@npm:5.1.1" 1856 | dependencies: 1857 | "@xmldom/xmldom": "npm:^0.8.10" 1858 | concat-stream: "npm:^2.0.0" 1859 | file-type: "npm:^16.5.4" 1860 | node-ensure: "npm:^0.0.0" 1861 | yauzl: "npm:^3.1.3" 1862 | bin: 1863 | officeparser: officeParser.js 1864 | checksum: 10c0/8788dd537834959a0e8e1a9831fe9383d8cfe0cc8befd33bd9261e19d07bce04d05b79b2a85806f333921d38cf42bf8902b4414e5ed568753b3418c98bff229b 1865 | languageName: node 1866 | linkType: hard 1867 | 1868 | "onetime@npm:^6.0.0": 1869 | version: 6.0.0 1870 | resolution: "onetime@npm:6.0.0" 1871 | dependencies: 1872 | mimic-fn: "npm:^4.0.0" 1873 | checksum: 10c0/4eef7c6abfef697dd4479345a4100c382d73c149d2d56170a54a07418c50816937ad09500e1ed1e79d235989d073a9bade8557122aee24f0576ecde0f392bb6c 1874 | languageName: node 1875 | linkType: hard 1876 | 1877 | "option@npm:~0.2.1": 1878 | version: 0.2.4 1879 | resolution: "option@npm:0.2.4" 1880 | checksum: 10c0/b605e5f3f65b21e0a9ec49a4ead50acb953696678109bb0decd80cc4cc4b466691c14472b2e281866cef513fc63f0310a09677c2d4cedd1e0d9607be1ce25831 1881 | languageName: node 1882 | linkType: hard 1883 | 1884 | "p-map@npm:^4.0.0": 1885 | version: 4.0.0 1886 | resolution: "p-map@npm:4.0.0" 1887 | dependencies: 1888 | aggregate-error: "npm:^3.0.0" 1889 | checksum: 10c0/592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75 1890 | languageName: node 1891 | linkType: hard 1892 | 1893 | "package-json-from-dist@npm:^1.0.0": 1894 | version: 1.0.0 1895 | resolution: "package-json-from-dist@npm:1.0.0" 1896 | checksum: 10c0/e3ffaf6ac1040ab6082a658230c041ad14e72fabe99076a2081bb1d5d41210f11872403fc09082daf4387fc0baa6577f96c9c0e94c90c394fd57794b66aa4033 1897 | languageName: node 1898 | linkType: hard 1899 | 1900 | "pako@npm:~1.0.2": 1901 | version: 1.0.11 1902 | resolution: "pako@npm:1.0.11" 1903 | checksum: 10c0/86dd99d8b34c3930345b8bbeb5e1cd8a05f608eeb40967b293f72fe469d0e9c88b783a8777e4cc7dc7c91ce54c5e93d88ff4b4f060e6ff18408fd21030d9ffbe 1904 | languageName: node 1905 | linkType: hard 1906 | 1907 | "parse5@npm:^7.0.0": 1908 | version: 7.1.2 1909 | resolution: "parse5@npm:7.1.2" 1910 | dependencies: 1911 | entities: "npm:^4.4.0" 1912 | checksum: 10c0/297d7af8224f4b5cb7f6617ecdae98eeaed7f8cbd78956c42785e230505d5a4f07cef352af10d3006fa5c1544b76b57784d3a22d861ae071bbc460c649482bf4 1913 | languageName: node 1914 | linkType: hard 1915 | 1916 | "path-is-absolute@npm:^1.0.0": 1917 | version: 1.0.1 1918 | resolution: "path-is-absolute@npm:1.0.1" 1919 | checksum: 10c0/127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078 1920 | languageName: node 1921 | linkType: hard 1922 | 1923 | "path-key@npm:^3.1.0": 1924 | version: 3.1.1 1925 | resolution: "path-key@npm:3.1.1" 1926 | checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c 1927 | languageName: node 1928 | linkType: hard 1929 | 1930 | "path-key@npm:^4.0.0": 1931 | version: 4.0.0 1932 | resolution: "path-key@npm:4.0.0" 1933 | checksum: 10c0/794efeef32863a65ac312f3c0b0a99f921f3e827ff63afa5cb09a377e202c262b671f7b3832a4e64731003fa94af0263713962d317b9887bd1e0c48a342efba3 1934 | languageName: node 1935 | linkType: hard 1936 | 1937 | "path-scurry@npm:^1.11.1": 1938 | version: 1.11.1 1939 | resolution: "path-scurry@npm:1.11.1" 1940 | dependencies: 1941 | lru-cache: "npm:^10.2.0" 1942 | minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" 1943 | checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d 1944 | languageName: node 1945 | linkType: hard 1946 | 1947 | "path-scurry@npm:^2.0.0": 1948 | version: 2.0.0 1949 | resolution: "path-scurry@npm:2.0.0" 1950 | dependencies: 1951 | lru-cache: "npm:^11.0.0" 1952 | minipass: "npm:^7.1.2" 1953 | checksum: 10c0/3da4adedaa8e7ef8d6dc4f35a0ff8f05a9b4d8365f2b28047752b62d4c1ad73eec21e37b1579ef2d075920157856a3b52ae8309c480a6f1a8bbe06ff8e52b33c 1954 | languageName: node 1955 | linkType: hard 1956 | 1957 | "pathe@npm:^1.1.2": 1958 | version: 1.1.2 1959 | resolution: "pathe@npm:1.1.2" 1960 | checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 1961 | languageName: node 1962 | linkType: hard 1963 | 1964 | "pathval@npm:^2.0.0": 1965 | version: 2.0.0 1966 | resolution: "pathval@npm:2.0.0" 1967 | checksum: 10c0/602e4ee347fba8a599115af2ccd8179836a63c925c23e04bd056d0674a64b39e3a081b643cc7bc0b84390517df2d800a46fcc5598d42c155fe4977095c2f77c5 1968 | languageName: node 1969 | linkType: hard 1970 | 1971 | "pdfjs-dist@npm:^5.2.133": 1972 | version: 5.2.133 1973 | resolution: "pdfjs-dist@npm:5.2.133" 1974 | dependencies: 1975 | "@napi-rs/canvas": "npm:^0.1.67" 1976 | dependenciesMeta: 1977 | "@napi-rs/canvas": 1978 | optional: true 1979 | checksum: 10c0/13a20a27fb39b53e2209b19bd72ac5d6b680d83ca9e5a074779c7fb518cb745fcf30f28aaf1bb4e6509b8bf38ea46dd8d3d9cd5971c0d83ec72e7c10be9fd29b 1980 | languageName: node 1981 | linkType: hard 1982 | 1983 | "peek-readable@npm:^4.1.0": 1984 | version: 4.1.0 1985 | resolution: "peek-readable@npm:4.1.0" 1986 | checksum: 10c0/f9b81ce3eed185cc9ebbf7dff0b6e130dd6da7b05f1802bbf726a78e4d84990b0a65f8e701959c50eb1124cc2ad352205147954bf39793faba29bb00ce742a44 1987 | languageName: node 1988 | linkType: hard 1989 | 1990 | "pend@npm:~1.2.0": 1991 | version: 1.2.0 1992 | resolution: "pend@npm:1.2.0" 1993 | checksum: 10c0/8a87e63f7a4afcfb0f9f77b39bb92374afc723418b9cb716ee4257689224171002e07768eeade4ecd0e86f1fa3d8f022994219fb45634f2dbd78c6803e452458 1994 | languageName: node 1995 | linkType: hard 1996 | 1997 | "picocolors@npm:^1.1.1": 1998 | version: 1.1.1 1999 | resolution: "picocolors@npm:1.1.1" 2000 | checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 2001 | languageName: node 2002 | linkType: hard 2003 | 2004 | "postcss@npm:^8.4.43": 2005 | version: 8.5.1 2006 | resolution: "postcss@npm:8.5.1" 2007 | dependencies: 2008 | nanoid: "npm:^3.3.8" 2009 | picocolors: "npm:^1.1.1" 2010 | source-map-js: "npm:^1.2.1" 2011 | checksum: 10c0/c4d90c59c98e8a0c102b77d3f4cac190f883b42d63dc60e2f3ed840f16197c0c8e25a4327d2e9a847b45a985612317dc0534178feeebd0a1cf3eb0eecf75cae4 2012 | languageName: node 2013 | linkType: hard 2014 | 2015 | "proc-log@npm:^4.1.0, proc-log@npm:^4.2.0": 2016 | version: 4.2.0 2017 | resolution: "proc-log@npm:4.2.0" 2018 | checksum: 10c0/17db4757c2a5c44c1e545170e6c70a26f7de58feb985091fb1763f5081cab3d01b181fb2dd240c9f4a4255a1d9227d163d5771b7e69c9e49a561692db865efb9 2019 | languageName: node 2020 | linkType: hard 2021 | 2022 | "process-nextick-args@npm:~2.0.0": 2023 | version: 2.0.1 2024 | resolution: "process-nextick-args@npm:2.0.1" 2025 | checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 2026 | languageName: node 2027 | linkType: hard 2028 | 2029 | "process@npm:^0.11.10": 2030 | version: 0.11.10 2031 | resolution: "process@npm:0.11.10" 2032 | checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3 2033 | languageName: node 2034 | linkType: hard 2035 | 2036 | "promise-retry@npm:^2.0.1": 2037 | version: 2.0.1 2038 | resolution: "promise-retry@npm:2.0.1" 2039 | dependencies: 2040 | err-code: "npm:^2.0.2" 2041 | retry: "npm:^0.12.0" 2042 | checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 2043 | languageName: node 2044 | linkType: hard 2045 | 2046 | "readable-stream@npm:^3.0.2": 2047 | version: 3.6.2 2048 | resolution: "readable-stream@npm:3.6.2" 2049 | dependencies: 2050 | inherits: "npm:^2.0.3" 2051 | string_decoder: "npm:^1.1.1" 2052 | util-deprecate: "npm:^1.0.1" 2053 | checksum: 10c0/e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7 2054 | languageName: node 2055 | linkType: hard 2056 | 2057 | "readable-stream@npm:^4.7.0": 2058 | version: 4.7.0 2059 | resolution: "readable-stream@npm:4.7.0" 2060 | dependencies: 2061 | abort-controller: "npm:^3.0.0" 2062 | buffer: "npm:^6.0.3" 2063 | events: "npm:^3.3.0" 2064 | process: "npm:^0.11.10" 2065 | string_decoder: "npm:^1.3.0" 2066 | checksum: 10c0/fd86d068da21cfdb10f7a4479f2e47d9c0a9b0c862fc0c840a7e5360201580a55ac399c764b12a4f6fa291f8cee74d9c4b7562e0d53b3c4b2769f2c98155d957 2067 | languageName: node 2068 | linkType: hard 2069 | 2070 | "readable-stream@npm:~2.3.6": 2071 | version: 2.3.8 2072 | resolution: "readable-stream@npm:2.3.8" 2073 | dependencies: 2074 | core-util-is: "npm:~1.0.0" 2075 | inherits: "npm:~2.0.3" 2076 | isarray: "npm:~1.0.0" 2077 | process-nextick-args: "npm:~2.0.0" 2078 | safe-buffer: "npm:~5.1.1" 2079 | string_decoder: "npm:~1.1.1" 2080 | util-deprecate: "npm:~1.0.1" 2081 | checksum: 10c0/7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa 2082 | languageName: node 2083 | linkType: hard 2084 | 2085 | "readable-web-to-node-stream@npm:^3.0.0": 2086 | version: 3.0.4 2087 | resolution: "readable-web-to-node-stream@npm:3.0.4" 2088 | dependencies: 2089 | readable-stream: "npm:^4.7.0" 2090 | checksum: 10c0/2dc417d5d0b0c0191fcf57f87df3b2853db21d1da5554ec32b1e1c5a515e5a1243fc077a23f74046d711c2d736628f64b31054a8379b95bb016212430b5110c5 2091 | languageName: node 2092 | linkType: hard 2093 | 2094 | "retry@npm:^0.12.0": 2095 | version: 0.12.0 2096 | resolution: "retry@npm:0.12.0" 2097 | checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe 2098 | languageName: node 2099 | linkType: hard 2100 | 2101 | "rollup@npm:^4.20.0": 2102 | version: 4.30.1 2103 | resolution: "rollup@npm:4.30.1" 2104 | dependencies: 2105 | "@rollup/rollup-android-arm-eabi": "npm:4.30.1" 2106 | "@rollup/rollup-android-arm64": "npm:4.30.1" 2107 | "@rollup/rollup-darwin-arm64": "npm:4.30.1" 2108 | "@rollup/rollup-darwin-x64": "npm:4.30.1" 2109 | "@rollup/rollup-freebsd-arm64": "npm:4.30.1" 2110 | "@rollup/rollup-freebsd-x64": "npm:4.30.1" 2111 | "@rollup/rollup-linux-arm-gnueabihf": "npm:4.30.1" 2112 | "@rollup/rollup-linux-arm-musleabihf": "npm:4.30.1" 2113 | "@rollup/rollup-linux-arm64-gnu": "npm:4.30.1" 2114 | "@rollup/rollup-linux-arm64-musl": "npm:4.30.1" 2115 | "@rollup/rollup-linux-loongarch64-gnu": "npm:4.30.1" 2116 | "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.30.1" 2117 | "@rollup/rollup-linux-riscv64-gnu": "npm:4.30.1" 2118 | "@rollup/rollup-linux-s390x-gnu": "npm:4.30.1" 2119 | "@rollup/rollup-linux-x64-gnu": "npm:4.30.1" 2120 | "@rollup/rollup-linux-x64-musl": "npm:4.30.1" 2121 | "@rollup/rollup-win32-arm64-msvc": "npm:4.30.1" 2122 | "@rollup/rollup-win32-ia32-msvc": "npm:4.30.1" 2123 | "@rollup/rollup-win32-x64-msvc": "npm:4.30.1" 2124 | "@types/estree": "npm:1.0.6" 2125 | fsevents: "npm:~2.3.2" 2126 | dependenciesMeta: 2127 | "@rollup/rollup-android-arm-eabi": 2128 | optional: true 2129 | "@rollup/rollup-android-arm64": 2130 | optional: true 2131 | "@rollup/rollup-darwin-arm64": 2132 | optional: true 2133 | "@rollup/rollup-darwin-x64": 2134 | optional: true 2135 | "@rollup/rollup-freebsd-arm64": 2136 | optional: true 2137 | "@rollup/rollup-freebsd-x64": 2138 | optional: true 2139 | "@rollup/rollup-linux-arm-gnueabihf": 2140 | optional: true 2141 | "@rollup/rollup-linux-arm-musleabihf": 2142 | optional: true 2143 | "@rollup/rollup-linux-arm64-gnu": 2144 | optional: true 2145 | "@rollup/rollup-linux-arm64-musl": 2146 | optional: true 2147 | "@rollup/rollup-linux-loongarch64-gnu": 2148 | optional: true 2149 | "@rollup/rollup-linux-powerpc64le-gnu": 2150 | optional: true 2151 | "@rollup/rollup-linux-riscv64-gnu": 2152 | optional: true 2153 | "@rollup/rollup-linux-s390x-gnu": 2154 | optional: true 2155 | "@rollup/rollup-linux-x64-gnu": 2156 | optional: true 2157 | "@rollup/rollup-linux-x64-musl": 2158 | optional: true 2159 | "@rollup/rollup-win32-arm64-msvc": 2160 | optional: true 2161 | "@rollup/rollup-win32-ia32-msvc": 2162 | optional: true 2163 | "@rollup/rollup-win32-x64-msvc": 2164 | optional: true 2165 | fsevents: 2166 | optional: true 2167 | bin: 2168 | rollup: dist/bin/rollup 2169 | checksum: 10c0/a318c57e2ca9741e1503bcd75483949c6e83edd72234a468010a3098a34248f523e44f7ad4fde90dc5c2da56abc1b78ac42a9329e1dbd708682728adbd8df7cc 2170 | languageName: node 2171 | linkType: hard 2172 | 2173 | "safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": 2174 | version: 5.1.2 2175 | resolution: "safe-buffer@npm:5.1.2" 2176 | checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 2177 | languageName: node 2178 | linkType: hard 2179 | 2180 | "safe-buffer@npm:~5.2.0": 2181 | version: 5.2.1 2182 | resolution: "safe-buffer@npm:5.2.1" 2183 | checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 2184 | languageName: node 2185 | linkType: hard 2186 | 2187 | "safer-buffer@npm:>= 2.1.2 < 3.0.0": 2188 | version: 2.1.2 2189 | resolution: "safer-buffer@npm:2.1.2" 2190 | checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 2191 | languageName: node 2192 | linkType: hard 2193 | 2194 | "semver@npm:^7.3.5": 2195 | version: 7.6.3 2196 | resolution: "semver@npm:7.6.3" 2197 | bin: 2198 | semver: bin/semver.js 2199 | checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf 2200 | languageName: node 2201 | linkType: hard 2202 | 2203 | "setimmediate@npm:^1.0.5": 2204 | version: 1.0.5 2205 | resolution: "setimmediate@npm:1.0.5" 2206 | checksum: 10c0/5bae81bfdbfbd0ce992893286d49c9693c82b1bcc00dcaaf3a09c8f428fdeacf4190c013598b81875dfac2b08a572422db7df779a99332d0fce186d15a3e4d49 2207 | languageName: node 2208 | linkType: hard 2209 | 2210 | "shebang-command@npm:^2.0.0": 2211 | version: 2.0.0 2212 | resolution: "shebang-command@npm:2.0.0" 2213 | dependencies: 2214 | shebang-regex: "npm:^3.0.0" 2215 | checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e 2216 | languageName: node 2217 | linkType: hard 2218 | 2219 | "shebang-regex@npm:^3.0.0": 2220 | version: 3.0.0 2221 | resolution: "shebang-regex@npm:3.0.0" 2222 | checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 2223 | languageName: node 2224 | linkType: hard 2225 | 2226 | "siginfo@npm:^2.0.0": 2227 | version: 2.0.0 2228 | resolution: "siginfo@npm:2.0.0" 2229 | checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34 2230 | languageName: node 2231 | linkType: hard 2232 | 2233 | "signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": 2234 | version: 4.1.0 2235 | resolution: "signal-exit@npm:4.1.0" 2236 | checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 2237 | languageName: node 2238 | linkType: hard 2239 | 2240 | "simple-git@npm:^3.27.0": 2241 | version: 3.27.0 2242 | resolution: "simple-git@npm:3.27.0" 2243 | dependencies: 2244 | "@kwsites/file-exists": "npm:^1.1.1" 2245 | "@kwsites/promise-deferred": "npm:^1.1.1" 2246 | debug: "npm:^4.3.5" 2247 | checksum: 10c0/ef56cabea585377d3e0ca30e4e93447f465d91f23eaf751693cc31f366b5f7636facf52ad5bcd598bfdf295fa60732e7a394303d378995b52e2d221d92e5f9f4 2248 | languageName: node 2249 | linkType: hard 2250 | 2251 | "smart-buffer@npm:^4.2.0": 2252 | version: 4.2.0 2253 | resolution: "smart-buffer@npm:4.2.0" 2254 | checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 2255 | languageName: node 2256 | linkType: hard 2257 | 2258 | "socks-proxy-agent@npm:^8.0.3": 2259 | version: 8.0.4 2260 | resolution: "socks-proxy-agent@npm:8.0.4" 2261 | dependencies: 2262 | agent-base: "npm:^7.1.1" 2263 | debug: "npm:^4.3.4" 2264 | socks: "npm:^2.8.3" 2265 | checksum: 10c0/345593bb21b95b0508e63e703c84da11549f0a2657d6b4e3ee3612c312cb3a907eac10e53b23ede3557c6601d63252103494caa306b66560f43af7b98f53957a 2266 | languageName: node 2267 | linkType: hard 2268 | 2269 | "socks@npm:^2.8.3": 2270 | version: 2.8.3 2271 | resolution: "socks@npm:2.8.3" 2272 | dependencies: 2273 | ip-address: "npm:^9.0.5" 2274 | smart-buffer: "npm:^4.2.0" 2275 | checksum: 10c0/d54a52bf9325165770b674a67241143a3d8b4e4c8884560c4e0e078aace2a728dffc7f70150660f51b85797c4e1a3b82f9b7aa25e0a0ceae1a243365da5c51a7 2276 | languageName: node 2277 | linkType: hard 2278 | 2279 | "source-map-js@npm:^1.2.1": 2280 | version: 1.2.1 2281 | resolution: "source-map-js@npm:1.2.1" 2282 | checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf 2283 | languageName: node 2284 | linkType: hard 2285 | 2286 | "sprintf-js@npm:^1.1.3": 2287 | version: 1.1.3 2288 | resolution: "sprintf-js@npm:1.1.3" 2289 | checksum: 10c0/09270dc4f30d479e666aee820eacd9e464215cdff53848b443964202bf4051490538e5dd1b42e1a65cf7296916ca17640aebf63dae9812749c7542ee5f288dec 2290 | languageName: node 2291 | linkType: hard 2292 | 2293 | "sprintf-js@npm:~1.0.2": 2294 | version: 1.0.3 2295 | resolution: "sprintf-js@npm:1.0.3" 2296 | checksum: 10c0/ecadcfe4c771890140da5023d43e190b7566d9cf8b2d238600f31bec0fc653f328da4450eb04bd59a431771a8e9cc0e118f0aa3974b683a4981b4e07abc2a5bb 2297 | languageName: node 2298 | linkType: hard 2299 | 2300 | "ssri@npm:^10.0.0": 2301 | version: 10.0.6 2302 | resolution: "ssri@npm:10.0.6" 2303 | dependencies: 2304 | minipass: "npm:^7.0.3" 2305 | checksum: 10c0/e5a1e23a4057a86a97971465418f22ea89bd439ac36ade88812dd920e4e61873e8abd6a9b72a03a67ef50faa00a2daf1ab745c5a15b46d03e0544a0296354227 2306 | languageName: node 2307 | linkType: hard 2308 | 2309 | "stackback@npm:0.0.2": 2310 | version: 0.0.2 2311 | resolution: "stackback@npm:0.0.2" 2312 | checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983 2313 | languageName: node 2314 | linkType: hard 2315 | 2316 | "std-env@npm:^3.8.0": 2317 | version: 3.8.0 2318 | resolution: "std-env@npm:3.8.0" 2319 | checksum: 10c0/f560a2902fd0fa3d648d7d0acecbd19d664006f7372c1fba197ed4c216b4c9e48db6e2769b5fe1616d42a9333c9f066c5011935035e85c59f45dc4f796272040 2320 | languageName: node 2321 | linkType: hard 2322 | 2323 | "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": 2324 | version: 4.2.3 2325 | resolution: "string-width@npm:4.2.3" 2326 | dependencies: 2327 | emoji-regex: "npm:^8.0.0" 2328 | is-fullwidth-code-point: "npm:^3.0.0" 2329 | strip-ansi: "npm:^6.0.1" 2330 | checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b 2331 | languageName: node 2332 | linkType: hard 2333 | 2334 | "string-width@npm:^5.0.1, string-width@npm:^5.1.2": 2335 | version: 5.1.2 2336 | resolution: "string-width@npm:5.1.2" 2337 | dependencies: 2338 | eastasianwidth: "npm:^0.2.0" 2339 | emoji-regex: "npm:^9.2.2" 2340 | strip-ansi: "npm:^7.0.1" 2341 | checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca 2342 | languageName: node 2343 | linkType: hard 2344 | 2345 | "string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0": 2346 | version: 1.3.0 2347 | resolution: "string_decoder@npm:1.3.0" 2348 | dependencies: 2349 | safe-buffer: "npm:~5.2.0" 2350 | checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d 2351 | languageName: node 2352 | linkType: hard 2353 | 2354 | "string_decoder@npm:~1.1.1": 2355 | version: 1.1.1 2356 | resolution: "string_decoder@npm:1.1.1" 2357 | dependencies: 2358 | safe-buffer: "npm:~5.1.0" 2359 | checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e 2360 | languageName: node 2361 | linkType: hard 2362 | 2363 | "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": 2364 | version: 6.0.1 2365 | resolution: "strip-ansi@npm:6.0.1" 2366 | dependencies: 2367 | ansi-regex: "npm:^5.0.1" 2368 | checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 2369 | languageName: node 2370 | linkType: hard 2371 | 2372 | "strip-ansi@npm:^7.0.1": 2373 | version: 7.1.0 2374 | resolution: "strip-ansi@npm:7.1.0" 2375 | dependencies: 2376 | ansi-regex: "npm:^6.0.1" 2377 | checksum: 10c0/a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4 2378 | languageName: node 2379 | linkType: hard 2380 | 2381 | "strip-final-newline@npm:^3.0.0": 2382 | version: 3.0.0 2383 | resolution: "strip-final-newline@npm:3.0.0" 2384 | checksum: 10c0/a771a17901427bac6293fd416db7577e2bc1c34a19d38351e9d5478c3c415f523f391003b42ed475f27e33a78233035df183525395f731d3bfb8cdcbd4da08ce 2385 | languageName: node 2386 | linkType: hard 2387 | 2388 | "strtok3@npm:^6.2.4": 2389 | version: 6.3.0 2390 | resolution: "strtok3@npm:6.3.0" 2391 | dependencies: 2392 | "@tokenizer/token": "npm:^0.3.0" 2393 | peek-readable: "npm:^4.1.0" 2394 | checksum: 10c0/8f1483a2a6758404502f2fc431586fcf37d747b10b125596ab5ec92319c247dd1195f82ba0bc2eaa582db3d807b5cca4b67ff61411756fec6622d051f8e255c2 2395 | languageName: node 2396 | linkType: hard 2397 | 2398 | "system-architecture@npm:^0.1.0": 2399 | version: 0.1.0 2400 | resolution: "system-architecture@npm:0.1.0" 2401 | checksum: 10c0/1969974ea5d31a9ac7c38f2657cfe8255b36f9e1d5ba3c58cb84c24fbeedf562778b8511f18a0abe6d70ae90148cfcaf145ecf26e37c0a53a3829076f3238cbb 2402 | languageName: node 2403 | linkType: hard 2404 | 2405 | "tar@npm:^6.1.11, tar@npm:^6.2.1": 2406 | version: 6.2.1 2407 | resolution: "tar@npm:6.2.1" 2408 | dependencies: 2409 | chownr: "npm:^2.0.0" 2410 | fs-minipass: "npm:^2.0.0" 2411 | minipass: "npm:^5.0.0" 2412 | minizlib: "npm:^2.1.1" 2413 | mkdirp: "npm:^1.0.3" 2414 | yallist: "npm:^4.0.0" 2415 | checksum: 10c0/a5eca3eb50bc11552d453488344e6507156b9193efd7635e98e867fab275d527af53d8866e2370cd09dfe74378a18111622ace35af6a608e5223a7d27fe99537 2416 | languageName: node 2417 | linkType: hard 2418 | 2419 | "tinybench@npm:^2.9.0": 2420 | version: 2.9.0 2421 | resolution: "tinybench@npm:2.9.0" 2422 | checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c 2423 | languageName: node 2424 | linkType: hard 2425 | 2426 | "tinyexec@npm:^0.3.1": 2427 | version: 0.3.2 2428 | resolution: "tinyexec@npm:0.3.2" 2429 | checksum: 10c0/3efbf791a911be0bf0821eab37a3445c2ba07acc1522b1fa84ae1e55f10425076f1290f680286345ed919549ad67527d07281f1c19d584df3b74326909eb1f90 2430 | languageName: node 2431 | linkType: hard 2432 | 2433 | "tinypool@npm:^1.0.1": 2434 | version: 1.0.2 2435 | resolution: "tinypool@npm:1.0.2" 2436 | checksum: 10c0/31ac184c0ff1cf9a074741254fe9ea6de95026749eb2b8ec6fd2b9d8ca94abdccda731f8e102e7f32e72ed3b36d32c6975fd5f5523df3f1b6de6c3d8dfd95e63 2437 | languageName: node 2438 | linkType: hard 2439 | 2440 | "tinyrainbow@npm:^1.2.0": 2441 | version: 1.2.0 2442 | resolution: "tinyrainbow@npm:1.2.0" 2443 | checksum: 10c0/7f78a4b997e5ba0f5ecb75e7ed786f30bab9063716e7dff24dd84013fb338802e43d176cb21ed12480561f5649a82184cf31efb296601a29d38145b1cdb4c192 2444 | languageName: node 2445 | linkType: hard 2446 | 2447 | "tinyspy@npm:^3.0.2": 2448 | version: 3.0.2 2449 | resolution: "tinyspy@npm:3.0.2" 2450 | checksum: 10c0/55ffad24e346622b59292e097c2ee30a63919d5acb7ceca87fc0d1c223090089890587b426e20054733f97a58f20af2c349fb7cc193697203868ab7ba00bcea0 2451 | languageName: node 2452 | linkType: hard 2453 | 2454 | "token-types@npm:^4.1.1": 2455 | version: 4.2.1 2456 | resolution: "token-types@npm:4.2.1" 2457 | dependencies: 2458 | "@tokenizer/token": "npm:^0.3.0" 2459 | ieee754: "npm:^1.2.1" 2460 | checksum: 10c0/e9a4a139deba9515770cd7ac36a8f53f953b9d035d309e88a66d706760dba0df420753f2b8bdee6b9f3cbff8d66b24e69571e8dea27baa7b378229ab1bcca399 2461 | languageName: node 2462 | linkType: hard 2463 | 2464 | "ts-node@npm:^10.9.2": 2465 | version: 10.9.2 2466 | resolution: "ts-node@npm:10.9.2" 2467 | dependencies: 2468 | "@cspotcode/source-map-support": "npm:^0.8.0" 2469 | "@tsconfig/node10": "npm:^1.0.7" 2470 | "@tsconfig/node12": "npm:^1.0.7" 2471 | "@tsconfig/node14": "npm:^1.0.0" 2472 | "@tsconfig/node16": "npm:^1.0.2" 2473 | acorn: "npm:^8.4.1" 2474 | acorn-walk: "npm:^8.1.1" 2475 | arg: "npm:^4.1.0" 2476 | create-require: "npm:^1.1.0" 2477 | diff: "npm:^4.0.1" 2478 | make-error: "npm:^1.1.1" 2479 | v8-compile-cache-lib: "npm:^3.0.1" 2480 | yn: "npm:3.1.1" 2481 | peerDependencies: 2482 | "@swc/core": ">=1.2.50" 2483 | "@swc/wasm": ">=1.2.50" 2484 | "@types/node": "*" 2485 | typescript: ">=2.7" 2486 | peerDependenciesMeta: 2487 | "@swc/core": 2488 | optional: true 2489 | "@swc/wasm": 2490 | optional: true 2491 | bin: 2492 | ts-node: dist/bin.js 2493 | ts-node-cwd: dist/bin-cwd.js 2494 | ts-node-esm: dist/bin-esm.js 2495 | ts-node-script: dist/bin-script.js 2496 | ts-node-transpile-only: dist/bin-transpile.js 2497 | ts-script: dist/bin-script-deprecated.js 2498 | checksum: 10c0/5f29938489f96982a25ba650b64218e83a3357d76f7bede80195c65ab44ad279c8357264639b7abdd5d7e75fc269a83daa0e9c62fd8637a3def67254ecc9ddc2 2499 | languageName: node 2500 | linkType: hard 2501 | 2502 | "typedarray@npm:^0.0.6": 2503 | version: 0.0.6 2504 | resolution: "typedarray@npm:0.0.6" 2505 | checksum: 10c0/6005cb31df50eef8b1f3c780eb71a17925f3038a100d82f9406ac2ad1de5eb59f8e6decbdc145b3a1f8e5836e17b0c0002fb698b9fe2516b8f9f9ff602d36412 2506 | languageName: node 2507 | linkType: hard 2508 | 2509 | "typescript@npm:^5.7.2": 2510 | version: 5.7.2 2511 | resolution: "typescript@npm:5.7.2" 2512 | bin: 2513 | tsc: bin/tsc 2514 | tsserver: bin/tsserver 2515 | checksum: 10c0/a873118b5201b2ef332127ef5c63fb9d9c155e6fdbe211cbd9d8e65877283797cca76546bad742eea36ed7efbe3424a30376818f79c7318512064e8625d61622 2516 | languageName: node 2517 | linkType: hard 2518 | 2519 | "typescript@patch:typescript@npm%3A^5.7.2#optional!builtin": 2520 | version: 5.7.2 2521 | resolution: "typescript@patch:typescript@npm%3A5.7.2#optional!builtin::version=5.7.2&hash=74658d" 2522 | bin: 2523 | tsc: bin/tsc 2524 | tsserver: bin/tsserver 2525 | checksum: 10c0/c891ccf04008bc1305ba34053db951f8a4584b4a1bf2f68fd972c4a354df3dc5e62c8bfed4f6ac2d12e5b3b1c49af312c83a651048f818cd5b4949d17baacd79 2526 | languageName: node 2527 | linkType: hard 2528 | 2529 | "underscore@npm:^1.13.1": 2530 | version: 1.13.7 2531 | resolution: "underscore@npm:1.13.7" 2532 | checksum: 10c0/fad2b4aac48847674aaf3c30558f383399d4fdafad6dd02dd60e4e1b8103b52c5a9e5937e0cc05dacfd26d6a0132ed0410ab4258241240757e4a4424507471cd 2533 | languageName: node 2534 | linkType: hard 2535 | 2536 | "undici-types@npm:~5.26.4": 2537 | version: 5.26.5 2538 | resolution: "undici-types@npm:5.26.5" 2539 | checksum: 10c0/bb673d7876c2d411b6eb6c560e0c571eef4a01c1c19925175d16e3a30c4c428181fb8d7ae802a261f283e4166a0ac435e2f505743aa9e45d893f9a3df017b501 2540 | languageName: node 2541 | linkType: hard 2542 | 2543 | "undici-types@npm:~6.20.0": 2544 | version: 6.20.0 2545 | resolution: "undici-types@npm:6.20.0" 2546 | checksum: 10c0/68e659a98898d6a836a9a59e6adf14a5d799707f5ea629433e025ac90d239f75e408e2e5ff086afc3cace26f8b26ee52155293564593fbb4a2f666af57fc59bf 2547 | languageName: node 2548 | linkType: hard 2549 | 2550 | "unique-filename@npm:^3.0.0": 2551 | version: 3.0.0 2552 | resolution: "unique-filename@npm:3.0.0" 2553 | dependencies: 2554 | unique-slug: "npm:^4.0.0" 2555 | checksum: 10c0/6363e40b2fa758eb5ec5e21b3c7fb83e5da8dcfbd866cc0c199d5534c42f03b9ea9ab069769cc388e1d7ab93b4eeef28ef506ab5f18d910ef29617715101884f 2556 | languageName: node 2557 | linkType: hard 2558 | 2559 | "unique-slug@npm:^4.0.0": 2560 | version: 4.0.0 2561 | resolution: "unique-slug@npm:4.0.0" 2562 | dependencies: 2563 | imurmurhash: "npm:^0.1.4" 2564 | checksum: 10c0/cb811d9d54eb5821b81b18205750be84cb015c20a4a44280794e915f5a0a70223ce39066781a354e872df3572e8155c228f43ff0cce94c7cbf4da2cc7cbdd635 2565 | languageName: node 2566 | linkType: hard 2567 | 2568 | "util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": 2569 | version: 1.0.2 2570 | resolution: "util-deprecate@npm:1.0.2" 2571 | checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 2572 | languageName: node 2573 | linkType: hard 2574 | 2575 | "v8-compile-cache-lib@npm:^3.0.1": 2576 | version: 3.0.1 2577 | resolution: "v8-compile-cache-lib@npm:3.0.1" 2578 | checksum: 10c0/bdc36fb8095d3b41df197f5fb6f11e3a26adf4059df3213e3baa93810d8f0cc76f9a74aaefc18b73e91fe7e19154ed6f134eda6fded2e0f1c8d2272ed2d2d391 2579 | languageName: node 2580 | linkType: hard 2581 | 2582 | "vite-node@npm:2.1.8": 2583 | version: 2.1.8 2584 | resolution: "vite-node@npm:2.1.8" 2585 | dependencies: 2586 | cac: "npm:^6.7.14" 2587 | debug: "npm:^4.3.7" 2588 | es-module-lexer: "npm:^1.5.4" 2589 | pathe: "npm:^1.1.2" 2590 | vite: "npm:^5.0.0" 2591 | bin: 2592 | vite-node: vite-node.mjs 2593 | checksum: 10c0/cb28027a7425ba29780e216164c07d36a4ff9eb60d83afcad3bc222fd5a5f3e36030071c819edd6d910940f502d49e52f7564743617bc1c5875485b0952c72d5 2594 | languageName: node 2595 | linkType: hard 2596 | 2597 | "vite@npm:^5.0.0": 2598 | version: 5.4.11 2599 | resolution: "vite@npm:5.4.11" 2600 | dependencies: 2601 | esbuild: "npm:^0.21.3" 2602 | fsevents: "npm:~2.3.3" 2603 | postcss: "npm:^8.4.43" 2604 | rollup: "npm:^4.20.0" 2605 | peerDependencies: 2606 | "@types/node": ^18.0.0 || >=20.0.0 2607 | less: "*" 2608 | lightningcss: ^1.21.0 2609 | sass: "*" 2610 | sass-embedded: "*" 2611 | stylus: "*" 2612 | sugarss: "*" 2613 | terser: ^5.4.0 2614 | dependenciesMeta: 2615 | fsevents: 2616 | optional: true 2617 | peerDependenciesMeta: 2618 | "@types/node": 2619 | optional: true 2620 | less: 2621 | optional: true 2622 | lightningcss: 2623 | optional: true 2624 | sass: 2625 | optional: true 2626 | sass-embedded: 2627 | optional: true 2628 | stylus: 2629 | optional: true 2630 | sugarss: 2631 | optional: true 2632 | terser: 2633 | optional: true 2634 | bin: 2635 | vite: bin/vite.js 2636 | checksum: 10c0/d536bb7af57dd0eca2a808f95f5ff1d7b7ffb8d86e17c6893087680a0448bd0d15e07475270c8a6de65cb5115592d037130a1dd979dc76bcef8c1dda202a1874 2637 | languageName: node 2638 | linkType: hard 2639 | 2640 | "vitest@npm:^2.1.8": 2641 | version: 2.1.8 2642 | resolution: "vitest@npm:2.1.8" 2643 | dependencies: 2644 | "@vitest/expect": "npm:2.1.8" 2645 | "@vitest/mocker": "npm:2.1.8" 2646 | "@vitest/pretty-format": "npm:^2.1.8" 2647 | "@vitest/runner": "npm:2.1.8" 2648 | "@vitest/snapshot": "npm:2.1.8" 2649 | "@vitest/spy": "npm:2.1.8" 2650 | "@vitest/utils": "npm:2.1.8" 2651 | chai: "npm:^5.1.2" 2652 | debug: "npm:^4.3.7" 2653 | expect-type: "npm:^1.1.0" 2654 | magic-string: "npm:^0.30.12" 2655 | pathe: "npm:^1.1.2" 2656 | std-env: "npm:^3.8.0" 2657 | tinybench: "npm:^2.9.0" 2658 | tinyexec: "npm:^0.3.1" 2659 | tinypool: "npm:^1.0.1" 2660 | tinyrainbow: "npm:^1.2.0" 2661 | vite: "npm:^5.0.0" 2662 | vite-node: "npm:2.1.8" 2663 | why-is-node-running: "npm:^2.3.0" 2664 | peerDependencies: 2665 | "@edge-runtime/vm": "*" 2666 | "@types/node": ^18.0.0 || >=20.0.0 2667 | "@vitest/browser": 2.1.8 2668 | "@vitest/ui": 2.1.8 2669 | happy-dom: "*" 2670 | jsdom: "*" 2671 | peerDependenciesMeta: 2672 | "@edge-runtime/vm": 2673 | optional: true 2674 | "@types/node": 2675 | optional: true 2676 | "@vitest/browser": 2677 | optional: true 2678 | "@vitest/ui": 2679 | optional: true 2680 | happy-dom: 2681 | optional: true 2682 | jsdom: 2683 | optional: true 2684 | bin: 2685 | vitest: vitest.mjs 2686 | checksum: 10c0/e70631bad5662d6c60c5cf836a4baf58b890db6654fef1f608fe6a86aa49a2b9f078aac74b719d4d3c87c5c781968cc73590a7935277b48f3d8b6fb9c5b4d276 2687 | languageName: node 2688 | linkType: hard 2689 | 2690 | "which@npm:^2.0.1": 2691 | version: 2.0.2 2692 | resolution: "which@npm:2.0.2" 2693 | dependencies: 2694 | isexe: "npm:^2.0.0" 2695 | bin: 2696 | node-which: ./bin/node-which 2697 | checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f 2698 | languageName: node 2699 | linkType: hard 2700 | 2701 | "which@npm:^4.0.0": 2702 | version: 4.0.0 2703 | resolution: "which@npm:4.0.0" 2704 | dependencies: 2705 | isexe: "npm:^3.1.1" 2706 | bin: 2707 | node-which: bin/which.js 2708 | checksum: 10c0/449fa5c44ed120ccecfe18c433296a4978a7583bf2391c50abce13f76878d2476defde04d0f79db8165bdf432853c1f8389d0485ca6e8ebce3bbcded513d5e6a 2709 | languageName: node 2710 | linkType: hard 2711 | 2712 | "why-is-node-running@npm:^2.3.0": 2713 | version: 2.3.0 2714 | resolution: "why-is-node-running@npm:2.3.0" 2715 | dependencies: 2716 | siginfo: "npm:^2.0.0" 2717 | stackback: "npm:0.0.2" 2718 | bin: 2719 | why-is-node-running: cli.js 2720 | checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054 2721 | languageName: node 2722 | linkType: hard 2723 | 2724 | "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": 2725 | version: 7.0.0 2726 | resolution: "wrap-ansi@npm:7.0.0" 2727 | dependencies: 2728 | ansi-styles: "npm:^4.0.0" 2729 | string-width: "npm:^4.1.0" 2730 | strip-ansi: "npm:^6.0.0" 2731 | checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da 2732 | languageName: node 2733 | linkType: hard 2734 | 2735 | "wrap-ansi@npm:^8.1.0": 2736 | version: 8.1.0 2737 | resolution: "wrap-ansi@npm:8.1.0" 2738 | dependencies: 2739 | ansi-styles: "npm:^6.1.0" 2740 | string-width: "npm:^5.0.1" 2741 | strip-ansi: "npm:^7.0.1" 2742 | checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 2743 | languageName: node 2744 | linkType: hard 2745 | 2746 | "xmlbuilder@npm:^10.0.0": 2747 | version: 10.1.1 2748 | resolution: "xmlbuilder@npm:10.1.1" 2749 | checksum: 10c0/26c465e8bd16b4e882d39c2e2a29bb277434d254717aa05df117dd0009041d92855426714b2d1a6a5f76983640349f4edb80073b6ae374e0e6c3d13029ea8237 2750 | languageName: node 2751 | linkType: hard 2752 | 2753 | "yallist@npm:^4.0.0": 2754 | version: 4.0.0 2755 | resolution: "yallist@npm:4.0.0" 2756 | checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a 2757 | languageName: node 2758 | linkType: hard 2759 | 2760 | "yauzl@npm:^3.1.3": 2761 | version: 3.2.0 2762 | resolution: "yauzl@npm:3.2.0" 2763 | dependencies: 2764 | buffer-crc32: "npm:~0.2.3" 2765 | pend: "npm:~1.2.0" 2766 | checksum: 10c0/7b40b3dc46b95761a2a764391d257a11f494d365875af73a1b48fe16d4bd103dd178612e60168d12a0e59a8ba4f6411a15a5e8871d5a5f78255d6cc1ce39ee62 2767 | languageName: node 2768 | linkType: hard 2769 | 2770 | "yn@npm:3.1.1": 2771 | version: 3.1.1 2772 | resolution: "yn@npm:3.1.1" 2773 | checksum: 10c0/0732468dd7622ed8a274f640f191f3eaf1f39d5349a1b72836df484998d7d9807fbea094e2f5486d6b0cd2414aad5775972df0e68f8604db89a239f0f4bf7443 2774 | languageName: node 2775 | linkType: hard 2776 | --------------------------------------------------------------------------------