├── .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 | 
3 | CoPa: LLM Prompting Templating
4 |
5 |
6 |
7 | [](https://badge.fury.io/js/copa)
8 | [](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 |
--------------------------------------------------------------------------------