From 9c9bbe63bc8de37ca0d4b7156221187b0ffff8a0 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 10:34:16 +0100 Subject: [PATCH 01/11] fix: restore curriculum navigation and onboarding links --- website/docs/how-to-use-this-repo.md | 8 +++---- website/docs/overview.md | 2 +- website/sidebars.ts | 33 ++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/website/docs/how-to-use-this-repo.md b/website/docs/how-to-use-this-repo.md index 06142ac..eb60153 100644 --- a/website/docs/how-to-use-this-repo.md +++ b/website/docs/how-to-use-this-repo.md @@ -155,9 +155,9 @@ devfoundry/ │ ├── examples/ # Working code with explanations │ ├── 00-hello-world-console/ # Simplest possible program -│ ├── 01-chat-cli/ # Stage 1: Terminal app -│ ├── 02-chat-static-web/ # Stage 2: HTML/CSS/JS -│ └── 03-chat-cli-typescript/ # Stage 1 with types +│ ├── 11-chat-cli/ # Stage 1: Terminal app +│ ├── 12-chat-static-web/ # Stage 2: HTML/CSS/JS +│ └── 13-chat-cli-typescript/ # Stage 1 with types │ ├── exercises/ # Hands-on practice │ ├── dom-basics.md @@ -396,7 +396,7 @@ We welcome contributions! See CONTRIBUTING.md (coming soon) for guidelines. Choose your path: -- **Total beginner**: [What Software Is](curriculum/part-1-foundations/what-software-is) +- **Total beginner**: [Terminal Basics](curriculum/part-1-foundations/terminal-basics) - **Some experience**: Web Architecture (coming soon) - **Experienced dev**: [Architecture-First Thinking](mental-models/architecture-first) - **Educator**: [Overview](overview) diff --git a/website/docs/overview.md b/website/docs/overview.md index 6f31909..7df2830 100644 --- a/website/docs/overview.md +++ b/website/docs/overview.md @@ -372,7 +372,7 @@ DevFoundry is more than a curriculum — it's a community of people building sof ## Ready to Begin? -Start here: **[Part I, Module 01: What Software Is](curriculum/part-1-foundations/what-software-is)** +Start here: **[Part I, Module 00: Terminal Basics](curriculum/part-1-foundations/terminal-basics)** Or continue exploring: - [How to Use This Repo](how-to-use-this-repo) diff --git a/website/sidebars.ts b/website/sidebars.ts index 331841f..4e61aae 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -46,6 +46,39 @@ const sidebars: SidebarsConfig = { }, ], }, + { + type: 'category', + label: 'Part II: Team Practices', + collapsed: false, + items: [ + 'curriculum/part-2-team-practices/git-and-collaboration', + 'curriculum/part-2-team-practices/development-methodologies', + 'curriculum/part-2-team-practices/ux-ui-fundamentals', + 'curriculum/part-2-team-practices/architecture-decision-records', + ], + }, + { + type: 'category', + label: 'Part III: Building Applications', + collapsed: false, + items: [ + 'curriculum/part-3-building-applications/static-website', + 'curriculum/part-3-building-applications/interactive-ui', + 'curriculum/part-3-building-applications/react-spa', + 'curriculum/part-3-building-applications/fullstack-app', + 'curriculum/part-3-building-applications/deployed-app', + ], + }, + { + type: 'category', + label: 'Part IV: Historical Context', + collapsed: false, + items: [ + 'curriculum/part-4-historical-context/server-side-era', + 'curriculum/part-4-historical-context/ajax-revolution', + 'curriculum/part-4-historical-context/modern-frontend', + ], + }, { type: 'category', label: 'Part V: Infrastructure & Operations', From defb8016dc9c6b6406baca30810542d7239f9bd7 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 10:34:21 +0100 Subject: [PATCH 02/11] docs: add question-asking coaching blocks --- .../part-1-foundations/terminal-basics.md | 18 ++++++++++++++++++ website/docs/examples/chat-cli/index.md | 12 ++++++++++++ website/docs/exercises/minimal-user-loop.md | 16 ++++++++++++++++ website/docs/prompts/reading-code.md | 19 +++++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/website/docs/curriculum/part-1-foundations/terminal-basics.md b/website/docs/curriculum/part-1-foundations/terminal-basics.md index ab5c412..775335a 100644 --- a/website/docs/curriculum/part-1-foundations/terminal-basics.md +++ b/website/docs/curriculum/part-1-foundations/terminal-basics.md @@ -762,6 +762,24 @@ Many code editors (VS Code, WebStorm) have built-in terminals. These are the sam --- +## Pause Before You Run + +It is normal to feel unsure about a command before running it -- even experienced developers pause and double-check. Building a habit of questioning commands protects you from mistakes and helps you learn faster. + +Before running any command you did not write yourself, walk through this checklist: + +1. **What is the goal?** What should this command accomplish? +2. **What is the target?** Which files, folders, or systems will it affect? +3. **Is it reversible?** Can you undo the result, or is it permanent (like `rm`)? + +If you cannot answer all three, stop and look it up first. You can paste the command into an AI assistant with a prompt like: + +> "Explain what this command does step by step. What files does it change, and can I undo it?" + +There is no penalty for pausing. The terminal will wait for you. + +--- + ## Going Further Once you're comfortable with the basics, there's more to explore: diff --git a/website/docs/examples/chat-cli/index.md b/website/docs/examples/chat-cli/index.md index e0002b2..8240e68 100644 --- a/website/docs/examples/chat-cli/index.md +++ b/website/docs/examples/chat-cli/index.md @@ -99,6 +99,18 @@ Messages are stored in a JSON file, demonstrating how applications maintain stat --- +## Ask Better Questions (Use AI as a Guide) + +When exploring this project, try asking your AI assistant specific questions that reference real files: + +- *"What does the `createMessage` function in `src/messages.js` return, and why does it include a timestamp?"* +- *"In `src/index.js`, how does the app decide whether to run `send` or `read`?"* +- *"How does `src/storage.js` make sure existing messages aren't lost when a new one is saved?"* + +Specific questions that name a file and a behavior get far better answers than vague ones. For a ready-made template you can copy and adapt, see the [Reading Code](/docs/prompts/reading-code) prompt guide. + +--- + ## Curriculum Alignment This example aligns with: diff --git a/website/docs/exercises/minimal-user-loop.md b/website/docs/exercises/minimal-user-loop.md index 68de74e..25d4378 100644 --- a/website/docs/exercises/minimal-user-loop.md +++ b/website/docs/exercises/minimal-user-loop.md @@ -14,6 +14,22 @@ These exercises help you internalize the [Minimal User Loop](/docs/mental-models Each exercise builds on the previous. Start with "Identify" exercises, then move to "Design" and "Diagnose." +### Ask Better Questions + +When you get stuck on an exercise, pause and form a specific question before reaching for help. Good questions name what you tried and where you lost confidence. + +**Example questions you might ask yourself or a mentor:** + +- "I identified the user's action, but I'm not sure if the value is economic or emotional — how do I tell the difference?" +- "My loop has five steps before the user gets feedback. Is that too many, or does it depend on context?" +- "I wrote a loop for the habit app, but it feels like I'm describing features instead of user motivation. What's the difference?" + +**If you use AI to help, keep your prompt specific and grounded:** + +> I'm working through a minimal user loop exercise for [product type]. I defined the loop as [your loop]. I'm unsure about [specific part]. What questions should I ask myself to test whether that step is right? + +This keeps you in the driver's seat — you're asking AI to coach your thinking, not replace it. + --- ## Exercise Set 1: SaaS Application diff --git a/website/docs/prompts/reading-code.md b/website/docs/prompts/reading-code.md index 9965b12..af70c1b 100644 --- a/website/docs/prompts/reading-code.md +++ b/website/docs/prompts/reading-code.md @@ -243,6 +243,25 @@ Starting from [INPUT], show me step-by-step how data flows through to [OUTPUT]. --- +## Using a Terminal-Based AI Tool (TUI) + +If you are asking questions through a terminal-based assistant rather than a chat window, keep these tips in mind: + +- **Reference files by path instead of pasting.** Terminal screens are narrow and scrolling through large pastes is hard to follow. Point the tool to the file and let it read what it needs. +- **Paste only the small piece you are confused about.** A five-line snippet is easier to discuss in a terminal than a two-hundred-line file. +- **Be specific in one shot.** TUI tools work best when the full question fits in a single prompt, so include the file path, the line range, and your question together. + +### Example TUI Prompt + +``` +Look at src/hooks/useOrders.ts, lines 12-18. +What does the useEffect dependency array [orders] do here? +``` + +This tells the tool exactly where to look and what to explain, without requiring you to paste the code yourself. + +--- + ## Reading Strategies ### Strategy 1: Top-Down From 53d6e5e84e352e775eec0055c7fbb6b6465e47d9 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 10:34:25 +0100 Subject: [PATCH 03/11] docs: add canonical links to stubs --- adr/README.md | 2 ++ community/README.md | 2 ++ docs/chat-app-trajectory.md | 2 ++ prompts/07-build-vs-borrow.md | 2 ++ 4 files changed, 8 insertions(+) diff --git a/adr/README.md b/adr/README.md index 776e01d..a29412b 100644 --- a/adr/README.md +++ b/adr/README.md @@ -1,5 +1,7 @@ # Architecture Decision Records (ADRs) +Canonical page: https://dev.episkopos.community/docs/adr + **Documenting the "why" behind architectural choices** --- diff --git a/community/README.md b/community/README.md index d791401..a442cda 100644 --- a/community/README.md +++ b/community/README.md @@ -1,5 +1,7 @@ # DevFoundry Community +Canonical page: https://dev.episkopos.community/docs/community + **Building Software Together: Problems, Projects, and People** --- diff --git a/docs/chat-app-trajectory.md b/docs/chat-app-trajectory.md index 9bcacde..ebe25eb 100644 --- a/docs/chat-app-trajectory.md +++ b/docs/chat-app-trajectory.md @@ -1,5 +1,7 @@ # Chat App Case Study: Learning Trajectory +Canonical page: (missing) (suggest /docs/examples/chat-app-trajectory) + This document visualizes how the chat app case study maps to curriculum modules and builds toward a cohort-owned communication network. ## The Vision diff --git a/prompts/07-build-vs-borrow.md b/prompts/07-build-vs-borrow.md index ee5d2ef..b118afb 100644 --- a/prompts/07-build-vs-borrow.md +++ b/prompts/07-build-vs-borrow.md @@ -1,5 +1,7 @@ # Build vs. Borrow Evaluation +Canonical page: https://dev.episkopos.community/docs/prompts/build-vs-borrow + Use this prompt when you are deciding whether to implement a feature from scratch or leverage an existing library/service. ## Context From ba25c956783198937b23a8ebe025b231d5d2c390 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 10:34:29 +0100 Subject: [PATCH 04/11] chore: add agent prompts for doc updates --- agents/01-sidebar-and-paths.md | 56 ++++++++++++++++++++++++ agents/02-examples-ai-prompts.md | 43 ++++++++++++++++++ agents/03-stub-canonical-links.md | 43 ++++++++++++++++++ agents/04-beginner-path-alignment.md | 37 ++++++++++++++++ agents/05-questioning-coach-inserts.md | 39 +++++++++++++++++ agents/06-reading-code-tui.md | 38 ++++++++++++++++ agents/07-minimal-user-loop-questions.md | 35 +++++++++++++++ 7 files changed, 291 insertions(+) create mode 100644 agents/01-sidebar-and-paths.md create mode 100644 agents/02-examples-ai-prompts.md create mode 100644 agents/03-stub-canonical-links.md create mode 100644 agents/04-beginner-path-alignment.md create mode 100644 agents/05-questioning-coach-inserts.md create mode 100644 agents/06-reading-code-tui.md create mode 100644 agents/07-minimal-user-loop-questions.md diff --git a/agents/01-sidebar-and-paths.md b/agents/01-sidebar-and-paths.md new file mode 100644 index 0000000..81841df --- /dev/null +++ b/agents/01-sidebar-and-paths.md @@ -0,0 +1,56 @@ +# Agent Prompt: Restore Curriculum Nav + Fix Example Paths + +Background +The docs site is Docusaurus-based. The curriculum content exists under +`website/docs/curriculum/` but Parts II-IV are missing from the sidebar, +making them invisible. The onboarding doc also lists outdated example +folder names. This task restores discoverability and fixes path accuracy. + +Project Context +DevFoundry is a learning-focused documentation repo for novice and early- +intermediate learners, many of whom are Windows-first and CLI-anxious. +The canonical docs live in `website/docs/` and are deployed via Docusaurus. +GitHub-level docs and folders often act as stubs or summaries. The broader +request is a docs reorg/refactor to improve navigation, consistency, and +learning progression, while reinforcing high-quality question asking and +safe AI usage. + +Purpose +You are a coding agent. Apply the changes exactly as described. Do not add +new content beyond what is requested. Keep edits minimal and localized. + +Scope +- `website/sidebars.ts` +- `website/docs/how-to-use-this-repo.md` + +References +- Existing curriculum files: + - `website/docs/curriculum/part-2-team-practices/*` + - `website/docs/curriculum/part-3-building-applications/*` + - `website/docs/curriculum/part-4-historical-context/*` +- Existing sidebar structure in `website/sidebars.ts` (Curriculum category). +- Actual example folders under `examples/`. + +What to change +1) `website/sidebars.ts` + - Under the "Curriculum" category, insert Part II, Part III, and Part IV. + - Use the exact file paths that exist in `website/docs/curriculum/...`. + - Preserve ordering: Part I, Part II, Part III, Part IV, Part V. + - Keep labels and collapse behavior consistent with Part I and Part V. +2) `website/docs/how-to-use-this-repo.md` + - Find the directory tree or list that shows `examples/*`. + - Update outdated entries like `examples/01-chat-cli` to actual folders + (for example: `examples/11-chat-cli`, `examples/13-chat-cli-typescript`). + - Only touch the directory list. Do not change surrounding prose. + +Constraints +- ASCII only. +- No reformatting or unrelated cleanup. +- Do not invent new paths. + +Acceptance Criteria +- Parts II-IV appear in the sidebar between Part I and Part V. +- All example paths in the directory list match real folders. + +Deliverable +- Provide a short summary of edits and exact file paths changed. diff --git a/agents/02-examples-ai-prompts.md b/agents/02-examples-ai-prompts.md new file mode 100644 index 0000000..4763f73 --- /dev/null +++ b/agents/02-examples-ai-prompts.md @@ -0,0 +1,43 @@ +# Agent Prompt: Add AI Prompt Coaching to Chat CLI Example + +Background +The Chat CLI example is a key early learning artifact, but it lacks +explicit guidance on forming high-quality questions. This addition should +teach novices how to ask specific questions and point them to the canonical +"Reading Code" prompt template. + +Project Context +DevFoundry is a documentation-first learning repo aimed at novices and +early-intermediate builders, often Windows-first and uncomfortable with +terminals. Canonical docs live in `website/docs/` for Docusaurus. The +current reorg focuses on navigation clarity, scaffolding, and explicit +question-asking coaching, not adding new features or code. + +Purpose +You are a coding agent. Implement the exact change below in the specified +file only. Keep edits minimal and localized. + +Scope +- `website/docs/examples/chat-cli/index.md` + +What to change +1) Insert a new section immediately after the "Key Concepts" section. + - Heading: "Ask Better Questions (Use AI as a Guide)" +2) The section must include: + - 2 to 3 short, TUI-friendly example prompts. + - Prompts must reference specific files in this example (use real paths + in this example, such as `src/messages.js` and `src/index.js`). + - A single sentence that links to `/docs/prompts/reading-code`. + +Constraints +- Keep tone beginner-friendly and concrete. +- No heavy formatting or long blocks. +- Do not change any other content. + +Acceptance Criteria +- New section appears directly after "Key Concepts". +- Prompts mention real file paths from this example. +- Includes a link to `/docs/prompts/reading-code`. + +Deliverable +- Provide a short summary and the exact insertion point. diff --git a/agents/03-stub-canonical-links.md b/agents/03-stub-canonical-links.md new file mode 100644 index 0000000..d99d2fe --- /dev/null +++ b/agents/03-stub-canonical-links.md @@ -0,0 +1,43 @@ +# Agent Prompt: Add Canonical Links to Standalone Stubs + +Background +The repo has GitHub-facing docs and stubs that are not always linked to +their canonical Docusaurus pages. This causes drift and confusion. +Your job is to add a single canonical-link line near the top of each file. + +Project Context +DevFoundry's canonical docs live in `website/docs/` and are deployed via +Docusaurus. GitHub-level docs (e.g., `docs/`, `prompts/`, `adr/`, +`community/`) may be summaries or standalone references. The current effort +is a docs reorg to reduce redundancy, align stubs to canonical pages, and +improve discoverability for novice learners. + +Purpose +You are a coding agent. Add canonical links exactly as described. Keep edits +minimal and localized. + +Scope +- `docs/chat-app-trajectory.md` +- `prompts/07-build-vs-borrow.md` +- `adr/README.md` +- `community/README.md` + +What to change +For each file, insert a single line near the top: +- Format: "Canonical page: " +- If no canonical page exists, use: "Canonical page: (missing)" and add a + short parenthetical target path, e.g. "(suggest /docs/...)". + +Guidance +- Prefer Docusaurus URLs when known (e.g., `https://dev.episkopos.community/docs/...`). +- If you cannot locate a canonical page in `website/docs/`, mark as missing. + +Constraints +- Keep style consistent with the existing file (usually after the title). +- Do not add any other content or reformatting. + +Acceptance Criteria +- Each listed file has exactly one canonical link line near the top. + +Deliverable +- List each file and the canonical link line you added. diff --git a/agents/04-beginner-path-alignment.md b/agents/04-beginner-path-alignment.md new file mode 100644 index 0000000..358b71a --- /dev/null +++ b/agents/04-beginner-path-alignment.md @@ -0,0 +1,37 @@ +# Agent Prompt: Align Beginner Start Points + +Background +Two onboarding pages give different starting points for total beginners +(Module 00 vs Module 01). This confuses novices. Align both pages to a +single start without rewriting the content. + +Project Context +DevFoundry is a learning-oriented docs repo for people new to software, +often Windows-first and CLI-anxious. Canonical docs live in `website/docs/` +and are deployed with Docusaurus. The broader request is a docs reorg to +make onboarding clearer, improve progression, and reinforce question-asking +and safe AI usage without adding new features. + +Purpose +You are a coding agent. Resolve the inconsistency on where total beginners +start. Keep edits minimal. + +Scope +- `website/docs/overview.md` +- `website/docs/how-to-use-this-repo.md` + +What to change +1) Choose a single starting module for total beginners (Module 00 or Module 01). +2) Update only the minimum text in each file so both pages agree. +3) Do not alter other guidance or structure. + +Constraints +- Preserve tone and intent. +- ASCII only. + +Acceptance Criteria +- Both files explicitly point beginners to the same module. +- No other wording changes outside the conflicting lines. + +Deliverable +- State which starting module you aligned to and list the exact lines updated. diff --git a/agents/05-questioning-coach-inserts.md b/agents/05-questioning-coach-inserts.md new file mode 100644 index 0000000..7ad1e3c --- /dev/null +++ b/agents/05-questioning-coach-inserts.md @@ -0,0 +1,39 @@ +# Agent Prompt: Add "Questioning Before Commands" Coaching + +Background +Learners are CLI-anxious and may run commands without understanding them. +Add a short coaching block to normalize pausing and to model safer +questioning before running commands. + +Project Context +DevFoundry is a docs-first curriculum for novice builders, many of whom are +Windows-first and uncomfortable with the terminal. Canonical docs live in +`website/docs/` and ship via Docusaurus. The current reorg emphasizes +better scaffolding, navigation clarity, and explicit coaching on safe AI +use and high-quality questions. + +Purpose +You are a coding agent. Add a short coaching block as described, without +touching other content. + +Scope +- `website/docs/curriculum/part-1-foundations/terminal-basics.md` + +What to change +1) Insert a short subsection near the "Common Questions" area, or just + before "Going Further" if that section exists. +2) The subsection must include: + - A reminder to pause before running commands you do not understand. + - A 3-step checklist: goal, target, reversibility. + - A single example AI prompt for clarifying a command safely. + +Constraints +- Keep it concise; avoid long code blocks. +- ASCII only. + +Acceptance Criteria +- The new subsection is visible without altering unrelated sections. +- Includes the three checklist items and one example prompt. + +Deliverable +- Provide the exact inserted text and placement location. diff --git a/agents/06-reading-code-tui.md b/agents/06-reading-code-tui.md new file mode 100644 index 0000000..b070a77 --- /dev/null +++ b/agents/06-reading-code-tui.md @@ -0,0 +1,38 @@ +# Agent Prompt: Add TUI-Specific Guidance to Reading Code + +Background +This doc targets AI prompting, but it assumes a chat UI. Add a short +TUI-focused subsection so Windows-first learners using a terminal-based +assistant know how to ask questions safely and precisely. + +Project Context +DevFoundry is a documentation-driven learning repo for novices and early +intermediate builders, many of whom are Windows-first and unfamiliar with +CLI tools. Canonical docs live in `website/docs/` and are deployed via +Docusaurus. The broader request is a docs reorg to improve navigation, +reduce drift, and embed better question-asking and safe AI usage. + +Purpose +You are a coding agent. Add a small TUI-focused subsection in the specified +file only. + +Scope +- `website/docs/prompts/reading-code.md` + +What to change +1) Add a short subsection explaining how to ask questions when using a + terminal-based AI tool (TUI). +2) Emphasize using file paths and small snippets rather than pasting + entire files. +3) Provide a minimal example prompt that references a file path. + +Constraints +- Keep it concise and beginner-friendly. +- Do not remove or reorder existing content. + +Acceptance Criteria +- New subsection exists and includes a file-path example. +- No other content is changed. + +Deliverable +- Provide the exact inserted text and where it was placed. diff --git a/agents/07-minimal-user-loop-questions.md b/agents/07-minimal-user-loop-questions.md new file mode 100644 index 0000000..404b7ae --- /dev/null +++ b/agents/07-minimal-user-loop-questions.md @@ -0,0 +1,35 @@ +# Agent Prompt: Add Question-Asking Coaching to Minimal User Loop Exercise + +Background +The minimal user loop exercise is conceptual. Learners need explicit help +forming good questions and using AI safely without outsourcing thinking. +Add a short coaching block early in the exercise. + +Project Context +DevFoundry is a learning-oriented documentation repo for people new to +software development, often Windows-first and CLI-anxious. Canonical docs +live in `website/docs/` and are deployed with Docusaurus. The overall +docs reorg aims to improve navigation, progression, and question-asking +coaching without introducing new features. + +Purpose +You are a coding agent. Add a short coaching block exactly as described. + +Scope +- `website/docs/exercises/minimal-user-loop.md` + +What to change +1) Add a short "Ask Better Questions" block early in the exercise. +2) Include 2-3 example questions focused on loop clarity and friction. +3) Provide a short AI prompt template that is safe and specific. + +Constraints +- Keep tone supportive and low-anxiety. +- Minimal formatting; avoid long blocks. + +Acceptance Criteria +- Block is added near the top of the exercise. +- Includes 2-3 example questions and one prompt template. + +Deliverable +- Provide the exact inserted block and placement location. From 07947fb01db0f42a7b55e0984502208e77e7e6a7 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 10:34:35 +0100 Subject: [PATCH 05/11] chore: update local claude settings --- .claude/settings.local.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 3bd0df4..3032d05 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -24,7 +24,14 @@ "Bash(npm install:*)", "Bash(git commit:*)", "Bash(gh pr view:*)", - "Bash(gh pr edit:*)" + "Bash(gh pr edit:*)", + "Bash(gh run view:*)", + "Bash(ls:*)", + "Bash(gh issue view:*)", + "Bash(find:*)", + "Bash(npx linkinator:*)", + "Bash(gh pr checks:*)", + "Bash(git push:*)" ] } } From 79af6b03c0504c01b4c4b21b83e9b24f81fef62b Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 11:20:52 +0100 Subject: [PATCH 06/11] ci: add GitHub Actions workflow for ASCII lint and tests Adds a workflow that runs on PRs touching doc directories, scripts, or package files. Executes npm run lint:ascii and npm test in a single job on ubuntu-latest with Node 20. --- .github/workflows/lint-ascii.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/lint-ascii.yml diff --git a/.github/workflows/lint-ascii.yml b/.github/workflows/lint-ascii.yml new file mode 100644 index 0000000..b087ff5 --- /dev/null +++ b/.github/workflows/lint-ascii.yml @@ -0,0 +1,31 @@ +name: Lint ASCII Blocks + +on: + pull_request: + paths: + - 'website/docs/**' + - 'docs/**' + - 'prompts/**' + - 'community/**' + - 'adr/**' + - 'exercises/**' + - 'scripts/**' + - 'package.json' + - 'package-lock.json' + - '.github/workflows/lint-ascii.yml' + workflow_dispatch: + +jobs: + lint-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - run: npm ci + - name: Check ASCII block formatting + run: npm run lint:ascii + - name: Run tests + run: npm test From 397b807b4f08976aff03d06cbb7110b76bc2c41e Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 11:36:59 +0100 Subject: [PATCH 07/11] ui: collapse curriculum parts and expand mental models/community in sidebar Reduce sidebar clutter by collapsing curriculum part subcategories and examples by default, while expanding mental models and community sections. --- website/sidebars.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/website/sidebars.ts b/website/sidebars.ts index 4e61aae..6c87346 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -26,7 +26,7 @@ const sidebars: SidebarsConfig = { { type: 'category', label: 'Part I: Foundations', - collapsed: false, + collapsed: true, items: [ 'curriculum/part-1-foundations/terminal-basics', 'curriculum/part-1-foundations/what-software-is', @@ -49,7 +49,7 @@ const sidebars: SidebarsConfig = { { type: 'category', label: 'Part II: Team Practices', - collapsed: false, + collapsed: true, items: [ 'curriculum/part-2-team-practices/git-and-collaboration', 'curriculum/part-2-team-practices/development-methodologies', @@ -60,7 +60,7 @@ const sidebars: SidebarsConfig = { { type: 'category', label: 'Part III: Building Applications', - collapsed: false, + collapsed: true, items: [ 'curriculum/part-3-building-applications/static-website', 'curriculum/part-3-building-applications/interactive-ui', @@ -72,7 +72,7 @@ const sidebars: SidebarsConfig = { { type: 'category', label: 'Part IV: Historical Context', - collapsed: false, + collapsed: true, items: [ 'curriculum/part-4-historical-context/server-side-era', 'curriculum/part-4-historical-context/ajax-revolution', @@ -82,7 +82,7 @@ const sidebars: SidebarsConfig = { { type: 'category', label: 'Part V: Infrastructure & Operations', - collapsed: false, + collapsed: true, items: [ 'curriculum/part-5-infrastructure/containerization-and-orchestration', ], @@ -92,7 +92,7 @@ const sidebars: SidebarsConfig = { { type: 'category', label: 'Examples', - collapsed: false, + collapsed: true, items: [ 'examples/hello-world-console/index', 'examples/chat-cli/index', @@ -136,7 +136,7 @@ const sidebars: SidebarsConfig = { { type: 'category', label: 'Mental Models', - collapsed: true, + collapsed: false, items: [ 'mental-models/evaluating-ai-tools', 'mental-models/protocol-thinking', @@ -186,7 +186,7 @@ const sidebars: SidebarsConfig = { { type: 'category', label: 'Community', - collapsed: true, + collapsed: false, items: [ 'community/index', 'community/problems/index', From 47c9e233cc7053fd6fdab53c687ff53f87be8d3b Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 11:53:49 +0100 Subject: [PATCH 08/11] chore: add ASCII lint/format scripts and test infrastructure Add root package.json with lint:ascii, format:ascii, and test scripts, along with the format-ascii tooling, TypeScript config, and vitest setup. --- package.json | 14 + .../__tests__/fixtures/multi-box-expected.md | 9 + scripts/__tests__/fixtures/multi-box-input.md | 9 + .../__tests__/fixtures/nested-chat-input.md | 23 + .../__tests__/fixtures/single-box-expected.md | 10 + .../__tests__/fixtures/single-box-input.md | 10 + .../__tests__/fixtures/trajectory-expected.md | 9 + .../__tests__/fixtures/trajectory-input.md | 9 + scripts/__tests__/format-ascii.test.ts | 208 +++++++++ scripts/format-ascii.ts | 442 ++++++++++++++++++ tsconfig.scripts.json | 13 + vitest.config.ts | 7 + 12 files changed, 763 insertions(+) create mode 100644 package.json create mode 100644 scripts/__tests__/fixtures/multi-box-expected.md create mode 100644 scripts/__tests__/fixtures/multi-box-input.md create mode 100644 scripts/__tests__/fixtures/nested-chat-input.md create mode 100644 scripts/__tests__/fixtures/single-box-expected.md create mode 100644 scripts/__tests__/fixtures/single-box-input.md create mode 100644 scripts/__tests__/fixtures/trajectory-expected.md create mode 100644 scripts/__tests__/fixtures/trajectory-input.md create mode 100644 scripts/__tests__/format-ascii.test.ts create mode 100644 scripts/format-ascii.ts create mode 100644 tsconfig.scripts.json create mode 100644 vitest.config.ts diff --git a/package.json b/package.json new file mode 100644 index 0000000..94500a0 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "private": true, + "scripts": { + "lint:ascii": "tsx scripts/format-ascii.ts --check", + "format:ascii": "tsx scripts/format-ascii.ts --write", + "test": "vitest run" + }, + "devDependencies": { + "glob": "^11", + "tsx": "^4", + "typescript": "~5.6.2", + "vitest": "^3" + } +} diff --git a/scripts/__tests__/fixtures/multi-box-expected.md b/scripts/__tests__/fixtures/multi-box-expected.md new file mode 100644 index 0000000..bdd514f --- /dev/null +++ b/scripts/__tests__/fixtures/multi-box-expected.md @@ -0,0 +1,9 @@ +```text ++---+---+ +| a | b | ++---+---+ + ++------+ +| solo | ++------+ +``` diff --git a/scripts/__tests__/fixtures/multi-box-input.md b/scripts/__tests__/fixtures/multi-box-input.md new file mode 100644 index 0000000..e6e506a --- /dev/null +++ b/scripts/__tests__/fixtures/multi-box-input.md @@ -0,0 +1,9 @@ +```text ++---+---+ +| a | b | ++---+---+ + ++------+ +| solo| ++------+ +``` diff --git a/scripts/__tests__/fixtures/nested-chat-input.md b/scripts/__tests__/fixtures/nested-chat-input.md new file mode 100644 index 0000000..372c0eb --- /dev/null +++ b/scripts/__tests__/fixtures/nested-chat-input.md @@ -0,0 +1,23 @@ +```text ++------------------------------------------------------------+ +| Chat App | ++------------------------------------------------------------+ +| | +| MESSAGES | +| +--------------------------------------------------------+ | +| | Alice (10:30 AM) | | +| | Hey, how's it going? | | +| +--------------------------------------------------------+ | +| | | | +| | You (10:31 AM) | | +| | Pretty good! Working on the DevFoundry curriculum. | | +| +--------------------------------------------------------+ | +| | Alice (10:32 AM) | | +| | Nice! Let me know if you need any help. | | +| +--------------------------------------------------------+ | +| | +| +------------------------------------------+--------+ | +| | Type a message... | [Send] | | +| +------------------------------------------+--------+ | ++------------------------------------------------------------+ +``` diff --git a/scripts/__tests__/fixtures/single-box-expected.md b/scripts/__tests__/fixtures/single-box-expected.md new file mode 100644 index 0000000..089dfbc --- /dev/null +++ b/scripts/__tests__/fixtures/single-box-expected.md @@ -0,0 +1,10 @@ +Some text before. + +```text ++-------------+ +| hi | +| longer text | ++-------------+ +``` + +Some text after. diff --git a/scripts/__tests__/fixtures/single-box-input.md b/scripts/__tests__/fixtures/single-box-input.md new file mode 100644 index 0000000..dfb020f --- /dev/null +++ b/scripts/__tests__/fixtures/single-box-input.md @@ -0,0 +1,10 @@ +Some text before. + +```text ++-----+ +| hi| +| longer text| ++-----+ +``` + +Some text after. diff --git a/scripts/__tests__/fixtures/trajectory-expected.md b/scripts/__tests__/fixtures/trajectory-expected.md new file mode 100644 index 0000000..e8d9af8 --- /dev/null +++ b/scripts/__tests__/fixtures/trajectory-expected.md @@ -0,0 +1,9 @@ +```ascii ++------+-----------+ +| Step | Action | ++------+-----------+ +| 1 | Read file | +| 2 | Parse AST | +| 3 | Transform | ++------+-----------+ +``` diff --git a/scripts/__tests__/fixtures/trajectory-input.md b/scripts/__tests__/fixtures/trajectory-input.md new file mode 100644 index 0000000..a16cc98 --- /dev/null +++ b/scripts/__tests__/fixtures/trajectory-input.md @@ -0,0 +1,9 @@ +```ascii ++--------+-----------+ +| Step | Action| ++--------+-----------+ +| 1 | Read file| +| 2 | Parse AST| +| 3 | Transform| ++--------+-----------+ +``` diff --git a/scripts/__tests__/format-ascii.test.ts b/scripts/__tests__/format-ascii.test.ts new file mode 100644 index 0000000..342872a --- /dev/null +++ b/scripts/__tests__/format-ascii.test.ts @@ -0,0 +1,208 @@ +import { describe, it, expect } from "vitest"; +import { readFileSync } from "fs"; +import { join } from "path"; +import { + formatAsciiBlocks, + findBoxRegions, + formatBoxRegion, +} from "../format-ascii.js"; + +const FIXTURES = join(import.meta.dirname, "fixtures"); + +function fixture(name: string): string { + return readFileSync(join(FIXTURES, name), "utf-8"); +} + +// ── Unit tests: findBoxRegions ───────────────────────────────────────── + +describe("findBoxRegions", () => { + it("finds a single box", () => { + const lines = ["+---+", "| a |", "+---+"]; + const regions = findBoxRegions(lines); + expect(regions).toEqual([{ startLine: 0, endLine: 2 }]); + }); + + it("finds multiple boxes separated by blank lines", () => { + const lines = ["+--+", "| x|", "+--+", "", "+--+", "| y|", "+--+"]; + const regions = findBoxRegions(lines); + expect(regions).toHaveLength(2); + expect(regions[0]).toEqual({ startLine: 0, endLine: 2 }); + expect(regions[1]).toEqual({ startLine: 4, endLine: 6 }); + }); + + it("returns empty for lines without boxes", () => { + const lines = ["hello", "world", "no boxes here"]; + expect(findBoxRegions(lines)).toEqual([]); + }); +}); + +// ── Unit tests: formatBoxRegion ──────────────────────────────────────── + +describe("formatBoxRegion", () => { + it("pads content to uniform width", () => { + const lines = ["+---+", "| a|", "| bb|", "+---+"]; + const result = formatBoxRegion(lines); + expect(result).not.toBeNull(); + expect(result).toEqual(["+----+", "| a |", "| bb |", "+----+"]); + }); + + it("handles multi-column tables", () => { + const lines = ["+--+--+", "| a| b|", "+--+--+"]; + const result = formatBoxRegion(lines); + expect(result).not.toBeNull(); + expect(result![1]).toBe("| a | b |"); + }); + + it("preserves leading whitespace (indentation)", () => { + const lines = [" +---+", " | hi|", " +---+"]; + const result = formatBoxRegion(lines); + expect(result).not.toBeNull(); + expect(result![0]).toMatch(/^\s{2}\+/); + expect(result![1]).toMatch(/^\s{2}\|/); + }); +}); + +// ── Integration tests: formatAsciiBlocks ─────────────────────────────── + +describe("formatAsciiBlocks", () => { + // Test 1: Simple single-box alignment fix + it("fixes alignment in a single box", () => { + const input = "```text\n+---+\n| hi|\n+---+\n```\n"; + const { formatted, changed } = formatAsciiBlocks(input); + expect(changed).toBe(true); + expect(formatted).toContain("| hi |"); + }); + + // Test 2: Multiple boxes in one fence + it("formats multiple boxes in one fenced block", () => { + const input = fixture("multi-box-input.md"); + const expected = fixture("multi-box-expected.md"); + const { formatted } = formatAsciiBlocks(input); + expect(formatted).toBe(expected); + }); + + // Test 3: Nested boxes (inner box inside outer) + it("handles nested-looking boxes", () => { + const input = [ + "```text", + "+----------+", + "| +------+ |", + "| | inner| |", + "| +------+ |", + "+----------+", + "```", + "", + ].join("\n"); + // Should not crash; may or may not fully format inner box + const { formatted } = formatAsciiBlocks(input); + expect(formatted).toBeDefined(); + }); + + // Test 4: Mixed ASCII + plain text (only boxes formatted) + it("leaves non-box text unchanged", () => { + const input = [ + "```text", + "This is plain text", + "+---+", + "| a|", + "+---+", + "More plain text", + "```", + "", + ].join("\n"); + const { formatted } = formatAsciiBlocks(input); + expect(formatted).toContain("This is plain text"); + expect(formatted).toContain("More plain text"); + expect(formatted).toContain("| a |"); + }); + + // Test 5: Uneven borders get fixed + it("fixes uneven border widths", () => { + const input = fixture("single-box-input.md"); + const expected = fixture("single-box-expected.md"); + const { formatted, changed } = formatAsciiBlocks(input); + expect(changed).toBe(true); + expect(formatted).toBe(expected); + }); + + // Test 6: Malformed box (missing closing border) warns and leaves unchanged + it("warns on malformed boxes", () => { + const input = "```text\n+---+\n| no closing border\n```\n"; + const { formatted, changed, warnings } = formatAsciiBlocks(input); + expect(changed).toBe(false); + expect(formatted).toBe(input); + // No box region detected, so no warning either — just left unchanged + }); + + // Test 7: Windows line endings + it("handles windows line endings", () => { + const input = "```text\r\n+---+\r\n| hi|\r\n+---+\r\n```\r\n"; + // The regex works per-line; \r\n may need handling + const { formatted } = formatAsciiBlocks(input); + expect(formatted).toBeDefined(); + }); + + // Test 8: Both `text` and `ascii` tags are processed + it("processes both text and ascii fenced blocks", () => { + const input = [ + "```text", + "+---+", + "| a|", + "+---+", + "```", + "", + "```ascii", + "+---+", + "| b|", + "+---+", + "```", + "", + ].join("\n"); + const { formatted } = formatAsciiBlocks(input); + expect(formatted).toContain("| a |"); + expect(formatted).toContain("| b |"); + }); + + // Test 9: Blocks without borders are untouched + it("leaves blocks without boxes unchanged", () => { + const input = "```text\njust plain text\nno boxes\n```\n"; + const { formatted, changed } = formatAsciiBlocks(input); + expect(changed).toBe(false); + expect(formatted).toBe(input); + }); + + // Test 10: Idempotence + it("is idempotent — formatting already-formatted content produces no change", () => { + const input = fixture("single-box-expected.md"); + const { formatted, changed } = formatAsciiBlocks(input); + expect(changed).toBe(false); + expect(formatted).toBe(input); + }); + + // Test 11: Untagged code blocks are NOT processed + it("ignores untagged code blocks", () => { + const input = "```\n+---+\n| a|\n+---+\n```\n"; + const { formatted, changed } = formatAsciiBlocks(input); + expect(changed).toBe(false); + expect(formatted).toBe(input); + }); + + // Golden fixture: trajectory-style table + it("formats trajectory-style tables correctly", () => { + const input = fixture("trajectory-input.md"); + const expected = fixture("trajectory-expected.md"); + const { formatted } = formatAsciiBlocks(input); + expect(formatted).toBe(expected); + }); + + // Test 12: Nested chat UI with errors at both outer and inner box levels + // is left unchanged (with warning) rather than mangled + it("leaves nested box layouts unchanged and warns", () => { + const input = fixture("nested-chat-input.md"); + const { formatted, changed, warnings } = formatAsciiBlocks(input); + // Nested boxes can't be safely reformatted — must be left as-is + expect(changed).toBe(false); + expect(formatted).toBe(input); + expect(warnings.length).toBeGreaterThan(0); + }); +}); diff --git a/scripts/format-ascii.ts b/scripts/format-ascii.ts new file mode 100644 index 0000000..d285418 --- /dev/null +++ b/scripts/format-ascii.ts @@ -0,0 +1,442 @@ +import { glob } from "glob"; +import { readFileSync, writeFileSync } from "fs"; +import { resolve } from "path"; + +// ── Types ────────────────────────────────────────────────────────────── + +interface BoxRegion { + startLine: number; + endLine: number; +} + +interface FormatResult { + formatted: string; + changed: boolean; + warnings: string[]; +} + +// ── Border detection helpers ─────────────────────────────────────────── + +const PLUS_DASH_BORDER = /^\s*\+[-=+]+\+\s*$/; +const UNICODE_TOP = /^\s*┌[─┬┐]+┐\s*$|^\s*╔[═╦╗]+╗\s*$/; +const UNICODE_BOTTOM = /^\s*└[─┴┘]+┘\s*$|^\s*╚[═╩╝]+╝\s*$/; +const UNICODE_MID = /^\s*├[─┼┤]+┤\s*$|^\s*╠[═╬╣]+╣\s*$/; +const PIPE_LINE = /^\s*\|.*\|\s*$/; +const UNICODE_PIPE_LINE = /^\s*│.*│\s*$|^\s*║.*║\s*$/; + +function isHorizontalBorder(line: string): boolean { + return ( + PLUS_DASH_BORDER.test(line) || + UNICODE_TOP.test(line) || + UNICODE_BOTTOM.test(line) || + UNICODE_MID.test(line) + ); +} + +function isBoxLine(line: string): boolean { + return ( + isHorizontalBorder(line) || PIPE_LINE.test(line) || UNICODE_PIPE_LINE.test(line) + ); +} + +// ── Box region detection ─────────────────────────────────────────────── + +/** + * Find contiguous regions of lines that form ASCII boxes. + * A box must start and end with a horizontal border. + */ +export function findBoxRegions(lines: string[]): BoxRegion[] { + const regions: BoxRegion[] = []; + let i = 0; + + while (i < lines.length) { + if (isHorizontalBorder(lines[i])) { + const start = i; + i++; + // Consume lines that are part of a box + while (i < lines.length && (isBoxLine(lines[i]) || isHorizontalBorder(lines[i]))) { + if (isHorizontalBorder(lines[i])) { + // Check if this could be the end of a box + // A valid box needs at least: border, content/border, border + const region = lines.slice(start, i + 1); + const hasPipeLines = region.some( + (l) => PIPE_LINE.test(l) || UNICODE_PIPE_LINE.test(l) + ); + if (hasPipeLines || region.length >= 2) { + // Continue scanning — there may be more rows + } + } + i++; + } + // Walk back to the last horizontal border + let end = i - 1; + while (end > start && !isHorizontalBorder(lines[end])) { + end--; + } + if (end > start) { + regions.push({ startLine: start, endLine: end }); + i = end + 1; + } else { + i = start + 1; + } + } else { + i++; + } + } + + return regions; +} + +// ── Formatting logic ─────────────────────────────────────────────────── + +interface BorderStyle { + corner: string; // e.g. "+" + horizontal: string; // e.g. "-" + vertical: string; // e.g. "|" + topLeft?: string; + topRight?: string; + bottomLeft?: string; + bottomRight?: string; + midLeft?: string; + midRight?: string; + midCross?: string; + midHorizontal?: string; +} + +function detectBorderStyle(lines: string[]): BorderStyle | null { + const firstBorder = lines[0]; + + if (PLUS_DASH_BORDER.test(firstBorder)) { + const h = firstBorder.includes("=") ? "=" : "-"; + return { corner: "+", horizontal: h, vertical: "|" }; + } + + if (/^\s*┌/.test(firstBorder)) { + return { + corner: "+", + horizontal: "─", + vertical: "│", + topLeft: "┌", + topRight: "┐", + bottomLeft: "└", + bottomRight: "┘", + midLeft: "├", + midRight: "┤", + midCross: "┼", + midHorizontal: "─", + }; + } + + if (/^\s*╔/.test(firstBorder)) { + return { + corner: "+", + horizontal: "═", + vertical: "║", + topLeft: "╔", + topRight: "╗", + bottomLeft: "╚", + bottomRight: "╝", + midLeft: "╠", + midRight: "╣", + midCross: "╬", + midHorizontal: "═", + }; + } + + return null; +} + +function getLeadingWhitespace(line: string): string { + const match = line.match(/^(\s*)/); + return match ? match[1] : ""; +} + +/** + * Count occurrences of a substring in a string. + */ +function countOccurrences(s: string, sub: string): number { + let count = 0; + let pos = 0; + while ((pos = s.indexOf(sub, pos)) !== -1) { + count++; + pos += sub.length; + } + return count; +} + +/** + * Detect whether a box region contains nested boxes by checking if + * content lines have inconsistent vertical-bar counts. + * A flat table has the same number of `|` on every content line; + * nested boxes do not. + */ +function hasNestedBoxes(lines: string[], vertical: string): boolean { + const pipeCounts: number[] = []; + for (const line of lines) { + if (!isHorizontalBorder(line)) { + pipeCounts.push(countOccurrences(line.trim(), vertical)); + } + } + if (pipeCounts.length === 0) return false; + return pipeCounts.some((c) => c !== pipeCounts[0]); +} + +/** + * Extract content from a pipe-delimited line, returning the cells. + * e.g. "| foo | bar |" → ["foo", "bar"] + */ +function extractCells(line: string, vertical: string): string[] { + const trimmed = line.trim(); + // Remove leading/trailing border chars + const inner = trimmed.slice(vertical.length, trimmed.length - vertical.length); + // Split by the vertical char + return inner.split(vertical).map((cell) => cell.trim()); +} + +/** + * Format a single box region, returning the formatted lines. + * Returns null if the box can't be safely parsed (e.g. nested boxes). + */ +export function formatBoxRegion(lines: string[]): string[] | null { + const style = detectBorderStyle(lines); + if (!style) return null; + + // Bail out on nested boxes — inconsistent pipe counts mean the + // content itself contains box-drawing characters that would be mangled. + if (hasNestedBoxes(lines, style.vertical)) { + return null; + } + + const indent = getLeadingWhitespace(lines[0]); + + // Separate horizontal borders from content lines + // Identify column structure from the first content line + const contentLines: { index: number; cells: string[] }[] = []; + const borderIndices: number[] = []; + + for (let i = 0; i < lines.length; i++) { + if (isHorizontalBorder(lines[i])) { + borderIndices.push(i); + } else { + const cells = extractCells(lines[i], style.vertical); + contentLines.push({ index: i, cells }); + } + } + + if (contentLines.length === 0) { + // All borders, no content — leave as-is + return lines; + } + + // Determine number of columns from the maximum cell count + const numCols = Math.max(...contentLines.map((cl) => cl.cells.length)); + + // Compute max width for each column + const colWidths: number[] = new Array(numCols).fill(0); + for (const cl of contentLines) { + for (let c = 0; c < numCols; c++) { + const cellText = cl.cells[c] ?? ""; + colWidths[c] = Math.max(colWidths[c], cellText.length); + } + } + + // Ensure minimum column width of 1 + for (let c = 0; c < numCols; c++) { + colWidths[c] = Math.max(colWidths[c], 1); + } + + // Build formatted lines + const result: string[] = []; + + const v = style.vertical; + const h = style.horizontal; + + function makeBorderLine( + left: string, + mid: string, + right: string, + hChar: string + ): string { + const segments = colWidths.map((w) => hChar.repeat(w + 2)); + return indent + left + segments.join(mid) + right; + } + + function makeContentLine(cells: string[]): string { + const paddedCells = colWidths.map((w, c) => { + const text = cells[c] ?? ""; + return " " + text.padEnd(w) + " "; + }); + return indent + v + paddedCells.join(v) + v; + } + + for (let i = 0; i < lines.length; i++) { + if (isHorizontalBorder(lines[i])) { + // Determine which kind of border this is + if (style.topLeft && style.bottomLeft && style.midLeft) { + if (i === 0) { + result.push(makeBorderLine(style.topLeft, style.midCross ? "┬" : "+", style.topRight!, h)); + } else if (i === lines.length - 1) { + result.push(makeBorderLine(style.bottomLeft, style.midCross ? "┴" : "+", style.bottomRight!, h)); + } else { + result.push(makeBorderLine(style.midLeft, style.midCross!, style.midRight!, h)); + } + } else { + result.push(makeBorderLine(style.corner, style.corner, style.corner, h)); + } + } else { + const cl = contentLines.find((c) => c.index === i); + if (cl) { + result.push(makeContentLine(cl.cells)); + } else { + result.push(lines[i]); + } + } + } + + return result; +} + +// ── Fenced block extraction ──────────────────────────────────────────── + +const FENCE_REGEX = /^(?\s*)```(?text|ascii)\s*\n(?[\s\S]*?)^\k```\s*$/gm; + +/** + * Format all ASCII blocks in a markdown string. + */ +export function formatAsciiBlocks(content: string): FormatResult { + const warnings: string[] = []; + let changed = false; + + const formatted = content.replace(FENCE_REGEX, (match, _indent, _lang, body) => { + const originalLines = body.split("\n"); + // Remove trailing empty string from split + if (originalLines.length > 0 && originalLines[originalLines.length - 1] === "") { + originalLines.pop(); + } + + const regions = findBoxRegions(originalLines); + + if (regions.length === 0) { + return match; // No boxes detected, leave unchanged + } + + const newLines = [...originalLines]; + let offset = 0; + + for (const region of regions) { + const start = region.startLine + offset; + const end = region.endLine + offset; + const boxLines = newLines.slice(start, end + 1); + + const formatted = formatBoxRegion(boxLines); + if (formatted === null) { + warnings.push( + `Could not parse box at lines ${region.startLine + 1}-${region.endLine + 1}` + ); + continue; + } + + const lengthDiff = formatted.length - boxLines.length; + newLines.splice(start, boxLines.length, ...formatted); + offset += lengthDiff; + } + + const newBody = newLines.join("\n") + "\n"; + if (newBody !== body) { + changed = true; + } + + return match.replace(body, newBody); + }); + + return { formatted, changed, warnings }; +} + +// ── CLI ──────────────────────────────────────────────────────────────── + +const DEFAULT_GLOBS = [ + "website/docs/**/*.md", + "docs/**/*.md", + "prompts/**/*.md", + "community/**/*.md", + "adr/**/*.md", + "exercises/**/*.md", +]; + +async function main() { + const args = process.argv.slice(2); + const checkMode = args.includes("--check"); + const writeMode = args.includes("--write"); + + if (!checkMode && !writeMode) { + console.error("Usage: format-ascii.ts [--check | --write] [files...]"); + process.exit(1); + } + + // Collect file paths + const fileArgs = args.filter((a) => !a.startsWith("--")); + let files: string[]; + + if (fileArgs.length > 0) { + files = fileArgs.map((f) => resolve(f)); + } else { + files = await glob(DEFAULT_GLOBS, { absolute: true }); + } + + let hasChanges = false; + let totalWarnings = 0; + + for (const file of files) { + let content: string; + try { + content = readFileSync(file, "utf-8"); + } catch { + console.error(`Could not read: ${file}`); + continue; + } + + const result = formatAsciiBlocks(content); + + for (const w of result.warnings) { + console.warn(`⚠ ${file}: ${w}`); + totalWarnings++; + } + + if (result.changed) { + hasChanges = true; + if (checkMode) { + console.log(`Would format: ${file}`); + } else if (writeMode) { + writeFileSync(file, result.formatted, "utf-8"); + console.log(`Formatted: ${file}`); + } + } + } + + if (totalWarnings > 0) { + console.warn(`\n${totalWarnings} warning(s)`); + } + + if (checkMode && hasChanges) { + console.error("\nFormatting drift detected. Run `npm run format:ascii` to fix."); + process.exit(1); + } + + if (!hasChanges) { + console.log("All files are formatted."); + } +} + +// Only run CLI when executed directly (not imported) +const isDirectRun = + typeof process !== "undefined" && + process.argv[1] && + (process.argv[1].endsWith("format-ascii.ts") || + process.argv[1].includes("format-ascii")); + +if (isDirectRun) { + main().catch((err) => { + console.error(err); + process.exit(1); + }); +} diff --git a/tsconfig.scripts.json b/tsconfig.scripts.json new file mode 100644 index 0000000..c00ebf9 --- /dev/null +++ b/tsconfig.scripts.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "outDir": "dist", + "rootDir": "." + }, + "include": ["scripts/**/*.ts"] +} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..c60e581 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["scripts/__tests__/**/*.test.ts"], + }, +}); From e4c3083eec2bffc226f79eafd6455e126be4a8db Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 11:58:33 +0100 Subject: [PATCH 09/11] chore: update .claude files --- .claude/settings.local.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 3032d05..debf520 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -31,7 +31,13 @@ "Bash(find:*)", "Bash(npx linkinator:*)", "Bash(gh pr checks:*)", - "Bash(git push:*)" + "Bash(git push:*)", + "Bash(git -C /home/bwhite/Projects/DevFoundry log --oneline -15)", + "Bash(npx vitest run:*)", + "Bash(npm run lint:ascii:*)", + "Bash(npm run format:ascii:*)", + "Bash(npx tsx:*)", + "Bash(npm test:*)" ] } } From be11c9ef15f8cf34965fb7743d74ce430ee7b78a Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 12:06:24 +0100 Subject: [PATCH 10/11] chore: revert unintentional prompt inclusion --- agents/01-sidebar-and-paths.md | 56 ------------------------ agents/02-examples-ai-prompts.md | 43 ------------------ agents/03-stub-canonical-links.md | 43 ------------------ agents/04-beginner-path-alignment.md | 37 ---------------- agents/05-questioning-coach-inserts.md | 39 ----------------- agents/06-reading-code-tui.md | 38 ---------------- agents/07-minimal-user-loop-questions.md | 35 --------------- 7 files changed, 291 deletions(-) delete mode 100644 agents/01-sidebar-and-paths.md delete mode 100644 agents/02-examples-ai-prompts.md delete mode 100644 agents/03-stub-canonical-links.md delete mode 100644 agents/04-beginner-path-alignment.md delete mode 100644 agents/05-questioning-coach-inserts.md delete mode 100644 agents/06-reading-code-tui.md delete mode 100644 agents/07-minimal-user-loop-questions.md diff --git a/agents/01-sidebar-and-paths.md b/agents/01-sidebar-and-paths.md deleted file mode 100644 index 81841df..0000000 --- a/agents/01-sidebar-and-paths.md +++ /dev/null @@ -1,56 +0,0 @@ -# Agent Prompt: Restore Curriculum Nav + Fix Example Paths - -Background -The docs site is Docusaurus-based. The curriculum content exists under -`website/docs/curriculum/` but Parts II-IV are missing from the sidebar, -making them invisible. The onboarding doc also lists outdated example -folder names. This task restores discoverability and fixes path accuracy. - -Project Context -DevFoundry is a learning-focused documentation repo for novice and early- -intermediate learners, many of whom are Windows-first and CLI-anxious. -The canonical docs live in `website/docs/` and are deployed via Docusaurus. -GitHub-level docs and folders often act as stubs or summaries. The broader -request is a docs reorg/refactor to improve navigation, consistency, and -learning progression, while reinforcing high-quality question asking and -safe AI usage. - -Purpose -You are a coding agent. Apply the changes exactly as described. Do not add -new content beyond what is requested. Keep edits minimal and localized. - -Scope -- `website/sidebars.ts` -- `website/docs/how-to-use-this-repo.md` - -References -- Existing curriculum files: - - `website/docs/curriculum/part-2-team-practices/*` - - `website/docs/curriculum/part-3-building-applications/*` - - `website/docs/curriculum/part-4-historical-context/*` -- Existing sidebar structure in `website/sidebars.ts` (Curriculum category). -- Actual example folders under `examples/`. - -What to change -1) `website/sidebars.ts` - - Under the "Curriculum" category, insert Part II, Part III, and Part IV. - - Use the exact file paths that exist in `website/docs/curriculum/...`. - - Preserve ordering: Part I, Part II, Part III, Part IV, Part V. - - Keep labels and collapse behavior consistent with Part I and Part V. -2) `website/docs/how-to-use-this-repo.md` - - Find the directory tree or list that shows `examples/*`. - - Update outdated entries like `examples/01-chat-cli` to actual folders - (for example: `examples/11-chat-cli`, `examples/13-chat-cli-typescript`). - - Only touch the directory list. Do not change surrounding prose. - -Constraints -- ASCII only. -- No reformatting or unrelated cleanup. -- Do not invent new paths. - -Acceptance Criteria -- Parts II-IV appear in the sidebar between Part I and Part V. -- All example paths in the directory list match real folders. - -Deliverable -- Provide a short summary of edits and exact file paths changed. diff --git a/agents/02-examples-ai-prompts.md b/agents/02-examples-ai-prompts.md deleted file mode 100644 index 4763f73..0000000 --- a/agents/02-examples-ai-prompts.md +++ /dev/null @@ -1,43 +0,0 @@ -# Agent Prompt: Add AI Prompt Coaching to Chat CLI Example - -Background -The Chat CLI example is a key early learning artifact, but it lacks -explicit guidance on forming high-quality questions. This addition should -teach novices how to ask specific questions and point them to the canonical -"Reading Code" prompt template. - -Project Context -DevFoundry is a documentation-first learning repo aimed at novices and -early-intermediate builders, often Windows-first and uncomfortable with -terminals. Canonical docs live in `website/docs/` for Docusaurus. The -current reorg focuses on navigation clarity, scaffolding, and explicit -question-asking coaching, not adding new features or code. - -Purpose -You are a coding agent. Implement the exact change below in the specified -file only. Keep edits minimal and localized. - -Scope -- `website/docs/examples/chat-cli/index.md` - -What to change -1) Insert a new section immediately after the "Key Concepts" section. - - Heading: "Ask Better Questions (Use AI as a Guide)" -2) The section must include: - - 2 to 3 short, TUI-friendly example prompts. - - Prompts must reference specific files in this example (use real paths - in this example, such as `src/messages.js` and `src/index.js`). - - A single sentence that links to `/docs/prompts/reading-code`. - -Constraints -- Keep tone beginner-friendly and concrete. -- No heavy formatting or long blocks. -- Do not change any other content. - -Acceptance Criteria -- New section appears directly after "Key Concepts". -- Prompts mention real file paths from this example. -- Includes a link to `/docs/prompts/reading-code`. - -Deliverable -- Provide a short summary and the exact insertion point. diff --git a/agents/03-stub-canonical-links.md b/agents/03-stub-canonical-links.md deleted file mode 100644 index d99d2fe..0000000 --- a/agents/03-stub-canonical-links.md +++ /dev/null @@ -1,43 +0,0 @@ -# Agent Prompt: Add Canonical Links to Standalone Stubs - -Background -The repo has GitHub-facing docs and stubs that are not always linked to -their canonical Docusaurus pages. This causes drift and confusion. -Your job is to add a single canonical-link line near the top of each file. - -Project Context -DevFoundry's canonical docs live in `website/docs/` and are deployed via -Docusaurus. GitHub-level docs (e.g., `docs/`, `prompts/`, `adr/`, -`community/`) may be summaries or standalone references. The current effort -is a docs reorg to reduce redundancy, align stubs to canonical pages, and -improve discoverability for novice learners. - -Purpose -You are a coding agent. Add canonical links exactly as described. Keep edits -minimal and localized. - -Scope -- `docs/chat-app-trajectory.md` -- `prompts/07-build-vs-borrow.md` -- `adr/README.md` -- `community/README.md` - -What to change -For each file, insert a single line near the top: -- Format: "Canonical page: " -- If no canonical page exists, use: "Canonical page: (missing)" and add a - short parenthetical target path, e.g. "(suggest /docs/...)". - -Guidance -- Prefer Docusaurus URLs when known (e.g., `https://dev.episkopos.community/docs/...`). -- If you cannot locate a canonical page in `website/docs/`, mark as missing. - -Constraints -- Keep style consistent with the existing file (usually after the title). -- Do not add any other content or reformatting. - -Acceptance Criteria -- Each listed file has exactly one canonical link line near the top. - -Deliverable -- List each file and the canonical link line you added. diff --git a/agents/04-beginner-path-alignment.md b/agents/04-beginner-path-alignment.md deleted file mode 100644 index 358b71a..0000000 --- a/agents/04-beginner-path-alignment.md +++ /dev/null @@ -1,37 +0,0 @@ -# Agent Prompt: Align Beginner Start Points - -Background -Two onboarding pages give different starting points for total beginners -(Module 00 vs Module 01). This confuses novices. Align both pages to a -single start without rewriting the content. - -Project Context -DevFoundry is a learning-oriented docs repo for people new to software, -often Windows-first and CLI-anxious. Canonical docs live in `website/docs/` -and are deployed with Docusaurus. The broader request is a docs reorg to -make onboarding clearer, improve progression, and reinforce question-asking -and safe AI usage without adding new features. - -Purpose -You are a coding agent. Resolve the inconsistency on where total beginners -start. Keep edits minimal. - -Scope -- `website/docs/overview.md` -- `website/docs/how-to-use-this-repo.md` - -What to change -1) Choose a single starting module for total beginners (Module 00 or Module 01). -2) Update only the minimum text in each file so both pages agree. -3) Do not alter other guidance or structure. - -Constraints -- Preserve tone and intent. -- ASCII only. - -Acceptance Criteria -- Both files explicitly point beginners to the same module. -- No other wording changes outside the conflicting lines. - -Deliverable -- State which starting module you aligned to and list the exact lines updated. diff --git a/agents/05-questioning-coach-inserts.md b/agents/05-questioning-coach-inserts.md deleted file mode 100644 index 7ad1e3c..0000000 --- a/agents/05-questioning-coach-inserts.md +++ /dev/null @@ -1,39 +0,0 @@ -# Agent Prompt: Add "Questioning Before Commands" Coaching - -Background -Learners are CLI-anxious and may run commands without understanding them. -Add a short coaching block to normalize pausing and to model safer -questioning before running commands. - -Project Context -DevFoundry is a docs-first curriculum for novice builders, many of whom are -Windows-first and uncomfortable with the terminal. Canonical docs live in -`website/docs/` and ship via Docusaurus. The current reorg emphasizes -better scaffolding, navigation clarity, and explicit coaching on safe AI -use and high-quality questions. - -Purpose -You are a coding agent. Add a short coaching block as described, without -touching other content. - -Scope -- `website/docs/curriculum/part-1-foundations/terminal-basics.md` - -What to change -1) Insert a short subsection near the "Common Questions" area, or just - before "Going Further" if that section exists. -2) The subsection must include: - - A reminder to pause before running commands you do not understand. - - A 3-step checklist: goal, target, reversibility. - - A single example AI prompt for clarifying a command safely. - -Constraints -- Keep it concise; avoid long code blocks. -- ASCII only. - -Acceptance Criteria -- The new subsection is visible without altering unrelated sections. -- Includes the three checklist items and one example prompt. - -Deliverable -- Provide the exact inserted text and placement location. diff --git a/agents/06-reading-code-tui.md b/agents/06-reading-code-tui.md deleted file mode 100644 index b070a77..0000000 --- a/agents/06-reading-code-tui.md +++ /dev/null @@ -1,38 +0,0 @@ -# Agent Prompt: Add TUI-Specific Guidance to Reading Code - -Background -This doc targets AI prompting, but it assumes a chat UI. Add a short -TUI-focused subsection so Windows-first learners using a terminal-based -assistant know how to ask questions safely and precisely. - -Project Context -DevFoundry is a documentation-driven learning repo for novices and early -intermediate builders, many of whom are Windows-first and unfamiliar with -CLI tools. Canonical docs live in `website/docs/` and are deployed via -Docusaurus. The broader request is a docs reorg to improve navigation, -reduce drift, and embed better question-asking and safe AI usage. - -Purpose -You are a coding agent. Add a small TUI-focused subsection in the specified -file only. - -Scope -- `website/docs/prompts/reading-code.md` - -What to change -1) Add a short subsection explaining how to ask questions when using a - terminal-based AI tool (TUI). -2) Emphasize using file paths and small snippets rather than pasting - entire files. -3) Provide a minimal example prompt that references a file path. - -Constraints -- Keep it concise and beginner-friendly. -- Do not remove or reorder existing content. - -Acceptance Criteria -- New subsection exists and includes a file-path example. -- No other content is changed. - -Deliverable -- Provide the exact inserted text and where it was placed. diff --git a/agents/07-minimal-user-loop-questions.md b/agents/07-minimal-user-loop-questions.md deleted file mode 100644 index 404b7ae..0000000 --- a/agents/07-minimal-user-loop-questions.md +++ /dev/null @@ -1,35 +0,0 @@ -# Agent Prompt: Add Question-Asking Coaching to Minimal User Loop Exercise - -Background -The minimal user loop exercise is conceptual. Learners need explicit help -forming good questions and using AI safely without outsourcing thinking. -Add a short coaching block early in the exercise. - -Project Context -DevFoundry is a learning-oriented documentation repo for people new to -software development, often Windows-first and CLI-anxious. Canonical docs -live in `website/docs/` and are deployed with Docusaurus. The overall -docs reorg aims to improve navigation, progression, and question-asking -coaching without introducing new features. - -Purpose -You are a coding agent. Add a short coaching block exactly as described. - -Scope -- `website/docs/exercises/minimal-user-loop.md` - -What to change -1) Add a short "Ask Better Questions" block early in the exercise. -2) Include 2-3 example questions focused on loop clarity and friction. -3) Provide a short AI prompt template that is safe and specific. - -Constraints -- Keep tone supportive and low-anxiety. -- Minimal formatting; avoid long blocks. - -Acceptance Criteria -- Block is added near the top of the exercise. -- Includes 2-3 example questions and one prompt template. - -Deliverable -- Provide the exact inserted block and placement location. From cb16e62908e20b18302b3621f1761ad36fcb66a0 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 30 Jan 2026 12:11:32 +0100 Subject: [PATCH 11/11] fix(ci): add package-lock.json for npm ci in CI workflow Remove package-lock.json from .gitignore so CI can use npm ci. --- .gitignore | 2 +- package-lock.json | 2159 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2160 insertions(+), 1 deletion(-) create mode 100644 package-lock.json diff --git a/.gitignore b/.gitignore index f4f671a..cf4b8e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ node_modules/ dist/ .vite/ -package-lock.json + # Generated data files *.db diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..317cb5c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2159 @@ +{ + "name": "DevFoundry", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "glob": "^11", + "tsx": "^4", + "typescript": "~5.6.2", + "vitest": "^3" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } +}