commit 6bd4c9382a8ffb034c22316732f50011d66bfd6b Author: chungyeong Date: Sat May 9 22:22:13 2026 +0900 chore: scaffold devflow workspace diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..766f911 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +node_modules/ +dist/ +coverage/ +.turbo/ +.DS_Store +.env +.env.local +.env.*.local +*.log +*.tsbuildinfo +data/ +!.gitkeep diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..2bd5a0a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 diff --git a/apps/.gitkeep b/apps/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/apps/.gitkeep @@ -0,0 +1 @@ + diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..d2504ef --- /dev/null +++ b/biome.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false, + "ignore": ["node_modules", "dist", "coverage", "data"] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 100 + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noExplicitAny": "error" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double", + "semicolons": "always", + "trailingCommas": "all" + } + }, + "json": { + "formatter": { + "trailingCommas": "none" + } + } +} diff --git a/docs/plan.md b/docs/plan.md new file mode 100644 index 0000000..860fadd --- /dev/null +++ b/docs/plan.md @@ -0,0 +1,1741 @@ +# Devflow Implementation Plan v3 r4 + +## 0. Document Status + +- This document supersedes v2 and all earlier v3 drafts where conflicting. +- Single-user, single-machine assumption. No auth, no retention policy, no observability dashboards, no multi-tenancy. +- Target OS: macOS 13+ / Linux. No Windows. +- All paths are Unix-style. All times are stored UTC. +- Decisions in this document are locked unless explicitly marked `(provisional)`. Override requires updating this document, not only code. +- r1 applied CC-1 through CC-5. +- r2 applied CC-6 through CC-10. +- r3 applied CC-11 through CC-15. +- r4 applies CC-16 through CC-18. + +## 1. Stack Decisions + +### 1.1 Workspace + +- `pnpm 9` with workspaces. No Turbo. +- Node 22 LTS, pinned by `.nvmrc` and `package.json#engines`. +- TypeScript 5.6 with project references via `tsc -b`. +- `strict: true`. +- No `any` unless accompanied by an explicit annotation comment explaining why. + +### 1.2 Tooling + +- Build: + - `tsup` for libraries, CJS + ESM dual output. + - `vite` for `apps/web`. + - `tsx` for `apps/cli`, `apps/api`, and `apps/worker` in dev. + - `node` for prod-ish local runs. +- Test: + - `vitest` with workspace config. + - Coverage via `@vitest/coverage-v8`. + - No coverage gate at M1. + - M9 adds coverage gate: >=70% lines on `packages/core`, `packages/session`, `packages/run-engine`. +- Lint/format: + - `biome`. + - One root config. +- Pre-commit: + - `lefthook`. + - Runs `biome check --write` on staged files. + - Runs `tsc -b --noEmit` on changed packages. + - Runs related Vitest tests on changed packages. + +### 1.3 Database + +- Postgres 16 via Docker Compose. +- Drizzle ORM + `drizzle-kit generate`. +- Generated SQL migrations are committed. +- Migrations are never auto-applied at runtime except through the explicit migration runner invoked by `devflow up`. +- Migration runner: + - `scripts/migrate.ts`. + - Takes `DATABASE_URL`. + - `devflow up` waits for Postgres health and then runs pending migrations. + +### 1.4 Logging + +- `pino`. +- `pino-pretty` in dev, JSON otherwise. +- Standard fields: + - `time` + - `level` + - `module` + - `runId?` + - `phaseId?` + - `role?` + - `eventId?` +- Levels: + - `trace`: transcript chunks only. + - `debug`: internal state transitions. + - `info`: run events. + - `warn`: recoverable errors. + - `error`: human-required or fatal errors. + +### 1.5 Config + +- Single Zod schema in `packages/core/src/config.ts`. +- Source precedence, high to low: + - `process.env` + - `.env.local` + - `.env` + - schema defaults +- Config is loaded once at process start, validated, frozen, and exported as typed `Config`. +- Config validation failure is fatal. +- Required keys at M1: + - `DATABASE_URL` + - `WORKSPACE_ROOT` + - `LOG_LEVEL` +- M5 adds: + - `TEMPORAL_ADDRESS` +- Path canonicalization: + - `WORKSPACE_ROOT` is resolved through `fs.realpathSync` and stored as an absolute path at config load. + - Any path entering the system must be canonicalized before storage or hashing. + - `repo_path` and `worktree_root` rules are defined in section 4. + +Backend registration: + +```ts +const BackendConfig = z.object({ + id: Backend, // codex | claude | fake + enabled: z.boolean(), + binaryPath: z.string().optional(), // resolved from PATH if absent; required for codex/claude +}); +``` + +- `fake` is always available. +- `codex` and `claude` are available only when: + - `enabled=true` + - binary resolves at process start. +- Resolution failure: + - `doctor` warns. + - binding fails fast at run start with `human_required:backend_unavailable`. +- Binding reads from `config.backends`, never directly from `PATH`. + +### 1.6 HTTP + +- `fastify` 5. +- `@fastify/sensible`. +- SSE primary strategy: + - Try `fastify-sse-v2`. + - Fastify 5 compatibility is not assumed. + - M1 includes a smoke test. +- SSE fallback: + - Native `reply.raw`. + - Headers: + - `content-type: text/event-stream` + - `cache-control: no-cache` + - `connection: keep-alive` + - Write `data: \n\n`. + - Manage heartbeats and reconnect manually. +- WebSocket is deferred unless SSE fails under transcript volume. + +## 2. Directory Layout + +```text +devflow/ +├── package.json +├── pnpm-workspace.yaml +├── tsconfig.base.json +├── biome.json +├── lefthook.yml +├── vitest.workspace.ts +├── docker-compose.yml +├── .nvmrc +├── .env.example +├── docs/ +│ ├── plan.md +│ ├── adr/ +│ └── schemas/ +│ ├── artifacts/ +│ ├── personas/ +│ └── templates/ +├── scripts/ +│ ├── migrate.ts +│ └── seed.ts +├── packages/ +│ ├── core/ +│ │ └── src/ +│ │ ├── config.ts +│ │ ├── enums.ts +│ │ ├── hash.ts +│ │ ├── errors.ts +│ │ ├── template.ts +│ │ ├── persona.ts +│ │ ├── binding.ts +│ │ ├── prompt-envelope.ts +│ │ ├── artifact-schema.ts +│ │ ├── run-event.ts +│ │ └── index.ts +│ ├── db/ +│ │ └── src/ +│ │ ├── schema/ +│ │ ├── migrations/ +│ │ ├── repositories/ +│ │ └── client.ts +│ ├── session/ +│ │ └── src/ +│ │ ├── adapter.ts +│ │ ├── fake.ts +│ │ ├── tmux.ts +│ │ ├── profiles/ +│ │ │ ├── codex.ts +│ │ │ └── claude.ts +│ │ ├── recovery.ts +│ │ └── transcript.ts +│ ├── harness/ +│ │ └── src/ +│ │ ├── git.ts +│ │ ├── worktree.ts +│ │ ├── runner.ts +│ │ ├── review.ts +│ │ └── backtest.ts +│ ├── run-engine/ +│ │ └── src/ +│ │ ├── engine.ts +│ │ ├── phase-executor.ts +│ │ └── approval.ts +│ └── workflows/ +│ └── src/ +│ ├── workflow.ts +│ └── activities.ts +├── apps/ +│ ├── api/ +│ ├── web/ +│ ├── cli/ +│ └── worker/ +└── tests/ + ├── e2e/ + └── fixtures/ +``` + +## 3. `devflow doctor` + +Exit codes: + +- `0`: all green. +- `1`: one or more red checks. +- `2`: internal or unknown error. + +Each check emits: + +- `name` +- `status`: `pass` | `fail` | `warn` +- `detail` +- `remediation` + +Closed check list: + +1. Node version satisfies `>=22.0.0 <23`. +2. pnpm version `>=9.0.0`. +3. `tmux` exists, version `>=3.3`. +4. `git` version `>=2.40`. +5. Docker daemon reachable. +6. Postgres container running, `pg_isready` ok, `DATABASE_URL` connects. +7. No pending Drizzle migrations. +8. `WORKSPACE_ROOT` exists and is writable. +9. `.env` resolves to valid `Config`. +10. `codex` in `PATH`, warn-only. +11. `claude` in `PATH`, warn-only. +12. Free disk on `WORKSPACE_ROOT` partition: + - warn under 10GB. + - fail under 2GB. + - target green threshold: >=5GB. + +Output: + +- Human table by default. +- `--json` for machine-readable output. +- `--quiet` prints only nonzero results. +- `--list-orphans` lists orphaned worktrees only; it never removes them. + +## 4. Database Schema + +First migration prelude: + +```sql +CREATE EXTENSION IF NOT EXISTS pgcrypto; +``` + +All tables use `gen_random_uuid()` primary keys unless noted. All times are `timestamptz`. Mutable rows include `updated_at`. JSON columns use `jsonb`. + +### 4.1 `workflow_templates` + +- `id uuid primary key default gen_random_uuid()` +- `name text not null` +- `version int not null` +- `hash text not null unique` +- `definition jsonb not null` +- `created_at timestamptz not null default now()` +- unique `(name, version)` + +### 4.2 `agent_personas` + +- `id uuid primary key default gen_random_uuid()` +- `name text not null` +- `version int not null` +- `hash text not null unique` +- `definition jsonb not null` +- `created_at timestamptz not null default now()` +- unique `(name, version)` + +### 4.3 `runs` + +- `id uuid primary key default gen_random_uuid()` +- `template_id uuid not null references workflow_templates(id)` +- `template_hash text not null` +- `state text not null` +- `repo_path text not null` + - canonical absolute path + - resolved through `fs.realpathSync` before insert +- `base_branch text not null` +- `worktree_root text not null` + - canonical absolute path under `WORKSPACE_ROOT//` +- `current_phase_id uuid references run_phases(id)` nullable and deferrable +- `started_at timestamptz` +- `ended_at timestamptz` +- `final_report_path text` +- `paused_from_state text` + - set when transitioning to `paused` + - cleared on resume + - null when state is not `paused` +- `created_at timestamptz not null default now()` +- `updated_at timestamptz` + +Active-run uniqueness: + +```sql +CREATE UNIQUE INDEX ux_active_run_repo_base +ON runs (repo_path, base_branch) +WHERE state NOT IN ('completed', 'failed', 'aborted'); +``` + +### 4.4 `run_inputs` + +- `id uuid primary key default gen_random_uuid()` +- `run_id uuid not null unique references runs(id) on delete cascade` +- `requirements_md text not null` +- `objective jsonb` +- `extra jsonb` +- `input_hash text not null` + +`input_hash` is based on: + +- `requirements_md` +- `objective` +- `extra` +- canonical `repo_path` +- `base_branch` + +### 4.5 `run_bindings` + +- `id uuid primary key default gen_random_uuid()` +- `run_id uuid not null references runs(id) on delete cascade` +- `role_id text not null` +- `persona_id uuid not null references agent_personas(id)` +- `persona_hash text not null` +- `backend text not null` +- `binding_hash text not null` +- unique `(run_id, role_id)` + +### 4.6 `run_phases` + +- `id uuid primary key default gen_random_uuid()` +- `run_id uuid not null references runs(id) on delete cascade` +- `phase_key text not null` +- `seq int not null` +- `state text not null` +- `attempts int not null default 0` +- `started_at timestamptz` +- `ended_at timestamptz` +- unique `(run_id, phase_key)` + +### 4.7 `run_events` + +Append-only. + +- `id bigserial primary key` +- `run_id uuid not null references runs(id) on delete cascade` +- `phase_id uuid references run_phases(id)` +- `seq bigint not null` +- `type text not null` +- `payload jsonb not null` +- `idempotency_key text not null` +- `ts timestamptz not null default now()` +- unique `(run_id, seq)` +- unique `(run_id, idempotency_key)` +- index `(run_id, ts)` + +Concurrency: + +- All inserts go through `RunEventRepository.append()`. +- Raw SQL inserts into `run_events` are forbidden. +- `append()` takes `pg_advisory_xact_lock(hash64('devflow:run-events', run_id))`. +- Inside that same transaction it assigns: + +```sql +seq := COALESCE(MAX(seq), 0) + 1 +``` + +### 4.8 `approval_requests` + +- `id uuid primary key default gen_random_uuid()` +- `run_id uuid not null references runs(id)` +- `phase_id uuid references run_phases(id)` +- `gate_key text not null` +- `state text not null` +- `idempotency_key text not null` +- `payload jsonb not null` +- `created_at timestamptz not null default now()` +- `resolved_at timestamptz` +- unique `(idempotency_key)` + +### 4.9 `approval_decisions` + +Append-only and immutable. + +- `id uuid primary key default gen_random_uuid()` +- `approval_request_id uuid not null references approval_requests(id)` +- `action text not null` + - `approve` + - `reject` + - `request_changes` + - `abort` +- `comment text` +- `decided_at timestamptz not null default now()` +- `idempotency_key text not null unique` + +`pause` is not an approval decision. + +### 4.10 `tui_sessions` + +- `id uuid primary key default gen_random_uuid()` +- `run_id uuid not null references runs(id) on delete cascade` +- `role_id text not null` +- `backend text not null` +- `cwd text not null` +- `expected_artifact_path text` +- `expected_schema text` +- `last_prompt_hash text` +- `last_prompt_at timestamptz` +- `last_capture_seq bigint not null default 0` +- `last_known_pane_pid int` +- `tmux_session text` +- `tmux_window text` +- `state text not null` +- `recovery_attempts int not null default 0` +- unique `(run_id, role_id)` + +### 4.11 `tui_transcript_chunks` + +Append-only. + +- `id bigserial primary key` +- `session_id uuid not null references tui_sessions(id) on delete cascade` +- `seq bigint not null` +- `content text not null` +- `captured_at timestamptz not null default now()` +- unique `(session_id, seq)` + +### 4.12 `artifacts` + +- `id uuid primary key default gen_random_uuid()` +- `run_id uuid not null references runs(id) on delete cascade` +- `phase_id uuid references run_phases(id)` +- `path text not null` +- `schema_id text not null` +- `hash text not null` +- `valid boolean not null` +- `validation_error jsonb` +- `created_at timestamptz not null default now()` +- unique `(run_id, path, hash)` + +### 4.13 `commands` + +- `id uuid primary key default gen_random_uuid()` +- `run_id uuid not null references runs(id) on delete cascade` +- `phase_id uuid references run_phases(id)` +- `kind text not null` + - `git` + - `test` + - `e2e` + - `doctor` + - `backtest` + - `other` +- `argv text[] not null` +- `cwd text not null` +- `exit_code int` +- `stdout_path text` +- `stderr_path text` +- `started_at timestamptz` +- `ended_at timestamptz` + +### 4.14 `review_findings` + +- `id uuid primary key default gen_random_uuid()` +- `run_id uuid not null references runs(id) on delete cascade` +- `phase_id uuid references run_phases(id)` +- `reviewer_role text not null` +- `severity text not null` + - `info` + - `low` + - `medium` + - `high` + - `critical` +- `category text not null` + - `correctness` + - `evidence` + - `style` + - `security` + - `performance` + - `other` +- `file_path text` +- `line int` +- `summary text not null` +- `evidence text` +- `verifier_status text not null default 'unverified'` + - `unverified` + - `confirmed` + - `rejected` +- `created_at timestamptz not null default now()` + +### 4.15 Backtest Stub Tables + +`backtest_iterations` and `backtest_metrics` are created at M1 as stub tables: + +- `id uuid primary key default gen_random_uuid()` +- `run_id uuid not null references runs(id) on delete cascade` +- `payload jsonb` +- `created_at timestamptz not null default now()` + +Full schema is deferred to M12. + +## 5. Enums + +All enums live in `packages/core/src/enums.ts` as TypeScript `const` objects and Zod enums. + +### 5.1 `Backend` + +- `codex` +- `claude` +- `fake` + +Future `gemini` support adds an enum entry and a `BackendProfile`; no design change. + +### 5.2 `Capability` + +- `spec_write` +- `phase_planning` +- `task_dag_planning` +- `code_edit` +- `test_first_development` +- `code_review` +- `evidence_check` +- `command_execute` +- `backtest_run` +- `metric_extract` +- `failure_mining` +- `objective_eval` +- `final_report_compose` + +### 5.3 `RiskLevel` + +- `low` +- `medium` +- `high` + +Risk is declared per phase in the template. Persona has `maxRiskLevel`. Binding fails when `phase.risk > persona.maxRiskLevel`. + +### 5.4 `ApprovalDecisionAction` + +- `approve` +- `reject` +- `request_changes` +- `abort` + +`pause` is a run-level control operation, not an approval decision. + +### 5.5 `ApprovalState` + +- `pending` +- `approved` +- `rejected` +- `changes_requested` +- `aborted` +- `paused` + +`paused` is not an auto-decision. + +### 5.6 `RunState` + +- `created` +- `bound` +- `planning` +- `awaiting_approval` +- `executing` +- `paused` +- `completed` +- `failed` +- `aborted` + +### 5.7 `RunPhaseState` + +- `pending` +- `running` +- `awaiting_artifact` +- `validating` +- `awaiting_approval` +- `completed` +- `failed` +- `skipped` + +### 5.8 `SessionState` + +- `CREATED` +- `BOOTSTRAPPING` +- `READY` +- `BUSY` +- `WAITING_FOR_APPROVAL` +- `ARTIFACT_TIMEOUT` +- `HUNG` +- `CRASHED` +- `RESUMING` +- `REBOOTSTRAPPED` +- `FAILED_NEEDS_HUMAN` + +## 6. Content-Addressed Hashing + +### 6.1 Canonical JSON + +- Object keys sorted lexicographically by UTF-16 code units. +- No insignificant whitespace. +- Strings use standard JSON escaping. +- No Unicode normalization. +- Numbers use shortest round-trippable representation. +- Integers have no decimal point. +- No leading zeros. +- Arrays preserve order. +- No trailing newline. + +`packages/core/src/hash.ts` exports: + +```ts +canonicalize(value: unknown): string +hash(value: unknown): string +``` + +`hash()` returns `sha256hex(canonicalize(value))`. + +### 6.2 Hash Subjects + +- Template hash: + - `{ name, version, roles, phases, gates, capabilitiesRequired }` +- Persona hash: + - `{ name, version, capabilities, backend, maxRiskLevel, allowedRoles, promptConfig, modelConfig }` +- Binding hash: + - `{ runId, roleId, templateHash, personaHash, backend, override }` +- Run input hash: + - `{ templateHash, bindings: sorted[bindingHash], requirementsMd, objective, repoPath, baseBranch, extra }` +- Prompt hash: + - `{ runId, roleId, phaseKey, expectedArtifact, expectedSchema, instructions, attempt }` +- Artifact hash: + - SHA-256 of file bytes. + +Prompt hash uses `phaseKey`, not `phaseId`, because `PromptEnvelope` carries `phaseKey`. + +## 7. Template, Persona, Binding + +### 7.1 Template Schema + +```ts +const TemplatePhase = z.object({ + key: z.string(), + title: z.string(), + risk: RiskLevel, + roles: z.array(z.string()), + expectedArtifact: z + .object({ + path: z.string(), + schema: z.string(), + }) + .optional(), + gates: z.array(z.string()).default([]), + timeoutMs: z.number().int().positive().optional(), +}); + +const TemplateRole = z.object({ + id: z.string(), + requiredCapabilities: z.array(Capability), + preferredBackends: z.array(Backend).default([]), + count: z.number().int().min(1).default(1), + diversity: z + .object({ + requireDifferentBackends: z.boolean().default(false), + }) + .optional(), +}); + +const Template = z.object({ + name: z.string(), + version: z.number().int().positive(), + roles: z.array(TemplateRole), + phases: z.array(TemplatePhase), + defaultGates: z.array(z.string()).default([]), +}); +``` + +### 7.2 Persona Schema + +```ts +const Persona = z.object({ + name: z.string(), + version: z.number().int().positive(), + backend: Backend, + capabilities: z.array(Capability), + maxRiskLevel: RiskLevel, + allowedRoles: z.array(z.string()).optional(), + promptConfig: z + .object({ + systemPrompt: z.string().optional(), + instructionsPrelude: z.string().optional(), + }) + .default({}), + modelConfig: z.record(z.string(), z.unknown()).default({}), +}); +``` + +### 7.3 Override Semantics + +- Override may swap persona for a role. +- Override may constrain backend to a specific allowed backend. +- Override cannot add capabilities. +- Override cannot raise risk above persona `maxRiskLevel`. +- Diversity rules apply after override. +- Lock-time validation runs the full binding algorithm. +- On first binding failure, the run does not start. + +### 7.4 Binding Algorithm + +For each role: + +1. Select override persona if present; otherwise run `autoSelect`. +2. Assert backend is enabled in `config.backends`. +3. Assert non-fake backend binary resolved at process start. +4. Assert role id is in `allowedRoles`, unless `allowedRoles` is absent. +5. Assert required capabilities are a subset of persona capabilities. +6. Assert every phase using the role has risk <= persona `maxRiskLevel`. +7. Expand roles with `count > 1` into `roleId#0`, `roleId#1`, etc. +8. Enforce diversity rules after expansion. +9. Compute and persist `binding_hash` per role instance. + +`autoSelect` is deterministic. Sort candidates by: + +1. role `preferredBackends` order. +2. `persona.version desc`. +3. `persona.name asc`. +4. `persona.hash asc`. + +Personas whose backend is not in `preferredBackends` are eligible only if all preferred-backend personas fail capability or risk checks. + +Binding fails with `human_required:no_eligible_persona` if no persona satisfies requirements. + +### 7.5 Seeding + +Personas: + +- `docs/schemas/personas/@.yaml` +- filename encodes immutable identity. +- loader parses with Persona schema. +- loader computes `personaHash`. +- loader upserts keyed by `(name, version)`. +- hash mismatch on an existing row is fatal. + +Templates: + +- `docs/schemas/templates/@.yaml` +- same immutable version rule. + +Deleting a published file is allowed only when no run references that hash. + +## 8. Session Runtime + +### 8.1 SessionAdapter Interface + +```ts +export interface SessionAdapter { + start(input: StartInput): Promise; + sendPrompt(handle: SessionHandle, envelope: PromptEnvelope): Promise<{ promptId: string }>; + probe(handle: SessionHandle): Promise; + resume(handle: SessionHandle): Promise; + rebootstrap(handle: SessionHandle): Promise; + capture(handle: SessionHandle, fromSeq: bigint): AsyncIterable; + dispose(handle: SessionHandle): Promise; +} + +export interface StartInput { + runId: string; + roleId: string; + backend: Backend; + cwd: string; + expectedArtifactPath?: string; + expectedSchema?: string; + envelopePrelude?: string; +} + +export interface SessionHandle { + sessionId: string; + pid?: number; + tmuxSession?: string; + tmuxWindow?: string; +} + +export interface ProbeResult { + alive: boolean; + paneActive: boolean; + lastOutputAt?: Date; + hint?: string; +} + +export interface TranscriptChunk { + seq: bigint; + content: string; + capturedAt: Date; +} +``` + +### 8.2 Session State Machine + +- `CREATED -> BOOTSTRAPPING -> READY` +- `READY <-> BUSY` +- `BUSY -> WAITING_FOR_APPROVAL` +- `BUSY -> ARTIFACT_TIMEOUT` +- `BUSY -> HUNG` +- `BUSY -> CRASHED` +- `HUNG | CRASHED | ARTIFACT_TIMEOUT -> RESUMING -> READY` +- `RESUMING -> REBOOTSTRAPPED -> READY` +- exhausted errors -> `FAILED_NEEDS_HUMAN` + +### 8.3 Recovery Counters + +- `sendPrompt` retry: 2. +- `resume` retry: 2. +- `rebootstrap` retry: 1. +- artifact repair retry: 1. +- max hung time: configurable; default 20 minutes. + +Exhaustion creates a human gate with `recoveryHint`. + +### 8.4 SessionManager Singleton + +- M4: hosted in `apps/api`. +- M5+: hosted in `apps/worker`. +- Only SessionManager may call mutating `SessionAdapter` methods. +- Holds in-memory `Map`. +- Takes `pg_advisory_lock(hash64('devflow:session-manager'))`. +- Second instance exits code `3`. +- On start: + - query non-terminal `tui_sessions`. + - call `adapter.resume(handle)`. + - success: place handle in map. + - failure: session -> `FAILED_NEEDS_HUMAN`, append `session.failed`, create recovery gate. +- On SIGTERM/SIGINT: + - refuse new prompts. + - allow in-flight artifact polling up to 30s. + - persist `last_capture_seq`. + - release advisory lock. + +## 9. Prompt Envelope + +### 9.1 Wire Format + +```text +DEVFLOW_PROMPT_BEGIN +Run: +Role: +Phase: +Attempt: +Expected artifact: +Expected schema: +Dedup-Key: +Instructions: + +DEVFLOW_PROMPT_END +``` + +### 9.2 Schema + +```ts +const PromptEnvelope = z.object({ + uuid: z.string().uuid(), + runId: z.string().uuid(), + roleId: z.string(), + phaseKey: z.string(), + attempt: z.number().int().nonnegative(), + expectedArtifact: z.string(), + expectedSchema: z.string(), + dedupKey: z.string(), + instructions: z.string(), +}); +``` + +### 9.3 Rules + +- Prompt identity is `dedupKey`. +- Adapter refuses duplicate `dedupKey` for the same session within a run lifetime. +- `attempt` increments only when the engine intentionally re-sends after timeout or repair. +- Adapter-level retry does not increment attempt. +- Completion is never inferred from transcript text. +- Completion requires a schema-valid artifact. + +### 9.4 Backend Prelude + +Sent once at session bootstrap before the first envelope. + +Required structure: + +1. Backend identity statement. +2. Persona `instructionsPrelude`. +3. Protocol declaration: completion is signaled only by writing expected artifact files. +4. Envelope marker contract. +5. Approval/probe contract: `DEVFLOW_PROBE` must respond with one line `READY` or `BUSY `. + +Codex and Claude-specific addenda live in `packages/session/src/profiles/{codex,claude}.ts` and are populated at M10. + +## 10. Artifact Schema Registry + +### 10.1 Layout + +JSON Schema 2020-12 documents live at: + +```text +docs/schemas/artifacts/.json +``` + +`schema_id` format: + +```text +/@ +``` + +Examples: + +- `dev/spec@1` +- `dev/phase-plan@1` +- `dev/dag@1` +- `dev/review-finding-batch@1` +- `bt/objective@1` +- `bt/iteration-result@1` +- `common/final-report@1` + +### 10.2 Loader + +`packages/core/src/artifact-schema.ts` exports: + +```ts +function loadSchema(id: string): JsonSchema; +function validateArtifact( + id: string, + data: unknown +): { ok: true } | { ok: false; errors: ValidationError[] }; +``` + +Unknown schema id is fatal. + +### 10.3 Validation Flow + +1. Engine waits for `expectedArtifactPath` to appear. +2. Debounce 500ms after last `mtime` change. +3. Read file. +4. Compute SHA-256. +5. Validate against `expectedSchema`. +6. Valid: + - insert artifact row with `valid=true`. + - append `artifact.validated`. + - advance phase. +7. Invalid: + - insert artifact row with `valid=false`. + - append `artifact.invalid`. + - trigger one repair prompt. + - after repair exhaustion, create human gate. +8. Timeout: + - append `artifact.timeout`. + - probe session. + - enter recovery flow. + +### 10.4 Final Report + +At terminal run state, write atomically: + +- `//.report.md` +- `//.report.json` + +Both are written even on `failed` or `aborted`, best-effort. + +`common/final-report@1` minimum fields: + +- `runId` +- `templateHash` +- `bindings[]` +- `inputs` +- `phases[]` +- `approvals[]` +- `findings[]` +- `commands[]` +- `artifacts[]` +- `events.tail` +- `unresolved[]` +- `endedAt` +- `status` + +### 10.5 Backtest Objective Stub + +`bt/objective@1`: + +```json +{ + "targets": [ + { "metric": "sharpe", "op": "gte", "value": 1.5, "weight": 1.0 }, + { "metric": "mdd", "op": "lte", "value": 0.15, "weight": 1.0 } + ], + "stopWhen": "all" +} +``` + +- `op`: `gte` | `lte` | `eq` | `gt` | `lt` +- `stopWhen`: `all` | `weighted` +- `weighted` threshold is hardcoded at 0.8 at M12. +- Full DSL deferred to M12. + +## 11. Run Events + +Closed event types: + +```text +run.created +run.started +run.paused +run.resumed +run.completed +run.failed +run.aborted +phase.started +phase.completed +phase.failed +phase.skipped +prompt.sent +prompt.repaired +artifact.expected +artifact.validated +artifact.invalid +artifact.timeout +approval.requested +approval.resolved +session.created +session.ready +session.busy +session.idle +session.crashed +session.recovered +session.failed +command.started +command.completed +command.failed +review.batch_recorded +finding.verifier_resolved +backtest.iteration_started +backtest.iteration_completed +backtest.objective_evaluated +``` + +### 11.1 Idempotency Keys + +Every event append requires deterministic `idempotency_key`. + +| Event family | Key formula | +|---|---| +| `run.created`, `run.started`, `run.completed`, `run.failed`, `run.aborted` | `:` | +| `run.paused` | `run.paused::` | +| `run.resumed` | `run.resumed::` | +| `phase.started`, `phase.completed`, `phase.failed`, `phase.skipped` | `::` | +| `prompt.sent`, `prompt.repaired` | `:` | +| `artifact.expected`, `artifact.timeout` | `:::` | +| `artifact.validated`, `artifact.invalid` | `:::` | +| `approval.requested` | `approval.requested:` | +| `approval.resolved` | `approval.resolved::` | +| `session.created`, `session.failed` | `:` | +| `session.busy`, `session.idle` | `::` | +| `session.ready`, `session.crashed`, `session.recovered` | `::` | +| `command.started`, `command.completed`, `command.failed` | `:` | +| `review.batch_recorded` | `review.batch_recorded:::` | +| `finding.verifier_resolved` | `finding.verifier_resolved:` | +| `backtest.iteration_started`, `backtest.iteration_completed`, `backtest.objective_evaluated` | `:` | + +Definitions: + +- `phase_attempt` is incremented before event append. +- `recovery_attempts` is incremented before event append. +- `prompt_dedup_key` is the envelope dedup key. +- `approval_idempotency_key` is from `approval_requests`. +- Artifact expected/timeout events are per-attempt. +- Artifact validated/invalid events are content-keyed by path + hash. + +## 12. Fake Session Adapter + +### 12.1 Behavior + +- Deterministic. +- In-process. +- No PTY. +- No tmux. +- Drives engine end-to-end without real backends. + +### 12.2 Sentinel Triggers + +On `sendPrompt`, inspect `expectedSchema`. + +Fixture path: + +```text +tests/fixtures/fake-artifacts//.json +``` + +`scenarioName` comes from instruction header: + +```text +Scenario: +``` + +Default scenario: `ok`. + +Scenarios: + +- `ok`: write fixture to `expectedArtifactPath` after 50ms by default. +- `invalid`: write deliberately schema-invalid payload. +- `timeout`: never write. +- `crash`: throw `RecoverableError`. + +### 12.3 Transcript + +Fake adapter emits chunks such as: + +```text +[fake] received prompt ; will write in 50ms +``` + +## 13. State Machines + +### 13.1 Run State + +States: + +- `created` +- `bound` +- `planning` +- `awaiting_approval` +- `executing` +- `paused` +- `completed` +- `failed` +- `aborted` + +Transitions: + +| From | Trigger | To | Side effects | +|---|---|---|---| +| `created` | `lockBindings ok` | `bound` | persist bindings; emit `run.started` | +| `created` | `lockBindings fail` | `failed` | emit `run.failed` | +| `bound` | phase plan needed | `planning` | emit `phase.started` | +| `planning` | plan artifact valid | `awaiting_approval` | request approval | +| `awaiting_approval` | approve | `executing` | emit `approval.resolved`, `run.resumed` | +| `awaiting_approval` | reject | `failed` | emit `run.failed` | +| `awaiting_approval` | request_changes | `planning` | increment phase attempts | +| `awaiting_approval` | timeout | `paused` | set `paused_from_state='awaiting_approval'` | +| `executing` | phase ok, more phases | `executing` | next phase | +| `executing` | phase needs gate | `awaiting_approval` | request gate | +| `executing` | all phases done | `completed` | emit `run.completed`, write final report | +| `executing` | unrecoverable error | `failed` | emit `run.failed` | +| `executing` | manual `pauseRun` | `paused` | set `paused_from_state='executing'` | +| `planning` | manual `pauseRun` | `paused` | set `paused_from_state='planning'` | +| `paused` | resume | `paused_from_state` | emit `run.resumed`, clear `paused_from_state` | +| any non-terminal state | `abortRun` | `aborted` | emit `run.aborted`, dispose sessions | + +Non-terminal states for `abortRun`: + +- `created` +- `bound` +- `planning` +- `awaiting_approval` +- `executing` +- `paused` + +### 13.2 Run Phase State + +States: + +- `pending` +- `running` +- `awaiting_artifact` +- `validating` +- `awaiting_approval` +- `completed` +- `failed` +- `skipped` + +Transitions: + +| From | Trigger | To | +|---|---|---| +| `pending` | start | `running` | +| `running` | prompt sent, artifact expected | `awaiting_artifact` | +| `awaiting_artifact` | artifact appears | `validating` | +| `awaiting_artifact` | timeout | `running` after probe/repair, or `failed` after exhaustion | +| `validating` | valid | `awaiting_approval` if gate, else `completed` | +| `validating` | invalid | `running` after one repair, else `failed` | +| `awaiting_approval` | approve | `completed` | +| `awaiting_approval` | reject / abort | `failed` | +| `awaiting_approval` | request_changes | `running`, attempt + 1 | + +## 14. Approval State + +States: + +- `pending` +- `approved` +- `rejected` +- `changes_requested` +- `aborted` +- `paused` + +### 14.1 Transitions + +| From | Event | To | Side effects | +|---|---|---|---| +| `pending` | approve decision | `approved` | insert decision row | +| `pending` | reject decision | `rejected` | insert decision row; run -> `failed` | +| `pending` | request_changes decision | `changes_requested` | insert decision row; increment attempt | +| `pending` | abort decision | `aborted` | insert decision row; run -> `aborted` | +| `pending` | timeout | `paused` | run -> `paused`; no decision row | +| `paused` | unpause | `pending` | re-arm gate; no decision row | +| terminal states | any decision | unchanged | return 409 | + +Rules: + +- A `pending` request can transition to one non-pending state per pending epoch. +- Terminal approval states reject further decisions. +- `paused` may return to `pending` only through `unpause`. +- Manual pause is run-level `pauseRun`; it leaves approval gate in `pending`. +- Only `approve`, `reject`, `request_changes`, and `abort` create `approval_decisions` rows. +- Default timeout is null. +- Timeout never auto-approves or auto-rejects. + +### 14.2 Decision Idempotency + +- GUI: + - UUIDv4 per click. + - reused across automatic UI retries for the same logical action. +- CLI: + - UUIDv4 per invocation. + - `--client-token=` override for scripted retry. +- API: + - existing `(approval_request_id, action, client_token)` returns existing row with status 200. + - new decision inserts row and returns 201. + - same token with different action returns 409. + - decision on non-pending request returns 409. + +### 14.3 Destructive Command Enforcement + +Devflow-direct commands have hard enforcement. TUI-agent commands have best-effort enforcement. + +Hard-blocked Devflow-direct patterns: + +- `rm -rf` +- `git reset --hard` +- `git clean` +- `git push --force` +- `git push --force-with-lease` +- `git worktree remove --force` +- `git branch -D` +- `docker volume rm` +- `docker compose down -v` +- `DROP DATABASE` +- `DROP SCHEMA` +- migration rollback +- reads/writes touching `.env*`, `~/.ssh/`, `~/.aws/`, `~/.config/gcloud/`, `~/.kube/` +- files matching `*token*`, `*secret*`, `*credentials*`, `*.pem`, `*.key` + +TUI-agent command enforcement is best-effort: + +1. Prelude prohibits destructive operations. +2. Backend permission mode is set to safest available mode. +3. Transcript audit captures post-hoc evidence. +4. Human intervention goes through `devflow attach`. +5. Worktrees and branches are preserved by default. + +v1 does not claim real-time blocking of TUI-internal commands. + +## 15. Run Engine and Temporal Contract + +The M4 `RunEngine` contract is frozen before M5. M5 reimplements the same interface through Temporal. + +### 15.1 Public API + +```ts +interface RunEngine { + startRun(input: RunStartInput): Promise<{ runId: string }>; + signalApproval( + runId: string, + approvalRequestId: string, + action: ApprovalDecisionAction, + clientToken: string, + comment?: string + ): Promise; + pauseRun(runId: string): Promise; + resumeRun(runId: string): Promise; + abortRun(runId: string, reason: string): Promise; + getStatus(runId: string): Promise; +} +``` + +### 15.2 Temporal Shape + +- Namespace: `devflow`. +- Task queue: `devflow-runs`. +- Single worker process: `apps/worker`. +- Workflow: `runWorkflow(input: RunStartInput)`. +- Signals: + - `approve` + - `pause` + - `resume` + - `abort` + - `unpause` +- No Updates in M5. +- Status is read from DB. + +Activities: + +- `lockBindings(input)` +- `generatePhasePlan(runId, phaseKey, attempt)` +- `sendPromptToSession(sessionId, envelope)` +- `waitForArtifact(sessionId, expectedPath, expectedSchema, timeoutMs)` +- `validateArtifact(artifactPath, expectedSchema)` +- `recordEvent(runId, type, payload)` +- `requestApproval(runId, gateKey, phaseId, payload, idempotencyKey)` +- `runCommand(kind, argv, cwd, env)` +- `composeFinalReport(runId)` + +Retry policy: + +- Default: max attempts 3, exponential backoff start 1s, max 30s. +- `requestApproval`: max attempts 1. +- `composeFinalReport`: max attempts 1. +- `sendPromptToSession`: max attempts 2; further retry belongs to engine recovery. + +### 15.3 Hard Constraints + +- Workflow code holds only serializable state. +- No tmux handles in workflow state. +- No PTY refs in workflow state. +- No DB clients in workflow state. +- M5+ session interaction happens through activities calling SessionManager in `apps/worker`. +- M5+ API never calls mutating `SessionAdapter` methods. +- SessionManager advisory lock prevents API/worker ownership conflict during M4 -> M5 transition. +- Workflow code uses deterministic clock/randomness only. + +## 16. WriteSet and Worktree + +### 16.1 WriteSet + +- Each task declares `writeSet: string[]`. +- Patterns are relative to repo root. +- Glob engine: `fast-glob`. +- Options: + +```ts +{ + cwd: worktreeRoot, + dot: true, + followSymbolicLinks: false, + onlyFiles: true, + suppressErrors: false +} +``` + +Conflict detection: + +1. Expand writeSets. +2. Forbidden globs cause conflict if matched by more than one task: + - `pnpm-lock.yaml` + - `package-lock.json` + - `**/migrations/**` + - `**/*.generated.*` + - root `tsconfig*.json` + - `biome.json` + - `lefthook.yml` + - `.github/**` + - `.gitlab-ci.yml` +3. Pairwise file intersections must be empty. + +Conflict creates `parallel_dag_approved` gate. + +### 16.2 Worktree Lifecycle + +- Worktree root: + - `WORKSPACE_ROOT//` + - non-parallel main lane: `WORKSPACE_ROOT//main` +- Created via `git worktree add`. +- Branch name: + +```text +devflow// +``` + +- Terminal run state does not remove worktrees or branches. +- Output branches are deliverables. +- Disk growth is accepted. +- Cleanup is manual: + +```bash +devflow cleanup [--lane=] +``` + +Cleanup: + +- uses `git worktree remove` without `--force` by default. +- refuses dirty worktrees. +- `--force` requires an additional gate. +- `git branch -D` is destructive and gated. +- `doctor --list-orphans` lists only; it never removes. + +## 17. SSE Contract + +Endpoints: + +- `GET /sse/runs/:runId` +- `GET /sse/global` + +Heartbeat every 15 seconds. + +Events: + +| Event | Scope | +|---|---| +| `run.state_changed` | both | +| `run.event_appended` | run | +| `phase.state_changed` | run | +| `approval.created` | both | +| `approval.resolved` | both | +| `session.state_changed` | run | +| `transcript.chunk_appended` | run | +| `artifact.validated` | run | + +Reconnect: + +- `Last-Event-ID` is last `run_events.seq`. +- server replays `seq > lastSeq`. +- non-run-event SSE types are not replayed; state is re-derived by fetch. + +## 18. Errors + +`packages/core/src/errors.ts`: + +```ts +type ErrorClass = 'recoverable' | 'human_required' | 'fatal'; + +class DevflowError extends Error { + readonly class: ErrorClass; + readonly code: string; + readonly runId?: string; + readonly phaseId?: string; + readonly recoveryHint?: string; + readonly cause?: unknown; +} +``` + +Recoverable: + +- `network_blip` +- `pane_briefly_unresponsive` +- `prompt_send_transient` +- `db_serialization_retry` + +Human required: + +- `artifact_invalid_after_repair` +- `artifact_timeout_exhausted` +- `destructive_command_blocked` +- `secret_access_blocked` +- `writeset_conflict` +- `merge_conflict` +- `objective_not_met` +- `review_dispute_unresolved` + +Fatal: + +- `db_unreachable` +- `workspace_permissions` +- `internal_state_corruption` +- `template_load_failed` +- `migration_pending` +- `config_invalid` + +Mapping: + +- recoverable -> retry; exhausted -> human_required. +- human_required -> run paused and gate created. +- fatal -> run failed, sessions disposed, final report best-effort. + +## 19. Concurrent Runs and Crash Recovery + +### 19.1 Active Run Uniqueness + +- `MAX_CONCURRENT_RUNS`, default 4. +- DB partial unique index is the source of truth: + - one active run per `(repo_path, base_branch)`. +- `repo_path` is canonicalized before insert. +- Advisory lock is auxiliary only: + +```text +pg_try_advisory_xact_lock(hash64('devflow:start-run', repoPath, baseBranch)) +``` + +- Unique-index violation returns: + +```json +{ "currentRunId": "...", "currentState": "..." } +``` + +with HTTP 409. + +### 19.2 Crash Recovery + +M4, no Temporal: + +- On `apps/api` startup, sweep non-terminal runs. +- Mark them `failed`. +- `final_report_path = null`. +- Append synthesized `run.failed` with reason `process_restart_unrecovered`. +- Cascade associated `tui_sessions` to `FAILED_NEEDS_HUMAN`. +- Append `session.failed`. +- This frees active-run uniqueness slots. + +M5+: + +- No sweep. +- Temporal durability owns in-flight workflow recovery. +- SessionManager resumes tmux sessions. +- Active-run partial index blocks duplicate runs until completion or explicit abort. + +## 20. Milestones + +### M1: Monorepo + Postgres + CLI Doctor + +- Scaffold workspace. +- Add pnpm, tsconfig, biome, lefthook, Vitest. +- Add Docker Compose for Postgres. +- Add Drizzle and first migration. +- Add `devflow doctor`. +- Implement checks 1-9. +- Stub checks 10-12 as warn where needed. +- Add SSE compatibility smoke test: + - minimal Fastify 5 server. + - `fastify-sse-v2` plugin. + - 30-second integration test. + - receive 3 events and reconnect. + - if plugin fails, implement native `reply.raw` SSE helper before M1 is green. + +### M2: Core Schema + Registry + Binding + +- Implement enums. +- Implement canonical hashing. +- Implement Template schema. +- Implement Persona schema. +- Implement seed loader. +- Implement binding algorithm. +- Implement artifact schema registry. +- Add first schemas: + - `dev/spec@1` + - `dev/phase-plan@1` + - `common/final-report@1` +- Tests: + - schema validation. + - override semantics. + - risk enforcement. + - diversity enforcement. + - deterministic auto-select. + +### M3: Fake Session Runtime + +- Implement `SessionAdapter`. +- Implement `FakeSessionAdapter`. +- Implement prompt envelope. +- Implement event recorder. +- Implement fake sentinel scenarios. +- Persist transcript chunks. +- Tests: + - prompt correlation. + - artifact validation. + - invalid artifact. + - timeout. + - fake crash. + +### M4: Minimal Run Engine + +- Implement `packages/run-engine`. +- Used directly by `apps/api`. +- No Temporal. +- Supports: + - start run. + - lock bindings. + - approval. + - fake prompt. + - artifact wait/validate. + - final report. +- Freeze the `RunEngine` contract. +- Full fake `development@1` minus reviewers. + +### M5: Temporal Integration + +- Reimplement `RunEngine` through Temporal. +- Preserve M4 behavior. +- Add parity tests using the same M4 scenarios. +- M5+ SessionManager lives in `apps/worker`. + +### M6: Real tmux SessionManager + +- Implement `TmuxSessionAdapter`. +- Decoupled from M5. +- May begin after M3 is stable. +- Pre-M5 real tmux is opt-in smoke only. +- Production run path remains fake until both M5 and M6 are green. + +### M7: TUI Recovery State Machine + +- Implement session state transitions. +- Implement recovery counters. +- Implement escalation to human gates. + +### M8: API + GUI Minimum + +- Implement Fastify routes. +- Implement SSE. +- Implement GUI screens: + - Dashboard. + - Templates. + - Personas. + - New Run. + - Run Detail. + - Approvals. + - TUI Sessions. + +### M9: `development@1` Fake-Agent Full Run + +- Add curated `development@1`. +- Add review consensus. +- Add verifier flow with fake reviewers. +- Add coverage gate >=70% lines for core/session/run-engine. + +### M10: Codex/Claude Opt-In Real Run + +- Implement profiles: + - `packages/session/src/profiles/codex.ts` + - `packages/session/src/profiles/claude.ts` +- Real backends become production-default only after both M5 and M6 are green. +- Until then real tmux/Codex/Claude are developer-flagged opt-in smoke only. + +### M11: Parallel Lanes + +- Add task DAG scheduler. +- Add writeSet detection. +- Add per-lane worktrees. +- Add merge coordinator. +- Add conflict gates. + +### M12: Backtest Workflow + +- Add `backtest-strategy@1`. +- Add objective evaluator. +- Add metric parser extension points. +- Add failure mining artifacts. +- Add Backtest Lab GUI. + +### M13: Template Factory + +- Generate draft template from natural language and repo discovery. +- Add harness design. +- Add template review. +- Add dry-run and promote flow. + +## 21. Out of Scope + +- Authentication. +- Authorization. +- Multi-user support. +- Data retention or archival policy. +- Observability dashboards. +- Remote template/persona registries. +- Multi-machine deployment. +- HA. +- Managed backups. +- Web ingress. +- TLS. +- Reverse proxy. + +## 22. Decision Log + +### Open Questions Closed + +| # | Question | Resolution | +|---|---|---| +| OQ-1 | Persona/template seeding format | Immutable YAML at `docs/schemas/{personas,templates}/@.yaml` | +| OQ-2 | Approval timeout default | `null`; timeout freezes only | +| OQ-3 | Final report format | Markdown and JSON | +| OQ-4 | Temporal namespace/queue | namespace `devflow`, task queue `devflow-runs` | +| OQ-5 | WriteSet glob engine | `fast-glob` | +| OQ-6 | Backtest objective DSL | Stub in M12, full DSL deferred | +| OQ-7 | Codex/Claude prompt prelude | Structure locked, exact text deferred to M10 | + +### Blocking Corrections Applied + +| # | Issue | Resolution | +|---|---|---| +| CC-1 | Terminal state deleted worktrees/branches | Preserve by default; manual gated cleanup only | +| CC-2 | SessionManager location conflict | M4 API, M5+ worker | +| CC-3 | Event duplicates under retry | `run_events.idempotency_key` | +| CC-4 | Destructive command enforcement overclaimed | Devflow-direct hard, TUI best-effort | +| CC-5 | UUID extension missing | `CREATE EXTENSION IF NOT EXISTS pgcrypto` | +| CC-6 | Advisory lock not enough for active-run uniqueness | partial unique index | +| CC-7 | Undefined transition sequence in event keys | cause-based keys | +| CC-8 | Approval paused transition missing | explicit approval transition table | +| CC-9 | AutoSelect order nondeterministic | deterministic sort | +| CC-10 | SSE plugin compatibility assumed | M1 smoke + native fallback | +| CC-11 | ApprovalAction included pause | split `ApprovalDecisionAction`; `pauseRun` is run-level | +| CC-12 | Artifact hash key collision | include phase id and path | +| CC-13 | Resume previous state not stored | `runs.paused_from_state` | +| CC-14 | repo path aliasing | canonical realpath storage | +| CC-15 | M4 sweep left tmux sessions ambiguous | cascade session state to `FAILED_NEEDS_HUMAN`; real tmux production-default only after M5+M6 | +| CC-16 | Prompt hash used phaseId but envelope uses phaseKey | prompt hash uses phaseKey | +| CC-17 | abortRun transition too narrow | abort from any non-terminal run state | +| CC-18 | approval pending transition wording conflicted with pause epoch | pending can transition once per pending epoch; paused may unpause to pending | + +### Future Open Questions + +- FOQ-1, M12: full backtest objective DSL. +- FOQ-2, M13: template factory generation prompts. +- FOQ-3, post-M10: optional third backend such as Gemini. +- FOQ-4, post-M8: WebSocket vs SSE if transcript pressure requires it. + +## 23. Kickoff Order + +1. M1.1: repo + pnpm + tsconfig + biome + lefthook + vitest workspace. +2. M1.2: docker-compose + Postgres healthcheck + drizzle-kit + first migration. +3. M1.3: `apps/cli` skeleton + `devflow doctor`. +4. M1.4: `packages/core` skeleton with config, enums, errors, hash, prompt-envelope, run-event types. +5. M2.1: Zod schemas for Template/Persona, persona YAML loader, hashing. +6. M2.2: Binding algorithm + tests. +7. M2.3: Artifact schema registry + first three schemas. +8. M3.1: `SessionAdapter` interface + `FakeSessionAdapter`. +9. M3.2: Transcript chunk capture + DB persistence. +10. M3.3: engine-shaped harness running a single fake phase end-to-end. +11. M4: assemble run engine; lock contract; full fake `development@1` minus reviewers. +12. M5 in parallel with M6 once M4 is green. diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..3357b0a --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,12 @@ +pre-commit: + parallel: false + commands: + biome: + glob: "*.{ts,tsx,js,jsx,json,jsonc,md,yml,yaml}" + run: npx pnpm@9.15.9 biome check --write {staged_files} + stage_fixed: true + typecheck: + run: npx pnpm@9.15.9 typecheck + test: + glob: "*.{ts,tsx,js,jsx}" + run: npx pnpm@9.15.9 vitest related --run --passWithNoTests {staged_files} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fad36dd --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "devflow", + "version": "0.0.0", + "private": true, + "type": "module", + "packageManager": "pnpm@9.15.9", + "engines": { + "node": ">=22.0.0 <23", + "pnpm": ">=9.0.0 <10" + }, + "scripts": { + "build": "tsc -b", + "typecheck": "tsc -b --noEmit", + "test": "vitest run", + "test:watch": "vitest", + "coverage": "vitest run --coverage", + "lint": "biome check .", + "format": "biome check --write ." + }, + "devDependencies": { + "@biomejs/biome": "1.9.4", + "@types/node": "22.10.2", + "@vitest/coverage-v8": "2.1.8", + "lefthook": "2.1.6", + "tsup": "8.3.5", + "tsx": "4.19.2", + "typescript": "5.6.3", + "vite": "6.0.3", + "vitest": "2.1.8" + } +} diff --git a/packages/.gitkeep b/packages/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/packages/.gitkeep @@ -0,0 +1 @@ + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..6f6efed --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,2444 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@biomejs/biome': + specifier: 1.9.4 + version: 1.9.4 + '@types/node': + specifier: 22.10.2 + version: 22.10.2 + '@vitest/coverage-v8': + specifier: 2.1.8 + version: 2.1.8(vitest@2.1.8(@types/node@22.10.2)) + lefthook: + specifier: 2.1.6 + version: 2.1.6 + tsup: + specifier: 8.3.5 + version: 8.3.5(postcss@8.5.14)(tsx@4.19.2)(typescript@5.6.3) + tsx: + specifier: 4.19.2 + version: 4.19.2 + typescript: + specifier: 5.6.3 + version: 5.6.3 + vite: + specifier: 6.0.3 + version: 6.0.3(@types/node@22.10.2)(tsx@4.19.2) + vitest: + specifier: 2.1.8 + version: 2.1.8(@types/node@22.10.2) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@biomejs/biome@1.9.4': + resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@1.9.4': + resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@1.9.4': + resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@1.9.4': + resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@1.9.4': + resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@1.9.4': + resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@1.9.4': + resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@1.9.4': + resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@1.9.4': + resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.24.2': + resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.24.2': + resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.24.2': + resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.24.2': + resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.24.2': + resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.24.2': + resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.24.2': + resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.24.2': + resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.24.2': + resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.24.2': + resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.24.2': + resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.24.2': + resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.24.2': + resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.24.2': + resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.24.2': + resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.24.2': + resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.24.2': + resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.24.2': + resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.24.2': + resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.24.2': + resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.2': + resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.24.2': + resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.24.2': + resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.24.2': + resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.24.2': + resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} + engines: {node: '>=8'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@rollup/rollup-android-arm-eabi@4.60.3': + resolution: {integrity: sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.3': + resolution: {integrity: sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.3': + resolution: {integrity: sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.3': + resolution: {integrity: sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.3': + resolution: {integrity: sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.3': + resolution: {integrity: sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.60.3': + resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.60.3': + resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.60.3': + resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.60.3': + resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.60.3': + resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.60.3': + resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.60.3': + resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.60.3': + resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.60.3': + resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.60.3': + resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.60.3': + resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.60.3': + resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.60.3': + resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.3': + resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.3': + resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.3': + resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.3': + resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.60.3': + resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} + cpu: [x64] + os: [win32] + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/node@22.10.2': + resolution: {integrity: sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==} + + '@vitest/coverage-v8@2.1.8': + resolution: {integrity: sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==} + peerDependencies: + '@vitest/browser': 2.1.8 + vitest: 2.1.8 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/expect@2.1.8': + resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} + + '@vitest/mocker@2.1.8': + resolution: {integrity: sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.8': + resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} + + '@vitest/pretty-format@2.1.9': + resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} + + '@vitest/runner@2.1.8': + resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} + + '@vitest/snapshot@2.1.8': + resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} + + '@vitest/spy@2.1.8': + resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} + + '@vitest/utils@2.1.8': + resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.24.2: + resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} + engines: {node: '>=18'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + lefthook-darwin-arm64@2.1.6: + resolution: {integrity: sha512-hyB7eeiX78BS66f70byTJacDLC/xV1vgMv9n+idFUsrM7J3Udd/ag9Ag5NP3t0eN0EqQqAtrNnt35EH01lxnRQ==} + cpu: [arm64] + os: [darwin] + + lefthook-darwin-x64@2.1.6: + resolution: {integrity: sha512-5Ka6cFxiH83krt+OMRQtmS6zqoZR5SLXSudLjTbZA1c3ZqF0+dqkeb4XcB6plx6WR0GFizabuc6Bi3iXPIe1eQ==} + cpu: [x64] + os: [darwin] + + lefthook-freebsd-arm64@2.1.6: + resolution: {integrity: sha512-VswyOg5CVN3rMaOJ2HtnkltiMKgFHW/wouWxXsV8RxSa4tgWOKxM0EmSXi8qc2jX+LRga6B0uOY6toXS01zWxA==} + cpu: [arm64] + os: [freebsd] + + lefthook-freebsd-x64@2.1.6: + resolution: {integrity: sha512-vXsCUFYuVwrVWwcypB7Zt2Hf+5pl1V1la7ZfvGYZaTRURu0zF/XUnMF/nOz/PebGv0f4x/iOWXWwP7E42xRWsg==} + cpu: [x64] + os: [freebsd] + + lefthook-linux-arm64@2.1.6: + resolution: {integrity: sha512-WDJiQhJdZOvKORZd+kF/ms2l6NSsXzdA9ahflyr65V90AC4jES223W8VtEMbGPUtHuGWMEZ/v/XvwlWv0Ioz9g==} + cpu: [arm64] + os: [linux] + + lefthook-linux-x64@2.1.6: + resolution: {integrity: sha512-C18nCd7nTX1AVL4TcvwMmLAO1VI1OuGluIOTjiPkBQ746Ls1HhL5rl//jMPACmT28YmxIQJ2ZcLPNmhvEVBZvw==} + cpu: [x64] + os: [linux] + + lefthook-openbsd-arm64@2.1.6: + resolution: {integrity: sha512-mZOMxM8HiPxVFXDO3PtCUbH4GB8rkveXhsgXF27oAZTYVzQ3gO9vT6r/pxit6msqRXz3fvcwimLVJgb8eRsa8A==} + cpu: [arm64] + os: [openbsd] + + lefthook-openbsd-x64@2.1.6: + resolution: {integrity: sha512-sG9ALLZSnnMOfXu+B7SmxFhJhuoAh4bqi5En5aaHJET48TqrLOcWWZuH+7ArFM6gr/U5KfSUvdmHFmY8WqCcIg==} + cpu: [x64] + os: [openbsd] + + lefthook-windows-arm64@2.1.6: + resolution: {integrity: sha512-lD8yFWY4Csuljd0Rqs7EQaySC0VvDf7V3rN1FhRMUISTRDHutebIom1Loc8ckQPvKYGC6mftT9k0GvipsS+Brw==} + cpu: [arm64] + os: [win32] + + lefthook-windows-x64@2.1.6: + resolution: {integrity: sha512-q4z2n3xucLscoWiyMwFViEj3N8MDSkPulMwcJYuCYFHoPhP1h+icqNu7QRLGYj6AnVrCQweiUJY3Tb2X+GbD/A==} + cpu: [x64] + os: [win32] + + lefthook@2.1.6: + resolution: {integrity: sha512-w9sBoR0mdN+kJc3SB85VzpiAAl451/rxdCRcZlwW71QLjkeH3EBQFgc4VMj5apePychYDHAlqEWTB8J8JK/j1Q==} + hasBin: true + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss@8.5.14: + resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + engines: {node: ^10 || ^12 || >=14} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + rollup@4.60.3: + resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + test-exclude@7.0.2: + resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} + engines: {node: '>=18'} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + + tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tsup@8.3.5: + resolution: {integrity: sha512-Tunf6r6m6tnZsG9GYWndg0z8dEV7fD733VBFzFJ5Vcm1FtlXB8xBD/rtrBi2a3YKEV7hHtxiZtW5EAVADoe1pA==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + tsx@4.19.2: + resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} + engines: {node: '>=18.0.0'} + hasBin: true + + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + vite-node@2.1.8: + resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vite@6.0.3: + resolution: {integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + 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 + + vitest@2.1.8: + resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.8 + '@vitest/ui': 2.1.8 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + + whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.29.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@bcoe/v8-coverage@0.2.3': {} + + '@biomejs/biome@1.9.4': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 1.9.4 + '@biomejs/cli-darwin-x64': 1.9.4 + '@biomejs/cli-linux-arm64': 1.9.4 + '@biomejs/cli-linux-arm64-musl': 1.9.4 + '@biomejs/cli-linux-x64': 1.9.4 + '@biomejs/cli-linux-x64-musl': 1.9.4 + '@biomejs/cli-win32-arm64': 1.9.4 + '@biomejs/cli-win32-x64': 1.9.4 + + '@biomejs/cli-darwin-arm64@1.9.4': + optional: true + + '@biomejs/cli-darwin-x64@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64@1.9.4': + optional: true + + '@biomejs/cli-linux-x64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-x64@1.9.4': + optional: true + + '@biomejs/cli-win32-arm64@1.9.4': + optional: true + + '@biomejs/cli-win32-x64@1.9.4': + optional: true + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/aix-ppc64@0.23.1': + optional: true + + '@esbuild/aix-ppc64@0.24.2': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.23.1': + optional: true + + '@esbuild/android-arm64@0.24.2': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-arm@0.23.1': + optional: true + + '@esbuild/android-arm@0.24.2': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/android-x64@0.23.1': + optional: true + + '@esbuild/android-x64@0.24.2': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.23.1': + optional: true + + '@esbuild/darwin-arm64@0.24.2': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.23.1': + optional: true + + '@esbuild/darwin-x64@0.24.2': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.23.1': + optional: true + + '@esbuild/freebsd-arm64@0.24.2': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.23.1': + optional: true + + '@esbuild/freebsd-x64@0.24.2': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.23.1': + optional: true + + '@esbuild/linux-arm64@0.24.2': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-arm@0.23.1': + optional: true + + '@esbuild/linux-arm@0.24.2': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.23.1': + optional: true + + '@esbuild/linux-ia32@0.24.2': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.23.1': + optional: true + + '@esbuild/linux-loong64@0.24.2': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.23.1': + optional: true + + '@esbuild/linux-mips64el@0.24.2': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.23.1': + optional: true + + '@esbuild/linux-ppc64@0.24.2': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.23.1': + optional: true + + '@esbuild/linux-riscv64@0.24.2': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.23.1': + optional: true + + '@esbuild/linux-s390x@0.24.2': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/linux-x64@0.23.1': + optional: true + + '@esbuild/linux-x64@0.24.2': + optional: true + + '@esbuild/netbsd-arm64@0.24.2': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/netbsd-x64@0.24.2': + optional: true + + '@esbuild/openbsd-arm64@0.23.1': + optional: true + + '@esbuild/openbsd-arm64@0.24.2': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.23.1': + optional: true + + '@esbuild/openbsd-x64@0.24.2': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.23.1': + optional: true + + '@esbuild/sunos-x64@0.24.2': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.23.1': + optional: true + + '@esbuild/win32-arm64@0.24.2': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.23.1': + optional: true + + '@esbuild/win32-ia32@0.24.2': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@esbuild/win32-x64@0.23.1': + optional: true + + '@esbuild/win32-x64@0.24.2': + optional: true + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/schema@0.1.6': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@rollup/rollup-android-arm-eabi@4.60.3': + optional: true + + '@rollup/rollup-android-arm64@4.60.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.60.3': + optional: true + + '@rollup/rollup-darwin-x64@4.60.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.60.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.60.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.60.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.3': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.3': + optional: true + + '@types/estree@1.0.8': {} + + '@types/estree@1.0.9': {} + + '@types/node@22.10.2': + dependencies: + undici-types: 6.20.0 + + '@vitest/coverage-v8@2.1.8(vitest@2.1.8(@types/node@22.10.2))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 0.2.3 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.21 + magicast: 0.3.5 + std-env: 3.10.0 + test-exclude: 7.0.2 + tinyrainbow: 1.2.0 + vitest: 2.1.8(@types/node@22.10.2) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@2.1.8': + dependencies: + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.3.3 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.8(vite@5.4.21(@types/node@22.10.2))': + dependencies: + '@vitest/spy': 2.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 5.4.21(@types/node@22.10.2) + + '@vitest/pretty-format@2.1.8': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/pretty-format@2.1.9': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.8': + dependencies: + '@vitest/utils': 2.1.8 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + magic-string: 0.30.21 + pathe: 1.1.2 + + '@vitest/spy@2.1.8': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + loupe: 3.2.1 + tinyrainbow: 1.2.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + any-promise@1.3.0: {} + + assertion-error@2.0.1: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + brace-expansion@2.1.0: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + + bundle-require@5.1.0(esbuild@0.24.2): + dependencies: + esbuild: 0.24.2 + load-tsconfig: 0.2.5 + + cac@6.7.14: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + check-error@2.1.3: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@4.1.1: {} + + consola@3.4.2: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + eastasianwidth@0.2.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + es-module-lexer@1.7.0: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + + esbuild@0.24.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.2 + '@esbuild/android-arm': 0.24.2 + '@esbuild/android-arm64': 0.24.2 + '@esbuild/android-x64': 0.24.2 + '@esbuild/darwin-arm64': 0.24.2 + '@esbuild/darwin-x64': 0.24.2 + '@esbuild/freebsd-arm64': 0.24.2 + '@esbuild/freebsd-x64': 0.24.2 + '@esbuild/linux-arm': 0.24.2 + '@esbuild/linux-arm64': 0.24.2 + '@esbuild/linux-ia32': 0.24.2 + '@esbuild/linux-loong64': 0.24.2 + '@esbuild/linux-mips64el': 0.24.2 + '@esbuild/linux-ppc64': 0.24.2 + '@esbuild/linux-riscv64': 0.24.2 + '@esbuild/linux-s390x': 0.24.2 + '@esbuild/linux-x64': 0.24.2 + '@esbuild/netbsd-arm64': 0.24.2 + '@esbuild/netbsd-x64': 0.24.2 + '@esbuild/openbsd-arm64': 0.24.2 + '@esbuild/openbsd-x64': 0.24.2 + '@esbuild/sunos-x64': 0.24.2 + '@esbuild/win32-arm64': 0.24.2 + '@esbuild/win32-ia32': 0.24.2 + '@esbuild/win32-x64': 0.24.2 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.3.0: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fsevents@2.3.3: + optional: true + + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + has-flag@4.0.0: {} + + html-escaper@2.0.2: {} + + is-fullwidth-code-point@3.0.0: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + joycon@3.1.1: {} + + lefthook-darwin-arm64@2.1.6: + optional: true + + lefthook-darwin-x64@2.1.6: + optional: true + + lefthook-freebsd-arm64@2.1.6: + optional: true + + lefthook-freebsd-x64@2.1.6: + optional: true + + lefthook-linux-arm64@2.1.6: + optional: true + + lefthook-linux-x64@2.1.6: + optional: true + + lefthook-openbsd-arm64@2.1.6: + optional: true + + lefthook-openbsd-x64@2.1.6: + optional: true + + lefthook-windows-arm64@2.1.6: + optional: true + + lefthook-windows-x64@2.1.6: + optional: true + + lefthook@2.1.6: + optionalDependencies: + lefthook-darwin-arm64: 2.1.6 + lefthook-darwin-x64: 2.1.6 + lefthook-freebsd-arm64: 2.1.6 + lefthook-freebsd-x64: 2.1.6 + lefthook-linux-arm64: 2.1.6 + lefthook-linux-x64: 2.1.6 + lefthook-openbsd-arm64: 2.1.6 + lefthook-openbsd-x64: 2.1.6 + lefthook-windows-arm64: 2.1.6 + lefthook-windows-x64: 2.1.6 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + load-tsconfig@0.2.5: {} + + lodash.sortby@4.7.0: {} + + loupe@3.2.1: {} + + lru-cache@10.4.3: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.3.5: + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.8.0 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.0 + + minipass@7.1.3: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.12: {} + + object-assign@4.1.1: {} + + package-json-from-dist@1.0.1: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + pathe@1.1.2: {} + + pathval@2.0.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + pirates@4.0.7: {} + + postcss-load-config@6.0.1(postcss@8.5.14)(tsx@4.19.2): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + postcss: 8.5.14 + tsx: 4.19.2 + + postcss@8.5.14: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + punycode@2.3.1: {} + + readdirp@4.1.2: {} + + resolve-from@5.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + rollup@4.60.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.3 + '@rollup/rollup-android-arm64': 4.60.3 + '@rollup/rollup-darwin-arm64': 4.60.3 + '@rollup/rollup-darwin-x64': 4.60.3 + '@rollup/rollup-freebsd-arm64': 4.60.3 + '@rollup/rollup-freebsd-x64': 4.60.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.3 + '@rollup/rollup-linux-arm-musleabihf': 4.60.3 + '@rollup/rollup-linux-arm64-gnu': 4.60.3 + '@rollup/rollup-linux-arm64-musl': 4.60.3 + '@rollup/rollup-linux-loong64-gnu': 4.60.3 + '@rollup/rollup-linux-loong64-musl': 4.60.3 + '@rollup/rollup-linux-ppc64-gnu': 4.60.3 + '@rollup/rollup-linux-ppc64-musl': 4.60.3 + '@rollup/rollup-linux-riscv64-gnu': 4.60.3 + '@rollup/rollup-linux-riscv64-musl': 4.60.3 + '@rollup/rollup-linux-s390x-gnu': 4.60.3 + '@rollup/rollup-linux-x64-gnu': 4.60.3 + '@rollup/rollup-linux-x64-musl': 4.60.3 + '@rollup/rollup-openbsd-x64': 4.60.3 + '@rollup/rollup-openharmony-arm64': 4.60.3 + '@rollup/rollup-win32-arm64-msvc': 4.60.3 + '@rollup/rollup-win32-ia32-msvc': 4.60.3 + '@rollup/rollup-win32-x64-gnu': 4.60.3 + '@rollup/rollup-win32-x64-msvc': 4.60.3 + fsevents: 2.3.3 + + semver@7.8.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + source-map-js@1.2.1: {} + + source-map@0.8.0-beta.0: + dependencies: + whatwg-url: 7.1.0 + + stackback@0.0.2: {} + + std-env@3.10.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.16 + ts-interface-checker: 0.1.13 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + test-exclude@7.0.2: + dependencies: + '@istanbuljs/schema': 0.1.6 + glob: 10.5.0 + minimatch: 10.2.5 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinypool@1.1.1: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} + + tr46@1.0.1: + dependencies: + punycode: 2.3.1 + + tree-kill@1.2.2: {} + + ts-interface-checker@0.1.13: {} + + tsup@8.3.5(postcss@8.5.14)(tsx@4.19.2)(typescript@5.6.3): + dependencies: + bundle-require: 5.1.0(esbuild@0.24.2) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.24.2 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(postcss@8.5.14)(tsx@4.19.2) + resolve-from: 5.0.0 + rollup: 4.60.3 + source-map: 0.8.0-beta.0 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.16 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.14 + typescript: 5.6.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + + tsx@4.19.2: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.14.0 + optionalDependencies: + fsevents: 2.3.3 + + typescript@5.6.3: {} + + undici-types@6.20.0: {} + + vite-node@2.1.8(@types/node@22.10.2): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.4.21(@types/node@22.10.2) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.21(@types/node@22.10.2): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.14 + rollup: 4.60.3 + optionalDependencies: + '@types/node': 22.10.2 + fsevents: 2.3.3 + + vite@6.0.3(@types/node@22.10.2)(tsx@4.19.2): + dependencies: + esbuild: 0.24.2 + postcss: 8.5.14 + rollup: 4.60.3 + optionalDependencies: + '@types/node': 22.10.2 + fsevents: 2.3.3 + tsx: 4.19.2 + + vitest@2.1.8(@types/node@22.10.2): + dependencies: + '@vitest/expect': 2.1.8 + '@vitest/mocker': 2.1.8(vite@5.4.21(@types/node@22.10.2)) + '@vitest/pretty-format': 2.1.9 + '@vitest/runner': 2.1.8 + '@vitest/snapshot': 2.1.8 + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 1.1.2 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.1.1 + tinyrainbow: 1.2.0 + vite: 5.4.21(@types/node@22.10.2) + vite-node: 2.1.8(@types/node@22.10.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.10.2 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + webidl-conversions@4.0.2: {} + + whatwg-url@7.1.0: + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..3ff5faa --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - "apps/*" + - "packages/*" diff --git a/tests/workspace-smoke.test.ts b/tests/workspace-smoke.test.ts new file mode 100644 index 0000000..bd98cde --- /dev/null +++ b/tests/workspace-smoke.test.ts @@ -0,0 +1,7 @@ +import { describe, expect, it } from "vitest"; + +describe("workspace smoke", () => { + it("runs the root Vitest workspace", () => { + expect("devflow").toBe("devflow"); + }); +}); diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..fc46c37 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "noImplicitOverride": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "composite": true + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fdfab78 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "noEmit": true, + "types": ["node", "vitest"] + }, + "include": ["vitest.workspace.ts", "tests/**/*.ts"], + "references": [] +} diff --git a/vitest.workspace.ts b/vitest.workspace.ts new file mode 100644 index 0000000..ccdafb8 --- /dev/null +++ b/vitest.workspace.ts @@ -0,0 +1,11 @@ +import { defineWorkspace } from "vitest/config"; + +export default defineWorkspace([ + { + test: { + name: "root", + include: ["tests/**/*.test.ts"], + environment: "node", + }, + }, +]);