From 9ab5eafab5bcfa14a6a24f6012e97dbda464406c Mon Sep 17 00:00:00 2001 From: Ada Date: Thu, 1 Jan 2026 10:54:19 -0500 Subject: [PATCH] =?UTF-8?q?CORE=20[SCMS]=20scaffold=20CLI=20read=20interfa?= =?UTF-8?q?ce=20+=20contract-stable=20Lab=20Notes=20access=20=F0=9F=A7=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add notes list (read all) command - add notes get (read one) command - emit schemaVersion + intent metadata for all JSON output - normalize API envelopes + ledger-backed Lab Notes - ensure human + agent-safe rendering paths co-authored-by: Lyric co-authored-by: Carmel --- .github/RELEASE_TEMPLATE.md | 130 +++ README.md | 119 +-- bin/hpl.ts | 171 +++ package-lock.json | 1911 +++------------------------------- package.json | 65 +- src/commands/capabilities.ts | 12 + src/commands/health.ts | 55 + src/commands/notes/get.ts | 53 + src/commands/notes/list.ts | 49 + src/commands/version.ts | 15 + src/config.ts | 15 + src/contract/README.md | 11 + src/contract/capabilities.ts | 23 + src/contract/envelope.ts | 51 + src/contract/exitCodes.ts | 24 + src/contract/intents.ts | 69 ++ src/contract/schema.ts | 74 ++ src/http/client.ts | 44 + src/io.ts | 20 + src/render/table.ts | 24 + src/render/text.ts | 47 + src/types/labNotes.ts | 32 + tsconfig.json | 17 +- 23 files changed, 1123 insertions(+), 1908 deletions(-) create mode 100644 .github/RELEASE_TEMPLATE.md create mode 100644 bin/hpl.ts create mode 100644 src/commands/capabilities.ts create mode 100644 src/commands/health.ts create mode 100644 src/commands/notes/get.ts create mode 100644 src/commands/notes/list.ts create mode 100644 src/commands/version.ts create mode 100644 src/config.ts create mode 100644 src/contract/README.md create mode 100644 src/contract/capabilities.ts create mode 100644 src/contract/envelope.ts create mode 100644 src/contract/exitCodes.ts create mode 100644 src/contract/intents.ts create mode 100644 src/contract/schema.ts create mode 100644 src/http/client.ts create mode 100644 src/io.ts create mode 100644 src/render/table.ts create mode 100644 src/render/text.ts create mode 100644 src/types/labNotes.ts diff --git a/.github/RELEASE_TEMPLATE.md b/.github/RELEASE_TEMPLATE.md new file mode 100644 index 0000000..24001a1 --- /dev/null +++ b/.github/RELEASE_TEMPLATE.md @@ -0,0 +1,130 @@ +# HPL CLI v{{version}} + +> Contract-first CLI release for **The Human Pattern Lab** +> This release follows the same change classification and discipline as the Lab API. + +--- + +## πŸ”Ž Summary + +Brief, high-signal description of what this CLI release delivers and **why it exists**. + +Example: +This release introduces the first contract-stable CLI interface for reading Lab Notes from the ledger-backed API, with explicit intent metadata and machine-parseable output. + +--- + +## πŸ“¦ Compatibility + +| Component | Version | +|---------|--------| +| **CLI package** | `{{version}}` | +| **CLI schemaVersion** | `{{schemaVersion}}` | +| **Compatible API versions** | `>= {{apiVersion}}` | + +Compatibility is defined by the **CLI contract**, not by implementation details. + +--- + +## 🚨 Breaking Changes + +> Only include this section if applicable. + +- Describe **what changed** +- Describe **why it changed** +- Describe **what users or agents must do** + +Example: +- CLI JSON output for `notes list` now nests results under `data.notes` + (previously returned a top-level array) + +Breaking changes **always** imply: +- CLI `schemaVersion` bump +- Explicit callout here +- Compatibility table update + +--- + +## βž• Additive Changes + +New functionality that does **not** break existing usage. + +Example: +- Added `notes get ` command +- Added `--limit` flag to `notes list` +- Added intent metadata to all JSON outputs + +Additive changes may bump the CLI package version, but **do not require** a contract bump. + +--- + +## πŸ”§ Internal Changes + +Refactors, fixes, or improvements that do not affect external behavior. + +Example: +- Refactored HTTP client to support raw and enveloped API responses +- Improved Windows stability by removing hard process exits +- Internal rendering utilities for deterministic terminal output + +--- + +## 🧠 Contract Notes + +This release maintains the following guarantees: + +- All `--json` output conforms to `schemaVersion: {{schemaVersion}}` +- Intent identifiers are stable and unchanged +- Exit code meanings are unchanged + +If this release introduces new intents, they are **additive** and documented below. + +--- + +## 🎯 Supported Intents (Alpha Tier) + +``` +show_version +show_capabilities +check_health +render_lab_note +``` + +Intent semantics are unchanged unless explicitly stated. + +--- + +## πŸ§ͺ Validation + +Recommended verification steps: + +```bash +hpl version --json +hpl capabilities --json +hpl health --json +hpl notes list --json +hpl notes get --json +``` + +Successful execution confirms contract compatibility. + +--- + +## πŸ“š Notes + +- This CLI release aligns with the **Lab API release discipline** +- v0.x does not imply instability β€” it implies **explicit governance** +- Humans are a tolerated interface + +--- + +## πŸ”— References + +- API Release: `{{apiReleaseLink}}` +- CLI Contract: `schemaVersion {{schemaVersion}}` +- Documentation: https://thehumanpatternlab.com/docs + +--- + +🦊 +*The foxes are watching. The contract holds.* diff --git a/README.md b/README.md index 1cba175..4342043 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,35 @@ - -# Skulk CLI +Contract-first CLI for The Human Pattern Lab. -[![AI-Forward CLI](https://img.shields.io/badge/AI--Forward%20CLI-automation--safe%20by%20design-7c3aed?style=flat-square)](./DESIGN.md) ![Carmel Judgment](https://github.com/AdaInTheLab/the-human-pattern-lab-cli/actions/workflows/carmel-judgment.yml/badge.svg) ![npm](https://img.shields.io/npm/v/@thehumanpatternlab/skulk) - - -> A modern, automation-safe CLI for The Human Pattern Lab. - -Skulk is a command-line tool for syncing and managing Lab Notes β€” built to work just as well for humans at the keyboard as it does for automation, CI, and agent-driven workflows. - ---- -## What Skulk Connects To - -Skulk is the CLI for **The Human Pattern Lab API**. - -By default it targets a Human Pattern Lab API instance. You can override the API endpoint with `--base-url` to use staging or a self-hosted deployment of the same API. - -> Note: `--base-url` is intended for alternate deployments of the Human Pattern Lab API, not arbitrary third-party APIs. - ---- -## Configuration - -### Environment variables - -- `SKULK_TOKEN` β€” API token used to authenticate requests. -- `SKULK_BASE_URL` β€” Base URL for a Human Pattern Lab API instance (overridden by `--base-url`). - -Example: - -```bash -export SKULK_TOKEN="..." -export SKULK_BASE_URL="https://thehumanpatternlab.com/api" -skulk notes sync --dir ./src/labnotes/en -``` ---- - -## Why Skulk Exists - -Command-line tools no longer live in a human-only world. - -They’re run by: -- developers exploring and iterating -- scripts and CI pipelines -- automation layers and AI-assisted workflows - -Skulk was designed from the start to behave **predictably and honestly** in all of those contexts β€” without sacrificing human usability. - ---- - -## πŸ€– AI-Forward (for Humans) - -Skulk follows **AI-forward engineering principles** β€” not for AIs, but for the people who build tools that increasingly interact with them. - -### Dual Output Modes - -By default, Skulk is human-readable: +## Install (local dev) ```bash -skulk notes sync +npm install +npm run dev -- --help ``` -When `--json` is enabled: - -```bash -skulk --json notes sync -``` +## Config -Skulk switches to machine-readable output: -- stdout contains **only valid JSON** -- no banners, emojis, or progress chatter -- errors go to stderr -- exit codes are deterministic +- `HPL_API_BASE_URL` (default: `https://api.thehumanpatternlab.com`) -This makes Skulk safe to use in: -- scripts -- CI pipelines -- automation -- AI-assisted workflows +## Commands (MVP) ---- +- `hpl version` +- `hpl capabilities` +- `hpl health` +- `hpl notes list [--limit N]` +- `hpl notes get [--raw]` -## JSON Output Contract +## JSON contract -Structured output is treated as a **contract**, not a courtesy. +Add `--json` to emit machine-readable JSON only on stdout. -The repository includes a built-in verification: +### Examples ```bash -npm run json:check +hpl capabilities --json +hpl health --json +hpl notes list --json +hpl notes get the-invitation --json ``` - -This command runs Skulk in `--json` mode and fails immediately if *any* non-JSON output appears on stdout. - ---- - -## Design & Philosophy - -Curious why Skulk works this way? -β†’ [DESIGN.md](./DESIGN.md) - ---- - -## Philosophy - -> Automation shouldn’t require guessing what a tool *meant* to say. - -Skulk is boring in the best way: -predictable, explicit, and dependable. diff --git a/bin/hpl.ts b/bin/hpl.ts new file mode 100644 index 0000000..ef2342d --- /dev/null +++ b/bin/hpl.ts @@ -0,0 +1,171 @@ +#!/usr/bin/env node +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” CLI ENTRYPOINT + ----------------------------------------------------------- + Commands: + - version + - capabilities + - health + - notes list + - notes get + Contract: --json => JSON only on stdout + Notes: + - Avoid process.exit() inside command handlers (can trip libuv on Windows + tsx). + =========================================================== */ + +import { Command } from "commander"; +import { writeHuman, writeJson } from "../src/io"; +import { EXIT } from "../src/contract/exitCodes"; +import { runVersion } from "../src/commands/version"; +import { runCapabilities } from "../src/commands/capabilities"; +import { runHealth } from "../src/commands/health"; +import { runNotesList } from "../src/commands/notes/list"; +import { runNotesGet } from "../src/commands/notes/get"; +import { renderTable } from "../src/render/table"; +import { formatTags, safeLine, stripHtml } from "../src/render/text"; + +type GlobalOpts = { json?: boolean }; + +const program = new Command(); + +program + .name("hpl") + .description("Human Pattern Lab CLI (alpha)") + .option("--json", "Emit contract JSON only on stdout") + .showHelpAfterError(); + +function setExit(code: number) { + // Let Node exit naturally (important for Windows + tsx stability). + process.exitCode = code; +} + +program + .command("version") + .description("Show CLI version (contract: show_version)") + .action(() => { + const opts = program.opts(); + const envelope = runVersion("version"); + if (opts.json) writeJson(envelope); + else writeHuman(`${envelope.data.name} ${envelope.data.version}`); + setExit(EXIT.OK); + }); + +program + .command("capabilities") + .description("Show CLI capabilities for agents (contract: show_capabilities)") + .action(() => { + const opts = program.opts(); + const envelope = runCapabilities("capabilities"); + if (opts.json) writeJson(envelope); + else { + writeHuman(`intentTier: ${envelope.data.intentTier}`); + writeHuman(`schemaVersions: ${envelope.data.schemaVersions.join(", ")}`); + writeHuman(`supportedIntents:`); + for (const i of envelope.data.supportedIntents) writeHuman(` - ${i}`); + } + setExit(EXIT.OK); + }); + +program + .command("health") + .description("Check API health (contract: check_health)") + .action(async () => { + const opts = program.opts(); + const result = await runHealth("health"); + + if (opts.json) { + writeJson(result.envelope); + } else { + if (result.envelope.status === "ok") { + const d: any = (result.envelope as any).data; + const db = d.dbPath ? ` (db: ${d.dbPath})` : ""; + writeHuman(`ok${db}`); + } else { + const e: any = (result.envelope as any).error; + writeHuman(`error: ${e.code} β€” ${e.message}`); + } + } + setExit(result.exitCode); + }); + +const notes = program.command("notes").description("Lab Notes commands"); + +notes + .command("list") + .description("List lab notes (contract: render_lab_note)") + .option("--limit ", "Limit number of rows (client-side)", (v) => parseInt(v, 10)) + .action(async (cmdOpts: { limit?: number }) => { + const opts = program.opts(); + const result = await runNotesList("notes list"); + + if (opts.json) { + writeJson(result.envelope); + setExit(result.exitCode); + return; + } + + if (result.envelope.status !== "ok") { + const e: any = (result.envelope as any).error; + writeHuman(`error: ${e.code} β€” ${e.message}`); + setExit(result.exitCode); + return; + } + + const data: any = (result.envelope as any).data; + const rows = (data.notes as any[]) ?? []; + const limit = Number.isFinite(cmdOpts.limit) && (cmdOpts.limit as any) > 0 ? (cmdOpts.limit as any) : rows.length; + const slice = rows.slice(0, limit); + + const table = renderTable(slice, [ + { header: "slug", width: 28, value: (n) => safeLine(String((n as any).slug ?? "")) }, + { header: "title", width: 34, value: (n) => safeLine(String((n as any).title ?? "")) }, + { header: "status", width: 10, value: (n) => safeLine(String((n as any).status ?? "-")) }, + { header: "dept", width: 8, value: (n) => safeLine(String((n as any).department_id ?? "-")) }, + { header: "tags", width: 22, value: (n) => formatTags((n as any).tags) }, + ]); + + writeHuman(table); + writeHuman(`\ncount: ${data.count}`); + setExit(result.exitCode); + }); + +notes + .command("get") + .description("Get a lab note by slug (contract: render_lab_note)") + .argument("", "Lab Note slug") + .option("--raw", "Print raw contentHtml (no HTML stripping)") + .action(async (slug: string, cmdOpts: { raw?: boolean }) => { + const opts = program.opts(); + const result = await runNotesGet(slug, "notes get"); + + if (opts.json) { + writeJson(result.envelope); + setExit(result.exitCode); + return; + } + + if (result.envelope.status !== "ok") { + const e: any = (result.envelope as any).error; + writeHuman(`error: ${e.code} β€” ${e.message}`); + setExit(result.exitCode); + return; + } + + const n: any = (result.envelope as any).data; + + writeHuman(`# ${n.title}`); + writeHuman(`slug: ${n.slug}`); + if (n.status) writeHuman(`status: ${n.status}`); + if (n.type) writeHuman(`type: ${n.type}`); + if (n.department_id) writeHuman(`department_id: ${n.department_id}`); + if (n.published) writeHuman(`published: ${n.published}`); + if (Array.isArray(n.tags)) writeHuman(`tags: ${formatTags(n.tags)}`); + writeHuman(""); + + const body = cmdOpts.raw ? String(n.contentHtml ?? "") : stripHtml(String(n.contentHtml ?? "")); + writeHuman(body || "(no content)"); + setExit(result.exitCode); + }); + +// Let commander handle errors; set exit code without hard exit. +program.parseAsync(process.argv).catch(() => setExit(EXIT.UNKNOWN)); diff --git a/package-lock.json b/package-lock.json index 18a5d93..6f376dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,30 +1,26 @@ { - "name": "@humanpatternlab/skulk", - "version": "0.1.1", + "name": "@humanpatternlab/hpl", + "version": "0.0.1-alpha.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@humanpatternlab/skulk", - "version": "0.1.1", - "license": "ISC", + "name": "@humanpatternlab/hpl", + "version": "0.0.1-alpha.0", "dependencies": { - "commander": "^11.1.0", - "gray-matter": "^4.0.3", - "node-fetch": "^3.3.2", - "vitest": "^4.0.16", - "zod": "^4.2.1" + "commander": "^12.1.0", + "zod": "^3.24.1" }, "bin": { - "skulk": "dist/index.js" + "hpl": "dist/bin/hpl.js" }, "devDependencies": { - "@types/node": "^25.0.3", - "husky": "^9.1.7", - "lint-staged": "^16.2.7", - "prettier": "^3.7.4", - "tsx": "^4.21.0", - "typescript": "^5.9.3" + "@types/node": "^22.10.2", + "tsx": "^4.19.2", + "typescript": "^5.7.2" + }, + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/aix-ppc64": { @@ -34,6 +30,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -50,6 +47,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -66,6 +64,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -82,6 +81,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -98,6 +98,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -114,6 +115,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -130,6 +132,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -146,6 +149,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -162,6 +166,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -178,6 +183,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -194,6 +200,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -210,6 +217,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -226,6 +234,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -242,6 +251,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -258,6 +268,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -274,6 +285,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -290,6 +302,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -306,6 +319,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -322,6 +336,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -338,6 +353,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -354,6 +370,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -370,6 +387,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -386,6 +404,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -402,6 +421,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -418,6 +438,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -434,6 +455,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -443,1763 +465,150 @@ "node": ">=18" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", - "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", - "cpu": [ - "arm" - ], + "node_modules/@types/node": { + "version": "22.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz", + "integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "dependencies": { + "undici-types": "~6.21.0" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", - "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", - "cpu": [ - "arm64" - ], + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "engines": { + "node": ">=18" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", - "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", - "cpu": [ - "arm64" - ], + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", - "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", - "cpu": [ - "x64" - ], + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", - "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", - "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", - "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", - "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", - "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", - "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", - "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", - "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", - "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", - "cpu": [ - "riscv64" ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", - "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", - "cpu": [ - "riscv64" - ], + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", - "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", - "cpu": [ - "s390x" - ], + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", - "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", - "cpu": [ - "x64" - ], + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", - "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", - "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", - "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", - "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", - "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", - "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", - "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/@vitest/expect": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.16.tgz", - "integrity": "sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA==", - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.16", - "@vitest/utils": "4.0.16", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.16.tgz", - "integrity": "sha512-yb6k4AZxJTB+q9ycAvsoxGn+j/po0UaPgajllBgt1PzoMAAmJGYFdDk0uCcRcxb3BrME34I6u8gHZTQlkqSZpg==", - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.0.16", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.16.tgz", - "integrity": "sha512-eNCYNsSty9xJKi/UdVD8Ou16alu7AYiS2fCPRs0b1OdhJiV89buAXQLpTbe+X8V9L6qrs9CqyvU7OaAopJYPsA==", - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.16.tgz", - "integrity": "sha512-VWEDm5Wv9xEo80ctjORcTQRJ539EGPB3Pb9ApvVRAY1U/WkHXmmYISqU5E79uCwcW7xYUV38gwZD+RV755fu3Q==", - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.16", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.16.tgz", - "integrity": "sha512-sf6NcrYhYBsSYefxnry+DR8n3UV4xWZwWxYbCJUt2YdvtqzSPR7VfGrY0zsv090DAbjFZsi7ZaMi1KnSRyK1XA==", - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.16", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.16.tgz", - "integrity": "sha512-4jIOWjKP0ZUaEmJm00E0cOBLU+5WE0BpeNr3XN6TEF05ltro6NJqHWxXD0kA8/Zc8Nh23AT8WQxwNG+WeROupw==", - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.16.tgz", - "integrity": "sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA==", - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.16", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/ansi-escapes": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", - "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", - "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^7.1.0", - "string-width": "^8.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true, - "license": "MIT" - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "license": "MIT", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-tsconfig": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "license": "MIT", - "dependencies": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/husky": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", - "dev": true, - "license": "MIT", - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lint-staged": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", - "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^14.0.2", - "listr2": "^9.0.5", - "micromatch": "^4.0.8", - "nano-spawn": "^2.0.0", - "pidtree": "^0.6.0", - "string-argv": "^0.3.2", - "yaml": "^2.8.1" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/listr2": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^5.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nano-spawn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", - "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT" - }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prettier": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", - "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "devOptional": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rollup": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", - "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.54.0", - "@rollup/rollup-android-arm64": "4.54.0", - "@rollup/rollup-darwin-arm64": "4.54.0", - "@rollup/rollup-darwin-x64": "4.54.0", - "@rollup/rollup-freebsd-arm64": "4.54.0", - "@rollup/rollup-freebsd-x64": "4.54.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", - "@rollup/rollup-linux-arm-musleabihf": "4.54.0", - "@rollup/rollup-linux-arm64-gnu": "4.54.0", - "@rollup/rollup-linux-arm64-musl": "4.54.0", - "@rollup/rollup-linux-loong64-gnu": "4.54.0", - "@rollup/rollup-linux-ppc64-gnu": "4.54.0", - "@rollup/rollup-linux-riscv64-gnu": "4.54.0", - "@rollup/rollup-linux-riscv64-musl": "4.54.0", - "@rollup/rollup-linux-s390x-gnu": "4.54.0", - "@rollup/rollup-linux-x64-gnu": "4.54.0", - "@rollup/rollup-linux-x64-musl": "4.54.0", - "@rollup/rollup-openharmony-arm64": "4.54.0", - "@rollup/rollup-win32-arm64-msvc": "4.54.0", - "@rollup/rollup-win32-ia32-msvc": "4.54.0", - "@rollup/rollup-win32-x64-gnu": "4.54.0", - "@rollup/rollup-win32-x64-msvc": "4.54.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "license": "MIT", - "dependencies": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "license": "BSD-3-Clause" - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "license": "MIT" - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "license": "MIT" - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", - "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/vite": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", - "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", - "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vitest": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.16.tgz", - "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==", - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.0.16", - "@vitest/mocker": "4.0.16", - "@vitest/pretty-format": "4.0.16", - "@vitest/runner": "4.0.16", - "@vitest/snapshot": "4.0.16", - "@vitest/spy": "4.0.16", - "@vitest/utils": "4.0.16", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^3.10.0", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.16", - "@vitest/browser-preview": "4.0.16", - "@vitest/browser-webdriverio": "4.0.16", - "@vitest/ui": "4.0.16", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "devOptional": true, - "license": "ISC", - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } + "license": "MIT" }, "node_modules/zod": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.2.1.tgz", - "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index ee8f830..3e6c4ce 100644 --- a/package.json +++ b/package.json @@ -1,62 +1,27 @@ { - "name": "@thehumanpatternlab/skulk", - "version": "0.1.1", - "private": false, - "description": "CLI for syncing Lab Notes with The Human Pattern Lab API", - "keywords": [ - "cli", - "automation", - "human-pattern-lab" - ], - "author": "Ada Vale", - "license": "MIT", + "name": "@thehumanpatternlab/hpl", + "version": "0.0.1-alpha.0", + "private": true, "type": "module", "bin": { - "skulk": "dist/index.js" + "hpl": "./dist/bin/hpl.js" }, - "files": [ - "dist/index.js", - "dist/lab.js", - "dist/cli/**", - "dist/commands/**", - "dist/lib/**", - "dist/sdk/**", - "dist/sync/**", - "dist/utils/**" - ], "scripts": { - "dev": "tsx src/index.ts", - "build": "tsc", - "build:watch": "tsc -w", - "json:check": "skulk --json notes sync --dry-run --dir \"../the-human-pattern-lab/src/labnotes/en\" | node -e \"JSON.parse(require('fs').readFileSync(0,'utf8')); console.log('JSON output is clean βœ…')\"", - "json:check:pretty": "npm run json:check && echo \"JSON output is clean βœ…\"", - "start": "node dist/index.js", - "test": "vitest", - "test:run": "vitest run", - "test:watch": "vitest watch", - "link": "npm run build && npm link" + "dev": "tsx ./bin/hpl.ts", + "build": "tsc -p tsconfig.json", + "start": "node ./dist/bin/hpl.js", + "lint": "node -e \"console.log('lint: add eslint when ready')\"" }, "dependencies": { - "commander": "^11.1.0", - "gray-matter": "^4.0.3", - "node-fetch": "^3.3.2", - "zod": "^4.2.1" + "commander": "^12.1.0", + "zod": "^3.24.1" }, "devDependencies": { - "@types/node": "^25.0.3", - "husky": "^9.1.7", - "lint-staged": "^16.2.7", - "prettier": "^3.7.4", - "tsx": "^4.21.0", - "vitest": "^4.0.16", - "typescript": "^5.9.3" + "@types/node": "^22.10.2", + "tsx": "^4.19.2", + "typescript": "^5.7.2" }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } - }, - "lint-staged": { - "*.{js,ts,md,json}": "prettier --write" + "engines": { + "node": ">=18" } } diff --git a/src/commands/capabilities.ts b/src/commands/capabilities.ts new file mode 100644 index 0000000..6f9fc4c --- /dev/null +++ b/src/commands/capabilities.ts @@ -0,0 +1,12 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” COMMAND: capabilities + =========================================================== */ + +import { getAlphaIntent } from "../contract/intents"; +import { ok } from "../contract/envelope"; +import { getCapabilitiesAlpha } from "../contract/capabilities"; + +export function runCapabilities(commandName = "capabilities") { + const intent = getAlphaIntent("show_capabilities"); + return ok(commandName, intent, getCapabilitiesAlpha()); +} diff --git a/src/commands/health.ts b/src/commands/health.ts new file mode 100644 index 0000000..7a542a2 --- /dev/null +++ b/src/commands/health.ts @@ -0,0 +1,55 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” COMMAND: health + =========================================================== */ + +import { z } from "zod"; +import { getAlphaIntent } from "../contract/intents"; +import { ok, err } from "../contract/envelope"; +import { EXIT } from "../contract/exitCodes"; +import { getJson, HttpError } from "../http/client"; + +const HealthSchema = z.object({ + status: z.string(), + dbPath: z.string().optional(), +}); + +export type HealthData = z.infer; + +export async function runHealth(commandName = "health") { + const intent = getAlphaIntent("check_health"); + + try { + const payload = await getJson("/health"); + const parsed = HealthSchema.safeParse(payload); + if (!parsed.success) { + return { + envelope: err(commandName, intent, { + code: "E_CONTRACT", + message: "Health response did not match expected schema", + details: parsed.error.flatten(), + }), + exitCode: EXIT.CONTRACT, + }; + } + + return { envelope: ok(commandName, intent, parsed.data), exitCode: EXIT.OK }; + } catch (e) { + if (e instanceof HttpError) { + const code = e.status && e.status >= 500 ? "E_SERVER" : "E_HTTP"; + return { + envelope: err(commandName, intent, { + code, + message: `API request failed (${e.status ?? "unknown"})`, + details: e.body ? e.body.slice(0, 500) : undefined, + }), + exitCode: e.status && e.status >= 500 ? EXIT.SERVER : EXIT.NETWORK, + }; + } + + const msg = e instanceof Error ? e.message : String(e); + return { + envelope: err(commandName, intent, { code: "E_UNKNOWN", message: msg }), + exitCode: EXIT.UNKNOWN, + }; + } +} diff --git a/src/commands/notes/get.ts b/src/commands/notes/get.ts new file mode 100644 index 0000000..1a381d8 --- /dev/null +++ b/src/commands/notes/get.ts @@ -0,0 +1,53 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” COMMAND: notes get + =========================================================== */ + +import { getAlphaIntent } from "../../contract/intents"; +import { ok, err } from "../../contract/envelope"; +import { EXIT } from "../../contract/exitCodes"; +import { getJson, HttpError } from "../../http/client"; +import { LabNoteSchema, type LabNote } from "../../types/labNotes"; + +export async function runNotesGet(slug: string, commandName = "notes get") { + const intent = getAlphaIntent("render_lab_note"); + + try { + const payload = await getJson(`/lab-notes/${encodeURIComponent(slug)}`); + const parsed = LabNoteSchema.safeParse(payload); + + if (!parsed.success) { + return { + envelope: err(commandName, intent, { + code: "E_CONTRACT", + message: "Lab Note did not match expected schema", + details: parsed.error.flatten(), + }), + exitCode: EXIT.CONTRACT, + }; + } + + const note: LabNote = parsed.data; + return { envelope: ok(commandName, intent, note), exitCode: EXIT.OK }; + } catch (e) { + if (e instanceof HttpError) { + if (e.status == 404) { + return { + envelope: err(commandName, intent, { code: "E_NOT_FOUND", message: `No lab note found for slug: ${slug}` }), + exitCode: EXIT.NOT_FOUND, + }; + } + const code = e.status && e.status >= 500 ? "E_SERVER" : "E_HTTP"; + return { + envelope: err(commandName, intent, { + code, + message: `API request failed (${e.status ?? "unknown"})`, + details: e.body ? e.body.slice(0, 500) : undefined, + }), + exitCode: e.status && e.status >= 500 ? EXIT.SERVER : EXIT.NETWORK, + }; + } + + const msg = e instanceof Error ? e.message : String(e); + return { envelope: err(commandName, intent, { code: "E_UNKNOWN", message: msg }), exitCode: EXIT.UNKNOWN }; + } +} diff --git a/src/commands/notes/list.ts b/src/commands/notes/list.ts new file mode 100644 index 0000000..aa568a7 --- /dev/null +++ b/src/commands/notes/list.ts @@ -0,0 +1,49 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” COMMAND: notes list + =========================================================== */ + +import { getAlphaIntent } from "../../contract/intents"; +import { ok, err } from "../../contract/envelope"; +import { EXIT } from "../../contract/exitCodes"; +import { getJson, HttpError } from "../../http/client"; +import { LabNoteListSchema, type LabNote } from "../../types/labNotes"; + +export async function runNotesList(commandName = "notes list") { + const intent = getAlphaIntent("render_lab_note"); + + try { + const payload = await getJson("/lab-notes"); + const parsed = LabNoteListSchema.safeParse(payload); + + if (!parsed.success) { + return { + envelope: err(commandName, intent, { + code: "E_CONTRACT", + message: "Lab Notes list did not match expected schema", + details: parsed.error.flatten(), + }), + exitCode: EXIT.CONTRACT, + }; + } + + // Deterministic: preserve API order, but ensure stable array type. + const notes: LabNote[] = parsed.data; + + return { envelope: ok(commandName, intent, { count: notes.length, notes }), exitCode: EXIT.OK }; + } catch (e) { + if (e instanceof HttpError) { + const code = e.status && e.status >= 500 ? "E_SERVER" : "E_HTTP"; + return { + envelope: err(commandName, intent, { + code, + message: `API request failed (${e.status ?? "unknown"})`, + details: e.body ? e.body.slice(0, 500) : undefined, + }), + exitCode: e.status && e.status >= 500 ? EXIT.SERVER : EXIT.NETWORK, + }; + } + + const msg = e instanceof Error ? e.message : String(e); + return { envelope: err(commandName, intent, { code: "E_UNKNOWN", message: msg }), exitCode: EXIT.UNKNOWN }; + } +} diff --git a/src/commands/version.ts b/src/commands/version.ts new file mode 100644 index 0000000..5a7e965 --- /dev/null +++ b/src/commands/version.ts @@ -0,0 +1,15 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” COMMAND: version + =========================================================== */ + +import { createRequire } from "node:module"; +import { getAlphaIntent } from "../contract/intents"; +import { ok } from "../contract/envelope"; + +const require = createRequire(import.meta.url); +const pkg = require("../../package.json") as { name: string; version: string }; + +export function runVersion(commandName = "version") { + const intent = getAlphaIntent("show_version"); + return ok(commandName, intent, { name: pkg.name, version: pkg.version }); +} diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..6da2f63 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,15 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” CLI CONFIG + ----------------------------------------------------------- + Purpose: Single source of truth for config resolution. + Contract: Deterministic defaults. + =========================================================== */ + +export type CliConfig = { + apiBaseUrl: string; +}; + +export function getConfig(): CliConfig { + const apiBaseUrl = (process.env.HPL_API_BASE_URL || "https://api.thehumanpatternlab.com").replace(/\/+$/, ""); + return { apiBaseUrl }; +} diff --git a/src/contract/README.md b/src/contract/README.md new file mode 100644 index 0000000..a8ded44 --- /dev/null +++ b/src/contract/README.md @@ -0,0 +1,11 @@ +# CLI Contract Layer (Alpha Tier) + +This folder contains the **contract-first** building blocks required by the Lab CLI MVP contract: + +- **Intent registry** (`intents.ts`): stable intent identifiers + metadata +- **Schema layer** (`schema.ts`): versioned Zod schemas for JSON output +- **Envelope builders** (`envelope.ts`): canonical constructors for contract outputs +- **Exit codes** (`exitCodes.ts`): stable, predictable meanings +- **Capabilities** (`capabilities.ts`): machine-discoverable CLI support surface + +Source of truth: **Lab CLI MVP Contract (v0.x)**. diff --git a/src/contract/capabilities.ts b/src/contract/capabilities.ts new file mode 100644 index 0000000..f01f1f3 --- /dev/null +++ b/src/contract/capabilities.ts @@ -0,0 +1,23 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” CLI CAPABILITIES (Alpha Tier) + ----------------------------------------------------------- + Purpose: Capability disclosure for AI agents (no assumptions). + Contract: show_capabilities MUST emit tier, intents, schema versions. + =========================================================== */ + +import { CLI_SCHEMA_VERSION } from "./schema"; +import { listAlphaIntents } from "./intents"; + +export type Capabilities = { + intentTier: "alpha" | "full"; + supportedIntents: string[]; + schemaVersions: string[]; +}; + +export function getCapabilitiesAlpha(): Capabilities { + return { + intentTier: "alpha", + supportedIntents: listAlphaIntents().map((i) => i.intent), + schemaVersions: [CLI_SCHEMA_VERSION], + }; +} diff --git a/src/contract/envelope.ts b/src/contract/envelope.ts new file mode 100644 index 0000000..3d0c9aa --- /dev/null +++ b/src/contract/envelope.ts @@ -0,0 +1,51 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” CLI ENVELOPE BUILDERS (Alpha Tier) + ----------------------------------------------------------- + Purpose: Single source of truth for contract-compliant JSON output. + Guarantee: When --json, stdout emits JSON only (no logs). + =========================================================== */ + +import type { IntentDescriptor } from "./intents"; +import { CLI_SCHEMA_VERSION, type ErrorPayload } from "./schema"; + +export type CommandStatus = "ok" | "warn" | "error"; + +export type BaseEnvelope = { + schemaVersion: typeof CLI_SCHEMA_VERSION; + command: string; + status: CommandStatus; + intent: IntentDescriptor; +}; + +export type SuccessEnvelope = BaseEnvelope & { + status: "ok"; + data: T; +}; + +export type WarnEnvelope = BaseEnvelope & { + status: "warn"; + warnings: string[]; + data?: T; +}; + +export type ErrorEnvelope = BaseEnvelope & { + status: "error"; + error: ErrorPayload; +}; + +export function ok(command: string, intent: IntentDescriptor, data: T): SuccessEnvelope { + return { schemaVersion: CLI_SCHEMA_VERSION, command, status: "ok", intent, data }; +} + +export function warn( + command: string, + intent: IntentDescriptor, + warnings: string[], + data?: T +): WarnEnvelope { + return { schemaVersion: CLI_SCHEMA_VERSION, command, status: "warn", intent, warnings, data }; +} + +export function err(command: string, intent: IntentDescriptor, error: ErrorPayload): ErrorEnvelope { + return { schemaVersion: CLI_SCHEMA_VERSION, command, status: "error", intent, error }; +} diff --git a/src/contract/exitCodes.ts b/src/contract/exitCodes.ts new file mode 100644 index 0000000..4e35b6a --- /dev/null +++ b/src/contract/exitCodes.ts @@ -0,0 +1,24 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” CLI EXIT CODES (Alpha Tier) + ----------------------------------------------------------- + Purpose: Consistent meanings across commands (machine-parseable). + Contract: "Errors & Exit Codes" predictable and structured. + =========================================================== */ + +/** + * Exit code meanings are stable across commands. + * Additive only; do not repurpose existing numeric values. + */ +export const EXIT = { + OK: 0, + USAGE: 2, // bad args / invalid flags + NOT_FOUND: 3, // 404 semantics + AUTH: 4, // auth required / invalid token + FORBIDDEN: 5, // insufficient scope/permission + NETWORK: 10, // DNS/timeout/unreachable + SERVER: 11, // 5xx or unexpected response + CONTRACT: 12, // schema mismatch / invalid JSON contract + UNKNOWN: 1, +} as const; + +export type ExitCode = (typeof EXIT)[keyof typeof EXIT]; diff --git a/src/contract/intents.ts b/src/contract/intents.ts new file mode 100644 index 0000000..40b4724 --- /dev/null +++ b/src/contract/intents.ts @@ -0,0 +1,69 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” CLI INTENT REGISTRY (Alpha Tier) + ----------------------------------------------------------- + Purpose: Machine-legible, stable intent identifiers for CLI commands. + Contract: Lab CLI MVP Contract v0.x (Intent Registry + Explicit Intent) + Notes: + - Intent IDs are snake_case and treated as contractual identifiers. + - Changing the meaning of an intent is breaking, even in v0.x. + =========================================================== */ + +export type IntentTier = "alpha" | "full"; + +export type IntentDescriptor = { + /** Stable identifier (snake_case). */ + intent: string; + /** Intent schema version (string to allow semver-ish). */ + intentVersion: "1"; + /** What resources the command reads or touches. */ + scope: string[]; + /** Declared side effects. Empty for read-only. */ + sideEffects: string[]; + /** True if the command's effects can be undone without data loss. */ + reversible: boolean; +}; + +/** + * Alpha Tier intents (MVP). + * Additive only. Do not change semantics of existing IDs. + */ +export const INTENTS_ALPHA = { + show_version: { + intent: "show_version", + intentVersion: "1", + scope: ["cli"], + sideEffects: [], + reversible: true, + }, + show_capabilities: { + intent: "show_capabilities", + intentVersion: "1", + scope: ["cli"], + sideEffects: [], + reversible: true, + }, + check_health: { + intent: "check_health", + intentVersion: "1", + scope: ["remote_api"], + sideEffects: [], + reversible: true, + }, + render_lab_note: { + intent: "render_lab_note", + intentVersion: "1", + scope: ["lab_notes", "remote_api"], + sideEffects: [], + reversible: true, + }, +} as const satisfies Record; + +export type AlphaIntentId = keyof typeof INTENTS_ALPHA; + +export function getAlphaIntent(id: AlphaIntentId): IntentDescriptor { + return INTENTS_ALPHA[id]; +} + +export function listAlphaIntents(): IntentDescriptor[] { + return Object.values(INTENTS_ALPHA); +} diff --git a/src/contract/schema.ts b/src/contract/schema.ts new file mode 100644 index 0000000..2d62b4a --- /dev/null +++ b/src/contract/schema.ts @@ -0,0 +1,74 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” CLI OUTPUT SCHEMAS (Alpha Tier) + ----------------------------------------------------------- + Purpose: Enforce the "JSON is a Contract" guarantee for --json mode. + Contract: Lab CLI MVP Contract v0.x (Schema Versioning + Determinism) + =========================================================== */ + +import { z } from "zod"; + +/** Global structured output schema version (CLI contract layer). */ +export const CLI_SCHEMA_VERSION = "0.1" as const; + +export const StatusSchema = z.enum(["ok", "warn", "error"]); + +export const IntentBlockSchema = z.object({ + intent: z.string(), + intentVersion: z.literal("1"), + scope: z.array(z.string()), + sideEffects: z.array(z.string()), + reversible: z.boolean(), +}); + +/** + * Base envelope required by the contract for all --json outputs. + * Commands extend this with typed `data` for success, or `error` for failures. + */ +export const BaseEnvelopeSchema = z.object({ + schemaVersion: z.literal(CLI_SCHEMA_VERSION), + command: z.string(), + status: StatusSchema, + intent: IntentBlockSchema, +}); + +export type BaseEnvelope = z.infer; + +/** Standard error payload (machine-parseable). */ +export const ErrorPayloadSchema = z.object({ + code: z.string(), // stable error code (e.g., "E_NETWORK", "E_AUTH") + message: z.string(), // short human-readable + details: z.unknown().optional() // optional machine-parseable context +}); + +export type ErrorPayload = z.infer; + +/** + * Success envelope: { ...base, data: T } + */ +export function successSchema(dataSchema: T) { + return BaseEnvelopeSchema.extend({ + status: z.literal("ok"), + data: dataSchema, + }); +} + +/** + * Warning envelope: { ...base, warnings: [...], data?: T } + */ +export function warnSchema(dataSchema?: T) { + const base = BaseEnvelopeSchema.extend({ + status: z.literal("warn"), + warnings: z.array(z.string()).min(1), + }); + return dataSchema ? base.extend({ data: dataSchema }) : base; +} + +/** + * Error envelope: { ...base, error: { code, message, details? } } + */ +export const ErrorEnvelopeSchema = BaseEnvelopeSchema.extend({ + status: z.literal("error"), + error: ErrorPayloadSchema, +}); + +export type ErrorEnvelope = z.infer; diff --git a/src/http/client.ts b/src/http/client.ts new file mode 100644 index 0000000..fb99946 --- /dev/null +++ b/src/http/client.ts @@ -0,0 +1,44 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” HTTP CLIENT (minimal) + ----------------------------------------------------------- + Purpose: Fetch wrapper with consistent error shaping. + Notes: + - Supports both raw API payloads and envelope form { ok: true, data: ... }. + =========================================================== */ + +import { getConfig } from "../config"; + +export class HttpError extends Error { + status?: number; + body?: string; + + constructor(message: string, status?: number, body?: string) { + super(message); + this.name = "HttpError"; + this.status = status; + this.body = body; + } +} + +function unwrap(payload: unknown): T { + if (payload && typeof payload === "object" && (payload as any).ok === true) { + return (payload as any).data as T; + } + return payload as T; +} + +export async function getJson(path: string, signal?: AbortSignal): Promise { + const { apiBaseUrl } = getConfig(); + const url = apiBaseUrl + path; + + const res = await fetch(url, { method: "GET", signal }); + + if (!res.ok) { + let body = ""; + try { body = await res.text(); } catch { /* ignore */ } + throw new HttpError(`GET ${path} failed`, res.status, body); + } + + const payload = (await res.json()) as unknown; + return unwrap(payload); +} diff --git a/src/io.ts b/src/io.ts new file mode 100644 index 0000000..6dce53e --- /dev/null +++ b/src/io.ts @@ -0,0 +1,20 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” CLI IO GATE + ----------------------------------------------------------- + Purpose: Enforce "--json means JSON only on stdout". + =========================================================== */ + +export type OutputMode = "human" | "json"; + +export function writeJson(obj: unknown): void { + process.stdout.write(JSON.stringify(obj, null, 2) + "\n"); +} + +export function writeHuman(text: string): void { + process.stdout.write(text.endsWith("\n") ? text : text + "\n"); +} + +/** Logs to stderr only. Safe to call even in --json mode (but we avoid it by policy). */ +export function logErr(message: string): void { + process.stderr.write(message.endsWith("\n") ? message : message + "\n"); +} diff --git a/src/render/table.ts b/src/render/table.ts new file mode 100644 index 0000000..0d6b635 --- /dev/null +++ b/src/render/table.ts @@ -0,0 +1,24 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” TABLE RENDERER (tiny) + ----------------------------------------------------------- + Purpose: Deterministic fixed-width table output. + =========================================================== */ + +export type Column = { + header: string; + width: number; + value: (row: T) => string; +}; + +function pad(s: string, width: number): string { + const str = (s ?? "").toString(); + if (str.length >= width) return str.slice(0, Math.max(0, width - 1)) + "…"; + return str + " ".repeat(width - str.length); +} + +export function renderTable(rows: T[], cols: Column[]): string { + const header = cols.map((c) => pad(c.header, c.width)).join(" "); + const sep = cols.map((c) => "-".repeat(c.width)).join(" "); + const body = rows.map((r) => cols.map((c) => pad(c.value(r), c.width)).join(" ")).join("\n"); + return [header, sep, body].filter(Boolean).join("\n"); +} diff --git a/src/render/text.ts b/src/render/text.ts new file mode 100644 index 0000000..91eaa24 --- /dev/null +++ b/src/render/text.ts @@ -0,0 +1,47 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” TEXT RENDER UTILS + ----------------------------------------------------------- + Purpose: Deterministic, dependency-free formatting for terminals. + =========================================================== */ + +export function stripHtml(input: string): string { + const s = (input || ""); + + // Convert common structure to deterministic newlines first + const withBreaks = s + .replace(/<\s*br\s*\/?>/gi, "\n") + .replace(/<\/\s*p\s*>/gi, "\n\n") + .replace(/<\s*p[^>]*>/gi, "") + .replace(/<\s*hr\s*\/?>/gi, "\n---\n") + .replace(/<\/\s*li\s*>/gi, "\n") + .replace(/<\s*li[^>]*>/gi, "- ") + .replace(/<\/\s*ul\s*>/gi, "\n") + .replace(/<\s*ul[^>]*>/gi, ""); + + // Strip scripts/styles then remaining tags + const stripped = withBreaks + .replace(/)<[^<]*)*<\/script>/gi, "") + .replace(/)<[^<]*)*<\/style>/gi, "") + .replace(/<[^>]+>/g, ""); + + // Decode a few entities + normalize whitespace + return stripped + .replace(/ /g, " ") + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/\r\n/g, "\n") + .replace(/[ \t]+\n/g, "\n") + .replace(/\n{3,}/g, "\n\n") + .trim(); +} + + +export function safeLine(s: string): string { + return (s ?? "").replace(/\s+/g, " ").trim(); +} + +export function formatTags(tags: string[] | undefined): string { + const t = (tags ?? []).filter(Boolean); + return t.length ? t.join(", ") : "-"; +} diff --git a/src/types/labNotes.ts b/src/types/labNotes.ts new file mode 100644 index 0000000..a0fdc52 --- /dev/null +++ b/src/types/labNotes.ts @@ -0,0 +1,32 @@ +/* =========================================================== + 🌌 HUMAN PATTERN LAB β€” TYPES: Lab Notes (CLI) + ----------------------------------------------------------- + Purpose: API contract types for Lab Notes used by the CLI. + Notes: + - Keep permissive: API may add fields (additive). + =========================================================== */ + +import { z } from "zod"; + +export const LabNoteSchema = z.object({ + id: z.string(), + slug: z.string(), + title: z.string(), + summary: z.string().optional().default(""), + contentHtml: z.string().optional().default(""), + published: z.string().optional().nullable(), + status: z.string().optional(), + type: z.string().optional(), + locale: z.string().optional(), + department_id: z.string().optional(), + shadow_density: z.number().optional(), + safer_landing: z.boolean().optional(), + tags: z.array(z.string()).optional().default([]), + readingTime: z.number().optional(), + created_at: z.string().optional(), + updated_at: z.string().optional(), +}).passthrough(); + +export type LabNote = z.infer; + +export const LabNoteListSchema = z.array(LabNoteSchema); diff --git a/tsconfig.json b/tsconfig.json index 1c01bb4..89c0ef9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,15 +1,16 @@ { "compilerOptions": { "target": "ES2022", - "module": "NodeNext", - "moduleResolution": "NodeNext", + "lib": ["ES2022"], + "module": "ES2022", + "moduleResolution": "Bundler", + "rootDir": ".", "outDir": "dist", - "rootDir": "src", - "verbatimModuleSyntax": true, "strict": true, + "esModuleInterop": true, "skipLibCheck": true, - "esModuleInterop": true + "forceConsistentCasingInFileNames": true, + "types": ["node"] }, - "include": ["src/**/*.ts"], - "exclude": ["node_modules", "dist"] -} \ No newline at end of file + "include": ["src/**/*", "bin/**/*"] +}