diff --git a/.github/docs-corpus/check_drift.sh b/.github/docs-corpus/check_drift.sh new file mode 100644 index 00000000..ab623305 --- /dev/null +++ b/.github/docs-corpus/check_drift.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +# git diff omits untracked replacement pages when a generated route changes. +# Porcelain includes those pages, deletions, staged changes and working-tree edits. +changes=$(git status --porcelain=v1 --untracked-files=all -- src/content/docs) +if [[ -n "$changes" ]]; then + git diff -- src/content/docs + git diff --cached -- src/content/docs + printf '%s\n' "$changes" + printf '%s\n' \ + 'DRIFT: the committed site does not match its pinned generation inputs.' \ + 'Commit regenerated content together with the input pin changes.' + exit 1 +fi +printf '%s\n' 'content: committed tree matches the pinned inputs (regeneration is a no-op).' diff --git a/.github/docs-corpus/test_check_drift.py b/.github/docs-corpus/test_check_drift.py new file mode 100644 index 00000000..5ccd6a2c --- /dev/null +++ b/.github/docs-corpus/test_check_drift.py @@ -0,0 +1,72 @@ +"""Exercise the drift gate at its real Git boundary, including new routes.""" + +import pathlib +import subprocess +import tempfile +import unittest + + +GATE = pathlib.Path(__file__).with_name("check_drift.sh").resolve() + + +class DriftGateTest(unittest.TestCase): + def setUp(self): + self.temp = tempfile.TemporaryDirectory() + self.addCleanup(self.temp.cleanup) + self.repo = pathlib.Path(self.temp.name) + self.git("init", "--quiet") + self.git("config", "user.name", "Drift gate test") + self.git("config", "user.email", "drift-test@example.invalid") + self.page = self.repo / "src/content/docs/index.md" + self.page.parent.mkdir(parents=True) + self.page.write_text("committed page\n") + self.git("add", "src/content/docs") + self.git("commit", "--quiet", "-m", "baseline") + + def git(self, *args): + return subprocess.run( + ["git", "-C", str(self.repo), *args], + check=True, capture_output=True, text=True, + ) + + def gate(self): + return subprocess.run( + ["bash", str(GATE)], cwd=self.repo, capture_output=True, text=True, + ) + + def test_clean_content(self): + result = self.gate() + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + self.assertIn("regeneration is a no-op", result.stdout) + + def test_modified_content(self): + self.page.write_text("regenerated page\n") + result = self.gate() + self.assertEqual(result.returncode, 1) + self.assertIn("DRIFT:", result.stdout) + + def test_deleted_content(self): + self.page.unlink() + self.assertEqual(self.gate().returncode, 1) + + def test_untracked_route_without_tracked_diff(self): + route = self.page.parent / "reference/new-version/plugin.md" + route.parent.mkdir(parents=True) + route.write_text("new generated route\n") + self.assertEqual(self.git("diff", "--exit-code").returncode, 0) + result = self.gate() + self.assertEqual(result.returncode, 1) + self.assertIn("?? src/content/docs/reference/new-version/plugin.md", result.stdout) + + def test_staged_content(self): + self.page.write_text("staged generated page\n") + self.git("add", "src/content/docs") + self.assertEqual(self.gate().returncode, 1) + + def test_unrelated_change(self): + (self.repo / "STYLE.md").write_text("unrelated style edit\n") + self.assertEqual(self.gate().returncode, 0) + + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 56286f80..32ad7328 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -6,7 +6,7 @@ # consumer fetch trees and was removed), and this workflow # # 1. clones the pinned charly (recursive, with its box/* submodules) into /tmp/charly -# at CI time and checks out the pinned commit b79851d, plus the pinned +# at CI time and checks out the recorded source commit, plus the pinned # marketplace submodule (the corpus the skill pages project from), # 2. builds the standalone plugin-docs CLI binary at the pinned plugin tag (generation # reads the pinned charly SOURCE TREE, so that checkout never has to compile), @@ -64,7 +64,7 @@ jobs: # submodules: --recursive at clone time pulls each box at its default-branch HEAD, # but the committed docs content was generated against the box commits the pinned # charly checkout records — checkout-then-init pins them exactly. - git clone https://github.com/opencharly/charly.git /tmp/charly && git -C /tmp/charly checkout 3cabeb3f003dedc6d6b201352cba792daf93c1cf && git -C /tmp/charly submodule update --init --recursive + git clone https://github.com/opencharly/charly.git /tmp/charly && git -C /tmp/charly checkout bafd8dbc3110904872831998fb4caa701cc2990c && git -C /tmp/charly submodule update --init --recursive # The four root narratives (SOUL.md/VISION.md/GRIEVANCES.md/LIBERATION.md) moved # from the charly root to the UMBRELLA root (opencharly/opencharly#357); the # generator reads them from the umbrella checkout passed as --narrative below. @@ -76,15 +76,22 @@ jobs: node-version-file: .node-version cache: npm + # setup-go hashes only files inside GITHUB_WORKSPACE. Keep the module it + # actually compiles here, rather than keying its cache on /tmp/charly. + - name: Fetch the pinned docs generator + run: git clone --depth 1 --branch v2026.289.0814 https://github.com/opencharly/plugin-docs.git .docs-generator + - uses: actions/setup-go@v7 with: - go-version-file: /tmp/charly/charly/go.mod - cache-dependency-path: /tmp/charly/charly/go.sum + go-version-file: .docs-generator/candy/plugin-docs/go.mod + cache-dependency-path: .docs-generator/candy/plugin-docs/go.sum - name: Build the standalone plugin-docs CLI binary - run: | - git clone --depth 1 --branch v2026.278.0442 https://github.com/opencharly/plugin-docs.git /tmp/plugin-docs - cd /tmp/plugin-docs/candy/plugin-docs && go build -o /tmp/plugin-docs-bin ./cmd/serve + working-directory: .docs-generator/candy/plugin-docs + run: go build -o /tmp/plugin-docs-bin ./cmd/serve + + - name: Test the generated-content drift gate + run: python3 .github/docs-corpus/test_check_drift.py - name: Write the corpus wiring candy from the pins file run: | @@ -111,14 +118,7 @@ jobs: # Regeneration on a clean tree is a no-op by contract. A diff here means a # docs PR must bump the charly pin (the CI-time commit) and commit the regenerated # pages in the same change. - run: | - if ! git diff --exit-code -- src/content/docs; then - echo "DRIFT: the committed site does not match the pinned charly checkout." - echo "Bump the charly CI-time commit in deploy.yml and commit the regenerated" - echo "content in the same docs PR (this workflow is the gate)." - exit 1 - fi - echo "content: committed tree matches the pinned charly (regeneration is a no-op)." + run: bash .github/docs-corpus/check_drift.sh # `npm ci` rather than `npm install`: it installs strictly from the committed lockfile and # FAILS if package.json and the lockfile disagree. That is deliberate — a lockfile missing diff --git a/.gitignore b/.gitignore index 1f0be264..ae0aa5f9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ node_modules/ .astro/ .DS_Store .wrangler/ +.docs-generator/ bin/ diff --git a/STYLE.md b/STYLE.md new file mode 100644 index 00000000..61ab554a --- /dev/null +++ b/STYLE.md @@ -0,0 +1,74 @@ +# OpenCharly website style guide + +> Canonical design reference: the supplied OpenCharly Cinematic Assetboard. This document governs the Astro/Starlight site at https://opencharly.ai. + +## Design identity + +OpenCharly is the agentic DevOps tool for people and their agents. The website should feel like a premium chocolatier's workshop fused with precision engineering: cinematic, richly rendered, warm, whimsical and technically credible. **A kinder internet.** + +Use the original gold crown with colored droplets and the original OpenCharly wordmark. **Do not redraw the logo as generic flat SVG geometry.** The supplied Charly illustration is the canonical mascot: cream armor, copper mechanisms, black faceplate, amber eyes and chocolate apron with a gold crown. Keep its proportions and materials. + +## Brand palette + +| Token | Hex | Purpose | +| --- | --- | --- | +| Cocoa | `#1A0F0A` | Dark canvas | +| Ganache | `#382A22` | Panels | +| Caramel | `#D4A574` | Warm highlights | +| Crème | `#F8EBD7` | Dark-mode text | +| Flame blue | `#2563EB` | Interactive brand hue | +| Gold | `#D4AF37` | Crown and signature accents | +| Ivory | `#FAF9F4` | Light background | + +The theme uses this warm palette. For accessibility, links on dark cocoa use a lighter derived blue (`#9BC3FF`), and light-theme links use `#1746B2`. Derived UI colors are implementation choices, not new official brand swatches. + +## Nine families + +| Family | Color | Visual metaphor | +| --- | --- | --- | +| Forge & Build | `#F97316` | Forged gear | +| Proof & Evaluation | `#10B981` | Verification emblem | +| Agents & Intelligence | `#AB50F6` | Illuminated brain | +| Runtime & Boxes | `#3B82F6` | Crystal cube | +| Network & Connectivity | `#06B6D4` | Connected sphere | +| Systems & Security | `#F4A308` | Shield | +| Tooling & Developer UX | `#64748B` | Terminal | +| Media & Interfaces | `#EC4899` | Media symbol | +| Packaging & Distribution | `#8B5CF6` | Package | + +Keep the nine original family illustrations from the visual guide as visual references. Never replace them with unrelated stock icons. Family colors are accents, not full-page background colors. Family names describe the website's visual taxonomy; product claims must be verified against the `charly` and `marketplace` sources. + +## Typography + +Use **Playfair Display** for display headings and **Inter** for UI, navigation and body copy; use a system monospace stack for CLI and code. The CSS theme loads the two display families through Google Fonts via Starlight's `head` entries. Keep code copyable and technical content readable. + +## Website design + +- Rich original artwork belongs in the homepage hero, social previews and family cards; documentation should retain clear hierarchy and generous whitespace. +- Prefer dark cocoa as the signature experience, with an accessible warm ivory light theme. +- Use fine caramel borders, restrained gold highlights, softly rounded cards, and subtle lighting. Avoid neon gradients and generic SaaS iconography. +- Keep navigation, search, code blocks and generated reference pages intact. +- Do not edit generated `src/content/docs/index.md`, `reference/**`, or `recipes/**` by hand. The homepage content comes from `charly/README.md`. +- Use responsive raster formats for cinematic illustrations. SVG is appropriate only for authentic source vector artwork or simple functional UI symbols, never as a cheap redraw of the official logo. + +## Implementation and source limits + +`src/styles/opencharly.css` defines the warm neutral ramps, contrast-safe links, typography, focus and reduced-motion behavior. Starlight retains its navigation, search, sidebar, code controls and generated narrative. The `Hero` override adds artwork only on the homepage; the original hero renders its generated title, tagline and actions. The `SiteTitle` override presents the crown and wordmark on an intentional black plaque in both themes. Family cards are a visual showcase, not a new navigation taxonomy. + +The operator approved extraction from the flattened **1774 × 887 RGB assetboard**. `assets/brand/assetboard.png` is the sole source copy. The dimensions printed inside the board describe unavailable originals; they are not the dimensions or transparency of these supplied pixels. All extracted assets preserve the black background. Do not remove it with color keying, redraw the logo, or enlarge the source and imply added detail. + +Run `node scripts/extract-brand.mjs` after `npm ci` to reproduce `public/brand/`. The script is the canonical crop manifest, with pixel coordinates excluding printed filenames, family labels and swatches. It exports: + +- Crown (216 × 178), wordmark (462 × 88), workshop hero (826 × 300) and waving mascot (305 × 291) as WebP. +- Nine family illustrations (190 × 152; packaging 184 × 152) as WebP, with HTML labels supplied separately for accessibility. +- Smaller 400px and 640px hero variants, without upscaling. +- Opaque 16px, 32px, 48px and 180px PNG favicons from the crown. Padding accommodates the crown's original aspect ratio. +- A 1200 × 630 PNG social card composed from native-size crops on black, without enlarging their pixels. + +The hero is capped at its source width, the mascot at 190 CSS pixels, family artwork at 190 CSS pixels, and the header wordmark below its native dimensions. These are intentionally compact web assets from a reference board; future higher-resolution source art should replace the canonical board and crop manifest together. + +## Quality bar + +The site includes branded English search labels and a custom recovery page built with StarlightPage. The recovery route owns the 404 output, with links home and to installation; it is excluded from search indexing. + +Check WCAG AA text contrast, keyboard and focus states, light/dark modes, mobile layouts, 200% zoom, reduced motion, reproducible asset extraction and `npm ci && npm run build`. Verify favicon and social metadata in the built HTML. Keep generated content owned by its generation workflow and retain the repository's PR-only validation policy. diff --git a/assets/brand/assetboard.png b/assets/brand/assetboard.png new file mode 100644 index 00000000..e9f0e75a Binary files /dev/null and b/assets/brand/assetboard.png differ diff --git a/astro.config.mjs b/astro.config.mjs index 098b1b34..5bdb4b68 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -12,14 +12,28 @@ export default defineConfig({ integrations: [ starlight({ title: 'OpenCharly', - description: - 'The wonky DevOps tool for you and your agents.', - social: [ - { icon: 'github', label: 'GitHub', href: 'https://github.com/opencharly/charly' }, + description: 'The wonky DevOps tool for you and your agents.', + favicon: '/brand/favicon-32.png', + // The recovery page uses StarlightPage directly, so it owns the /404 route. + disable404Route: true, + components: { Hero: './src/components/Hero.astro', SiteTitle: './src/components/SiteTitle.astro' }, + customCss: ['./src/styles/opencharly.css'], + head: [ + { tag: 'link', attrs: { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/brand/favicon-16.png' } }, + { tag: 'link', attrs: { rel: 'icon', type: 'image/png', sizes: '48x48', href: '/brand/favicon-48.png' } }, + { tag: 'link', attrs: { rel: 'apple-touch-icon', sizes: '180x180', href: '/brand/favicon-180.png' } }, + { tag: 'meta', attrs: { property: 'og:image', content: 'https://opencharly.ai/brand/social.png' } }, + { tag: 'meta', attrs: { property: 'og:image:width', content: '1200' } }, + { tag: 'meta', attrs: { property: 'og:image:height', content: '630' } }, + { tag: 'meta', attrs: { property: 'og:image:alt', content: 'OpenCharly crown and Charly in the chocolate workshop' } }, + { tag: 'meta', attrs: { name: 'twitter:card', content: 'summary_large_image' } }, + { tag: 'meta', attrs: { name: 'twitter:image', content: 'https://opencharly.ai/brand/social.png' } }, + { tag: 'link', attrs: { rel: 'preconnect', href: 'https://fonts.googleapis.com' } }, + { tag: 'link', attrs: { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: 'anonymous' } }, + { tag: 'link', attrs: { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Playfair+Display:wght@500;600;700&display=swap' } }, ], - editLink: { - baseUrl: 'https://github.com/opencharly/docs/edit/main/', - }, + social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/opencharly/charly' }], + editLink: { baseUrl: 'https://github.com/opencharly/docs/edit/main/' }, // Starlight >=0.39 requires an autogenerated group to be a `label` plus an `items` array // containing the autogenerate config — the older `{ label, autogenerate }` shape is gone. sidebar: [ diff --git a/marketplace b/marketplace index 37540028..61b80115 160000 --- a/marketplace +++ b/marketplace @@ -1 +1 @@ -Subproject commit 375400281b9fe19026217684f29dd8eb33ac39d9 +Subproject commit 61b80115fa22c6a007d92aadb2d1134cec72cae3 diff --git a/package-lock.json b/package-lock.json index a59b74fd..6e1f70ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,38 +8,55 @@ "name": "opencharly-docs", "version": "0.0.1", "dependencies": { - "@astrojs/starlight": "^0.41.6", - "astro": "^7.1.6", - "sharp": "^0.35.3" + "@astrojs/starlight": "^0.41.11", + "astro": "^7.4.0", + "sharp": "^0.35.5" }, "devDependencies": { - "wrangler": "4.118.0" + "wrangler": "4.151.0" } }, "node_modules/@astrojs/compiler-binding": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.3.2.tgz", - "integrity": "sha512-8w/9CWmYrAJJ8N0SY3O43ws2BgxoW6u3QsD8u2mE140lMYAlwh+tlNoUeSBq22wVheFuiBbR212l6ixZ2IIgCQ==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.5.2.tgz", + "integrity": "sha512-lEn76+0JcMQ5RDXU0wSMWJg2ZppiZvSULpghC29cfv4o9bhvWFDbQjsCtvjjXN9iVLFQ7fL3wTR2L2UU13mP8g==", "license": "MIT", "engines": { "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@astrojs/compiler-binding-darwin-arm64": "0.3.2", - "@astrojs/compiler-binding-darwin-x64": "0.3.2", - "@astrojs/compiler-binding-linux-arm64-gnu": "0.3.2", - "@astrojs/compiler-binding-linux-arm64-musl": "0.3.2", - "@astrojs/compiler-binding-linux-x64-gnu": "0.3.2", - "@astrojs/compiler-binding-linux-x64-musl": "0.3.2", - "@astrojs/compiler-binding-wasm32-wasi": "0.3.2", - "@astrojs/compiler-binding-win32-arm64-msvc": "0.3.2", - "@astrojs/compiler-binding-win32-x64-msvc": "0.3.2" + "@astrojs/compiler-binding-android-arm64": "0.5.2", + "@astrojs/compiler-binding-darwin-arm64": "0.5.2", + "@astrojs/compiler-binding-darwin-x64": "0.5.2", + "@astrojs/compiler-binding-linux-arm64-gnu": "0.5.2", + "@astrojs/compiler-binding-linux-arm64-musl": "0.5.2", + "@astrojs/compiler-binding-linux-x64-gnu": "0.5.2", + "@astrojs/compiler-binding-linux-x64-musl": "0.5.2", + "@astrojs/compiler-binding-wasm32-wasi": "0.5.2", + "@astrojs/compiler-binding-win32-arm64-msvc": "0.5.2", + "@astrojs/compiler-binding-win32-x64-msvc": "0.5.2" + } + }, + "node_modules/@astrojs/compiler-binding-android-arm64": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-android-arm64/-/compiler-binding-android-arm64-0.5.2.tgz", + "integrity": "sha512-kckIxon6Rm/Bxzh9mGPYpRRqUbToUQoHptCmpMmE+Yt0Xumq8CqrKUidyYhrBsrHVO7bxuRzzWUUqvpf+iYceQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@astrojs/compiler-binding-darwin-arm64": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.3.2.tgz", - "integrity": "sha512-MM8tn8CSimcfytaOla4b6acN8mKWiL/rlAA1fpT3/Wl7dNGSE4y8FjTN/zJVNnb63CsLWG5zZwCt01TXtDKh9g==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.5.2.tgz", + "integrity": "sha512-1ZG5Ar3dD8HtodX9XH1mRmE0qBXZlvjYXSFfpgFwocqfWnvhFuqtGUNseL8wgfImiRMztIjpQqlogQFQQtgiag==", "cpu": [ "arm64" ], @@ -53,9 +70,9 @@ } }, "node_modules/@astrojs/compiler-binding-darwin-x64": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.3.2.tgz", - "integrity": "sha512-2lXOlzf8xb7jLomRsf/aswh61/NnGusynB2OwFkK6k4pmOtpfXMYnG0PLfXrEvxXYj69NdCnmUYXtHDd+JOOag==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.5.2.tgz", + "integrity": "sha512-+kl35S7hiHJ2cb7eujwEsPFYYuSgE11uEE2Z20lAJ+undpgulMcW+weQqFPOSSZccEKHOiLIY+kQHkb4e4092w==", "cpu": [ "x64" ], @@ -69,9 +86,9 @@ } }, "node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.3.2.tgz", - "integrity": "sha512-BmU3kWj7qnLrd4vzm49zFEPJ5oFnn1tCT4Vt9hZbqdU5Cmb8GZl7fn6VFsnNfe7B18a2gIFtVzbLINtYl5kBjQ==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.5.2.tgz", + "integrity": "sha512-BqlR0EHNQLPLwgL9+xogjsAc7zGf0cHho2CPdhv0P1yqbVMwGVaGAqrANP6VYAXCqSC43AF4Czcxc2n+oqdesg==", "cpu": [ "arm64" ], @@ -88,9 +105,9 @@ } }, "node_modules/@astrojs/compiler-binding-linux-arm64-musl": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.3.2.tgz", - "integrity": "sha512-f0heT9ZZEseSu5bHCeb80eL2DH07ArE6U9xi1WT/PEusNjzPmEr3GJsjG1tRLo5VYUUYX7h3ScaqGmGrMOVGmw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.5.2.tgz", + "integrity": "sha512-GRGyby3AZWw5d6JQzidyxPyvGgHWsSusrpgKyFVpDTKctABF7L3Pd5V1cRJbV36/rcu+Eh292/wL7pF7MkmGkQ==", "cpu": [ "arm64" ], @@ -107,9 +124,9 @@ } }, "node_modules/@astrojs/compiler-binding-linux-x64-gnu": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.3.2.tgz", - "integrity": "sha512-M8fOUt0itRpqiGyoEA/ij184s8O+hqbCz3+YozRusOOM3osgGljpDThhbKAJjqh82wOo6FioQ4w8PBvU1XMD5Q==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.5.2.tgz", + "integrity": "sha512-9XAqGTMQAtIslMsjK3xdyY6OI9d59OZqcLBB6pvD/DcoR0daYswfrKx2azdDERDY4AqAnWPC7odVM1BmxYv3Vw==", "cpu": [ "x64" ], @@ -126,9 +143,9 @@ } }, "node_modules/@astrojs/compiler-binding-linux-x64-musl": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.3.2.tgz", - "integrity": "sha512-/Kebk8sO6HnLeSd691JkaAPfN7CqR9/KEXmWvyNPkaKNGmj8rTZ/lf2uXtnPu92Lan84UrKdIKVPy1fSo2encQ==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.5.2.tgz", + "integrity": "sha512-jOViewGeTh9bSfS8vK72ECxoy2yvmA+Pd/ZcEvBI5c7+7IcfHwZ5qA4L9fRYuOhSrAifvQ2dV4vm1XAtloaWBw==", "cpu": [ "x64" ], @@ -145,25 +162,27 @@ } }, "node_modules/@astrojs/compiler-binding-wasm32-wasi": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.3.2.tgz", - "integrity": "sha512-pUA6xbcOSB7DhfzIArB8BCAkFfAIqriiR7zl5zOStd6oU2G0kIKj+GUdGnyXyhfiv881Hffyk5tC0mR18sDjDw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.5.2.tgz", + "integrity": "sha512-Z7p64doar1uvR5C9Xs6j1CV9lGlPVQX7OQ2aAtZ/xKC5aGS6GB13nyc2UfQXTQLvZrvVwsyaflTQy6ziY5Bekw==", "cpu": [ "wasm32" ], "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.2.0" + "@emnapi/core": "1.11.3", + "@emnapi/runtime": "1.11.3", + "@napi-rs/wasm-runtime": "^1.2.5" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.3.2.tgz", - "integrity": "sha512-ESruf+6Qkl1trHUFxI6GSf6t52j8yN2kCNSzMWdzt7V/T09tFHrYzrVaJQohb2C9bJUH76pNvX6Zb51+xCQc9Q==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.5.2.tgz", + "integrity": "sha512-Tr13bh+ahTWsjXjzctK7pFpWV+dUU4FtBfETlR7gO+ueex0F+RDch7eRr0YfKysaRhk9tWm14lsCJ5uWyFPNHQ==", "cpu": [ "arm64" ], @@ -177,9 +196,9 @@ } }, "node_modules/@astrojs/compiler-binding-win32-x64-msvc": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.3.2.tgz", - "integrity": "sha512-wzzVrEbOwbsLWOdEbocskjMRx2aZPxJ7ZbmL+jnpBamFwmigm+2M/wzuM6JWncocgYwLic1csSpalBh96kQKXA==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.5.2.tgz", + "integrity": "sha512-SfKkI+jOQYLh6wojPvVPV0lFfQnxisweN9B+qCzRvZp7DHAuGif8Y0WcC5PUgN4jb8VKy57LggQDtggR46Du1g==", "cpu": [ "x64" ], @@ -193,21 +212,21 @@ } }, "node_modules/@astrojs/compiler-rs": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.3.2.tgz", - "integrity": "sha512-xlx/T7JovIKduu4ucbTQUxQ5+Q8wxkHxhLjnZk3VlJbhbQ9RLvvuDk1p2YYFYFQ5y14dVm3FGGO4isQXa4F+Tg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.5.2.tgz", + "integrity": "sha512-IvwYLB8t1M86rKO4oPdBi9GP4gzXcgrVlNgocjwos1jeeUuEIV8d9Crn1PvYD/5IKteWOxpIHomf7e8iYlkE+Q==", "license": "MIT", "dependencies": { - "@astrojs/compiler-binding": "0.3.2" + "@astrojs/compiler-binding": "0.5.2" }, "engines": { "node": ">=22.12.0" } }, "node_modules/@astrojs/internal-helpers": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.2.tgz", - "integrity": "sha512-yt7fMgPYqSM4Tmr+taTW6Per+hjJ8Pk6lA1PAcDyqzOt8HzJ6Kje5WzCxA2Sd+9wsUW7uhkLeoTMK0cXPwH9rQ==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.4.tgz", + "integrity": "sha512-nozZSy/mKYLqe4YrqbKtdOszedAfXYCtw3wZ0d+CAjz4GqQ4L9rl1ltIL5BlgwmYVinJg/RZ0MgGuWOdlyRZlA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.4", @@ -220,52 +239,214 @@ "unified": "^11.0.5" } }, - "node_modules/@astrojs/markdown-remark": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.2.2.tgz", - "integrity": "sha512-FGfmK84zSNcrsBd0dl1gXE9JvZYElp8EXQa2jpHVAxG4deGKAp43wspxFupjADJX7MSsMRHwYCnfT6EyVmgeFQ==", + "node_modules/@astrojs/markdown-satteri": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.3.8.tgz", + "integrity": "sha512-n8ItpFTCmlDsVR5+rwDmehSf+jFCYLWmZiisZNGuF7xILqYhsVeBfcha4qgS2Seq3fAc9Tm58ZVrvqFQ6RQgRQ==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.10.2", + "@astrojs/internal-helpers": "0.10.4", "@astrojs/prism": "4.0.2", "github-slugger": "^2.0.0", - "hast-util-from-html": "^2.0.3", - "hast-util-to-text": "^4.0.2", - "mdast-util-definitions": "^6.0.0", - "rehype-raw": "^7.0.0", - "rehype-stringify": "^10.0.1", - "remark-gfm": "^4.0.1", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.1.2", - "remark-smartypants": "^3.0.2", - "unified": "^11.0.5", - "unist-util-remove-position": "^5.0.0", - "unist-util-visit": "^5.1.0", - "unist-util-visit-parents": "^6.0.2", - "vfile": "^6.0.3" + "satteri": "^0.10.3" } }, - "node_modules/@astrojs/markdown-satteri": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.3.5.tgz", - "integrity": "sha512-CvWVEFAbay7YO+i9SaqDJubipA5ckiVB89QWoMJ5XC0m5CtFg8JwZ7Kau6X9sYY7FZURH0w2l03ISH2jOS/RDQ==", + "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-darwin-arm64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.10.5.tgz", + "integrity": "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-darwin-x64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.10.5.tgz", + "integrity": "sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-linux-arm64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.10.5.tgz", + "integrity": "sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-linux-arm64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.10.5.tgz", + "integrity": "sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-linux-x64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.10.5.tgz", + "integrity": "sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-linux-x64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.10.5.tgz", + "integrity": "sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-wasm32-wasi": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.10.5.tgz", + "integrity": "sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==", + "cpu": [ + "wasm32" + ], "license": "MIT", + "optional": true, "dependencies": { - "@astrojs/internal-helpers": "0.10.2", - "@astrojs/prism": "4.0.2", - "github-slugger": "^2.0.0", - "hast-util-from-html": "^2.0.3", - "satteri": "^0.9.1" + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-win32-arm64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.10.5.tgz", + "integrity": "sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@bruits/satteri-win32-x64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.10.5.tgz", + "integrity": "sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@astrojs/markdown-satteri/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@astrojs/markdown-satteri/node_modules/satteri": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.10.5.tgz", + "integrity": "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.5", + "@types/hast": "^3.0.5", + "@types/mdast": "^4.0.4", + "@types/unist": "^3.0.3" + }, + "optionalDependencies": { + "@bruits/satteri-darwin-arm64": "0.10.5", + "@bruits/satteri-darwin-x64": "0.10.5", + "@bruits/satteri-linux-arm64-gnu": "0.10.5", + "@bruits/satteri-linux-arm64-musl": "0.10.5", + "@bruits/satteri-linux-x64-gnu": "0.10.5", + "@bruits/satteri-linux-x64-musl": "0.10.5", + "@bruits/satteri-wasm32-wasi": "0.10.5", + "@bruits/satteri-win32-arm64-msvc": "0.10.5", + "@bruits/satteri-win32-x64-msvc": "0.10.5" } }, "node_modules/@astrojs/mdx": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-7.0.5.tgz", - "integrity": "sha512-wEM/HH1RiEntyPVagdiF+yArzfcYLKBB0C1RZspVidKZ97rRMbaqP1Nbl/GR0sJs8zwaceqxRymw8aOKKJRdYw==", + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-7.0.8.tgz", + "integrity": "sha512-RNuwq2ccTSi7NX9YqlR0noaWoVdOrZuJvdfWXotAzdhMVB0b0zEMLnNU+xar7le0GwTMlTObD/QAu8jeHA/3nA==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.10.2", - "@astrojs/markdown-remark": "7.2.2", + "@astrojs/internal-helpers": "0.10.4", + "@astrojs/markdown-remark": "7.2.4", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.16.0", "es-module-lexer": "^2.0.0", @@ -292,6 +473,31 @@ } } }, + "node_modules/@astrojs/mdx/node_modules/@astrojs/markdown-remark": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.2.4.tgz", + "integrity": "sha512-MvspGMynWKAjTe4/lTUdmBPHIFKNVLTCF6UlyWGogTGzNrTvjD+D4n48k7h8swxsEPKHK2TwxkZO7uoaCv1Pow==", + "license": "MIT", + "dependencies": { + "@astrojs/internal-helpers": "0.10.4", + "@astrojs/prism": "4.0.2", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.3", + "hast-util-to-text": "^4.0.2", + "mdast-util-definitions": "^6.0.0", + "rehype-raw": "^7.0.0", + "rehype-stringify": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.1.2", + "remark-smartypants": "^3.0.2", + "unified": "^11.0.5", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.1.0", + "unist-util-visit-parents": "^6.0.2", + "vfile": "^6.0.3" + } + }, "node_modules/@astrojs/prism": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.2.tgz", @@ -305,25 +511,24 @@ } }, "node_modules/@astrojs/sitemap": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.3.tgz", - "integrity": "sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.4.tgz", + "integrity": "sha512-LbKNC24bdUWcQf/pThB6qLlSqHojxGjZDURIzFocY8rlWnAn2t74nnhnK6S5x0NHriHoAduLEpVjRykmeGiVvA==", "license": "MIT", "dependencies": { "sitemap": "^9.0.0", - "stream-replace-string": "^2.0.0", "zod": "^4.3.6" } }, "node_modules/@astrojs/starlight": { - "version": "0.41.6", - "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.41.6.tgz", - "integrity": "sha512-Dt0/wY2JbFGUpxMgclw1j2Iqks2GG0LHYKgP7TfBXsFrs4LIbKvQ596lzyhXLz6nFcnPdIB9ZRFyDJeuVcx3Ug==", + "version": "0.41.11", + "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.41.11.tgz", + "integrity": "sha512-hM95Mbsl4l60SBwaNQA/HTxpOLGfeB5EfR9qY3kr0SsAVKUspCssjO0RVBsLiPAE6EA5xuORcCoz/Q6DTX+MuQ==", "license": "MIT", "dependencies": { - "@astrojs/markdown-satteri": "^0.3.2", - "@astrojs/mdx": "^7.0.0", - "@astrojs/sitemap": "^3.7.2", + "@astrojs/markdown-satteri": "^0.3.5", + "@astrojs/mdx": "^7.0.5", + "@astrojs/sitemap": "^3.7.3", "@pagefind/default-ui": "^1.3.0", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", @@ -362,18 +567,18 @@ } }, "node_modules/@astrojs/telemetry": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.3.tgz", - "integrity": "sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.4.0.tgz", + "integrity": "sha512-Qt2T6RGtYacyV8OZU3IcyFbsp69s6qIcnWvQvn7/p9MKebPCpEswP5Ji4RhifG3DfeBX7e07Pjj5smkd+Tfp7Q==", "license": "MIT", "dependencies": { "ci-info": "^4.4.0", "dset": "^3.1.4", "is-docker": "^4.0.0", - "package-manager-detector": "^1.6.0" + "package-manager-detector": "^1.9.0" }, "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0" + "node": ">=22.22.0" } }, "node_modules/@babel/helper-string-parser": { @@ -395,9 +600,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", - "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", "license": "MIT", "dependencies": { "@babel/types": "^7.29.8" @@ -600,9 +805,9 @@ } }, "node_modules/@clack/core": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz", - "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.5.1.tgz", + "integrity": "sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==", "license": "MIT", "dependencies": { "fast-wrap-ansi": "^0.2.0", @@ -613,12 +818,12 @@ } }, "node_modules/@clack/prompts": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.7.0.tgz", - "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.8.1.tgz", + "integrity": "sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==", "license": "MIT", "dependencies": { - "@clack/core": "1.4.3", + "@clack/core": "1.5.1", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" @@ -638,9 +843,9 @@ } }, "node_modules/@cloudflare/unenv-preset": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.1.tgz", - "integrity": "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.2.tgz", + "integrity": "sha512-JBP1+Z7ZSNG/d4mRP+y8VC5dka3tZVMLEZRvS+rzQ4DGV1EoxRFQckcJTTkXbHSQiTj0DtNI01Zwb/V2fX0mvQ==", "dev": true, "license": "MIT OR Apache-2.0", "peerDependencies": { @@ -654,9 +859,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20260730.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260730.1.tgz", - "integrity": "sha512-+MBHmPaiTe2KajryW0T24rZvWFxb41hD3d8anNzQqHzft6vSEb18+sp0znSwxgij7ApPhSM1+vhkNg4f3YMguA==", + "version": "1.20261012.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20261012.1.tgz", + "integrity": "sha512-dkTL9aY3V4D40b+jBpGPCistWUPFQ/M61wlWi6i1o8MvHFFgEw7EQkcaYEv6Yd3bkPDD/3TFT4hRsMb2xVZSwQ==", "cpu": [ "x64" ], @@ -671,9 +876,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20260730.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260730.1.tgz", - "integrity": "sha512-SBHKntPkKvNPgaCrTe99xC1CAl8ygJDzlYfK0LbuJ1muKadIw35WnhO0wu894fKBtllsVQdNzDLee+cm0ppLSQ==", + "version": "1.20261012.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20261012.1.tgz", + "integrity": "sha512-2/nVGcKXjNNI+DhxKSepTKvFng9H7aN2WXv6Zu67iqgI6JrxypNt5kTPv4ZHosxrcfyKMci/2RfN7GIrN0BitQ==", "cpu": [ "arm64" ], @@ -688,9 +893,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20260730.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260730.1.tgz", - "integrity": "sha512-ouyPOSMbiKPeSwUJUvxtMcxGAXs2J4aPE4T5ABIYX5ClcQx5j5bbHTmnqOQEY8sAuLTPjH7dY+iB6UI5ISlwwA==", + "version": "1.20261012.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20261012.1.tgz", + "integrity": "sha512-uMe7ONHnLxStD1Ye0YFHBO36uj4cStv5P53rW+5GVWXFT8BRjqVixlH0IqCAHe1Pmcwyd1+7fVoGde89MZSCJg==", "cpu": [ "x64" ], @@ -705,9 +910,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20260730.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260730.1.tgz", - "integrity": "sha512-YQ+Mi78U3TPdgBPtwq+Sm6rJU+Ihl2y0pjYtuuKkdmUbYzL7oLR6Xqq9wljhasnuCFICssDJaqhMep5WizYoEQ==", + "version": "1.20261012.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20261012.1.tgz", + "integrity": "sha512-I0VMdcXk7ygG5vYDce0ePTBFdnBXC0i9WiBY5mWiv0iTinbfea6/rHqSQ7B1UMpjgrYVs9E0m4bZ9ufsk5GCFA==", "cpu": [ "arm64" ], @@ -722,9 +927,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20260730.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260730.1.tgz", - "integrity": "sha512-27fAN+vUECW1oYVc1KOcHYpkL8COM2Uxtxql7TL595kxbjoqS5yckw7NLz7bTf2pALFCZWjqXDjZGJ/xbG4ZKQ==", + "version": "1.20261012.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20261012.1.tgz", + "integrity": "sha512-c5hQvNx574UEoknaCFvMa/NdLrrYiALNbe6sx1okW8uOiRYWxrFuA8WpXFnBJ5XJypm0TEAHYaUTGv3rRLpY7Q==", "cpu": [ "x64" ], @@ -752,9 +957,9 @@ } }, "node_modules/@ctrl/tinycolor": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", - "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.1.tgz", + "integrity": "sha512-Vh5uy9Y1JBMId6J1f68TMXnZrTCvNdo9Fu2k0d1YnJngR+sM5kWTKl441c/3TFs+cG0NWOjRWgQ/iaWhbYx+7A==", "license": "MIT", "engines": { "node": ">=14" @@ -766,7 +971,6 @@ "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.3", "tslib": "^2.4.0" @@ -788,15 +992,14 @@ "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", "cpu": [ "ppc64" ], @@ -810,9 +1013,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", "cpu": [ "arm" ], @@ -826,9 +1029,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", "cpu": [ "arm64" ], @@ -842,9 +1045,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", "cpu": [ "x64" ], @@ -858,9 +1061,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", "cpu": [ "arm64" ], @@ -874,9 +1077,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", "cpu": [ "x64" ], @@ -890,9 +1093,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", "cpu": [ "arm64" ], @@ -906,9 +1109,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", "cpu": [ "x64" ], @@ -922,9 +1125,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", "cpu": [ "arm" ], @@ -938,9 +1141,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", "cpu": [ "arm64" ], @@ -954,9 +1157,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", "cpu": [ "ia32" ], @@ -970,9 +1173,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", "cpu": [ "loong64" ], @@ -986,9 +1189,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", "cpu": [ "mips64el" ], @@ -1002,9 +1205,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", "cpu": [ "ppc64" ], @@ -1018,9 +1221,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", "cpu": [ "riscv64" ], @@ -1034,9 +1237,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", "cpu": [ "s390x" ], @@ -1050,9 +1253,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", "cpu": [ "x64" ], @@ -1066,9 +1269,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", "cpu": [ "arm64" ], @@ -1082,9 +1285,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", "cpu": [ "x64" ], @@ -1098,9 +1301,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", "cpu": [ "arm64" ], @@ -1114,9 +1317,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", "cpu": [ "x64" ], @@ -1130,9 +1333,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", "cpu": [ "arm64" ], @@ -1146,9 +1349,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", "cpu": [ "x64" ], @@ -1162,9 +1365,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", "cpu": [ "arm64" ], @@ -1178,9 +1381,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", "cpu": [ "ia32" ], @@ -1194,9 +1397,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", "cpu": [ "x64" ], @@ -1210,9 +1413,9 @@ } }, "node_modules/@expressive-code/core": { - "version": "0.44.1", - "resolved": "https://registry.npmjs.org/@expressive-code/core/-/core-0.44.1.tgz", - "integrity": "sha512-3dDo9N8D7hYrLNNMMWFovg3+aDUtnQm7c7z0GZc1c0LEFVBc0Q6lKG+tVT28gDadOvsgOANfCn35fgpe97Pmgg==", + "version": "0.44.2", + "resolved": "https://registry.npmjs.org/@expressive-code/core/-/core-0.44.2.tgz", + "integrity": "sha512-Yw5KonQCD1HoOO2P89y4wifqS9qrJcGVY0LkVMUsVZjhi++bhz4WwQ37inenKFNOEVo50P7cjoVsCdaVnUbq8w==", "license": "MIT", "dependencies": { "@ctrl/tinycolor": "^4.0.4", @@ -1227,31 +1430,31 @@ } }, "node_modules/@expressive-code/plugin-frames": { - "version": "0.44.1", - "resolved": "https://registry.npmjs.org/@expressive-code/plugin-frames/-/plugin-frames-0.44.1.tgz", - "integrity": "sha512-HC/bdRao9225ApcgO/e3jn8ZOhldKO7ob1O/Tcipvtv7Vb5nMphZhMtD9uuywpvxkPYBHJi3504WhrKg05Dwqg==", + "version": "0.44.2", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-frames/-/plugin-frames-0.44.2.tgz", + "integrity": "sha512-gVLm6TQMNIRWIaM7o+mCtxkGNjLZY5/2faSTLoXeo9wv/Pkj/0QAtZyXPVPrRsPARqiipATNFmfvQFLJudxPHQ==", "license": "MIT", "dependencies": { - "@expressive-code/core": "^0.44.1" + "@expressive-code/core": "^0.44.2" } }, "node_modules/@expressive-code/plugin-shiki": { - "version": "0.44.1", - "resolved": "https://registry.npmjs.org/@expressive-code/plugin-shiki/-/plugin-shiki-0.44.1.tgz", - "integrity": "sha512-YApiZt3buUzBwL5tqj8G+sYC5NjMjRCHgQwr9bmGl69rtcHy6fE9dooWUeKYB978fJT2BuxT5FeHcF47rA3SEg==", + "version": "0.44.2", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-shiki/-/plugin-shiki-0.44.2.tgz", + "integrity": "sha512-ebWIvCDzXvjyD8rH6T6DfytYJw1GoArLR4nusIAE4VxXrCQf3d+owytiv010KU/dUg+SRLZskDn0N+HaFXeuSg==", "license": "MIT", "dependencies": { - "@expressive-code/core": "^0.44.1", + "@expressive-code/core": "^0.44.2", "shiki": "^4.0.2" } }, "node_modules/@expressive-code/plugin-text-markers": { - "version": "0.44.1", - "resolved": "https://registry.npmjs.org/@expressive-code/plugin-text-markers/-/plugin-text-markers-0.44.1.tgz", - "integrity": "sha512-B3BsJoJ8CFMlcIX9f+X9tcI3C4zPDO601+YuLi9GheSTNro7ZfqSjLptMQKBHOWZvxnAtY5zvIX7iO/qtBhNBg==", + "version": "0.44.2", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-text-markers/-/plugin-text-markers-0.44.2.tgz", + "integrity": "sha512-SNI7EgUSiADqbqUzzMbj1ZeC/r2pa5eg3KyFOGAd3a7EsIA4qzjXQLp+ODWQtHVDKFCdGs4J3ovSJUqvKIK96g==", "license": "MIT", "dependencies": { - "@expressive-code/core": "^0.44.1" + "@expressive-code/core": "^0.44.2" } }, "node_modules/@img/colour": { @@ -1264,9 +1467,9 @@ } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", - "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz", + "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==", "cpu": [ "arm64" ], @@ -1282,13 +1485,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.2" + "@img/sharp-libvips-darwin-arm64": "1.3.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", - "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz", + "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==", "cpu": [ "x64" ], @@ -1304,20 +1507,20 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.2" + "@img/sharp-libvips-darwin-x64": "1.3.4" } }, "node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", - "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz", + "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==", "license": "Apache-2.0", "optional": true, "os": [ "freebsd" ], "dependencies": { - "@img/sharp-wasm32": "0.35.3" + "@img/sharp-wasm32": "0.35.5" }, "engines": { "node": ">=20.9.0" @@ -1327,9 +1530,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", - "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz", + "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==", "cpu": [ "arm64" ], @@ -1343,9 +1546,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", - "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz", + "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==", "cpu": [ "x64" ], @@ -1359,9 +1562,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", - "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz", + "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==", "cpu": [ "arm" ], @@ -1378,9 +1581,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", - "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz", + "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==", "cpu": [ "arm64" ], @@ -1397,9 +1600,9 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", - "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz", + "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==", "cpu": [ "ppc64" ], @@ -1416,9 +1619,9 @@ } }, "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", - "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz", + "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==", "cpu": [ "riscv64" ], @@ -1435,9 +1638,9 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", - "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz", + "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==", "cpu": [ "s390x" ], @@ -1454,9 +1657,9 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", - "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz", + "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==", "cpu": [ "x64" ], @@ -1473,9 +1676,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", - "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz", + "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==", "cpu": [ "arm64" ], @@ -1492,9 +1695,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", - "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz", + "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==", "cpu": [ "x64" ], @@ -1511,9 +1714,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", - "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz", + "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==", "cpu": [ "arm" ], @@ -1532,13 +1735,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.2" + "@img/sharp-libvips-linux-arm": "1.3.4" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", - "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz", + "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==", "cpu": [ "arm64" ], @@ -1557,13 +1760,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.2" + "@img/sharp-libvips-linux-arm64": "1.3.4" } }, "node_modules/@img/sharp-linux-ppc64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", - "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz", + "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==", "cpu": [ "ppc64" ], @@ -1582,13 +1785,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.2" + "@img/sharp-libvips-linux-ppc64": "1.3.4" } }, "node_modules/@img/sharp-linux-riscv64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", - "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz", + "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==", "cpu": [ "riscv64" ], @@ -1607,13 +1810,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.2" + "@img/sharp-libvips-linux-riscv64": "1.3.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", - "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz", + "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==", "cpu": [ "s390x" ], @@ -1632,13 +1835,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.2" + "@img/sharp-libvips-linux-s390x": "1.3.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", - "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz", + "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==", "cpu": [ "x64" ], @@ -1657,13 +1860,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.2" + "@img/sharp-libvips-linux-x64": "1.3.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", - "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz", + "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==", "cpu": [ "arm64" ], @@ -1682,13 +1885,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", - "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz", + "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==", "cpu": [ "x64" ], @@ -1707,17 +1910,17 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.2" + "@img/sharp-libvips-linuxmusl-x64": "1.3.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", - "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz", + "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==", "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.11.1" + "@emnapi/runtime": "^1.11.3" }, "engines": { "node": ">=20.9.0" @@ -1727,16 +1930,16 @@ } }, "node_modules/@img/sharp-webcontainers-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", - "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz", + "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==", "cpu": [ "wasm32" ], "license": "Apache-2.0", "optional": true, "dependencies": { - "@img/sharp-wasm32": "0.35.3" + "@img/sharp-wasm32": "0.35.5" }, "engines": { "node": ">=20.9.0" @@ -1746,9 +1949,9 @@ } }, "node_modules/@img/sharp-win32-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", - "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz", + "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==", "cpu": [ "arm64" ], @@ -1765,9 +1968,9 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", - "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz", + "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==", "cpu": [ "ia32" ], @@ -1784,9 +1987,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", - "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz", + "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==", "cpu": [ "x64" ], @@ -1813,9 +2016,9 @@ } }, "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==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -1867,9 +2070,9 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz", - "integrity": "sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.5.tgz", + "integrity": "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==", "license": "MIT", "optional": true, "dependencies": { @@ -1883,8 +2086,8 @@ "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3", - "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "node_modules/@oslojs/encoding": { @@ -1894,12 +2097,12 @@ "license": "MIT" }, "node_modules/@oxc-project/types": { - "version": "0.142.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz", - "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==", + "version": "0.154.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.154.0.tgz", + "integrity": "sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA==", "license": "MIT", "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://github.com/sponsors/oxc-project" } }, "node_modules/@pagefind/darwin-arm64": { @@ -2028,10 +2231,26 @@ "dev": true, "license": "MIT" }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.14.tgz", + "integrity": "sha512-aWR+XKH9+rW7m5fWq/5360J3mHycrx/o6xZM2DQFdJnTMdyP7/WzxPjhtLbVWdKo2y612/4U1bWqb3HQhiF7vg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.2.tgz", - "integrity": "sha512-l7x215OGvo1s52JWmR8U/DAVzEDWBCIbTm28aeJV/WDTSHgcKXaZTuBT0hJMs5NggilfJTW3clZVvd24yfKJxA==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.14.tgz", + "integrity": "sha512-QiVxHofl6A8lQU7WAtOUY4QMVZXohxwz7WJJoeh8NBEUyKfIkMRKhYyq8az/1RypNiIXzNTtiS6KwHz0erxYRQ==", "cpu": [ "arm64" ], @@ -2045,9 +2264,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.2.tgz", - "integrity": "sha512-9u9Xv6c1AJZT0FfwH5vrMG5Jjcwhc1MlyrPu0XfTqkzsmqfks2M6W/o5XwAJgVVN/jHpqqngC1WevHKKTIUtIA==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.14.tgz", + "integrity": "sha512-lTQOzHuBIooh3jIr5XINQkjPGEuGy+Dsy0meXDr6Sjty0b99kYgGh4uBC/8mJX1T0kC8d6S0aPP1Y+bHkh6aBw==", "cpu": [ "arm64" ], @@ -2061,9 +2280,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.2.tgz", - "integrity": "sha512-9W1mbGZAfW3oqd85bhBkmpyHCCzL1TeG/zFFP3vg7b0rlly8cxOcre5nXwz+LHazCwac2MNWgPdPCHndABjpWQ==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.14.tgz", + "integrity": "sha512-hyMKEGatjmBYCs/Q4sbIcL/GqpFEqsX3wc+HYVQ/85A4rxc1o7rPm4DUI4GV4k/h0ITddwFSGpqQunI14GXjTA==", "cpu": [ "x64" ], @@ -2077,9 +2296,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.2.tgz", - "integrity": "sha512-0p1lhiCSCyaerFwtrdZQUx7NqGk6LQnaRKWX7tFQqwQgvX0rjM15cIkm3pax1UpEakK14C4mOxx/jSqCBdBRqQ==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.14.tgz", + "integrity": "sha512-u371GbXoVXrEgP20PwzoGNOdAOqAMhzo19JzzY+V4YmmnC+DTOoqdbMu+O+54emM59Mik/UdrtWgcuEDKWRPKA==", "cpu": [ "x64" ], @@ -2093,9 +2312,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.2.tgz", - "integrity": "sha512-e+cOJXrJ2L3zx6YzqPg+f6Wbk3V1cKB8bOhbaYdVYN3DdquzNdRAmrbETz1qnt5yp/c7JNlNjmITiA2cVneQ7w==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.14.tgz", + "integrity": "sha512-BqwKsdZQf6EqVWr8fv2MrDYzAvOZ7+NYFSJESRGs87fkseEhs0TU9TXgRJTkZoRRkxTizyEg1LKUXfU3/78uqg==", "cpu": [ "arm" ], @@ -2109,9 +2328,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.2.tgz", - "integrity": "sha512-JsSMsj6sNat/MuhG5fnBD7QgbtpHKVe30x5/bAVirDHdhoQRXJkF6xc0Jqk8O4fiCUQAzMOoH9wZi3m60c8wtg==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.14.tgz", + "integrity": "sha512-SD9kY8M009x/7s57Z1dgUVlP5+uYBgKQK0Tkr1WIWngrtUJmRCW1RJFMY7QDla2khXhmg2i5Io7MUjcmZNZ/KQ==", "cpu": [ "arm64" ], @@ -2128,9 +2347,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.2.tgz", - "integrity": "sha512-B5G/zJdHaoJn9vD50eGHWkiWfmq8Uhi3IiLPJTzmZTrAalk1bztUikSXo0qga18ibE0IXboyeMUnhPjhAJ45wQ==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.14.tgz", + "integrity": "sha512-BJ2CL19M6uuWesMgnqJzgxoI+N+eV7b0A9O9vLV42y+gitC41fNa8KElau1tHVzuLWX5GzEuxMPhAO0tQXQMkg==", "cpu": [ "arm64" ], @@ -2147,9 +2366,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.2.tgz", - "integrity": "sha512-6mC/awzKka8W6EoekjegpfGkjz8jXWDX63pqu/HYVpyKtZfu65Jsh4QAH3Kej3CAv/c1oGX7psTmFEbr0mDxLA==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.14.tgz", + "integrity": "sha512-4+Kl8daPV8NDHaD7mfCcc1pRM+Qg7ab8DyMm5FG5WoZgv4h2i3KFN1CybYBNbQqmuYm7ftJLvmMI1eHYJ22S/Q==", "cpu": [ "ppc64" ], @@ -2166,9 +2385,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.2.tgz", - "integrity": "sha512-412MX9fJLdA1IK28EZnc8jYv2HRTleOZgfLQumJ5zy7OeJLZlg/CETwFaXjNmGVxG51cFHpKLqb5LKvBC+HsHA==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.14.tgz", + "integrity": "sha512-V/h8ePq1fKDrmtFMz6xcCN3DKvuvMRrwwD1q0PkBeeo4DpK64biaKvqWGVxqCeYKqeRk7gE7/iKPxLCn08O97A==", "cpu": [ "s390x" ], @@ -2185,9 +2404,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.2.tgz", - "integrity": "sha512-Q/+HI/ToJafZ1iCqGgVQXUEkIjufHCTF0gBQ2a5o3cg7GJ2h0qyq3nvvSmU+bGda2/7ygXpTY4TM6gO9OhQ0ZA==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.14.tgz", + "integrity": "sha512-WxalXzgrLVpKC93xfpaJ3gCXUWzeCr+FRCbDVD2mUAy4L6Vo3lNVz0epUEUpxPWJkLNYUwM4OSIikv36OJ9mLg==", "cpu": [ "x64" ], @@ -2204,9 +2423,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.2.tgz", - "integrity": "sha512-ZKp/w41n6wCvxzxQHtQSbuphfX3Y4cCvbjkKHusrLx4lh+JWLTU7StSltO/DKARISzbj368d+qUaCjI8K2wzXw==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.14.tgz", + "integrity": "sha512-3G3tnAmTpdk9jO3GQtyHXqeFD2SlecfTws/Y3M2mmj9nMBwwuLT4kur8sZKeu7ENUHSpVO3cIsm5A52LEWWwlg==", "cpu": [ "x64" ], @@ -2223,9 +2442,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.2.tgz", - "integrity": "sha512-pxE6xD4KS3eAROkKK5yrhB9/3+vhlhVGMvlQLbdpzrBGDbKrnzx3RLwPaHvasLo6jgaiBLn7e04Df9C4tYhjmA==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.14.tgz", + "integrity": "sha512-qyr5XiNGxm2ytx17vvtcJ9nXn6v1gENETi503bJx3OGwZ1tSonj7BosxbMa/xeAfSl5iS9X6KjEWYXLu6v1L7Q==", "cpu": [ "arm64" ], @@ -2239,9 +2458,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.2.tgz", - "integrity": "sha512-4MqEue5re+xIZzAWsB8sj0P1kqZySWqIuN4t6QaIO/YA6SFwySOLruvWQFzfmqk8LBK2P30KCSJwf6mJCZZ5/A==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.14.tgz", + "integrity": "sha512-oA4o5o0S2yB199YyYXDzKUv1Z56Rc+mgOjwm7Z/vJ9Z8igiDPYvoOuDyo6g7AK/ZaF09nPhDKVnGBcYHO11GXA==", "cpu": [ "arm64" ], @@ -2255,9 +2474,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.2.tgz", - "integrity": "sha512-NweNxxD0Nf9t8v7kodun45Ijp3EIwYY+uydPP6qBEYvfBqhIjN6dZMzlQja3tqX/aLs3F3Uz+AxDpKgRhpOZQg==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.14.tgz", + "integrity": "sha512-9mE94bf2GZUaR/fUSXCMpBoWkctu421Mi0ORpm4zqfbkjKep7RxzPFa5etcGs5h+2KApoWBOA/hAJa/7saGgEQ==", "cpu": [ "x64" ], @@ -2276,42 +2495,14 @@ "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "license": "MIT" }, - "node_modules/@rollup/pluginutils": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", - "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, "node_modules/@shikijs/core": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.4.1.tgz", - "integrity": "sha512-VeR2CY6Nn9/WbisoYLOQZ7HZOnwTrpBuOw4wExjqLnBCi62BNWynBUO6K2uPIASPFJwAv7cX1fUu+LrPlSstcw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.5.0.tgz", + "integrity": "sha512-6CIgwq+bt2JZ3OSjb/nBkkwEf/CfpHcbam+Mg5Pllco7HAGRQ2/EFhZrrJtbyNTgKwknfVS+llsXGygiDGwJWw==", "license": "MIT", "dependencies": { - "@shikijs/primitive": "4.4.1", - "@shikijs/types": "4.4.1", + "@shikijs/primitive": "4.5.0", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.5", "hast-util-to-html": "^9.0.5" @@ -2321,12 +2512,12 @@ } }, "node_modules/@shikijs/engine-javascript": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.4.1.tgz", - "integrity": "sha512-6U4lJBh8LTvIkEVqRHv/rr3ruwtO6IweFQt1ME1ntHJMGHS+6N86vfYGO1o8c/DtOCTia2lfhdQBtBrps1sDfQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.5.0.tgz", + "integrity": "sha512-Ed6UdEj84LyYkwnxM5CvSMWAD+id9ExTYri0/+x41U9zrgNifPSS9lZm0JqBP0VfYI8yr8tY5nbNq9+p9R0kFA==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.4.1", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.6" }, @@ -2335,12 +2526,12 @@ } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.4.1.tgz", - "integrity": "sha512-p23RugMKss0r5DAtRJW1yAXUDl60JvhQYV20yuxei//26JyDSJefV3umyWzzwep2weblMnJGDYahuti6XkcMgA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.5.0.tgz", + "integrity": "sha512-dKVmbJecVdB9recl8a/CU4jdpNXyjJQrIcesIkpS70s5HS02ohpnCSpMUbotPnEUzbAcLQ+S4hwZYbkBBiTcJw==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.4.1", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2" }, "engines": { @@ -2348,24 +2539,24 @@ } }, "node_modules/@shikijs/langs": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.4.1.tgz", - "integrity": "sha512-xb2kCMloBCIraIy2fS5MW0t/BxVY3q2nDyQKBoeSeq6KNrQbShHetCFlw2n35fGIJ6t3+hXDLQogP5ir9O9bvA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.5.0.tgz", + "integrity": "sha512-wwBTqwduXSz0X4v9Qa2EWeFaYJEw1clCncWjoRNQRbVDu3SPRTRWucnouYapKj3b8Q+sk/41Vbc4B5c8nuYzLA==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.4.1" + "@shikijs/types": "4.5.0" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/primitive": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.4.1.tgz", - "integrity": "sha512-ko2OfDoG89YuQ7xL5LtcQiWKb7NIv1Ephb7g48TVU198OzAMLC8lXVEwaJGHK4sUMYrfAGJDqYmNLOLiW/Kz8w==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.5.0.tgz", + "integrity": "sha512-UM7ShlA8oz0OWxLLO8BmO9Ip6fVqdkt8yF0EH7nOCqHfrx1eEAzF0ZUVK7L+I8NEgeu1PEWSRlxaiPPeCb4iDg==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.4.1", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.5" }, @@ -2374,21 +2565,21 @@ } }, "node_modules/@shikijs/themes": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.4.1.tgz", - "integrity": "sha512-wudOaoFro+/Zl9gQv2W1Ur5XlVduqvTuYLI483Xi0wgc1A+cy1hfB2r6ac6ufBgF+ID7KJEW7L41MHrzQ4wH+w==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.5.0.tgz", + "integrity": "sha512-zGb87H3UBbpuI4yoh5UguB1XbU+2BDU3kflM7UfZ+Cy2hWo9lBtqjSVK20gmLY6ukYl040hAypGXMgud9vul8Q==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.4.1" + "@shikijs/types": "4.5.0" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/types": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.4.1.tgz", - "integrity": "sha512-GOwCLQDHM5EjGUWNPrhzJbr6JP8V/Dx/CDVkWvbZ1Avw5JFnNUckrgbLmE07qtg4WlW7Q7QFndhjIkeU9XMPvw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.5.0.tgz", + "integrity": "sha512-drtPrtD8N0DENyD2cyt6Ajy+IWsiCLgMxODwLTpvH1UsN6a9jf90tNTPjqwHvA+0Lzu9e0txk8DjfqH1p9UJRw==", "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", @@ -2418,16 +2609,16 @@ } }, "node_modules/@speed-highlight/core": { - "version": "1.2.23", - "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.23.tgz", - "integrity": "sha512-iRoq6i6JDJP6Mt2A5JaPvzw0pgYHH6k92ij+yXiTrB7T2y9N789aWE3EHWj/5ztlJBokcCBja3iYLVdu5wgnkg==", + "version": "1.2.24", + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.24.tgz", + "integrity": "sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw==", "dev": true, "license": "CC0-1.0" }, "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", "license": "MIT", "optional": true, "dependencies": { @@ -2504,12 +2695,12 @@ } }, "node_modules/@types/node": { - "version": "24.13.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", - "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", + "version": "24.19.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.2.tgz", + "integrity": "sha512-93d49wCWJkCyN87MxLpNN6KXPCwFw7bVUg79mGUV1OS40JGWwVCr8n61DXCSqz7CV6/VfPkb7xec7uP2M+QHWQ==", "license": "MIT", "dependencies": { - "undici-types": "~7.18.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@types/sax": { @@ -2528,15 +2719,15 @@ "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", - "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", "license": "ISC" }, "node_modules/acorn": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", - "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.19.0.tgz", + "integrity": "sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -2555,9 +2746,9 @@ } }, "node_modules/am-i-vibing": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.4.0.tgz", - "integrity": "sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.5.0.tgz", + "integrity": "sha512-KLcsDhqf1XRrJmJr+9I/C0EX2K+sGrAGZFgkmd84c8TJO9zJBu+/kFInjazu1KfJWFhWDKdRWkpBzEs7s35DVA==", "license": "MIT", "dependencies": { "process-ancestry": "^0.1.0" @@ -2632,70 +2823,69 @@ } }, "node_modules/astro": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/astro/-/astro-7.1.6.tgz", - "integrity": "sha512-83x9rYbHazMaZkYrAFRVZXSQx2moFkz0F7cjTDUF3GWfS0a3p2vZXG1ZdhV86rStHApQCodBJW+XTD37xISIrQ==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/astro/-/astro-7.4.0.tgz", + "integrity": "sha512-6ThZU2bp7asGSceVcnh3r23dE88HpYN5vxtnCWYYrjr8lpQjx4eDW6/W8WgNlcc+T/b8zHmQ/EcS4DpQG4ZoOg==", "license": "MIT", "dependencies": { - "@astrojs/compiler-rs": "^0.3.2", - "@astrojs/internal-helpers": "0.10.2", - "@astrojs/markdown-satteri": "0.3.5", - "@astrojs/telemetry": "3.3.3", - "@capsizecss/unpack": "^4.0.0", - "@clack/prompts": "^1.1.0", + "@astrojs/compiler-rs": "^0.5.1", + "@astrojs/internal-helpers": "0.13.0", + "@astrojs/markdown-satteri": "0.4.4", + "@astrojs/telemetry": "3.4.0", + "@capsizecss/unpack": "^4.0.1", + "@clack/prompts": "^1.8.1", "@oslojs/encoding": "^1.1.0", - "@rollup/pluginutils": "^5.3.0", - "am-i-vibing": "^0.4.0", + "am-i-vibing": "^0.5.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", "cookie": "^2.0.1", - "devalue": "^5.8.1", - "diff": "^8.0.3", + "devalue": "^6.0.2", + "diff": "^9.0.0", "dset": "^3.1.4", - "es-module-lexer": "^2.0.0", - "esbuild": "^0.28.0", + "es-module-lexer": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.4.1", - "get-tsconfig": "5.0.0-beta.4", + "get-tsconfig": "5.0.0-beta.6", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", - "http-cache-semantics": "^4.2.0", - "js-yaml": "^4.3.0", + "http-cache-semantics": "^4.3.0", "jsonc-parser": "^3.3.1", - "magic-string": "^1.0.0", - "magicast": "^0.5.2", + "magic-string": "^1.4.3", + "magicast": "^0.5.5", "mrmime": "^2.0.1", "neotraverse": "^1.0.1", - "obug": "^2.1.1", - "p-limit": "^7.3.0", - "p-queue": "^9.1.0", - "package-manager-detector": "^1.6.0", + "obug": "^3.0.0", + "p-limit": "^7.3.3", + "p-queue": "^9.3.5", + "package-manager-detector": "^1.9.0", "piccolore": "^0.1.3", - "picomatch": "^4.0.4", - "semver": "^7.7.4", - "shiki": "^4.0.2", - "smol-toml": "^1.6.0", - "svgo": "^4.0.1", - "tinyclip": "^0.1.12", - "tinyexec": "^1.0.4", - "tinyglobby": "^0.2.15", - "ultrahtml": "^1.6.0", - "unifont": "~0.7.4", + "picomatch": "^4.0.7", + "rolldown": "^1.2.13", + "shiki": "^4.5.0", + "smol-toml": "^1.9.1", + "svgo": "^4.1.0", + "tinyclip": "^1.0.3", + "tinyexec": "^1.3.1", + "tinyglobby": "^0.2.17", + "tinyps": "^0.5.0", + "ultrahtml": "^1.7.0", + "unifont": "^1.0.3", "unstorage": "^1.17.5", - "vite": "^8.0.13", - "vitefu": "^1.1.2", + "verkit": "^0.5.0", + "vite": "^8.3.4", + "vitefu": "^1.1.3", "xxhash-wasm": "^1.1.0", "yargs-parser": "^22.0.0", - "zod": "^4.3.6" + "zod": "^4.6.6" }, "bin": { "astro": "bin/astro.mjs" }, "engines": { - "node": ">=22.12.0", + "node": ">=22.22.0", "npm": ">=9.6.5", "pnpm": ">=7.1.0" }, @@ -2704,10 +2894,10 @@ "url": "https://opencollective.com/astrodotbuild" }, "optionalDependencies": { - "sharp": "^0.34.0 || ^0.35.0" + "sharp": "^0.35.4" }, "peerDependencies": { - "@astrojs/markdown-remark": "7.2.2" + "@astrojs/markdown-remark": "^7.3.0" }, "peerDependenciesMeta": { "@astrojs/markdown-remark": { @@ -2716,30 +2906,264 @@ } }, "node_modules/astro-expressive-code": { - "version": "0.44.1", - "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.44.1.tgz", - "integrity": "sha512-DT1LnCqbHasBKlvzJ3m6LR4VI94wwx3W9EV/YbP1te4rqjOHsvsezHYuqb5MeLWLftXms/1FA9QBbwCo43DnJQ==", + "version": "0.44.2", + "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.44.2.tgz", + "integrity": "sha512-avop7nZcRwC7quvIxVguhwEZ9Tp6IoTzKUCLwP30Fb7+er+pWQgcysP01dcuzRIJo81kLGg30q/YAI2Yb1Sdzg==", "license": "MIT", "dependencies": { - "rehype-expressive-code": "^0.44.1", + "rehype-expressive-code": "^0.44.2", "url-extras": "^0.1.0" }, "peerDependencies": { "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta || ^7.0.0" } }, - "node_modules/astro/node_modules/magic-string": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.1.0.tgz", - "integrity": "sha512-kS3VHe0nEPST2saQV4Rbkchcd3UBRkVTQHo1D3h/ZTwFDhai/mfKkmtPAtD129EOI7K3HlHIsFOt0WrI2/oU9g==", + "node_modules/astro/node_modules/@astrojs/internal-helpers": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.13.0.tgz", + "integrity": "sha512-20jxQqnSmpskcGyad7N5l6Xf1gz0UCa6lNde44bEBdaXGpncEYfAZJ142r2ZgzBaG4dUyzGmhqZWv1INU2eiHQ==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "@types/hast": "^3.0.5", + "@types/mdast": "^4.0.4", + "picomatch": "^4.0.7", + "retext-smartypants": "^6.2.0", + "shiki": "^4.5.0", + "smol-toml": "^1.9.1", + "unified": "^11.0.5", + "yaml": "^2.9.1" } }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "node_modules/astro/node_modules/@astrojs/markdown-satteri": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.4.4.tgz", + "integrity": "sha512-Byhe9CAiGFJrhMACKpgN/FPf4lcwapqwFQAB7E1sPELTEJINfBIpgnEYOBTXzr//fvSSNhfp/X3AqN4mUV9p+A==", + "license": "MIT", + "dependencies": { + "@astrojs/internal-helpers": "0.13.0", + "@astrojs/prism": "4.1.0", + "github-slugger": "^2.0.0", + "satteri": "^0.10.5" + } + }, + "node_modules/astro/node_modules/@astrojs/prism": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.1.0.tgz", + "integrity": "sha512-zvRaL3MKTAXWfVQrHAlYtocRZWXBM6ruF3Bl7Lc7QgFHLRTfwMKo33KczlkvkXDY+qcytKhAWOT9dwUUYLUxAw==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.30.0" + }, + "engines": { + "node": ">=22.22.0" + } + }, + "node_modules/astro/node_modules/@bruits/satteri-darwin-arm64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.10.5.tgz", + "integrity": "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/astro/node_modules/@bruits/satteri-darwin-x64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.10.5.tgz", + "integrity": "sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/astro/node_modules/@bruits/satteri-linux-arm64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.10.5.tgz", + "integrity": "sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/astro/node_modules/@bruits/satteri-linux-arm64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.10.5.tgz", + "integrity": "sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/astro/node_modules/@bruits/satteri-linux-x64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.10.5.tgz", + "integrity": "sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/astro/node_modules/@bruits/satteri-linux-x64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.10.5.tgz", + "integrity": "sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/astro/node_modules/@bruits/satteri-wasm32-wasi": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.10.5.tgz", + "integrity": "sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/astro/node_modules/@bruits/satteri-win32-arm64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.10.5.tgz", + "integrity": "sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/astro/node_modules/@bruits/satteri-win32-x64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.10.5.tgz", + "integrity": "sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/astro/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/astro/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/astro/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/astro/node_modules/es-module-lexer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-3.0.4.tgz", + "integrity": "sha512-BldNY5mwkVu+cQ5Ymn3e6hB9Sx8XHx4ZevWbiUyZbfKxJxYO27Hf0wfzkxIaD5CAJMaGl3YspKELj0ff/7nCMA==", + "license": "MIT" + }, + "node_modules/astro/node_modules/magic-string": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.3.tgz", + "integrity": "sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/astro/node_modules/satteri": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.10.5.tgz", + "integrity": "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.5", + "@types/hast": "^3.0.5", + "@types/mdast": "^4.0.4", + "@types/unist": "^3.0.3" + }, + "optionalDependencies": { + "@bruits/satteri-darwin-arm64": "0.10.5", + "@bruits/satteri-darwin-x64": "0.10.5", + "@bruits/satteri-linux-arm64-gnu": "0.10.5", + "@bruits/satteri-linux-arm64-musl": "0.10.5", + "@bruits/satteri-linux-x64-gnu": "0.10.5", + "@bruits/satteri-linux-x64-musl": "0.10.5", + "@bruits/satteri-wasm32-wasi": "0.10.5", + "@bruits/satteri-win32-arm64-msvc": "0.10.5", + "@bruits/satteri-win32-x64-msvc": "0.10.5" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "license": "Apache-2.0", "engines": { @@ -2950,16 +3374,16 @@ } }, "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" }, "funding": { "url": "https://github.com/sponsors/fb55" @@ -2995,9 +3419,9 @@ } }, "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", "license": "BSD-2-Clause", "engines": { "node": ">= 6" @@ -3112,10 +3536,13 @@ } }, "node_modules/devalue": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.9.0.tgz", - "integrity": "sha512-RWrqdArjvPbsATEhOPUo6Wndc/iWnkWKlhIrdlF3zMMYo/c3CVtoaVAyLtWxz5h8nSlkHzxnzV2uLydPXmtF+A==", - "license": "MIT" + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-6.0.3.tgz", + "integrity": "sha512-3woMEITftG1wKeO/4d/QXH1DVKctTSZg3jNGPpjp9hNr5Hos8MCFF5McTML5ZtgKDObm2R591B0spRp2IVernA==", + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/devlop": { "version": "1.1.0", @@ -3131,9 +3558,9 @@ } }, "node_modules/diff": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -3251,9 +3678,9 @@ } }, "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", "license": "MIT" }, "node_modules/esast-util-from-estree": { @@ -3289,9 +3716,10 @@ } }, "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -3301,32 +3729,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" } }, "node_modules/escape-string-regexp": { @@ -3381,9 +3809,9 @@ } }, "node_modules/estree-util-scope": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", - "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.1.tgz", + "integrity": "sha512-B0np3dcdxqILX5e9nEi5/Fr4K7gL4oYFVPV1zRa2e9wRCbQoZZNWOZFYyoInvXUPJXBXjss+QXlWLJChDEHDkA==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -3439,15 +3867,15 @@ "license": "MIT" }, "node_modules/expressive-code": { - "version": "0.44.1", - "resolved": "https://registry.npmjs.org/expressive-code/-/expressive-code-0.44.1.tgz", - "integrity": "sha512-GakidxhapWDzpKLqEaFQ8wGk6gAqEtPQibu8+yPBfnDLgev5Vdsh1pasTxnrXL/mzIknyqeTwhMHTghdaiUrTg==", + "version": "0.44.2", + "resolved": "https://registry.npmjs.org/expressive-code/-/expressive-code-0.44.2.tgz", + "integrity": "sha512-MLNghkvhyFgVW4oCD5DxBuYnnTXIf0PygzGmfT6OZeOOYWh/D4sH1j931biElkA5RG/J9wY/iuSMGAPF5vzHOg==", "license": "MIT", "dependencies": { - "@expressive-code/core": "^0.44.1", - "@expressive-code/plugin-frames": "^0.44.1", - "@expressive-code/plugin-shiki": "^0.44.1", - "@expressive-code/plugin-text-markers": "^0.44.1" + "@expressive-code/core": "^0.44.2", + "@expressive-code/plugin-frames": "^0.44.2", + "@expressive-code/plugin-shiki": "^0.44.2", + "@expressive-code/plugin-text-markers": "^0.44.2" } }, "node_modules/extend": { @@ -3506,6 +3934,12 @@ "node": ">=8" } }, + "node_modules/fnv1a-64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/fnv1a-64/-/fnv1a-64-0.1.2.tgz", + "integrity": "sha512-mJbcILTPybAR1jdOwt/lVv8N2cffeJFFP+gVbSAwLEx1ujXH27RpPd8Rokec/KX9c76UYIB6Co+H4lQzxPnJfA==", + "license": "MIT" + }, "node_modules/fontace": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz", @@ -3542,9 +3976,9 @@ } }, "node_modules/get-tsconfig": { - "version": "5.0.0-beta.4", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.4.tgz", - "integrity": "sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==", + "version": "5.0.0-beta.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.6.tgz", + "integrity": "sha512-X6fBC0pmImC70gvX2zm56go9hx0MyoGVdG0tUCkg/D+Xnh5TJsOZ7iDbOdI3PvmtrDxnu1YdDufpK2QJX1Meqw==", "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -3971,15 +4405,15 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz", + "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==", "license": "BSD-2-Clause" }, "node_modules/i18next": { - "version": "26.3.6", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.6.tgz", - "integrity": "sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==", + "version": "26.4.6", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.4.6.tgz", + "integrity": "sha512-f/QHPNtH3XmBjL3sCRCrp5+jycwgV0W9fr1Vsy5msg1mR5grgaHc8eIbZhU7ASFwiGtF9PHVRQDqQ8Nf6iDTFA==", "funding": [ { "type": "individual", @@ -4091,9 +4525,9 @@ } }, "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "funding": [ { "type": "github", @@ -4409,9 +4843,9 @@ } }, "node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" @@ -4427,9 +4861,9 @@ } }, "node_modules/magicast": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.4.tgz", - "integrity": "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.5.tgz", + "integrity": "sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.7", @@ -4475,9 +4909,9 @@ } }, "node_modules/mdast-util-directive": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz", - "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.1.tgz", + "integrity": "sha512-Gqpa3MHorXYEZ0VfbroyvBlVKUfz371V6mIERqOYMcb0W1D3LwmFq1ZW4O2TDrbn+4ZmGLwMWeFRJgYZ+bc5fQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -4486,6 +4920,7 @@ "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", + "micromark-util-character": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-visit-parents": "^6.0.0" @@ -4496,9 +4931,9 @@ } }, "node_modules/mdast-util-find-and-replace": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.3.tgz", + "integrity": "sha512-xPgpDNl0/OXHsI7TlaIs22lWnH3KlpvZdXG1ET/m/YT2Hhdkx8lJV4kLphE6l9simyM4KPDFBwas08BgEob6Jw==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -4512,9 +4947,9 @@ } }, "node_modules/mdast-util-from-markdown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", - "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.1.0.tgz", + "integrity": "sha512-KRLgmPaP2H1ul2bpoJkOS+9pAcDAAj9Nu1mqLnh8NLeJG5tlvj42TH80PIGBpROWlRXLk0lDrWNuZCFy/tsB4A==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -4589,9 +5024,9 @@ } }, "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.1.tgz", + "integrity": "sha512-OuJHqvr455pwu2OaOrir7dbzqs4jlWKOtlu9L6GjcIjjQwNyw02VntQsr/Ek6/A13vgnXfUhBekWRUP1OkNivw==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -4749,9 +5184,9 @@ } }, "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.2.0.tgz", + "integrity": "sha512-2Jn/ADrHFFyyniBMi0bncTbJqU78K3/TEYvzvwrWWzD9MYPUa/Gm4r3nOeKFQg/PDM5BsbDYdc8ackW4NTY6NA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -4759,8 +5194,10 @@ "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", + "micromark-util-character": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" }, @@ -4789,9 +5226,9 @@ "license": "CC0-1.0" }, "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.3.tgz", + "integrity": "sha512-oGYfQzHSG5dOMovQcJ3fyTmZlWAWpi0XA0sJwJs+i6OT88o1+Jtw/8z0CmdowSLxGhhFK89rQ/oXph/wN02PNw==", "funding": [ { "type": "GitHub Sponsors", @@ -4814,6 +5251,7 @@ "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", @@ -4824,9 +5262,9 @@ } }, "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.4.tgz", + "integrity": "sha512-wxEeE8v8XVvOrxn1TZj74qYhAtTQsSqufHVS3uNVyT1MupXxhyaHk8/9xDNPh9BmL77QNDgWTkZ3RsYHB2ry7w==", "funding": [ { "type": "GitHub Sponsors", @@ -4843,18 +5281,19 @@ "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", + "micromark-factory-space": "^2.1.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", + "micromark-util-edit-map": "^1.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "micromark-util-types": "^2.0.3" } }, "node_modules/micromark-extension-directive": { @@ -4951,9 +5390,9 @@ } }, "node_modules/micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.2.tgz", + "integrity": "sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -5170,9 +5609,9 @@ } }, "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.1.0.tgz", + "integrity": "sha512-fS8hnLIjnjvdQIj39Geug8wWsR0HrYZ43KShKxNfwT7t2LOHo/LbWZEzEaSOjwtjdCsjoE6syHhonEzW0zv0+Q==", "funding": [ { "type": "GitHub Sponsors", @@ -5354,6 +5793,25 @@ "micromark-util-symbol": "^2.0.0" } }, + "node_modules/micromark-util-edit-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-edit-map/-/micromark-util-edit-map-1.0.0.tgz", + "integrity": "sha512-Pa2ljlsEL6sVwFaYeyrOLSYbQt73JvGbPOYFq+9AElXiSnfI5Q4465RRZ1sHv7lDjDOnGRDDaqPXqClqWK/q1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, "node_modules/micromark-util-encode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", @@ -5509,9 +5967,9 @@ "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.3.tgz", + "integrity": "sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==", "funding": [ { "type": "GitHub Sponsors", @@ -5525,16 +5983,16 @@ "license": "MIT" }, "node_modules/miniflare": { - "version": "5.20260730.0-alpha", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-5.20260730.0-alpha.tgz", - "integrity": "sha512-8/dspSXDshP6nSkCpjKO7BYc2qZoYSXm7iM+QxY7qJyJpAB3onnQSaiu0cvKJlfuMGwULl55hG69FJCcCMXU1Q==", + "version": "5.20261012.0-beta", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-5.20261012.0-beta.tgz", + "integrity": "sha512-Cjrs+vHHQ7krLO4HYELYpYBJBuMhcnNZD/Z5z/UcQSnFqWSQY3DhtTCFalXgI1/yO1iK+YrRKK8EYkumrEopxg==", "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "0.8.1", - "sharp": "0.35.2", - "undici": "7.28.0", - "workerd": "1.20260730.1", + "sharp": "0.35.5", + "undici": "7.29.1", + "workerd": "1.20261012.1", "ws": "8.21.0", "youch": "4.1.0-beta.10" }, @@ -5542,623 +6000,23 @@ "node": ">=22.0.0" } }, - "node_modules/miniflare/node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.2.tgz", - "integrity": "sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg==", - "cpu": [ - "arm64" - ], + "node_modules/miniflare/node_modules/undici": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz", + "integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==", "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], + "license": "MIT", "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.1" + "node": ">=20.18.1" } }, - "node_modules/miniflare/node_modules/@img/sharp-darwin-x64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.2.tgz", - "integrity": "sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.1" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.2.tgz", - "integrity": "sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "dependencies": { - "@img/sharp-wasm32": "0.35.2" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.1.tgz", - "integrity": "sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.1.tgz", - "integrity": "sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.1.tgz", - "integrity": "sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.1.tgz", - "integrity": "sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.1.tgz", - "integrity": "sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.1.tgz", - "integrity": "sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.1.tgz", - "integrity": "sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.1.tgz", - "integrity": "sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.1.tgz", - "integrity": "sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.1.tgz", - "integrity": "sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-linux-arm": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.2.tgz", - "integrity": "sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.1" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-linux-arm64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.2.tgz", - "integrity": "sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.1" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-linux-ppc64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.2.tgz", - "integrity": "sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.1" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-linux-riscv64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.2.tgz", - "integrity": "sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.1" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-linux-s390x": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.2.tgz", - "integrity": "sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.1" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-linux-x64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.2.tgz", - "integrity": "sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.1" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.2.tgz", - "integrity": "sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.1" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.2.tgz", - "integrity": "sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.1" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-wasm32": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.2.tgz", - "integrity": "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==", - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.11.1" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-webcontainers-wasm32": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.2.tgz", - "integrity": "sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@img/sharp-wasm32": "0.35.2" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-win32-arm64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.2.tgz", - "integrity": "sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-win32-ia32": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.2.tgz", - "integrity": "sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/@img/sharp-win32-x64": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.2.tgz", - "integrity": "sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/miniflare/node_modules/sharp": { - "version": "0.35.2", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.2.tgz", - "integrity": "sha512-FVtFjtBCMiJS6yb5CX7Sop45WFMpeGw6oRKuJnXYgf/f1ms/D7LE/ZUSNxnW7rZ/dbslQWYkoqFHGPaDBtaK4w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@img/colour": "^1.1.0", - "detect-libc": "^2.1.2", - "semver": "^7.8.4" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.35.2", - "@img/sharp-darwin-x64": "0.35.2", - "@img/sharp-freebsd-wasm32": "0.35.2", - "@img/sharp-libvips-darwin-arm64": "1.3.1", - "@img/sharp-libvips-darwin-x64": "1.3.1", - "@img/sharp-libvips-linux-arm": "1.3.1", - "@img/sharp-libvips-linux-arm64": "1.3.1", - "@img/sharp-libvips-linux-ppc64": "1.3.1", - "@img/sharp-libvips-linux-riscv64": "1.3.1", - "@img/sharp-libvips-linux-s390x": "1.3.1", - "@img/sharp-libvips-linux-x64": "1.3.1", - "@img/sharp-libvips-linuxmusl-arm64": "1.3.1", - "@img/sharp-libvips-linuxmusl-x64": "1.3.1", - "@img/sharp-linux-arm": "0.35.2", - "@img/sharp-linux-arm64": "0.35.2", - "@img/sharp-linux-ppc64": "0.35.2", - "@img/sharp-linux-riscv64": "0.35.2", - "@img/sharp-linux-s390x": "0.35.2", - "@img/sharp-linux-x64": "0.35.2", - "@img/sharp-linuxmusl-arm64": "0.35.2", - "@img/sharp-linuxmusl-x64": "0.35.2", - "@img/sharp-webcontainers-wasm32": "0.35.2", - "@img/sharp-win32-arm64": "0.35.2", - "@img/sharp-win32-ia32": "0.35.2", - "@img/sharp-win32-x64": "0.35.2" - } - }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", - "license": "MIT", - "engines": { - "node": ">=10" + "node": ">=10" } }, "node_modules/ms": { @@ -6168,9 +6026,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "funding": [ { "type": "github", @@ -6241,9 +6099,9 @@ } }, "node_modules/obug": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", - "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/obug/-/obug-3.0.0.tgz", + "integrity": "sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==", "funding": [ "https://github.com/sponsors/sxzz", "https://opencollective.com/debug" @@ -6264,12 +6122,6 @@ "ufo": "^1.6.1" } }, - "node_modules/ohash": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", - "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", - "license": "MIT" - }, "node_modules/oniguruma-parser": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", @@ -6288,9 +6140,9 @@ } }, "node_modules/p-limit": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.1.tgz", - "integrity": "sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.3.tgz", + "integrity": "sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ==", "license": "MIT", "dependencies": { "yocto-queue": "^1.2.1" @@ -6303,9 +6155,9 @@ } }, "node_modules/p-queue": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.3.tgz", - "integrity": "sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.5.tgz", + "integrity": "sha512-Lki/zhXFVmDhesBUn/yHRLW9Bte7mE7xoFHzTR8sIomV7a2z+LxYAPkGvdfidNiu4fKSfjtawixxSHcZci5QcQ==", "license": "MIT", "dependencies": { "eventemitter3": "^5.0.4", @@ -6319,9 +6171,9 @@ } }, "node_modules/p-timeout": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", - "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.2.tgz", + "integrity": "sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==", "license": "MIT", "engines": { "node": ">=20" @@ -6331,9 +6183,9 @@ } }, "node_modules/package-manager-detector": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz", - "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.9.0.tgz", + "integrity": "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==", "license": "MIT" }, "node_modules/pagefind": { @@ -6436,9 +6288,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", "engines": { "node": ">=12" @@ -6448,9 +6300,9 @@ } }, "node_modules/postcss": { - "version": "8.5.25", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", - "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "version": "8.5.30", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.30.tgz", + "integrity": "sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==", "funding": [ { "type": "opencollective", @@ -6467,9 +6319,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", + "nanoid": "^3.3.20", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -6548,9 +6400,9 @@ "license": "MIT" }, "node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -6668,12 +6520,12 @@ } }, "node_modules/rehype-expressive-code": { - "version": "0.44.1", - "resolved": "https://registry.npmjs.org/rehype-expressive-code/-/rehype-expressive-code-0.44.1.tgz", - "integrity": "sha512-+VZgs7Evw4LXRN3owpoBNSTpYuW6GeOdjqcUT1TuY8o/4MGPtbd0EU7Bgrju7X8KrQ6SslOBAuGWJ5fV5TriJQ==", + "version": "0.44.2", + "resolved": "https://registry.npmjs.org/rehype-expressive-code/-/rehype-expressive-code-0.44.2.tgz", + "integrity": "sha512-jvjQpsfWKBquDrEl5YQA3CJybRRIuDOYsui1BJTs5oKDUK8pPkJSSxY8FjxNlIFIdtgrTjC1zuahuY4Cc1j9SQ==", "license": "MIT", "dependencies": { - "expressive-code": "^0.44.1" + "expressive-code": "^0.44.2" } }, "node_modules/rehype-format": { @@ -6932,12 +6784,12 @@ } }, "node_modules/rolldown": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.2.tgz", - "integrity": "sha512-opwpo1tQBAcpSUJDt94B7hhLNGOKjCdE//XXjeLrnx9b83bjnw45tXdg1b09yEw/VLFBJGZpwRULMmOZo7ol+A==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.14.tgz", + "integrity": "sha512-eTBTTqMR6uHKLgcUqpJP8ntzDI6V4LYA8negAMBEI7gkgVvOdrx6VsvS2Ym+83KhOPdLCHWJu0w7UQFJZhHKNw==", "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.142.0", + "@oxc-project/types": "=0.154.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -6947,20 +6799,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.2.2", - "@rolldown/binding-darwin-arm64": "1.2.2", - "@rolldown/binding-darwin-x64": "1.2.2", - "@rolldown/binding-freebsd-x64": "1.2.2", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.2", - "@rolldown/binding-linux-arm64-gnu": "1.2.2", - "@rolldown/binding-linux-arm64-musl": "1.2.2", - "@rolldown/binding-linux-ppc64-gnu": "1.2.2", - "@rolldown/binding-linux-s390x-gnu": "1.2.2", - "@rolldown/binding-linux-x64-gnu": "1.2.2", - "@rolldown/binding-linux-x64-musl": "1.2.2", - "@rolldown/binding-openharmony-arm64": "1.2.2", - "@rolldown/binding-win32-arm64-msvc": "1.2.2", - "@rolldown/binding-win32-x64-msvc": "1.2.2" + "@rolldown/binding-android-arm-eabi": "1.2.14", + "@rolldown/binding-android-arm64": "1.2.14", + "@rolldown/binding-darwin-arm64": "1.2.14", + "@rolldown/binding-darwin-x64": "1.2.14", + "@rolldown/binding-freebsd-x64": "1.2.14", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.14", + "@rolldown/binding-linux-arm64-gnu": "1.2.14", + "@rolldown/binding-linux-arm64-musl": "1.2.14", + "@rolldown/binding-linux-ppc64-gnu": "1.2.14", + "@rolldown/binding-linux-s390x-gnu": "1.2.14", + "@rolldown/binding-linux-x64-gnu": "1.2.14", + "@rolldown/binding-linux-x64-musl": "1.2.14", + "@rolldown/binding-openharmony-arm64": "1.2.14", + "@rolldown/binding-win32-arm64-msvc": "1.2.14", + "@rolldown/binding-win32-x64-msvc": "1.2.14" } }, "node_modules/satteri": { @@ -7008,9 +6861,9 @@ } }, "node_modules/sharp": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", - "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz", + "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==", "license": "Apache-2.0", "dependencies": { "@img/colour": "^1.1.0", @@ -7024,31 +6877,31 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.35.3", - "@img/sharp-darwin-x64": "0.35.3", - "@img/sharp-freebsd-wasm32": "0.35.3", - "@img/sharp-libvips-darwin-arm64": "1.3.2", - "@img/sharp-libvips-darwin-x64": "1.3.2", - "@img/sharp-libvips-linux-arm": "1.3.2", - "@img/sharp-libvips-linux-arm64": "1.3.2", - "@img/sharp-libvips-linux-ppc64": "1.3.2", - "@img/sharp-libvips-linux-riscv64": "1.3.2", - "@img/sharp-libvips-linux-s390x": "1.3.2", - "@img/sharp-libvips-linux-x64": "1.3.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", - "@img/sharp-libvips-linuxmusl-x64": "1.3.2", - "@img/sharp-linux-arm": "0.35.3", - "@img/sharp-linux-arm64": "0.35.3", - "@img/sharp-linux-ppc64": "0.35.3", - "@img/sharp-linux-riscv64": "0.35.3", - "@img/sharp-linux-s390x": "0.35.3", - "@img/sharp-linux-x64": "0.35.3", - "@img/sharp-linuxmusl-arm64": "0.35.3", - "@img/sharp-linuxmusl-x64": "0.35.3", - "@img/sharp-webcontainers-wasm32": "0.35.3", - "@img/sharp-win32-arm64": "0.35.3", - "@img/sharp-win32-ia32": "0.35.3", - "@img/sharp-win32-x64": "0.35.3" + "@img/sharp-darwin-arm64": "0.35.5", + "@img/sharp-darwin-x64": "0.35.5", + "@img/sharp-freebsd-wasm32": "0.35.5", + "@img/sharp-libvips-darwin-arm64": "1.3.4", + "@img/sharp-libvips-darwin-x64": "1.3.4", + "@img/sharp-libvips-linux-arm": "1.3.4", + "@img/sharp-libvips-linux-arm64": "1.3.4", + "@img/sharp-libvips-linux-ppc64": "1.3.4", + "@img/sharp-libvips-linux-riscv64": "1.3.4", + "@img/sharp-libvips-linux-s390x": "1.3.4", + "@img/sharp-libvips-linux-x64": "1.3.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", + "@img/sharp-libvips-linuxmusl-x64": "1.3.4", + "@img/sharp-linux-arm": "0.35.5", + "@img/sharp-linux-arm64": "0.35.5", + "@img/sharp-linux-ppc64": "0.35.5", + "@img/sharp-linux-riscv64": "0.35.5", + "@img/sharp-linux-s390x": "0.35.5", + "@img/sharp-linux-x64": "0.35.5", + "@img/sharp-linuxmusl-arm64": "0.35.5", + "@img/sharp-linuxmusl-x64": "0.35.5", + "@img/sharp-webcontainers-wasm32": "0.35.5", + "@img/sharp-win32-arm64": "0.35.5", + "@img/sharp-win32-ia32": "0.35.5", + "@img/sharp-win32-x64": "0.35.5" }, "peerDependenciesMeta": { "@types/node": { @@ -7057,17 +6910,17 @@ } }, "node_modules/shiki": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.4.1.tgz", - "integrity": "sha512-rFP+iYKzjLEIqiMiKANhARqiAbk4deDhWnBtnUO/K0D0dPxMGDH4N0FVfBY/VeI+lPrV4wNGCHQZp7EOr7NNBw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.5.0.tgz", + "integrity": "sha512-OcRW72ngQvc+MSVWBRIovC/BTW589iUE/Vxav7VeM4RcY9MUjqB+IR6ILG1k9nuW6LiG/nct9uma4/MBtnZbmQ==", "license": "MIT", "dependencies": { - "@shikijs/core": "4.4.1", - "@shikijs/engine-javascript": "4.4.1", - "@shikijs/engine-oniguruma": "4.4.1", - "@shikijs/langs": "4.4.1", - "@shikijs/themes": "4.4.1", - "@shikijs/types": "4.4.1", + "@shikijs/core": "4.5.0", + "@shikijs/engine-javascript": "4.5.0", + "@shikijs/engine-oniguruma": "4.5.0", + "@shikijs/langs": "4.5.0", + "@shikijs/themes": "4.5.0", + "@shikijs/types": "4.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.5" }, @@ -7101,9 +6954,9 @@ } }, "node_modules/smol-toml": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.1.tgz", - "integrity": "sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.1.tgz", + "integrity": "sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ==", "license": "BSD-3-Clause", "engines": { "node": ">= 18" @@ -7122,9 +6975,9 @@ } }, "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==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -7140,10 +6993,10 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/stream-replace-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz", - "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==", + "node_modules/std-env": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.3.0.tgz", + "integrity": "sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==", "license": "MIT" }, "node_modules/stringify-entities": { @@ -7192,18 +7045,18 @@ } }, "node_modules/svgo": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.2.tgz", - "integrity": "sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.1.0.tgz", + "integrity": "sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==", "license": "MIT", "dependencies": { "commander": "^11.1.0", - "css-select": "^5.1.0", + "css-select": "^6.0.0", "css-tree": "^3.0.1", - "css-what": "^6.1.0", + "css-what": "^7.0.0", "csso": "^5.0.5", "picocolors": "^1.1.1", - "sax": "^1.5.0" + "sax": "1.6.1" }, "bin": { "svgo": "bin/svgo.js" @@ -7223,18 +7076,18 @@ "license": "MIT" }, "node_modules/tinyclip": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.15.tgz", - "integrity": "sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-1.0.3.tgz", + "integrity": "sha512-nTv2raKFMzGG6JJp0lpNDsRPdfFE6UHlu2rVEjXo8vkx1ZS3LW2CVXqIaLu8xZlu+6tbFs9V58Qc/Jmk/Ii7wA==", "license": "MIT", "engines": { "node": "^16.14.0 || >= 17.3.0" } }, "node_modules/tinyexec": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", - "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", "license": "MIT", "engines": { "node": ">=18" @@ -7256,6 +7109,12 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyps": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/tinyps/-/tinyps-0.5.0.tgz", + "integrity": "sha512-Llu7nEtVOGHh7jok32l6+udlu+4Np5vsYVB7zeTK614coSsro2qjwte7MFt/ouLM/h4kXqbGXktSMMvMsttSDw==", + "license": "MIT" + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -7302,19 +7161,18 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", - "dev": true, + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.12.2.tgz", + "integrity": "sha512-XtuDWVdqTLr3NAxm2ly9/hU6kUsJOgGh1RASzMBbsw6aWCOaQzHdW+QQDfdERjfJ2V5vL5pRPa4RetO9UfivDg==", "license": "MIT", "engines": { - "node": ">=20.18.1" + "node": ">=22.19.0" } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "license": "MIT" }, "node_modules/unenv": { @@ -7347,14 +7205,15 @@ } }, "node_modules/unifont": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz", - "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-1.0.3.tgz", + "integrity": "sha512-XGnEwj5sWdCbiBX01mWLSBncS0yMRjnLygau3IfdOlfjMacNIQvTGW4VH7pWBq+gGWArfSef/CensMLjMmIr/A==", "license": "MIT", "dependencies": { "css-tree": "^3.1.0", - "ofetch": "^1.5.1", - "ohash": "^2.0.11" + "fnv1a-64": "^0.1.2", + "std-env": "^4.2.0", + "undici": "^8.0.0" } }, "node_modules/unist-util-find-after": { @@ -7494,19 +7353,19 @@ } }, "node_modules/unstorage": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", - "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.6.tgz", + "integrity": "sha512-gjKtcmn/KwZuJZO9o2sc0esAQnhmTw0LviDHwevTXbJMYs0dRTp8ZEEWXHU0vTpzbN3cA0yxlTeyXssMp3zDqw==", "license": "MIT", "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", - "h3": "^1.15.10", - "lru-cache": "^11.2.7", + "h3": "^1.15.11", + "lru-cache": "^11.5.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", - "ufo": "^1.6.3" + "ufo": "^1.6.4" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", @@ -7517,7 +7376,7 @@ "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", - "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", @@ -7607,6 +7466,18 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/verkit": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.5.0.tgz", + "integrity": "sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==", + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -7650,15 +7521,15 @@ } }, "node_modules/vite": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.0.tgz", - "integrity": "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.4.tgz", + "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==", "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", - "picomatch": "^4.0.5", - "postcss": "^8.5.23", - "rolldown": "~1.2.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.29", + "rolldown": "~1.2.12", "tinyglobby": "^0.2.17" }, "bin": { @@ -7675,7 +7546,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0", + "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -7756,9 +7627,9 @@ } }, "node_modules/workerd": { - "version": "1.20260730.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260730.1.tgz", - "integrity": "sha512-zmfNIjwYSWFY5chGBOjWtH3xAE7p97FTC6vR4Ep98290ho6AeAR/NVcBD274YCLEUYzqm8yxdtZlxMybU8a3jA==", + "version": "1.20261012.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20261012.1.tgz", + "integrity": "sha512-tEHoMPsMga0seVjxfsR8Pd3f8IRqYwkq++dTUKI5Gdgj6zuSDluYwisydq+dn90SsIACwBquJUQ1nBpcOqaWTA==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -7769,28 +7640,28 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20260730.1", - "@cloudflare/workerd-darwin-arm64": "1.20260730.1", - "@cloudflare/workerd-linux-64": "1.20260730.1", - "@cloudflare/workerd-linux-arm64": "1.20260730.1", - "@cloudflare/workerd-windows-64": "1.20260730.1" + "@cloudflare/workerd-darwin-64": "1.20261012.1", + "@cloudflare/workerd-darwin-arm64": "1.20261012.1", + "@cloudflare/workerd-linux-64": "1.20261012.1", + "@cloudflare/workerd-linux-arm64": "1.20261012.1", + "@cloudflare/workerd-windows-64": "1.20261012.1" } }, "node_modules/wrangler": { - "version": "4.118.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.118.0.tgz", - "integrity": "sha512-9pkBw/b8zWqGx2S+oLhgHMR1M/4VOE8SynUFABnGWiSFGlcOQ4xiI/B71Xf66RYP2xzngU37IQFPtUruij3lYw==", + "version": "4.151.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.151.0.tgz", + "integrity": "sha512-ra8MpzSR+ClkbGofu9S+AmAKjytS60MqSuayXKpa1CAYIzP+NIc8q6EiF55Gz5PS3lxT4qcvMuPHihCNhTPpDg==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { "@cloudflare/kv-asset-handler": "0.5.0", - "@cloudflare/unenv-preset": "2.16.1", + "@cloudflare/unenv-preset": "2.16.2", "blake3-wasm": "2.1.5", - "esbuild": "0.28.1", - "miniflare": "5.20260730.0-alpha", + "esbuild": "0.28.2", + "miniflare": "5.20261012.0-beta", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", - "workerd": "1.20260730.1" + "workerd": "1.20261012.1" }, "bin": { "cf-wrangler": "bin/cf-wrangler.js", @@ -7804,7 +7675,7 @@ "fsevents": "2.3.3" }, "peerDependencies": { - "@cloudflare/workers-types": "^5.20260730.1" + "@cloudflare/workers-types": "^5.20261006.1" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -7840,6 +7711,21 @@ "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", "license": "MIT" }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs-parser": { "version": "22.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", @@ -7901,9 +7787,9 @@ } }, "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.7.tgz", + "integrity": "sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index b020677b..6f817e6e 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,11 @@ "astro": "astro" }, "dependencies": { - "@astrojs/starlight": "^0.41.6", - "astro": "^7.1.6", - "sharp": "^0.35.3" + "@astrojs/starlight": "^0.41.11", + "astro": "^7.4.0", + "sharp": "^0.35.5" }, "devDependencies": { - "wrangler": "4.118.0" + "wrangler": "4.151.0" } } diff --git a/public/brand/agents.webp b/public/brand/agents.webp new file mode 100644 index 00000000..6242598c Binary files /dev/null and b/public/brand/agents.webp differ diff --git a/public/brand/crown.webp b/public/brand/crown.webp new file mode 100644 index 00000000..b616b7a5 Binary files /dev/null and b/public/brand/crown.webp differ diff --git a/public/brand/favicon-16.png b/public/brand/favicon-16.png new file mode 100644 index 00000000..0ed95b8c Binary files /dev/null and b/public/brand/favicon-16.png differ diff --git a/public/brand/favicon-180.png b/public/brand/favicon-180.png new file mode 100644 index 00000000..31d981b4 Binary files /dev/null and b/public/brand/favicon-180.png differ diff --git a/public/brand/favicon-32.png b/public/brand/favicon-32.png new file mode 100644 index 00000000..88568d28 Binary files /dev/null and b/public/brand/favicon-32.png differ diff --git a/public/brand/favicon-48.png b/public/brand/favicon-48.png new file mode 100644 index 00000000..91141be8 Binary files /dev/null and b/public/brand/favicon-48.png differ diff --git a/public/brand/forge.webp b/public/brand/forge.webp new file mode 100644 index 00000000..059c5499 Binary files /dev/null and b/public/brand/forge.webp differ diff --git a/public/brand/hero-400.webp b/public/brand/hero-400.webp new file mode 100644 index 00000000..655f7ee7 Binary files /dev/null and b/public/brand/hero-400.webp differ diff --git a/public/brand/hero-640.webp b/public/brand/hero-640.webp new file mode 100644 index 00000000..ef7999e0 Binary files /dev/null and b/public/brand/hero-640.webp differ diff --git a/public/brand/hero.webp b/public/brand/hero.webp new file mode 100644 index 00000000..2eaf06e6 Binary files /dev/null and b/public/brand/hero.webp differ diff --git a/public/brand/mascot.webp b/public/brand/mascot.webp new file mode 100644 index 00000000..0f140978 Binary files /dev/null and b/public/brand/mascot.webp differ diff --git a/public/brand/media.webp b/public/brand/media.webp new file mode 100644 index 00000000..2b3c209f Binary files /dev/null and b/public/brand/media.webp differ diff --git a/public/brand/network.webp b/public/brand/network.webp new file mode 100644 index 00000000..fd5d034d Binary files /dev/null and b/public/brand/network.webp differ diff --git a/public/brand/packaging.webp b/public/brand/packaging.webp new file mode 100644 index 00000000..e9aafcdf Binary files /dev/null and b/public/brand/packaging.webp differ diff --git a/public/brand/proof.webp b/public/brand/proof.webp new file mode 100644 index 00000000..d4a80804 Binary files /dev/null and b/public/brand/proof.webp differ diff --git a/public/brand/runtime.webp b/public/brand/runtime.webp new file mode 100644 index 00000000..7aec42e9 Binary files /dev/null and b/public/brand/runtime.webp differ diff --git a/public/brand/security.webp b/public/brand/security.webp new file mode 100644 index 00000000..22f23b3f Binary files /dev/null and b/public/brand/security.webp differ diff --git a/public/brand/social.png b/public/brand/social.png new file mode 100644 index 00000000..70a52f4f Binary files /dev/null and b/public/brand/social.png differ diff --git a/public/brand/tooling.webp b/public/brand/tooling.webp new file mode 100644 index 00000000..31a98d3f Binary files /dev/null and b/public/brand/tooling.webp differ diff --git a/public/brand/wordmark.webp b/public/brand/wordmark.webp new file mode 100644 index 00000000..4186cf2c Binary files /dev/null and b/public/brand/wordmark.webp differ diff --git a/public/favicon.svg b/public/favicon.svg deleted file mode 100644 index 51fa8b29..00000000 --- a/public/favicon.svg +++ /dev/null @@ -1,10 +0,0 @@ - - OpenCharly - - - - - - - diff --git a/scripts/extract-brand.mjs b/scripts/extract-brand.mjs new file mode 100644 index 00000000..0685b12f --- /dev/null +++ b/scripts/extract-brand.mjs @@ -0,0 +1,49 @@ +// Rebuild from the supplied flattened RGB board. Coordinates exclude its printed labels. +import sharp from 'sharp'; +import { mkdir } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; +const root = new URL('../', import.meta.url); +const source = fileURLToPath(new URL('assets/brand/assetboard.png', root)); +const output = fileURLToPath(new URL('public/brand/', root)); +await mkdir(output, { recursive: true }); +export const crops = { + crown: [1006, 16, 216, 178], + wordmark: [202, 48, 462, 88], + hero: [24, 243, 826, 300], + mascot: [862, 253, 305, 291], + forge: [10, 584, 190, 152], + proof: [208, 584, 190, 152], + agents: [404, 584, 190, 152], + runtime: [600, 584, 190, 152], + network: [796, 584, 190, 152], + security: [992, 584, 190, 152], + tooling: [1188, 584, 190, 152], + media: [1384, 584, 190, 152], + packaging: [1580, 584, 184, 152], +}; +const metadata = await sharp(source).metadata(); +if (metadata.width !== 1774 || metadata.height !== 887 || metadata.hasAlpha) { + throw new Error('Expected the original 1774 × 887 opaque assetboard'); +} +const crop = (name) => { + const [left, top, width, height] = crops[name]; + return sharp(source).extract({ left, top, width, height }); +}; +for (const name of Object.keys(crops)) { + await crop(name).webp({ quality: 88 }).toFile(`${output}/${name}.webp`); +} +for (const width of [400, 640]) { + await crop('hero').resize({ width, withoutEnlargement: true }).webp({ quality: 86 }).toFile(`${output}/hero-${width}.webp`); +} +for (const size of [16, 32, 48, 180]) { + await crop('crown').resize(size, size, { fit: 'contain', background: '#000', withoutEnlargement: true }).png().toFile(`${output}/favicon-${size}.png`); +} +// Compose at social-card size; each source crop retains its native pixel dimensions. +await sharp({ create: { width: 1200, height: 630, channels: 3, background: '#000' } }) + .composite([ + { input: await crop('crown').resize({ width: 110 }).png().toBuffer(), left: 105, top: 43 }, + { input: await crop('wordmark').png().toBuffer(), left: 248, top: 48 }, + { input: await crop('hero').png().toBuffer(), left: 24, top: 236 }, + { input: await crop('mascot').png().toBuffer(), left: 875, top: 244 }, + ]).png().toFile(`${output}/social.png`); +console.log(`Extracted ${Object.keys(crops).length} opaque artwork crops, responsive hero, four favicons and social card.`); diff --git a/src/components/Hero.astro b/src/components/Hero.astro new file mode 100644 index 00000000..32146b27 --- /dev/null +++ b/src/components/Hero.astro @@ -0,0 +1,60 @@ +--- +import DefaultHero from '@astrojs/starlight/components/Hero.astro'; +const home = Astro.url.pathname === import.meta.env.BASE_URL; +const families = [ + ['forge', 'Forge & Build'], ['proof', 'Proof & Evaluation'], + ['agents', 'Agents & Intelligence'], ['runtime', 'Runtime & Boxes'], + ['network', 'Network & Connectivity'], ['security', 'Systems & Security'], + ['tooling', 'Tooling & Developer UX'], ['media', 'Media & Interfaces'], + ['packaging', 'Packaging & Distribution'], +]; +--- +{home ? ( +
+
+ Charly caramelizes a crème brûlée in a copper chocolate workshop overlooking the mountains. +

A kinder internet

+
+
+
+ Charly, the cream and copper robot chocolatier, waves hello. +
+
+

Inside the workshop

+

Nine families. One sweet toolkit.

+ +
+
+) : } + diff --git a/src/components/SiteTitle.astro b/src/components/SiteTitle.astro new file mode 100644 index 00000000..fc44192e --- /dev/null +++ b/src/components/SiteTitle.astro @@ -0,0 +1,14 @@ +--- +const { siteTitle, siteTitleHref } = Astro.locals.starlightRoute; +--- + + + + {siteTitle} + + diff --git a/src/content.config.ts b/src/content.config.ts index d9ee8c9d..6abb1600 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -1,7 +1,8 @@ import { defineCollection } from 'astro:content'; -import { docsLoader } from '@astrojs/starlight/loaders'; -import { docsSchema } from '@astrojs/starlight/schema'; +import { docsLoader, i18nLoader } from '@astrojs/starlight/loaders'; +import { docsSchema, i18nSchema } from '@astrojs/starlight/schema'; export const collections = { docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), + i18n: defineCollection({ loader: i18nLoader(), schema: i18nSchema() }), }; diff --git a/src/content/docs/recipes/agentteams/agentteams-cli.md b/src/content/docs/recipes/agentteams/agentteams-cli.md index 4c06ebed..b4cd2c05 100644 --- a/src/content/docs/recipes/agentteams/agentteams-cli.md +++ b/src/content/docs/recipes/agentteams/agentteams-cli.md @@ -46,7 +46,7 @@ resolves the controller's in-venue :8090 to a host-routable address over the reverse channel (a published port on the pod substrate, a live `ssh -L` forward on the vm substrate), pulls the admin SA token from the venue, and probes with the SAME REST client the command uses -(R3 — one surface covers the CLI and every bed). Methods: +(R2 — one surface covers the CLI and every bed). Methods: - `agentteams: status` — controller health + resource counts. - `agentteams: manager-running` — poll until a manager reaches Running diff --git a/src/content/docs/recipes/agentteams/agentteams.md b/src/content/docs/recipes/agentteams/agentteams.md index 01f4657f..1b2888f0 100644 --- a/src/content/docs/recipes/agentteams/agentteams.md +++ b/src/content/docs/recipes/agentteams/agentteams.md @@ -92,7 +92,7 @@ Host mappings auto-allocate at deploy and resolve as `${HOST_PORT:}`. ### Pod substrate -`charly box build agentteams` then `charly fleet add` / `charly start` — or +`charly box build agentteams` then `charly deploy add` / `charly start` — or run the disposable bed end to end: ``` diff --git a/src/content/docs/recipes/automation/agent.md b/src/content/docs/recipes/automation/agent.md index 118e7a24..586b389f 100644 --- a/src/content/docs/recipes/automation/agent.md +++ b/src/content/docs/recipes/automation/agent.md @@ -79,7 +79,7 @@ Never retry an agent failure automatically. Record the incident, collect ordered - Expect phase/status events such as endpoint bootstrap, `waiting-for-prompt`, `prompt-ready`, running/reattached, settled, and exit. - Treat silence, malformed frames, EOF before ACK, cleanup failure, warnings, and unexpected duration as incidents. -- Use no sleep, polling loop, backoff, or arbitrary timed retry — per the project rulebook R4. Synchronize on process, tmux control, gRPC, terminal, and context events. +- Use no sleep, polling loop, backoff, or arbitrary timed retry — per the project rulebook R3. Synchronize on process, tmux control, gRPC, terminal, and context events. - Preserve stdout for structured command results and use stderr for provider/operation/target progress and actionable failures. - For implementation acceptance, run the complete unmodified disposable R10 bed with `charly check run ` and use its per-step logs and summary. diff --git a/src/content/docs/recipes/automation/crabbox-deploy.md b/src/content/docs/recipes/automation/crabbox-deploy.md index fd189072..2285284a 100644 --- a/src/content/docs/recipes/automation/crabbox-deploy.md +++ b/src/content/docs/recipes/automation/crabbox-deploy.md @@ -24,7 +24,7 @@ CLI -> broker at loopback :8080 -> postgres :5432 -> leases via | Action | Command | Description | |--------|---------|-------------| -| CLI version | `crabbox --version` | Verified 0.48.1 pin | +| CLI version | `crabbox --version` | The pin is owned by `layer-crabbox`'s `CRABBOX_VERSION` — never restate a version here | | Doctor | `crabbox doctor` | Local prerequisites; exit 0 needs NO broker (or a reachable one) | | Providers | `crabbox providers` | Credential-free local provider matrix (local-container/ssh/external) | | Login (shared token) | `printf '%s' "$CRABBOX_SHARED_TOKEN" \| crabbox login --url http://127.0.0.1:8080 --token-stdin` | Broker auth | @@ -75,6 +75,6 @@ charly check run check-crabbox-e2e-pod # steps=13 PASS (coordinator+broker) ## Cross-References -- [`/charly-tools:crabbox`](/recipes/tools/crabbox/) — the CLI candy. +- [`/charly-tools:crabbox-cli`](/recipes/tools/crabbox-cli/) — the CLI candy. - [`/charly-check:crabbox`](/recipes/check/crabbox/) — the check verb. - [`/charly-crabbox:crabbox-coordinator`](/recipes/crabbox/crabbox-coordinator/) — the coordinator candy. diff --git a/src/content/docs/recipes/automation/openclaw-deploy.md b/src/content/docs/recipes/automation/openclaw-deploy.md index 029111e8..86292b3f 100644 --- a/src/content/docs/recipes/automation/openclaw-deploy.md +++ b/src/content/docs/recipes/automation/openclaw-deploy.md @@ -1,6 +1,6 @@ --- title: "openclaw-deploy" -description: "OpenClaw gateway configuration, model auth, browser integration, channel setup, or any box composing `openclaw-*` candies (`openclaw`, `openclaw-full`, or a custom box composing openclaw + sway-desktop)." +description: "OpenClaw gateway configuration, model auth, browser integration, channel setup, or any box composing the OpenClaw family's candies (`openclaw`, or a custom box composing openclaw + sway-desktop)." --- @@ -13,7 +13,7 @@ description: "OpenClaw gateway configuration, model auth, browser integration, c OpenClaw is an AI gateway that connects LLM agents to messaging channels (WhatsApp, Telegram, Discord, Slack, Signal, iMessage, IRC, Teams) and exposes them via a WebSocket API, CLI, and web Control UI. It runs as a Node.js process with an embedded agent runtime, model failover, browser automation, and multi-agent routing. -In OpenCharly, OpenClaw runs as a supervisord service inside containers. The `openclaw` candy provides the npm package; compose it with the `sway-desktop` metalayer (full Sway desktop + Chrome browser + VNC) for browser-based workflows like OAuth and web automation. For a desktop+browser box, compose your own from the candies (shown below); for non-browser channels use the headless `openclaw` / `openclaw-full` boxes. +In OpenCharly, OpenClaw runs as a supervisord service inside containers. The `openclaw` candy provides the npm package; compose it with the `sway-desktop` metalayer (full Sway desktop + Chrome browser + VNC) for browser-based workflows like OAuth and web automation. For a desktop+browser box, compose your own — the family's `openclaw` candy plus `sway-desktop`, adding whichever tool candies you need; for non-browser channels use the headless `openclaw` box, which is the composition shown below. The gateway listens on port 18789 (WebSocket + HTTP). All CLI commands (`openclaw *`) connect to the gateway WebSocket. The Control UI is served at the gateway root URL. Config is stored in `~/.openclaw/openclaw.json` (JSON5 format). @@ -54,48 +54,45 @@ The gateway binds to loopback only (no `--bind lan`). External access is handled ### Box -Compose your own desktop+browser box — e.g. an `openclaw-desktop` entry in `charly.yml` combining `openclaw-full` + `sway-desktop` on a Fedora base: +The OpenClaw family owns this box: `opencharly/layer-openclaw` provides `box/openclaw`, a **headless** gateway box (no desktop, no browser, no tool bundle) composing exactly two candies — the gateway layer and the out-of-process `openclaw:` check verb. Import the family and deploy its box rather than hand-assembling the candies yourself: ```yaml -openclaw-desktop: +openclaw: candy: - base: fedora + base: cachyos.cachyos candy: - - '@github.com/opencharly/layer-agent-forwarding' - - '@github.com/opencharly/layer-openclaw-full' - - '@github.com/opencharly/layer-sway-desktop' - - '@github.com/opencharly/pod-dbus' - - charly + - openclaw + - '@github.com/opencharly/plugin-openclaw/candy/plugin-openclaw:v2026.281.0939' ``` -A box declares no ports of its own — the composed candies publish them (openclaw -18789, wayvnc 5900, chrome 9222/9224) and `charly config -p` remaps them at deploy -time. The resulting box exposes: +A consumer that wants a desktop or a browser composes those candies on top. + +A box declares no ports of its own — the composed candies publish them (the headless +family box exposes exactly one: the gateway on 18789) and `charly config -p` remaps +them at deploy time. The resulting box exposes: | Port | Service | Protocol | |------|---------|----------| -| 18789 | Gateway WebSocket + Control UI | HTTP | -| 5900 | VNC (wayvnc) | TCP | -| 9222 | Chrome DevTools | HTTP | +| 18789 | OpenClaw gateway + Control UI | HTTP | Tunnel config exposes all ports via Tailscale (`ports: all`). Platform: linux/amd64 only. ### Host Alias ```bash -charly alias add openclaw openclaw-desktop +charly alias add openclaw openclaw # Now: openclaw --help (runs inside the container) ``` ### Lifecycle ```bash -charly box build openclaw-desktop # Build image -charly config openclaw-desktop # Generate quadlet, daemon-reload -charly start openclaw-desktop # Start via systemd -charly stop openclaw-desktop # Stop -charly status openclaw-desktop # Check systemd status -charly logs openclaw-desktop -f # Follow container logs +charly box build openclaw # Build image +charly config openclaw # Generate quadlet, daemon-reload +charly start openclaw # Start via systemd +charly stop openclaw # Stop +charly status openclaw # Check systemd status +charly logs openclaw -f # Follow container logs ``` ## Gateway Configuration @@ -249,7 +246,7 @@ models: { ### Connecting to Existing Chrome -In a composed openclaw desktop box (e.g. `openclaw-desktop`), Chrome already runs as a supervisord service on port 9222. OpenClaw must connect to it rather than launching a new instance: +In a composed OpenClaw **desktop** box — one that composes `sway-desktop` and Chrome, which the family's own headless box does not — Chrome already runs as a supervisord service on port 9222. OpenClaw must connect to it rather than launching a new instance: ```bash openclaw config set browser.cdpUrl "http://127.0.0.1:9222" diff --git a/src/content/docs/recipes/automation/tmux.md b/src/content/docs/recipes/automation/tmux.md index 94b61b32..27afe688 100644 --- a/src/content/docs/recipes/automation/tmux.md +++ b/src/content/docs/recipes/automation/tmux.md @@ -78,7 +78,7 @@ These commands never shell out recursively through `charly cmd`/`charly shell` a - Control disconnect detaches when persistence permits. Initial reattachment and sequence recovery use a structured resynchronization snapshot. - Normal zero exit or explicit close verifies server cleanup. Nonzero exit, malformed stream, evidence overflow, or cleanup failure creates an incident and performs no automatic restart. - Recovery requires a completed RCA, except an explicit emergency abort that still records the unresolved incident. -- Semantic readiness is driven by tmux control-output events. `waiting-for-prompt` and `prompt-ready` statuses make the boundary observable; no capture polling, sleeps, backoff, or timed retries — per R4, pace on observable state. +- Semantic readiness is driven by tmux control-output events. `waiting-for-prompt` and `prompt-ready` statuses make the boundary observable; no capture polling, sleeps, backoff, or timed retries — per R3, pace on observable state. ## Terminal agents diff --git a/src/content/docs/recipes/build/build.md b/src/content/docs/recipes/build/build.md index 52b8a690..2c8045e3 100644 --- a/src/content/docs/recipes/build/build.md +++ b/src/content/docs/recipes/build/build.md @@ -13,13 +13,13 @@ Invoked as `charly box build`. See [`/charly-image:image`](/recipes/image/image/ ## Overview -`charly box build` generates Containerfiles from `charly.yml` and layer definitions, then builds images in dependency order using the configured build engine (Docker or Podman). Images at the same dependency level are built in parallel (up to `--jobs` concurrent builds). +`charly box build` generates Containerfiles from `charly.yml` and layer definitions, then builds images in dependency order with **BuildKit**, charly's only image builder. Images at the same dependency level are built in parallel (up to `--jobs` concurrent builds). **Mode purity**: `charly box build` reads `charly.yml` only. `charly.yml` is never read during build — this is enforced by `LoadConfig` in `charly/loader_threaded.go` (it reads the PROJECT `charly.yml` only and never merges the per-host `charly.yml` overlay — no `MergeDeployOverlay`), to guarantee OCI labels are baked strictly from authored configuration, never from local deploy-time overrides. See [`/charly-internals:go`](/recipes/internals/go/) "Mode purity" for the architectural invariant this protects and the bug it prevents. -**Build-engine dispatch**: `charly box build` does not construct a generator host-side at all (the former `NewGenerator` is DELETED) — `BuildCmd.Run` computes the build tag, holds the build-activity retention lock, and dispatches through the COMPILED-IN `build:box` plugin (candy/plugin-build) over the F10 reverse channel; on return it runs the retention prune host-side. The plugin's `runBoxBuild` → `resolveBuildEngine` (candy/plugin-build/resolve.go) runs the ENTIRE build-engine RESOLVE plugin-side — loader, vocab, scan, connect, validate, box resolve, intermediates, order, effective versions, host-fs prep, render-seam-cache prep, render-prep, user-context, envelope projection, and drive-model — and returns `spec.BuildResolveReply` (the resolved-project envelope + a serializable drive-model: engine/platform, build order, per-image descriptors, resolved tunables; NO Containerfile content). This is the plugin-side replacement for the DELETED host `build-prep` fat seam (`charly/build_resolve_host.go`'s `hostBuildBuildResolve`). The plugin **OWNS the podman DRIVE** (the build-order loop, per-image build lock, `podman build`, push, and the inline-merge gate) IN the candy — it imports only the sdk module. It reaches the host ONLY for thin `buildengine-*` shards a sdk-only candy cannot hold: `buildengine-scan-local` (local candy scan), `buildengine-connect-plugins` (registry plugin connect), and `buildengine-prep` (the render-seam-floor `renderGenCache` — `hostBuildPrep` stores a CHEAP candy-scan-only Generator for the render-seam floor's reverse-channel consumers and returns an EMPTY map; the host-fs PREP itself moved plugin-side in the K3 host-prep move — `runHostFSPrep` in candy/plugin-build/host_prep.go). The resolved-project envelope + drive-model are NOT returned by `buildengine-prep` — they come from `resolveBuildEngine`'s reply. The render DRIVE is `sdk/deploykit.Generator`, driven by the candy over the envelope + `HostBuild("render-seam")` for the host-coupled render seams (#67 — the host no longer renders the `.build/` tree); `bake_plugin:` binary baking is INLINE via `deploykit.EmitBakedPlugins` (no `HostBuild("bake-plugins")` round-trip — that host-builder + `host_build_bake_plugins.go` are DELETED). `charly box generate` mirrors this via `build:generate` → `runBoxGenerate` → `resolveBuildEngine(..., generateOnly=true)`: `generateOnly` is a PLUGIN-SIDE parameter (NOT a `HostBuild("buildengine-prep")` argument — that host leg takes `spec.ResolvedProjectRequest`, which has no `GenerateOnly` field) that returns after the envelope projection (no engine/order drive-model); the candy renders the `.build/` tree itself via `deploykit.Generator` + returns the written Containerfile paths; no podman. (The resolved-project envelope that OTHER verbs fetch — `charly box inspect`, `charly fleet compile`, `charly check`, … — comes over the separate `InvokeProvider("build","project",OpResolve)` peer seam, the `build:project` word; the build/generate path projects its own envelope inside `resolveBuildEngine`.) See [`/charly-internals:plugin`](/recipes/internals/plugin/) (the `build` provider class + the in-proc reverse channel) and [`/charly-build:generate`](/recipes/build/generate/). +**Build dispatch**: `charly box build` does not construct a generator host-side at all (the former `NewGenerator` is DELETED) — `BuildCmd.Run` computes the build tag, holds the build-activity retention lock, and dispatches through the COMPILED-IN `build:box` plugin (candy/plugin-build) over the F10 reverse channel; on return it runs the retention prune host-side. The plugin's `runBoxBuild` → `resolveBuildEngine` (candy/plugin-build/resolve.go) runs the ENTIRE build RESOLVE plugin-side — loader, vocab, scan, connect, validate, box resolve, intermediates, order, effective versions, host-fs prep, render-seam-cache prep, render-prep, user-context, envelope projection, and drive-model — and returns `spec.BuildResolveReply` (the resolved-project envelope + a serializable drive-model: engine/platform, build order, per-image descriptors, resolved tunables; NO Containerfile content). This is the plugin-side replacement for the DELETED host `build-prep` fat seam (`charly/build_resolve_host.go`'s `hostBuildBuildResolve`). The plugin **OWNS the BuildKit DRIVE** (the build-order loop, per-image build lock, the `buildctl` argv, the store bridge, push, and the inline-merge gate) IN the candy — it imports only the sdk module. It reaches the host ONLY for thin `buildengine-*` shards a sdk-only candy cannot hold: `buildengine-scan-local` (local candy scan), `buildengine-connect-plugins` (registry plugin connect), and `buildengine-prep` (the render-seam-floor `renderGenCache` — `hostBuildPrep` stores a CHEAP candy-scan-only Generator for the render-seam floor's reverse-channel consumers and returns an EMPTY map; the host-fs PREP itself moved plugin-side in the K3 host-prep move — `runHostFSPrep` in candy/plugin-build/host_prep.go). The resolved-project envelope + drive-model are NOT returned by `buildengine-prep` — they come from `resolveBuildEngine`'s reply. The render DRIVE is `sdk/deploykit.Generator`, driven by the candy over the envelope + `HostBuild("render-seam")` for the host-coupled render seams (#67 — the host no longer renders the `.build/` tree); `bake_plugin:` binary baking is INLINE via `deploykit.EmitBakedPlugins` (no `HostBuild("bake-plugins")` round-trip — that host-builder + `host_build_bake_plugins.go` are DELETED). `charly box generate` mirrors this via `build:generate` → `runBoxGenerate` → `resolveBuildEngine(..., generateOnly=true)`: `generateOnly` is a PLUGIN-SIDE parameter (NOT a `HostBuild("buildengine-prep")` argument — that host leg takes `spec.ResolvedProjectRequest`, which has no `GenerateOnly` field) that returns after the envelope projection (no engine/order drive-model); the candy renders the `.build/` tree itself via `deploykit.Generator` + returns the written Containerfile paths; no podman. (The resolved-project envelope that OTHER verbs fetch — `charly box inspect`, `charly check`, … — comes over the separate `InvokeProvider("build","project",OpResolve)` peer seam, the `build:project` word; the build/generate path projects its own envelope inside `resolveBuildEngine`.) See [`/charly-internals:plugin`](/recipes/internals/plugin/) (the `build` provider class + the in-proc reverse channel) and [`/charly-build:generate`](/recipes/build/generate/). -**Build-mode emission**: the build-mode Containerfile render DRIVE is `sdk/deploykit.Generator.Generate` / `generateContainerfile` (relocated from `charly/generate.go` in #67), driven by `candy/plugin-build` over the resolved-project envelope + `HostBuild("render-seam")`; the `charly/generate.go` top-level `Generate`/`writeCandySteps` orchestrator is DELETED. the pod-overlay deploy path reaches `deploykit.Generator.EmitTasks` DIRECTLY — `charly/tasks.go` holds no shim and cannot hold one (P16 import purity forbids `charly/` importing the sdk); that path stays for the pod-overlay deploy path (the candy `plugin-deploy-pod` constructs `deploykit.OCITarget` + renders via `deploykit.NewRenderGeneratorFromProject`, the per-step fragment over the `HostBuild("step-emit","oci-emit-step")` seam); the build-mode render (in `sdk/deploykit`) drives `WriteCandySteps` → `EmitTasks` directly. The render walks each layer's ops directly to write Containerfile text — NOT the `InstallPlan` IR. It shares the package-cascade / shell-snippet / localpkg compiler helpers with the IR (one source of truth, R3), but the overall walk is the direct generator. The `InstallPlan` IR + `deploykit.OCITarget.Emit` is the DEPLOY-mode path used by `charly fleet add` (the candy `plugin-deploy-pod`'s `add_candy:` overlay synthesis, rendered in its own code via `deploykit.OCITarget` + `deploykit.NewRenderGeneratorFromProject` + the external out-of-process deploys; the local/vm/kubernetes/android substrates are external plugins via `pluginDeployTarget` (S3b, dispatched through `candy/plugin-fleet`'s `Invoke(OpDeployDispatch)`) — `deploy:local` via candy/plugin-deploy-local and `deploy:vm` via candy/plugin-deploy-vm DO consume the IR (the plugin walks it via `kit.WalkPlans` over the reverse channel, the vm one over the guest `SSHExecutor`), while `deploy:kubernetes` via candy/plugin-kube does NOT, materializing its Kustomize tree PLUGIN-side (`candy/plugin-kube/materialize.go`'s `materializeKustomize`, reaching `candy/plugin-k8sgen` peer-to-peer over `verb:k8sgen`/`OpEmit`)). See [`/charly-internals:install-plan`](/recipes/internals/install-plan/) for the IR and [`/charly-internals:generate-source`](/recipes/internals/generate-source/) for the Go call graph. +**Build-mode emission**: the build-mode Containerfile render DRIVE is `sdk/deploykit.Generator.Generate` / `generateContainerfile` (relocated from `charly/generate.go` in #67), driven by `candy/plugin-build` over the resolved-project envelope + `HostBuild("render-seam")`; the `charly/generate.go` top-level `Generate`/`writeCandySteps` orchestrator is DELETED. the pod-overlay deploy path reaches `deploykit.Generator.EmitTasks` DIRECTLY — `charly/tasks.go` holds no shim and cannot hold one (P16 import purity forbids `charly/` importing the sdk); that path stays for the pod-overlay deploy path (the candy `plugin-deploy-pod` constructs `deploykit.OCITarget` + renders via `deploykit.NewRenderGeneratorFromProject`, the per-step fragment over the `HostBuild("step-emit","oci-emit-step")` seam); the build-mode render (in `sdk/deploykit`) drives `WriteCandySteps` → `EmitTasks` directly. The render walks each layer's ops directly to write Containerfile text — NOT the `InstallPlan` IR. It shares the package-cascade / shell-snippet / localpkg compiler helpers with the IR (one source of truth, R2), but the overall walk is the direct generator. The `InstallPlan` IR + `deploykit.OCITarget.Emit` is the DEPLOY-mode path used by `charly deploy add` (the candy `plugin-deploy-pod`'s `add_candy:` overlay synthesis, rendered in its own code via `deploykit.OCITarget` + `deploykit.NewRenderGeneratorFromProject` + the external out-of-process deploys; the local/vm/kubernetes/android substrates are external plugins via `pluginDeployTarget` (S3b, dispatched through `candy/plugin-fleet`'s `Invoke(OpDeployDispatch)`) — `deploy:local` via candy/plugin-deploy-local and `deploy:vm` via candy/plugin-deploy-vm DO consume the IR (the plugin walks it via `kit.WalkPlans` over the reverse channel, the vm one over the guest `SSHExecutor`), while `deploy:kubernetes` via candy/plugin-kube does NOT, materializing its Kustomize tree PLUGIN-side (`candy/plugin-kube/materialize.go`'s `materializeKustomize`, reaching `candy/plugin-k8sgen` peer-to-peer over `verb:k8sgen`/`OpEmit`)). See [`/charly-internals:install-plan`](/recipes/internals/install-plan/) for the IR and [`/charly-internals:generate-source`](/recipes/internals/generate-source/) for the Go call graph. **Three-phase templates**: the embedded build vocabulary's format and builder definitions split each install operation into `phases.{prepare, install, cleanup}.{container, host}` — three phases × two venues. Build-mode emission reads the `container` cell; local deploys read `host` — the `(install, container)` cell is the single source of truth for build-mode package installation. See [`/charly-image:layer`](/recipes/image/layer/) "Service Declaration" for the analogue at the init-system level (`init..service_schema`). @@ -44,7 +44,7 @@ charly box build --cache image [image...] # Image cache (read-only, de charly box build --cache gha [image...] # GitHub Actions cache charly box build --no-cache [image...] # Disable cache entirely charly box build --jobs N [image...] # Max concurrent images per DAG level (0=auto from defaults.jobs, else 4) -charly box build --podman-jobs N [image...] # Max concurrent stages within a single podman build (0=auto: min(NCPU, defaults.podman_jobs_cap)) +charly box build --podman-jobs N [image...] # Max concurrent stages within a single build (0=auto: min(NCPU, defaults.stage_parallelism_cap)) charly box build --include-disabled # Build an `enabled: false` image without flipping authored config charly box build --dev-local-pkg # EVAL-BED ONLY: build localpkg candies (the charly toolchain) from LOCAL in-dev source, not the published release ``` @@ -59,7 +59,7 @@ in-development binary + plugins — a disposable check bed always tests the in-development charly, never a stale release. Generic across all kinds + all localpkg candies, one decision point (`deploykit.RenderLocalPkgImageInstall`); a production box build omits the flag. A dev build that cannot build via the plugin -HARD-errors (no silent release fallback, R4). +HARD-errors (no silent release fallback, R3). Full mechanics: [`/charly-internals:install-plan`](/recipes/internals/install-plan/) "Check-vs-production charly toolchain"; the candy view: [`/charly-tools:charly`](/recipes/tools/charly/). @@ -164,7 +164,7 @@ cat .build/my-image/Containerfile # Inspect generated output ## Build Flow 1. Run `charly box generate` internally (produces Containerfiles in `.build/`) -2. Resolve runtime config to get build engine (`engine.build`) +2. Resolve runtime config (there is no build-engine selection: BuildKit is the builder) 3. Resolve image build order (dependency ordering, grouped by level) 4. Filter to requested images (and their base dependencies) 5. For each level: build images in parallel (up to `--jobs` concurrent, default 4) @@ -177,23 +177,21 @@ charly exposes **two** parallelism knobs with distinct meanings: | Flag | Env var | `defaults:` key | What it controls | |---|---|---|---| | `--jobs N` | `CHARLY_BUILD_JOBS` | `jobs` | **Outer** concurrency: how many charly-level images to build in parallel within a DAG level (e.g., when `charly box build` rebuilds the whole graph). | -| `--podman-jobs N` | `CHARLY_PODMAN_JOBS` | `podman_jobs` (+ `podman_jobs_cap`) | **Inner** concurrency: passed to `podman build --jobs N`, controls how many stages of a *single* multi-stage build run concurrently. | +| `--podman-jobs N` | `CHARLY_PODMAN_JOBS` | `stage_parallelism` (+ `stage_parallelism_cap`) | **Inner** concurrency: how many stages of a *single* multi-stage build run concurrently. It becomes the BuildKit daemon's `[worker.oci] max-parallelism`, applied when the daemon starts. | Both knobs are **config-driven**: precedence is **CLI flag → env → `defaults:` in `charly.yml` → built-in fallback** (4). The inner auto value (when -`--podman-jobs` / `CHARLY_PODMAN_JOBS` / `defaults.podman_jobs` are all unset) is -CPU-proportional, capped at `defaults.podman_jobs_cap`: `min(NCPU, cap)`. The -cap is the operative ceiling; the repo ships `podman_jobs_cap: 8`. (A -high-concurrency `--cache-from` SIGABRT race in podman ≤ 5.7.x originally -motivated a hard cap of 4 — see `CHANGELOG/` for that history and the 20-run -race gate required before raising the cap on a new podman version.) +`--podman-jobs` / `CHARLY_PODMAN_JOBS` / `defaults.stage_parallelism` are all unset) is +CPU-proportional, capped at `defaults.stage_parallelism_cap`: `min(NCPU, cap)`. +The cap is the operative ceiling, and it is the project's own to set. (The 20-run +race gate required before raising it on a new engine version is in `CHANGELOG/`.) ```yaml # charly.yml — defaults: block defaults: jobs: 4 # outer: images per DAG level - podman_jobs: 0 # inner: 0 = auto = min(NCPU, podman_jobs_cap) - podman_jobs_cap: 8 # ceiling for the auto calc + stage_parallelism: 0 # inner: 0 = auto = min(NCPU, stage_parallelism_cap) + stage_parallelism_cap: 8 # ceiling for the auto calc ``` ```bash @@ -202,10 +200,10 @@ CHARLY_PODMAN_JOBS=8 charly update --build # via env charly box build --podman-jobs 1 # fully serialised, worst-case debugging ``` -Source: `candy/plugin-build/resolve.go` (`resolveDrivePodmanJobs`, feeding -`buildkit.ResolvePodmanJobs`; the host-resolved `PodmanJobs` value feeds `--jobs` -directly in `candy/plugin-build/podman.go`). Covered by -`candy/plugin-build/podman_test.go`. The outer `--jobs` knob and the inner `--podman-jobs` +Source: `candy/plugin-build/resolve.go` (`resolveDriveStageParallelism`, feeding +`buildkit.ResolveStageParallelism`; the host-resolved `StageParallelism` value is the +`MaxParallelism` the drive hands the daemon in `candy/plugin-build/buildkit.go`). +Covered by `buildkit/build_helpers_test.go` (`TestResolveStageParallelism`). The outer `--jobs` knob and the inner `--podman-jobs` are separate fields so the two semantics don't get conflated. ## Build-context excludes (`defaults.context_ignore`) @@ -334,10 +332,8 @@ OCI labels. The CLI accepts an explicit `--tag ` for pinning; an empty `--tag` resolves to newest-local automatically. Rationale: -1. **No stale-`:latest`-under-`--cache-from` bug.** The documented - caveat where podman's `--cache-from` silently pulls a stale - `:latest` from the remote registry is unreachable when charly never - emits `:latest` in the first place. +1. **Nothing can pin a stale float tag.** charly never emits `:latest`, so a build can never + resolve to a float tag a previous build left behind. 2. **No "ambiguous short name" errors under multiple tags.** Previously the resolver listed every `:latest` + `:` tag of the same image as competing candidates; the CalVer sort picks the newest @@ -395,12 +391,11 @@ Three kinds of source changes are real cache invalidators — if you see a long ## Push Mode -- **Docker:** `docker buildx build --push` for multi-platform builds -- **Podman:** `podman build --manifest` + `podman manifest push` +BuildKit's image exporter is the ONE push path — `--output type=image,name=,push=true` — +and the only one that can push the multi-platform image a `--push` build produces. It +covers both `docker buildx --push` and `podman manifest push`. -Podman manifest push uses retry with exponential backoff (3 attempts, 5s/10s/20s delays) to handle transient registry errors (e.g., GHCR 500 errors after long builds). - -Source: `candy/plugin-build/podman.go` (`retryCmd`). +Source: `candy/plugin-build/buildkit.go` (`pushOutput`). ## Layer Merging @@ -447,13 +442,17 @@ For filtered builds (`charly box build `), only the built images are merg ## Engine Configuration ```bash -charly settings set engine.build docker # or podman -charly settings set engine.run docker # or podman +charly settings set engine.run docker # or podman — which engine RUNS containers ``` +**There is no `engine.build`**: the image builder is BuildKit, which is not a container +engine — it cannot run a container and therefore cannot be selected like one. `engine.run` +is unaffected and still selectable. + ## Host Prerequisites (First Time) -Building images needs the `charly` binary and a container engine — `docker` or `podman`, whichever `engine.build` names. Nothing else, and no project checkout: `charly box build` runs against the `charly.yml` in the current directory, one started by `charly box new project ` or read from a published project with `--repo /`. +Building images needs the `charly` binary and a container engine — `docker` or `podman`, whichever `engine.run` names (BuildKit builds the image; the drive bridges it into +that engine's store). Nothing else, and no project checkout: `charly box build` runs against the `charly.yml` in the current directory, one started by `charly box new project ` or read from a published project with `--repo /`. Install `charly` as a distro-native package with your OWN package manager (`pacman -U` / `dnf install` / `apt install` / `apk add`) — the `charly generate-packages` plugin (nFPM) builds the `.pkg.tar.zst`/`.rpm`/`.deb`/`.apk`/`.ipk` published to the per-distro package repos. Obtaining the binary is covered end to end at [Install](https://opencharly.ai/start/install/); it is the one page that describes building from a source tree. @@ -516,9 +515,13 @@ Beyond the YAML-unmarshal symptom above, a stale `charly` binary can produce *sy If the symptom persists after upgrading, the copy on `$PATH` may not be the one you just installed — `which charly` reports which wins. -### Buildah cache-mount corruption (pixi tzdata et al.) +### Cache-mount corruption (pixi tzdata et al.) -Cache mounts declared via `--mount=type=cache,dst=,uid=,gid=` (used for pixi, npm, cargo, rattler, dnf) persist across builds and are **not** evicted by `charly box build --no-cache` (which only suppresses `--cache-from`; see above). A disk-full event mid-download can leave a partial package in the cache, and every subsequent build re-hits the same broken file: +Cache mounts are declared as `--mount=type=cache,id=charly-,dst=,sharing=locked` (pixi, npm, cargo, +rattler and dnf all use one — `buildkit.SharedCacheMount` emits the format). Their **id is stable on purpose**: +that is what makes the cache survive layer-hash churn, which is the entire reason cache mounts exist +(`candy/plugin-build/cache_mount_test.go`). A cache mount is therefore not the build cache: `charly box build +--no-cache` disables the build cache for that build, and the mount's contents persist regardless. A disk-full event mid-download can leave a partial package in the cache, and every subsequent build re-hits the same broken file: ``` error: × failed to link tzdata-2025c-hc9c84f9_1.conda @@ -535,71 +538,21 @@ Options, in order of least to most disruptive: `podman image prune -a -f` will delete tagged images that are **not referenced by a running container**. That means the image you just built via `charly box build` — and haven't started as a container yet — is eligible for prune. Observed sequence: `charly box build` → `podman image prune -af` → `sudo podman load` (manual rootful refresh) fails with `image not known`. Protect the fresh build by starting a container or use `prune` with explicit filters instead. -### `--no-cache` does not invalidate intermediate scratch-stage caches - -`charly box build --no-cache ` and `charly box build --cache none ` reliably disable the -cache for the **final image stage**, but in observed behavior they do **not** propagate -to intermediate scratch stages produced by `COPY candy// /` instructions -(`[15/25] STEP 2/2: COPY candy/labwc/ /` style). Editing a single file inside a layer -directory and rebuilding with `--no-cache` may still pull the labwc scratch stage from -cache, leaving the new file content out of the rebuilt image. - -**Workaround:** force a content-hash bump on the layer's `charly.yml`. The simplest is -adding (or removing) a trailing comment line: - -```bash -echo "" >> candy/labwc/charly.yml # bump content hash -charly box build selkies-desktop # now invalidates the labwc scratch stage -git checkout -- candy/labwc/charly.yml # revert the cosmetic change -``` - -This was discovered while shipping commit `febb9bd` (labwc autostart race fix): the -edit to `candy/labwc/autostart` did not propagate to the rebuilt image until -`candy/labwc/charly.yml` itself was touched. Two consecutive `--no-cache` rebuilds -produced the same image hash (`502c8012c7a5`) until the charly.yml content changed. - -Symptom: `charly box list tags ` shows a new tag, but `charly shell -c "cat /path/to/changed/file"` -returns the **old** content. - -### Known caveat: stale `:latest` under `--cache-from` - -charly's Containerfile generator currently emits `FROM /:latest` -for parent builder images (not pinned CalVer). When charly invokes -`podman build --cache-from /`, podman resolves those `FROM` -clauses at parse time and will **pull `:latest` from the remote registry**, -silently clobbering any locally-rebuilt `:latest` tag. For images that rebuild -their builder stages in the same invocation this can lead to the later -stages using the **stale registry builder** instead of the freshly-built one. +### Forcing a rebuild of one layer's scratch stage -**Symptom observed on this project:** `charly update selkies-desktop --build` -fails deep inside selkies' `pixi install && bash build.sh` step with -`error: can't find Rust compiler`. The remote -`ghcr.io/opencharly/fedora-builder:latest` predates the `build-toolchain` -layer adding `cargo` as an RPM, so its pixi env has no rustc — even though -the current local `build-toolchain/charly.yml` lists `cargo`. The build phase -that rebuilds fedora-builder locally *does* run, but parent-stage FROM -resolution happens before that stage exists, and podman pulls the stale -remote image. - -**Workaround until the generator is fixed:** +A layer's scratch stage is keyed by the layer directory's own content — the cache key is +`(parent-image-SHA, instruction-text, COPY-source-content)` (see "Cache Efficiency" above) — so editing any +file under `candy//` rebuilds that stage and everything downstream of it. To force that rebuild without +changing the file that matters, bump the layer's `charly.yml`: ```bash -charly box build --cache=none # or equivalently --no-cache at the charly level +echo "" >> candy/labwc/charly.yml # bump the layer's content hash +charly box build selkies-desktop # rebuilds the labwc scratch stage +git diff candy/labwc/charly.yml # the appended line, and nothing else ``` -Both `--cache=none` and `--no-cache` short-circuit `cacheArgs()` in -`candy/plugin-build/podman.go` (`driveConfig.cacheArgs`) and do NOT pass `--cache-from` to podman, so -the broken resolution path never fires. `--no-cache` is charly-level only — it -does *not* pass `--no-cache` to podman, it just skips `--cache-from`. - -**Proper fix (not yet implemented):** charly's generator should emit pinned -CalVer tags for builder `FROM` clauses (e.g., -`FROM ghcr.io/opencharly/fedora-builder:2026.105.0128`) or pass -`--pull=never` to podman so local tags aren't resolved from the remote. -Tracked as a follow-up. - -See also: [`/charly-build:generate`](/recipes/build/generate/) for the Containerfile generation path, [`/charly-core:charly-update`](/recipes/core/charly-update/) -for the `--build` flag that also picks up this caveat. +Remove the added line to revert it. Do not reach for `git checkout -- ` to undo it: that restores the +file from the index and discards any other uncommitted work it holds. ## Project directory override diff --git a/src/content/docs/recipes/build/docs.md b/src/content/docs/recipes/build/docs.md index f98c3f19..33f66bac 100644 --- a/src/content/docs/recipes/build/docs.md +++ b/src/content/docs/recipes/build/docs.md @@ -13,6 +13,35 @@ description: "The `charly docs generate` verb — the generator rendering the re **opencharly.ai** from the sources that already exist in this repository. It is served by `candy/plugin-docs`. +## R4 — documentation never routes around a defect + +The rulebook states R4 as a mandate (umbrella `AGENTS.md`, "The ground-truth rules +R1–R10"); this is its operationalization for every page this skill renders and every +hand-authored page beside it. + +- **Fix the product first.** When documented behaviour and the code disagree, establish + which side holds the INTENT, then fix the code BEFORE touching the prose. Editing docs + to match a bug is forbidden; so is editing them to avoid one. +- **The tells of a routed-around defect:** a `git clone`, a `cd`, or a `-C` standing in + for a flag that should work; an "except on…" caveat; a "known limitation" note in place + of a fix. Each describes the defect instead of removing it — and makes it permanent by + making it look intended. +- **Binary-only reader.** Every command a reader is told to run MUST work with nothing but + the `charly` binary installed — no clone, no `cd`, no pre-existing project, no unnamed + companion tool. Write every page for a reader who installed `charly` as a native package + with NO charly checkout on the machine: no `task` target, no `./bin/charly`, no + repo-relative path, no verb supplied by a candy that exists only in this repository. + `--repo /` reads a published project without a clone; + `charly box new project ` starts a local one. +- **The one exception is the INSTALL page**, where the reader obtains charly: it leads + with the native package and scopes the checkout to working ON charly. A + repository-maintenance command is named as maintenance this project performs, never as + a step the reader runs. +- **Anywhere else, needing more than the binary is a PRODUCT DEFECT** — the missing + capability is the bug, and the fix belongs in `charly`. If that fix is genuinely out of + scope, file it with its root cause and let the page say nothing rather than something + false: silence is recoverable, a documented workaround is taught. + ## Placement: a RUNTIME plugin, deliberately `plugin-docs` is **not** listed in `charly/charly.yml`'s `compiled_plugins:`. A dev-time @@ -53,8 +82,8 @@ charly docs generate \ ## What it emits -The generator owns six top-level entries — `index.md`, `grievances.md`, `vision.md`, -`liberation.md`, `reference/` and `recipes/` — and rewrites them wholesale each run, so a deleted +The generator owns seven top-level entries — `index.md`, `grievances.md`, `vision.md`, +`liberation.md`, `soul.md`, `reference/` and `recipes/` — and rewrites them wholesale each run, so a deleted source entity disappears from the site instead of lingering as an orphan page. (The table below expands `reference/` into its sub-trees plus the single file `reference/providers.md`, so it runs to many rows.) What stays hand-authored is the teaching narrative this repository has no @@ -79,6 +108,7 @@ not the page.** | `grievances.md` | `GRIEVANCES.md`, H1 dropped, repo-relative links rewritten for a web reader | | `vision.md` | `VISION.md`, H1 dropped, repo-relative links rewritten for a web reader | | `liberation.md` | `LIBERATION.md`, H1 dropped, repo-relative links rewritten — the deliberate easter-egg page, entered last in the sidebar as "Liberation" | +| `soul.md` | `SOUL.md`, H1 dropped, published verbatim — the identity of charly and every charly agent; self-contained, so there are no repo-relative links to rewrite | | `reference/cli/` | one page per `command:` provider word | | `reference/candy/` | every defined candy: packages, services, and its `plan:` as an acceptance spec | | `reference/box/` | every defined box | @@ -175,7 +205,7 @@ the pinned charly) belongs to the same cutover as the candy edit. `candy/*/charly.yml` — but the generator DOES project candy `skill:` entities directly from its own remote-aware walk (`collectCandySkills`), the complement that keeps a moved candy's recipe references resolving on the site even before the marketplace regeneration -lands (the stale-marketplace gap [`/charly-tools:crabbox`](/recipes/tools/crabbox/) measures — see the tests +lands (the stale-marketplace gap [`/charly-tools:crabbox-cli`](/recipes/tools/crabbox-cli/) measures — see the tests section). The long path still holds: a skill is authored as a `skill:` entity in its owning candy; `charly marketplace generate` projects that into the opencharly/marketplace repo (`/skills//SKILL.md`), and @@ -207,7 +237,7 @@ stylistic preference; the obvious surfaces are actively wrong for the purpose: - A plugin absent from `compiled_plugins:` still loads out-of-process when a plan references its word, so "in the binary" is not the same set as "exists". -So discovery is not the walked trees alone: the catalog is ONE assembly (R3/R5, +So discovery is not the walked trees alone: the catalog is ONE assembly (R2/R5, `assembleCatalog`) unioning three sets — 1. the **walked closure** — remote-ref-aware (`candywalk.CollectEntitiesRemote`): @@ -295,7 +325,7 @@ describe the bad shape rather than spelling it. The host renders every dynamic command word with a generic stub description, intercepts the depth-1 `--help` itself, and plugin-served help arrives in at least three mutually incompatible -formats with no machine-readable dump. Parsing that would be the fragile shim R4 forbids. Every +formats with no machine-readable dump. Parsing that would be the fragile shim R3 forbids. Every fact the site needs is already declared: `plugin.providers`, the per-plugin `schema/*.cue`, and each candy's `description:`. diff --git a/src/content/docs/recipes/build/generate.md b/src/content/docs/recipes/build/generate.md index 40e72fdc..f3c48707 100644 --- a/src/content/docs/recipes/build/generate.md +++ b/src/content/docs/recipes/build/generate.md @@ -17,13 +17,13 @@ Parses `charly.yml`, scans `candy/`, resolves the dependency graph, and emits al The generator is **config-driven** — distro format templates, builder stage templates, and init system fragments all come from the build vocabulary embedded in the `charly` binary at `charly/charly.yml` (three top-level sections: `distro:`, `builder:`, `init:`) — and **declarative per-task** for install logic — each task verb (see [`/charly-image:layer`](/recipes/image/layer/)) has a dedicated emitter that writes the right Containerfile directive. -**Build-engine dispatch**: `charly box generate` does not construct a generator host-side at all (the former `NewGenerator` is DELETED) — it is served by the COMPILED-IN `command:box` plugin (candy/plugin-box, nested under the `box` grammar group), whose generate handler invokes the peer `build:generate` plugin (candy/plugin-build) over the F10 reverse channel (InvokeProvider). The plugin's `runBoxGenerate` → `resolveBuildEngine(..., generateOnly=true)` (candy/plugin-build/resolve.go) runs the ENTIRE build-engine RESOLVE plugin-side — loader, vocab, scan, connect, validate, box resolve, intermediates, order, effective versions, host-fs prep, render-seam-cache prep, render-prep, user-context, and envelope projection — and returns the resolved-project envelope (`spec.BuildResolveReply.ResolvedProject`); `generateOnly` is a PLUGIN-SIDE parameter that returns after the envelope projection (no engine/order drive-model). The host is reached ONLY for thin `buildengine-*` shards (`buildengine-scan-local`, `buildengine-connect-plugins`, and `buildengine-prep` — the render-seam-floor `renderGenCache` populate, which returns an EMPTY map; the host-fs PREP itself moved plugin-side); the envelope + drive-model come from `resolveBuildEngine`'s reply, NOT from `HostBuild("buildengine-prep")` (that host leg takes `spec.ResolvedProjectRequest`, which has no `GenerateOnly` field). The candy renders the Containerfiles itself via `sdk/deploykit.Generator` over the envelope + `HostBuild("render-seam")` (#67 — the host no longer renders); the written paths are returned — no podman (generate builds nothing). `charly box build` uses the SAME resolve pipeline (`runBoxBuild` → `resolveBuildEngine(..., generateOnly=false)`, which additionally computes the drive-model), then the candy additionally OWNS the podman DRIVE (`podman build` / push / inline-merge) IN the candy. See [`/charly-internals:plugin`](/recipes/internals/plugin/) (the `build` provider class + the in-proc reverse channel) and [`/charly-build:build`](/recipes/build/build/). +**Build dispatch**: `charly box generate` does not construct a generator host-side at all (the former `NewGenerator` is DELETED) — it is served by the COMPILED-IN `command:box` plugin (candy/plugin-box, nested under the `box` grammar group), whose generate handler invokes the peer `build:generate` plugin (candy/plugin-build) over the F10 reverse channel (InvokeProvider). The plugin's `runBoxGenerate` → `resolveBuildEngine(..., generateOnly=true)` (candy/plugin-build/resolve.go) runs the ENTIRE build RESOLVE plugin-side — loader, vocab, scan, connect, validate, box resolve, intermediates, order, effective versions, host-fs prep, render-seam-cache prep, render-prep, user-context, and envelope projection — and returns the resolved-project envelope (`spec.BuildResolveReply.ResolvedProject`); `generateOnly` is a PLUGIN-SIDE parameter that returns after the envelope projection (no engine/order drive-model). The host is reached ONLY for thin `buildengine-*` shards (`buildengine-scan-local`, `buildengine-connect-plugins`, and `buildengine-prep` — the render-seam-floor `renderGenCache` populate, which returns an EMPTY map; the host-fs PREP itself moved plugin-side); the envelope + drive-model come from `resolveBuildEngine`'s reply, NOT from `HostBuild("buildengine-prep")` (that host leg takes `spec.ResolvedProjectRequest`, which has no `GenerateOnly` field). The candy renders the Containerfiles itself via `sdk/deploykit.Generator` over the envelope + `HostBuild("render-seam")` (#67 — the host no longer renders); the written paths are returned — no podman (generate builds nothing). `charly box build` uses the SAME resolve pipeline (`runBoxBuild` → `resolveBuildEngine(..., generateOnly=false)`, which additionally computes the drive-model), then the candy additionally OWNS the BuildKit DRIVE (the `buildctl` argv / push / inline-merge) IN the candy. See [`/charly-internals:plugin`](/recipes/internals/plugin/) (the `build` provider class + the in-proc reverse channel) and [`/charly-build:build`](/recipes/build/build/). -**Build-mode emission is `WriteCandySteps` → `EmitTasks`** in `sdk/deploykit` (`deploykit.Generator`, relocated from `charly/generate.go` in #67, driven by `candy/plugin-build` over the resolved-project envelope + `HostBuild("render-seam")`; the `charly/generate.go` top-level `Generate`/`writeCandySteps` orchestrator is DELETED). the pod-overlay deploy path reaches `deploykit.Generator.EmitTasks` DIRECTLY — `charly/tasks.go` holds no shim and cannot hold one (P16 import purity forbids `charly/` importing the sdk); that path stays for the pod-overlay deploy path (the candy `plugin-deploy-pod` constructs `deploykit.OCITarget` + renders via `deploykit.NewRenderGeneratorFromProject`, the per-step fragment over the `HostBuild("step-emit","oci-emit-step")` seam). The render walks each layer's ops directly to write Containerfile text — NOT the `InstallPlan` IR. Build shares the package-cascade, shell-snippet, and localpkg compiler helpers with the IR (`ResolveCascadePackages`, `CompileShellSnippetSteps`, `deploykit.RenderLocalPkgImageInstall` — one source of truth, R3, relocated to sdk/deploykit in W3), but the overall walk is the direct generator, not an `EmitTarget`. The `InstallPlan` IR + `deploykit.OCITarget.Emit` is the DEPLOY-mode path: the candy `plugin-deploy-pod`'s overlay-Containerfile synthesis (rendered in its own code via `deploykit.OCITarget` + `deploykit.NewRenderGeneratorFromProject`) when `add_candy:` is set, plus the external execution targets. (The local/vm/kubernetes/android substrates are external out-of-process plugins via `pluginDeployTarget` (S3b, dispatched through `candy/plugin-fleet`'s `Invoke(OpDeployDispatch)`): `deploy:local` (candy/plugin-deploy-local) and `deploy:vm` (candy/plugin-deploy-vm) DO consume the IR — the plugin walks it via `kit.WalkPlans` over the reverse channel, the vm one over the guest `SSHExecutor` so the walk runs inside the guest — while `deploy:kubernetes` (candy/plugin-kube) does NOT, materializing its Kustomize tree PLUGIN-side (`candy/plugin-kube/materialize.go`'s `materializeKustomize`, reaching `candy/plugin-k8sgen` peer-to-peer over `verb:k8sgen`/`OpEmit`).) See [`/charly-internals:install-plan`](/recipes/internals/install-plan/) for the IR catalog and [`/charly-internals:generate-source`](/recipes/internals/generate-source/) for the Go-level call graph. +**Build-mode emission is `WriteCandySteps` → `EmitTasks`** in `sdk/deploykit` (`deploykit.Generator`, relocated from `charly/generate.go` in #67, driven by `candy/plugin-build` over the resolved-project envelope + `HostBuild("render-seam")`; the `charly/generate.go` top-level `Generate`/`writeCandySteps` orchestrator is DELETED). the pod-overlay deploy path reaches `deploykit.Generator.EmitTasks` DIRECTLY — `charly/tasks.go` holds no shim and cannot hold one (P16 import purity forbids `charly/` importing the sdk); that path stays for the pod-overlay deploy path (the candy `plugin-deploy-pod` constructs `deploykit.OCITarget` + renders via `deploykit.NewRenderGeneratorFromProject`, the per-step fragment over the `HostBuild("step-emit","oci-emit-step")` seam). The render walks each layer's ops directly to write Containerfile text — NOT the `InstallPlan` IR. Build shares the package-cascade, shell-snippet, and localpkg compiler helpers with the IR (`ResolveCascadePackages`, `CompileShellSnippetSteps`, `deploykit.RenderLocalPkgImageInstall` — one source of truth, R2, relocated to sdk/deploykit in W3), but the overall walk is the direct generator, not an `EmitTarget`. The `InstallPlan` IR + `deploykit.OCITarget.Emit` is the DEPLOY-mode path: the candy `plugin-deploy-pod`'s overlay-Containerfile synthesis (rendered in its own code via `deploykit.OCITarget` + `deploykit.NewRenderGeneratorFromProject`) when `add_candy:` is set, plus the external execution targets. (The local/vm/kubernetes/android substrates are external out-of-process plugins via `pluginDeployTarget` (S3b, dispatched through `candy/plugin-fleet`'s `Invoke(OpDeployDispatch)`): `deploy:local` (candy/plugin-deploy-local) and `deploy:vm` (candy/plugin-deploy-vm) DO consume the IR — the plugin walks it via `kit.WalkPlans` over the reverse channel, the vm one over the guest `SSHExecutor` so the walk runs inside the guest — while `deploy:kubernetes` (candy/plugin-kube) does NOT, materializing its Kustomize tree PLUGIN-side (`candy/plugin-kube/materialize.go`'s `materializeKustomize`, reaching `candy/plugin-k8sgen` peer-to-peer over `verb:k8sgen`/`OpEmit`).) See [`/charly-internals:install-plan`](/recipes/internals/install-plan/) for the IR catalog and [`/charly-internals:generate-source`](/recipes/internals/generate-source/) for the Go-level call graph. **Build-time plugin execution**: the build path connects the project's external (out-of-tree) plugin candies via `loadProjectPlugins` (`charly/host_build_buildengine.go:51`, and `charly/check_cmd.go:70` for the check path), so a `run:` plugin verb — and a plugin builder — is registered + dialable DURING image generation, the SAME loader the deploy/check paths use. The host-side `NewGenerator` that used to perform this connect is DELETED. A builtin is already registered via `init()` and needs no connect; only an external one is host-built + connected here. `EmitTasks` then dispatches a `plugin:` verb step PLACEMENT-AGNOSTICALLY above the registry: a builtin `ProvisionActor` renders an act shell `RUN` in-proc (the zero-JSON fast path), while ANY other resolved provider — an external `grpcProvider`, or a builtin emitting a richer fragment — renders via `invokeOpEmitFragmentOpt` → `Invoke(OpEmit)` (in-proc for a builtin, go-plugin gRPC for an external), and the returned `spec.EmitReply.Fragment` is spliced verbatim into the Containerfile (egress-validated with the rest before write). This is operator-authorized build-time execution of host-built plugin code — a project's composed external plugins run as host code during its image builds. Detail → [`/charly-internals:plugin`](/recipes/internals/plugin/) (placement) + [`/charly-internals:generate-source`](/recipes/internals/generate-source/). -**Build-time BUILDER leg (all via `OpResolve`)**: the builder stage emission is `deploykit.Generator.EmitBuilderStages` / `EmitBuilderArtifacts` / `EmitExternalBuilderStages` / `EmitExternalBuilderArtifacts` (`sdk/deploykit/builders_render.go` — relocated from `charly/generate.go` in #67, driven by `candy/plugin-build` over the envelope + `HostBuild("render-seam")`); the shared builder `OpResolve` helper (`renderSeamCaller.resolveBuilderStage`, `sdk/deploykit/render_generator_from_project.go`) drives both legs (the former `charly/generate.go` is DELETED, K-wave 2). These render the four DETECTION-builders' stages (pixi/npm/aur — selected by a candy's `pixi.toml` / `package.json` / `aur:` section; cargo is INLINE) by `Invoke(OpResolve)`ing their plugins — NOT from an in-core `builders.` vocabulary (C10 moved the stage templates into the plugins' `kit.BuilderResolve`). For each detected `(candy, builder)`, `EmitBuilderStages` connects the plugin on-demand (`ensureBuildersConnected`) and calls the shared `resolveBuilderStage` → `prov.Invoke(OpResolve)` with a `spec.BuilderResolveInput` (the host-computed render context — builder ref, stage name, copy src, uid/gid/home, detected manifest/lockfile/build-script, aur packages/options, PRE-RENDERED cache-mount flags) as `op.Params` + a `spec.BuildEnv` as `op.Env`; the returned `spec.BuilderResolveReply.Stage` is written verbatim PRE-main-FROM (cached per `(candy, builder)`), `EmitBuilderArtifacts` writes the cached `CopyArtifacts` + once-per-builder `CopyBinary` POST-main-FROM, and cargo's `InlineFragment` splices in `WriteCandySteps` (deploykit). A candy that instead selects an OUT-OF-TREE builder via its `external_builder: ` field gets its multi-stage emitted by `EmitExternalBuilderStages` / `EmitExternalBuilderArtifacts` (run right after their detection counterparts), sharing the SAME `resolveBuilderStage` but sending a MINIMAL input (candy name only): the word resolves through `providerRegistry.ResolveBuilder` to an EXTERNAL `*grpcProvider`, and `EmitExternalBuilderStages` (the BUILDER-leg analogue of `invokeOpEmitFragmentOpt`) requires a non-empty `Stage`. An empty `Stage` (or empty cargo `InlineFragment`), an unresolvable word, or an Invoke error fails LOUDLY (R4) — never a silently-dropped builder stage. Every half is egress-validated with the rest of the Containerfile before write. Detail → [`/charly-internals:plugin`](/recipes/internals/plugin/) (placement) + [`/charly-internals:generate-source`](/recipes/internals/generate-source/). +**Build-time BUILDER leg (all via `OpResolve`)**: the builder stage emission is `deploykit.Generator.EmitBuilderStages` / `EmitBuilderArtifacts` / `EmitExternalBuilderStages` / `EmitExternalBuilderArtifacts` (`sdk/deploykit/builders_render.go` — relocated from `charly/generate.go` in #67, driven by `candy/plugin-build` over the envelope + `HostBuild("render-seam")`); the shared builder `OpResolve` helper (`renderSeamCaller.resolveBuilderStage`, `sdk/deploykit/render_generator_from_project.go`) drives both legs (the former `charly/generate.go` is DELETED, K-wave 2). These render the four DETECTION-builders' stages (pixi/npm/aur — selected by a candy's `pixi.toml` / `package.json` / `aur:` section; cargo is INLINE) by `Invoke(OpResolve)`ing their plugins — NOT from an in-core `builders.` vocabulary (C10 moved the stage templates into the plugins' `kit.BuilderResolve`). For each detected `(candy, builder)`, `EmitBuilderStages` connects the plugin on-demand (`ensureBuildersConnected`) and calls the shared `resolveBuilderStage` → `prov.Invoke(OpResolve)` with a `spec.BuilderResolveInput` (the host-computed render context — builder ref, stage name, copy src, uid/gid/home, detected manifest/lockfile/build-script, aur packages/options, PRE-RENDERED cache-mount flags) as `op.Params` + a `spec.BuildEnv` as `op.Env`; the returned `spec.BuilderResolveReply.Stage` is written verbatim PRE-main-FROM (cached per `(candy, builder)`), `EmitBuilderArtifacts` writes the cached `CopyArtifacts` + once-per-builder `CopyBinary` POST-main-FROM, and cargo's `InlineFragment` splices in `WriteCandySteps` (deploykit). A candy that instead selects an OUT-OF-TREE builder via its `external_builder: ` field gets its multi-stage emitted by `EmitExternalBuilderStages` / `EmitExternalBuilderArtifacts` (run right after their detection counterparts), sharing the SAME `resolveBuilderStage` but sending a MINIMAL input (candy name only): the word resolves through `providerRegistry.ResolveBuilder` to an EXTERNAL `*grpcProvider`, and `EmitExternalBuilderStages` (the BUILDER-leg analogue of `invokeOpEmitFragmentOpt`) requires a non-empty `Stage`. An empty `Stage` (or empty cargo `InlineFragment`), an unresolvable word, or an Invoke error fails LOUDLY (R3) — never a silently-dropped builder stage. Every half is egress-validated with the rest of the Containerfile before write. Detail → [`/charly-internals:plugin`](/recipes/internals/plugin/) (placement) + [`/charly-internals:generate-source`](/recipes/internals/generate-source/). **Three-phase templates**: the embedded build vocabulary's format (`formats.`) and builder (`builders.`) definitions carry a `phases: { prepare, install, cleanup }.{ container, host }` structure. The generator reads `phases.install.container` as the single source for build-mode package installation. The `host:` cell is consumed only when a `SystemPackagesStep` renders on a host venue (`RenderHostPackageCommand`) — for the external `local:` AND `vm:` deploys the plugin drives the `SystemPackages` host render via the host's `RunHostStep` channel — never by the generator. diff --git a/src/content/docs/recipes/build/migrate.md b/src/content/docs/recipes/build/migrate.md index a5ed46aa..0967cb33 100644 --- a/src/content/docs/recipes/build/migrate.md +++ b/src/content/docs/recipes/build/migrate.md @@ -1,124 +1,119 @@ --- title: "migrate" -description: "The `charly migrate` command — the single idempotent migration bringing any opencharly config to the latest schema CalVer." +description: "The `charly migrate` command — the single idempotent reshape pass bringing any opencharly config forward to the current schema." --- *Recipe card from the `charly-build` plugin (Commands — runtime CLI verbs).* -# charly migrate — single-command schema migration +# charly migrate — the version-free reshape pass -`charly migrate` is **one idempotent command** that brings any opencharly config — as far back as the supported schema floor — up to the **latest schema CalVer**, and only to the latest. There are no sub-verbs to choose between: `charly migrate` always applies every migration-table step newer than the config, up to HEAD. +`charly migrate` is **one idempotent command** that applies the declarative migration table to an opencharly config on disk. There are no sub-verbs to choose between: it walks the whole table in declaration order, and because every step is idempotent a re-run on an already-current project is a no-op. ```bash -charly migrate # migrate every reachable config to the latest schema CalVer -charly migrate --dry-run # print every change migrate would make; touch nothing +charly migrate # apply the table to every reachable config +charly migrate --dry-run # print every change migrate would make; touch nothing +charly migrate --project-only # skip the per-host overlay ``` The project directory is the current working directory; use the top-level `-C` / `--dir` / `CHARLY_PROJECT_DIR` global to point elsewhere (`main()` chdir's before dispatch). -## CalVer schema versioning +## There is no schema version -The YAML schema version is a **CalVer string** — `version: YYYY.DDD.HHMM`, the same fixed-width scheme as image tags (e.g. a HEAD like `version: 2026.174.1100`). It is CANONICAL fixed-width: a 4-digit year, a 3-digit zero-padded day-of-year, and a 4-digit zero-padded HHMM, so a plain alphanumeric sort of CalVer strings is chronological. `ParseCalVer` is EXTREMELY STRICT — it accepts ONLY that exact form (no `version: 4`, no non-padded `2026.45.830`); a non-canonical value is "not a CalVer", which the load gate treats as older-than-HEAD so it flows into `charly migrate`. `charly migrate` re-stamps every versioned file it brings forward to the canonical HEAD (`universalStamp`); a value that predates the supported floor — or is not a CalVer at all — is unmigratable and refused untouched (see "How it runs"). Every versioned file carries the stamp: +A config carries **no `version:` field**, and the schema is CLOSED: a `charly.yml` still carrying a retired key — `version:` above all — is an unknown field and **fails closed-CUE when it loads**. That load failure is the trigger to run `charly migrate`, and `charly migrate` is what removes the retired keys. -- every project `charly.yml` (splitting into per-kind `vm.yml` / `local.yml` / … siblings is an optional `import:` convenience a project MAY use — never the default; see [`/charly-image:image`](/recipes/image/image/)) -- the per-host `~/.config/charly/charly.yml` +There is no schema HEAD, no floor, and no version comparison anywhere in the engine. `charly migrate` does not decide *whether* a project needs migrating — it reshapes every project it is pointed at, and idempotency is what makes that safe. A universal final step, **`strip-version-stamp`**, removes a leftover top-level or per-entity `version:` key: from the root `charly.yml`, from every other project document, and — unless `--project-only` — from the per-host overlay. -The parsed `ParsedCalVer` type, `ParseCalVer(string) (ParsedCalVer, bool)`, `ParsedCalVer.Less`, and `MustCalVer` live in **`spec/spec/calver_parse.go`** (the parsed type is named `ParsedCalVer` because `spec` already binds `CalVer = string`, the CUE wire scalar); `sdk/kit/calver.go` re-exports them for kit consumers. **CUE owns the HEAD and floor:** `spec/schema/version.cue` defines `#SchemaVersion` (the HEAD CalVer every file is stamped to) and `#SchemaFloor` (the oldest version migratable FROM). The spec repo's `charly task cue-gen` emits `spec/spec/version_gen.go` with the `SchemaVersion` / `SchemaFloor` string consts; `spec.LatestSchemaCalVer()` and `spec.SchemaFloorCalVer()` parse them, re-exported as `kit.LatestSchemaVersion()` / `kit.SchemaFloor()` (what `candy/plugin-migrate/engine.go` calls) and shimmed in core by `charly/version.go`'s `LatestSchemaVersion()`. There is NO hand-maintained Go HEAD literal — the load-time gate requires `kit.LatestSchemaVersion()`, and `charly migrate` refuses anything below `kit.SchemaFloor()`. +### Per-merge release git tags -### Per-merge release git tags (decoupled from `version:`) - -Every landing of ANY repo carries a **fresh** annotated release git tag `v` — ONE per merge, so a repo accumulates MULTIPLE `v…` tags over time. The tag is **generated and applied by the fresh `pr-validator` at MERGE**, from the current UTC merge time — never by the author at push time (author-time stamps collide and mis-order across concurrent out-of-sync PRs; see [`/charly-internals:git-workflow`](/recipes/internals/git-workflow/) "CalVer"). This is **decoupled** from the `charly.yml` `version:` field: `version:` is the SCHEMA version (bumped only when a cutover raises `#SchemaVersion`), whereas the tag marks the merge moment. Tag EVERY landing — including one at an unchanged `version:` (a content change, submodule extraction, image drop). Tags are **immutable**: only ever ADD new ones, never move or force-push an existing tag (so the load-time gate never sees a "newer than supported" CalVer from a re-tag). Every component is fixed-width zero-padded — 4-digit year, 3-digit day-of-year, 4-digit HHMM (`v2026.064.1937`, `v2026.142.1640`) — so tags sort chronologically under a plain alphanumeric sort; the evaluator computes `v$(date -u +%Y.%j.%H%M)` at merge (`%j` and `%H%M` are already zero-padded). Each repo — the superproject, every `box/` submodule, `plugins`, and `docs` — is tagged independently on its merged `main` HEAD (the tag marks the merge, so a repo needs no `charly.yml` to be tagged); a producer repo's PR merges + tags BEFORE its consumer's pointer bump. The SOLE exception is `sdk`, which tags under its Go-module `v0..` scheme (a semver requirement, not an exemption). See the project rulebook "Post-Execution Policies" (`AGENTS.md` / `CLAUDE.md`) and [`/charly-internals:git-workflow`](/recipes/internals/git-workflow/). +Every landing of ANY repo carries a **fresh** annotated release git tag `v` — ONE per merge, so a repo accumulates MULTIPLE `v…` tags over time. The tag is **generated and applied by the fresh `pr-validator` at MERGE**, from the current UTC merge time — never by the author at push time (author-time stamps collide and mis-order across concurrent out-of-sync PRs; see [`/charly-internals:git-workflow`](/recipes/internals/git-workflow/) "CalVer"). Tag EVERY landing — a content change, a submodule extraction, an image drop. Tags are **immutable**: only ever ADD new ones, never move or force-push an existing tag. Every component is fixed-width zero-padded — 4-digit year, 3-digit day-of-year, 4-digit HHMM (`v2026.064.1937`, `v2026.142.1640`) — so tags sort chronologically under a plain alphanumeric sort; the evaluator computes `v$(date -u +%Y.%j.%H%M)` at merge (`%j` and `%H%M` are already zero-padded). Each repo — the superproject, every `box/` submodule, `plugins`, and `docs` — is tagged independently on its merged `main` HEAD (the tag marks the merge, so a repo needs no `charly.yml` to be tagged); a producer repo's PR merges + tags BEFORE its consumer's pointer bump. The SOLE exception is `sdk`, which tags under its Go-module `v0..` scheme (a semver requirement, not an exemption). The tag is independent of the migration table: the tag marks the MERGE, a migration entry marks the SCHEMA. See the project rulebook "Commit, push, land" (`AGENTS.md`) and [`/charly-internals:git-workflow`](/recipes/internals/git-workflow/). ## The migration table (declarative data) -The migration steps are **declarative DATA, not code**: an ordered list embedded from **`candy/plugin-migrate/migrations.cue`** (the TABLE lives in candy/plugin-migrate), validated at process start against the `#Migration` schema (`candy/plugin-migrate/schema/migration.cue` — a plugin-only validation schema that lives in the plugin per the kernel/plugin boundary law, concatenated at compile with the SDK's `version.cue` for `#CanonCalVer`). Each step is stamped with the CalVer of the date it landed and listed **chronologically** — the order the cutovers were authored in, which is the only correct replay order for an arbitrarily-old config. `charly migrate` applies every step whose version is newer than the config's stamp; each step is idempotent, so applying the whole set is safe (an already-current file is a no-op). +The migration steps are **declarative DATA, not code**: an ordered list embedded from **`candy/plugin-migrate/migrations.cue`**, validated at process start against the `#Migration` schema in **`candy/plugin-migrate/schema/migration.cue`**. That schema is `@go(-)` — it generates no Go type — and lives IN the plugin: it is validation-only, read by this engine and by no charly core code, so per the kernel/plugin boundary law it stays out of the SDK contract. The list is ORDERED — the order the cutovers were authored in, which is the only correct replay order — and `charly migrate` applies every step, in order. -A step is a small record: +A step is: ```cue -{version: "YYYY.DDD.HHMM", name: "", touches_host?: bool, ops?: [...#Op] | apply?: ""} +{name: string, touches_host?: bool, ops?: [...#MigrationOp] | apply?: string} ``` -`touches_host: true` flags a step that mutates per-host state (`~/.config/charly`, quadlets, `.secrets`) — those steps are skipped by remote-cache auto-migration (see below). A step carries EITHER an `ops:` list OR a single `apply:` hook, never both. +`name` labels the step for `--dry-run` output and progress. `touches_host: true` flags a step that mutates per-host state (`~/.config/charly`, quadlets, `.secrets`) — those steps are skipped by remote-cache auto-migration (see below). A step carries EITHER an `ops:` list OR a single `apply:` hook, never both; that "exactly one of the two" rule is enforced in Go, since CUE's field-presence comparison is too fragile for the gate. **The op vocabulary — each op is DATA, zero Go.** Four generic key transforms cover the common cutovers, all applied by ONE comment-preserving yaml.v3 interpreter (the op-walker in `candy/plugin-migrate/engine.go`): | Op | Shape | Effect | |---|---|---| -| `rename_key` | `{from, to, scope, under_kind?}` | rename a mapping key `from` → `to` | -| `delete_key` | `{key, scope, under_kind?}` | drop a mapping key | +| `rename_key` | `{from, to, scope?="any", under_kind?}` | rename a mapping key `from` → `to` | +| `delete_key` | `{key, scope?="any", under_kind?}` | drop a mapping key | | `remap_scalar` | `{key, from, to, under_kind?}` | rewrite a scalar VALUE `from` → `to` at `key` | | `move_key` | `{key, from_parent, to_parent, under_kind?}` | relocate a key between parent mappings | -`scope` is `root` (top-level keys only) or `any` (every depth); `under_kind` further scopes an op to entities of a named kind (e.g. only `vm:` nodes). None of the four ops needs a line of new Go — the walker interprets the data. +`scope` is `root` (top-level keys only) or `any` (every depth, the default; only `rename_key` / `delete_key` take it); `under_kind` further scopes an op to entities of a named kind (e.g. only `vm:` nodes). None of the four ops needs a line of new Go — the walker interprets the data. -**The `apply:` hook — the deliberate, visible EXCEPTION.** A structural reshape the four ops can't express (splitting one node into siblings, folding a list into a map) sets `apply: ""` naming a Go function registered in the core `goHooks` map. This is the ONLY path that runs bespoke Go for a migration, and it is intentionally conspicuous: a table entry carrying `apply:` is the signal that this step needed real code. +**The `apply:` hook — the deliberate, visible EXCEPTION.** A structural reshape the four ops can't express (splitting one node into siblings, folding a list into a map) sets `apply: ""` naming a Go function registered in the plugin's `goHooks` map. This is the ONLY path that runs bespoke Go for a migration, and it is intentionally conspicuous: a table entry carrying `apply:` is the signal that this step needed real code. -**CUE has NO transformation capability.** CUE is monotone unification — it can validate, default, require, and close, and nothing more; it CANNOT rewrite a config. So CUE owns exactly two things here: the version pins (`#SchemaVersion` / `#SchemaFloor`) and the SHAPE of the declarative table (`#Migration` validates every entry at startup). Every actual transform is Go — the generic op-walker, or an `apply:` hook. Do not expect CUE to migrate anything. +**CUE has NO transformation capability.** CUE is monotone unification — it can validate, default, require, and close, and nothing more; it CANNOT rewrite a config. So CUE owns exactly ONE thing here: the SHAPE of the declarative table (`#Migration` validates every entry at startup). Every actual transform is Go — the generic op-walker, or an `apply:` hook. Do not expect CUE to migrate anything. -**The current table.** The floor sits at the migration-baseline reset version (`2026.174.1100`), so any config predating it is unmigratable — the accepted clean-slate consequence. The table carries ONE entry, the schema-compaction cutover: +**The current table.** `candy/plugin-migrate/migrations.cue` is the authoritative list — read it there; each entry carries its own comment explaining the reshape and why the declarative ops could not express it. The entries run in the order the cutovers were authored in (the only correct replay order) and are: -| version | name | touches_host | apply | +| name | declarative ops | `apply:` hook | `touches_host` | |---|---|---|---| -| `2026.186.2323` | `compact-node-form` | `true` | `compactNodeForm` (goHook) | - -The `compactNodeForm` hook is a structural reshape the four generic ops can't express: it folds the former named data/step child-node grammar into the compact node form — collections (`env`/`volume`/`port`/`service`/…) inline in the kind value, steps as the ordered `plan:` list (a meaningful former step-node name becomes the step's `id:`), deploy data (`add_candy`/`install_opts`/`vm_state`/…) inline in the substrate node, and every authored step `plugin:`+`plugin_input:` pair rewritten to the `: ` verb sugar. Member children (sub-entities under a deployable kind) stay named children. Remote layer caches auto-migrate on fetch (see "Remote-cache auto-migration"). The same cutover DELETED the Calamares `target:` / `module:` / `package-group:` kinds (and their plugins) — they had zero core readers; they return as their own cutover when the installer feature is real. +| `compact-node-form` | — | `compactNodeForm` | `true` | +| `strip-candy-libvirt-field` | — | `stripCandyLibvirtField` | — | +| `strip-deploy-shell-overlay` | — | `stripDeployShellOverlay` | `true` | +| `k8s-to-kubernetes` | 2 × `rename_key` | — | — | +| `remove-candy-localpkg` | `delete_key` | — | — | +| `install-template-to-phases` | — | `installTemplateToPhases` | — | +| `reshape-graphics-gl` | — | `reshapeGraphicsGL` | — | +| `record-field-to-instrument` | — | `recordFieldToInstrument` | — | +| `unroll-group-deploy` | — | `unrollGroupDeploy` | — | +| `deploy-cpu-spelling` | — | `reshapeDeployCPU` | `true` | +| `rekey-legacy-vm-overlay` | — | `rekeyLegacyVMOverlay` | `true` | + +`compact-node-form` is the schema-compaction cutover: it folds the former named data/step child-node grammar into the compact node form — collections (`env`/`volume`/`port`/`service`/…) inline in the kind value, steps as the ordered `plan:` list (a meaningful former step-node name becomes the step's `id:`), deploy data (`add_candy`/`install_opts`/`vm_state`/…) inline in the substrate node, and every authored step `plugin:`+`plugin_input:` pair rewritten to the `: ` verb sugar. Member children (sub-entities under a deployable kind) stay named children. Remote layer caches auto-migrate on fetch (see "Remote-cache auto-migration"). + +On top of the table the engine ALWAYS applies one further step, **`strip-version-stamp`** — it is not a table entry, so it needs no author (see "There is no schema version"). ## How it runs -The migration engine is a **COMPILED-IN command plugin** (`candy/plugin-migrate`, `command:migrate`) — the engine, table, and CLI live in the plugin, out of charly core; core keeps only the below-floor/behind-head load-gate HINTS (the `Run: charly migrate` messages). `charly migrate` dispatches to the compiled-in `command:migrate` provider; the remote-cache auto-migration (`refs.go`) resolves the same provider and Invokes it (`OpRun --project-only`) in-proc. +The migration engine is a **COMPILED-IN command plugin** (`candy/plugin-migrate`, `command:migrate`) — the engine, table, and CLI live in the plugin, out of charly core; core keeps only the load-gate HINT (the `Run: charly migrate` message a closed-schema load failure carries). `charly migrate` dispatches to the compiled-in `command:migrate` provider; the remote-cache auto-migration resolves the same provider and Invokes it (`OpRun --project-only`) in-proc. Compiled-in placement is load-bearing: migrate is whole-project file-based and must run when the config is exactly what cannot load, so it can never be discovered out-of-process. -`runMigrations` (`candy/plugin-migrate/engine.go`) is **floor-gated**, comparing the config's `version:` stamp against `kit.SchemaFloor()` and `kit.LatestSchemaVersion()`: +`runMigrations` (`candy/plugin-migrate/engine.go`) walks the table in declaration order: -- **at HEAD** → no-op; prints `nothing to migrate (already at schema )`. -- **below the floor, or not a CalVer at all** → **unmigratable**: refused with an actionable error (`predates the supported floor … re-author against the current schema`) and **NO filesystem change**. Configs from before the baseline reset fall here. A stranded **per-host** config (`~/.config/charly/charly.yml`) at a below-floor version is doubly stuck: it can neither migrate NOR be WRITTEN — `saveDeployState` refuses to overwrite a config it cannot load (`refusing to overwrite … the existing per-host config fails to load … fix it (or remove it to regenerate) first`), so every pod/vm/local deploy — including a `charly check run ` at its `config`/`deploy-add` step — fails until it is reset. Since it holds only regenerable deploy STATE (no authored intent), back it up and reset it to a bare `version: ` stub (or remove it); the state rebuilds on the next deploy. -- **in `[floor, HEAD)`** → apply every migration-table step newer than the stamp (in order, via the op-walker / `apply:` hooks), then re-stamp every versioned file to HEAD (`universalStamp`). +- **no `charly.yml` in the directory** → reports `no in — nothing to migrate`. +- **otherwise** → applies every step (the generic op-walker or an `apply:` hook) in order, then the universal `strip-version-stamp`, and reports `nothing to migrate` when nothing changed. -Per-step backups follow the established `.bak.` convention. +**Backups are gitignored, never adjacent.** A step's per-file backup goes to `/.charly/backups/.`, and the tree is kept out of git by a `/.charly/.gitignore` containing a bare `*` (created on demand). A migration therefore never leaves `*.bak` files beside the originals and never dirties a working tree. ### Remote-cache auto-migration (project-only) -`sdk/loaderkit`'s refs seams (the former `charly/refs.go` is DELETED, K-wave 2) auto-run the remote-cache migration (`migrateCacheViaPeer`, `sdk/loaderkit/refs_seams_executor.go`) on a freshly-cloned remote-repo cache so external repos pull through at the latest schema. It skips every `touches_host` step and leaves the host-deploy path empty, so a remote fetch **never mutates the user's per-host state** — even the final re-stamp touches only the cache's project files. A remote whose config predates the floor **fails the fetch** with the same predates-floor error (an old remote is unmigratable — the accepted clean-slate consequence). - -## Load-time gate - -The load-time gate `GateSchemaVersion` (`sdk/loaderkit/load_unified.go` — the former `charly/unified.go` is DELETED, K-wave 2) is unchanged: `LoadUnified` parses the merged `version:` and rejects anything below HEAD (or absent, or non-CalVer): - -``` -charly.yml: schema 2026.186.2323 is required (found "4"). Run: charly migrate -``` - -A non-CalVer value (a legacy integer, empty, or garbage) parses as "older than every real CalVer", so a stale config trips the gate with a uniform `Run: charly migrate` hint — the forward-compat trigger that makes a future migration fire. Whether that migrate then SUCCEEDS depends on the floor: a config in `[floor, HEAD)` migrates; one below the floor is refused (see "How it runs"). Residual-key checks (e.g. `kind: deployment`, `target: host`, `secret_backend: kdbx`) remain as defense-in-depth, but every remediation hint points uniformly at bare `charly migrate`. +`sdk/loaderkit`'s refs seams auto-run the remote-cache migration on a freshly-cloned remote-repo cache so external repos pull through at the current schema. It skips every `touches_host` step and leaves the host-deploy path empty, so a remote fetch **never mutates the user's per-host state** — even the final `strip-version-stamp` touches only the cache's project files. -## Adding a future cutover +## Load-time enforcement: closedness -**From here to the end of "Standing rule" is maintenance the charly project performs on its OWN schema**, run from checkouts of the spec repo and the superproject. Nothing in these two sections is a step an charly user runs — the user-facing surface of a schema cutover is the single command `charly migrate`, unchanged. They are recorded here because this skill owns the migration table; the commands are named as this project's maintenance, not as instructions for the reader. +There is no version gate to trip. Compatibility has ONE mechanism — the **CLOSED CUE schema**: a retired key (a leftover `version:`, `kind: deployment`, `target: host`, `secret_backend: kdbx`, …) is an unknown field, and the load fails with a hard `field not allowed` diagnostic naming it. The same failure carries the `Run: charly migrate` hint, and `charly migrate` is what strips the key (see "There is no schema version"). Residual-key checks remain as defense-in-depth alongside the closedness gate. -The payoff of the declarative engine: the common case needs **zero new Go** — but since the schema lives in the spec module, a schema-version bump is **CROSS-REPO**: the spec repo lands + tags FIRST, then the superproject consumes the published module at the bumped require version (no submodule, no local checkout). +## Adding a future migration -1. Bump `#SchemaVersion` in **`spec/schema/version.cue`** to the new CalVer. -2. Run the spec repo's **`charly task cue-gen`** to regenerate `spec/spec/version_gen.go`. -3. **Land + tag the spec repo** (its Go-module tag scheme `v0..` — see [`/charly-internals:git-workflow`](/recipes/internals/git-workflow/)). -4. In the superproject: bump the `github.com/opencharly/spec` require version in `charly/go.mod` and every lockstep go.mod (the canonical-go.mod gate in `tools/gomod-canonical` asserts one shared pin; `charly task mods-tidy` re-syncs the go.sum files), append the matching entry to **`candy/plugin-migrate/migrations.cue`** (the TABLE lives in candy/plugin-migrate) with the same `version:` — **strictly greater** than the previous HEAD, expressing the transform as an `ops:` list (`rename_key` / `delete_key` / `remap_scalar` / `move_key`) — and run the superproject's own gates. +**This section is maintenance the charly project performs on its OWN schema.** Nothing in it is a step a charly user runs — the user-facing surface is the single command `charly migrate`, unchanged. It is recorded here because this skill owns the migration table. -That is the whole common case — no bespoke migrator type, no registry function, no per-migrator Go file. Only a **structural reshape the four ops can't express** additionally registers ONE `goHooks` entry (a Go function named by the step's `apply:` field). Update the HEAD-CalVer fixtures + the repo's own versioned YAML in the same change. +The declarative engine's payoff: the common case needs **zero new Go**. Append ONE entry to **`candy/plugin-migrate/migrations.cue`**, expressing the transform as an `ops:` list (`rename_key` / `delete_key` / `remap_scalar` / `move_key`). Because the table is order-driven and version-free, there is no CalVer to bump and no cross-repo sequence — the entry IS the whole change, and it is idempotent by contract. A **structural reshape the four ops can't express** additionally registers ONE `goHooks` entry (a Go function named by the step's `apply:` field). Ship the entry in the same change that alters the schema, and update the repo's own versioned YAML. The operator command never changes — it stays `charly migrate`. -**The validated schema is CUE-single-source.** The `@go()`-annotated `spec/schema/*.cue` defs are the sole source for the Go param structs (generated into `spec/spec` by `charly task cue-gen`); a wire-key change is a CUE edit first, then `charly task cue-gen`, then — only if it breaks existing on-disk configs — a migration-table entry here (plus the `#SchemaVersion` bump above). A pure codegen refactor that leaves every authored wire key untouched needs NO migration entry and NO `version:` bump. See the [`/charly-internals:go`](/recipes/internals/go/) recipe "How to change the charly.yml schema (CUE is the single source of truth)". +**The validated schema is CUE-single-source.** The `@go()`-annotated `spec/schema/*.cue` defs are the sole source for the Go param structs (generated into `spec/spec` by `charly task cue-gen`); a wire-key change is a CUE edit first, then `charly task cue-gen`, then — only if it breaks existing on-disk configs — a migration-table entry here. A pure codegen refactor that leaves every authored wire key untouched needs NO migration entry. See the [`/charly-internals:go`](/recipes/internals/go/) recipe "How to change the charly.yml schema (CUE is the single source of truth)". -### Standing rule: a schema/format change bumps `version:` AND mints a git tag +### Standing rule: a schema/format change ships its migration entry AND mints a git tag -Any change to the YAML schema or composition format (a key rename, a deleted key, a new key shape) is a hard-cutover that MUST: +Any change to the YAML schema or composition format (a key rename, a deleted key, a new key shape) is a hard-cutover that MUST ship a matching migration-table entry in the same change, so `charly migrate` can carry an existing config across. A migration entry WITHOUT the matching schema change (or vice-versa) is forbidden. -1. **Bump the `#SchemaVersion` CalVer** — edit `spec/schema/version.cue`, run `charly task cue-gen`, and append the matching entry to `candy/plugin-migrate/migrations.cue` (the cross-repo sequence under "Adding a future cutover"), then land the sdk PR (the fresh `pr-validator` merges + tags it), and in the superproject adopt the tagged sdk release as the new shared pinned require (the `charly task mods-tidy` sweep + canonical-go.mod gate keep every module on the one pin). The load-time gate then rejects any not-yet-migrated config with a `Run: charly migrate` hint, so every reader sees the new format. Raising `#SchemaVersion` WITHOUT the migration-table entry (or vice-versa) is forbidden — and `version:` is NEVER set above `LatestSchemaVersion()` (newer configs hard-fail at load). **The author writes a PLACEHOLDER `#SchemaVersion` / `version:` / `migrations.cue` CalVer; the fresh `pr-validator` FINALIZES it at MERGE** — re-stamping it strictly ABOVE the current `main` HEAD's schema version (two concurrent schema PRs would otherwise collide or mis-order; see [`/charly-internals:git-workflow`](/recipes/internals/git-workflow/) "CalVer"). -2. **The fresh `pr-validator` mints the per-merge git tag** at merge — `v` from the merge moment (see "Per-merge release git tags" above). The tag and the `version:` bump are decoupled: the tag marks the merge, `version:` marks the schema. A schema cutover happens to do BOTH at once, but a content-only landing (no schema change) still mints a tag at an unchanged `version:`. +Separately, **the fresh `pr-validator` mints the per-merge git tag** — `v` computed from the MERGE moment (see "Per-merge release git tags" above). The tag marks the MERGE and every landing gets one, schema change or not; it is independent of the migration table, which marks the SCHEMA. ## Idempotency -Running `charly migrate` twice is a no-op: after the first run the config is stamped at HEAD, so the second run hits the floor gate's "at HEAD → nothing to migrate" branch. Every op is itself idempotent (a rename with no matching key does nothing). The migration table's own invariants — every entry a valid `#Migration`, versions strictly ascending and unique, HEAD == `#SchemaVersion` — are validated against CUE at process start. +Running `charly migrate` twice is a no-op: every step's old shape is absent the second time, so each does nothing. An op with no matching key, a `strip-version-stamp` on a file with no stamp, and an `apply:` hook on an already-reshaped node are all inert. The table's own invariant — every entry a valid `#Migration` — is validated against CUE at process start. ## See Also @@ -127,5 +122,5 @@ Running `charly migrate` twice is a no-op: after the first run the config is sta - [`/charly-core:deploy`](/recipes/core/deploy/) — the deploy entries a migration may rewrite - [`/charly-local:local-spec`](/recipes/local/local-spec/) — `kind: local` templates - [`/charly-build:secrets`](/recipes/build/secrets/), [`/charly-build:settings`](/recipes/build/settings/) — the credential schema -- [`/charly-internals:go`](/recipes/internals/go/) — loader internals (`LoadUnified`, `ParseCalVer`, the `gateSchemaVersion` load gate, the `candy/plugin-migrate/engine.go` op-walker) +- [`/charly-internals:go`](/recipes/internals/go/) — loader internals (`LoadUnified` and the closedness gate; the `candy/plugin-migrate/engine.go` op-walker) - [`/charly-internals:cutover-policy`](/recipes/internals/cutover-policy/) — why hard-cutover + a single idempotent `charly migrate` is the required shape diff --git a/src/content/docs/recipes/build/pull.md b/src/content/docs/recipes/build/pull.md index 519ed24e..f7bc0612 100644 --- a/src/content/docs/recipes/build/pull.md +++ b/src/content/docs/recipes/build/pull.md @@ -96,8 +96,8 @@ per-call-site code: from local storage. 2. `dispatchBuildEnsure` (`charly/dispatch_build_ensure.go`) dispatches to candy/plugin-build's `build:ensure` word (`candy/plugin-build/ensure.go`), - which returns the same sentinel when the image is absent from both run and - build engines. + which returns the same sentinel when the image is absent from the RUN engine's + store (the one every later read resolves it through). 3. `FormatCLIError` in `charly/image.go` unwraps the sentinel at the top-level error boundary in `main()` and renders: diff --git a/src/content/docs/recipes/build/reconcile.md b/src/content/docs/recipes/build/reconcile.md index c2145b81..994bfe40 100644 --- a/src/content/docs/recipes/build/reconcile.md +++ b/src/content/docs/recipes/build/reconcile.md @@ -27,7 +27,7 @@ default mode is idempotent; `--remote` is not, because its target is whatever th remote's newest tag is at the moment of the call — see "`--remote` targets whatever is newest NOW" below before reaching for that flag. -The **zero-warnings R10 gate** (the project rulebook R1 (`AGENTS.md` / `CLAUDE.md`)) makes this load-bearing: a change +The **zero-warnings R10 gate** (the project rulebook R1 (`AGENTS.md`)) makes this load-bearing: a change that introduces a version mismatch is not landable until `charly box reconcile` clears the warning. diff --git a/src/content/docs/recipes/build/settings.md b/src/content/docs/recipes/build/settings.md index d36384f8..1dc07898 100644 --- a/src/content/docs/recipes/build/settings.md +++ b/src/content/docs/recipes/build/settings.md @@ -30,7 +30,6 @@ Manage charly's runtime configuration stored in `~/.config/charly/config.yml`. C | Key | Default | Env Var | Description | |-----|---------|---------|-------------| -| `engine.build` | `auto` | `CHARLY_BUILD_ENGINE` | Build engine (docker/podman) | | `engine.run` | `auto` | `CHARLY_RUN_ENGINE` | Run engine (docker/podman) | | `run_mode` | `auto` | `CHARLY_RUN_MODE` | Deployment mode (quadlet/direct) | | `bind_address` | `127.0.0.1` | `CHARLY_BIND_ADDRESS` | Default bind address for ports | @@ -47,12 +46,11 @@ Manage charly's runtime configuration stored in `~/.config/charly/config.yml`. C ### Engine Selection ```bash -# Switch to podman for both build and run -charly settings set engine.build podman +# Which engine RUNS containers (the builder is BuildKit, and is not selectable) charly settings set engine.run podman # Check current engine -charly settings get engine.build +charly settings get engine.run ``` ### Storage Paths diff --git a/src/content/docs/recipes/build/validate.md b/src/content/docs/recipes/build/validate.md index f7065f56..1d6e5b53 100644 --- a/src/content/docs/recipes/build/validate.md +++ b/src/content/docs/recipes/build/validate.md @@ -216,7 +216,7 @@ The unified form is **name-first**: every entity flattens to a top-level ` - **Cross-FILE name reuse is fine.** The same name MAY exist simultaneously in SEPARATE discovered files — a layer `candy/redis/charly.yml` (a `candy:` node with no `base:`/`from:`) and an image `box/redis/charly.yml` (a `candy:` node carrying `base:`/`from:`) resolve to distinct internal maps (`uf.Candy` vs `uf.Box`, routed by `base:`/`from:` presence), and the validator does NOT flag them. Verbs disambiguate by command context (`ResolveDeployRef` is image-first; `--add-candy ` selects the layer-first path). - **Same-document collision IS rejected.** Two top-level entities WITHIN one document (e.g. the root `charly.yml` carrying a `pod` + a `vm` + a `local`) MUST NOT share a name — they would collide on one YAML key. `charly box validate` flags the collision; rename one (the convention: keep the user-facing deploy, suffix the template it deploys — a `check-local` deploy + a `check-local-app` local template). -The loader still raises hard load-time errors on obsolete keys — the obsolete `qc` / `cachyos-dx` deployment names, and any obsolete `kind: deployment` doc or root-key `deployment:` (the deploy kind is now the name-first substrate kind: `pod:` / `vm:` / `kubernetes:` / `local:` / `android:` / `group:`). Every such error points at `charly migrate`. See the project rulebook (`AGENTS.md` / `CLAUDE.md`) and [`/charly-build:migrate`](/recipes/build/migrate/). +The loader still raises hard load-time errors on obsolete keys — the obsolete `qc` / `cachyos-dx` deployment names, and any obsolete `kind: deployment` doc or root-key `deployment:` (the deploy kind is now the name-first substrate kind: `pod:` / `vm:` / `kubernetes:` / `local:` / `android:` / `group:`). Every such error points at `charly migrate`. See the project rulebook (`AGENTS.md`) and [`/charly-build:migrate`](/recipes/build/migrate/). ## When to Use This Skill diff --git a/src/content/docs/recipes/cache/cache.md b/src/content/docs/recipes/cache/cache.md index 72a990d9..9c8ef77a 100644 --- a/src/content/docs/recipes/cache/cache.md +++ b/src/content/docs/recipes/cache/cache.md @@ -20,6 +20,28 @@ keeps so repeated resolutions do not re-fetch. It is served by `candy/plugin-cac - `charly cache refresh` — drop the cache and note the next resolution re-warms the refs. - `charly cache bypass` — persist the bypass; every resolution is fresh until turned off. - `charly cache bypass --off` — turn the bypass off; the cache resumes. +- `charly cache push ` — push a named cache (an OCI layout) to a registry. +- `charly cache pull ` — pull a named cache from a registry into its local layout. +- `charly cache ingest ` — ingest a remote image ref into a named store (the reserved + `registry` store by default), so charly's own registry can serve it. `--store ` + chooses the store, `--insecure` allows a plain-HTTP dev registry, `--refresh` re-resolves + even when the ref is already stored. + +## Ingesting into the registry store + +`charly cache ingest ` is the write half of the registry capability. It resolves the +ref's artifacts through `verb:oci` (the go-containerregistry transport stays single-homed in +plugin-oci) and lands them in a named `sdk/storekit` store: every blob is written +content-addressed by digest, then ONE entry keyed by the full ref — with the repo, the tag +and the digest the tag resolved to in its annotations (D-STORE-5). A mutable name therefore +resolves ONCE: a repeated `charly cache ingest ` is answered by the store with no second +fetch, and a re-run at an unchanged digest writes no second blob (`--refresh` forces the +re-resolution, not a rewrite). It needs the compiled-in placement, because the reverse +channel to `verb:oci` exists only there. + +The reserved store is `registry`, under the CACHE root: `~/.cache/charly/registry` +(`CHARLY_CACHE_DIR` overrides the root). That is `storekit`'s resolver — distinct from +`charly cache push`/`pull`'s config-rooted `~/.config/charly/cache/` layouts. ## Where the cache lives diff --git a/src/content/docs/recipes/candy-cli/candy.md b/src/content/docs/recipes/candy-cli/candy.md index 3330db44..2b420f1b 100644 --- a/src/content/docs/recipes/candy-cli/candy.md +++ b/src/content/docs/recipes/candy-cli/candy.md @@ -19,6 +19,16 @@ description: "`charly candy set` / `charly candy add-` — mutate a candy's - `charly candy add- ` — append packages to the distro-format section `` (e.g. `add-pac`, `add-deb`, `add-rpm`). The verb set derives from `sectionDistroPath`, so it cannot drift from the mapped formats. +- `charly candy params [--check]` — regenerate + `candy//params/cue_types_gen.go` from `candy//schema/*.cue`. This is + the pipeline's ONLY documented entry point: concatenate the schema (the + `schemaconcat` contract), head it `package params` + `@go(params)`, run the pinned + `cue exp gengotypes` (the `cuetoolchain` pin — provisioned checksum-verified into + the charly cache, so no `cue` install and no checkout are needed), then double + every json tag with a yaml tag (the `schemaretag` contract). `--check` writes + nothing: it exits non-zero when the committed file differs from that pipeline + OUTPUT, which is the drift gate a plugin repo's CI should run. `--schema/--pkg/--out` + is the explicit form for a schema that is not a candy's. ## When to use it diff --git a/src/content/docs/recipes/check/adb.md b/src/content/docs/recipes/check/adb.md index 5ca15c4a..6c78f39c 100644 --- a/src/content/docs/recipes/check/adb.md +++ b/src/content/docs/recipes/check/adb.md @@ -40,7 +40,7 @@ adb-exclusive fields (`arg:`, `apk:`, `property:`, `key:`, `query:`, `amount:`, `artifact:` and the artifact validators) — those live INSIDE the `adb:` map. Only the shared matchers (`stdout:`, `stderr:`, `exit_status:`) and `context:`/`id:`/ `timeout:` stay siblings. -**`context: [deploy]` only** — needs a running container with a +**`context: [runtime]` only** — needs a live deployment (a running container with a host-mapped ADB server port; the validator rejects `context: [build]` use at `charly box validate` time. @@ -51,7 +51,7 @@ Example — each step is an ordered list item under the candy/box `plan:` (mirro - check: the emulator is attached to the adb server id: emulator-is-up adb: devices - context: [deploy] + context: [runtime] stdout: - contains: "emulator-5554" - check: the emulator reports boot completed @@ -59,7 +59,7 @@ Example — each step is an ordered list item under the candy/box `plan:` (mirro adb: method: getprop property: sys.boot_completed - context: [deploy] + context: [runtime] stdout: - contains: "1" timeout: 300s @@ -171,7 +171,7 @@ is immune to the stdin-heredoc hazard that breaks shell-based settle loops - check: the emulator UI has settled past the ANR churn id: emulator-ui-settled adb: wait-ui-settled - context: [deploy] + context: [runtime] timeout: 600s stdout: - contains: settled @@ -197,7 +197,7 @@ Common pattern: - check: wait for the device to finish booting adb: wait-for-device timeout: 120s - context: [deploy] + context: [runtime] ``` ## Implementation diff --git a/src/content/docs/recipes/check/android-sdk.md b/src/content/docs/recipes/check/android-sdk.md new file mode 100644 index 00000000..b6e98ee8 --- /dev/null +++ b/src/content/docs/recipes/check/android-sdk.md @@ -0,0 +1,60 @@ +--- +title: "android-sdk" +description: "The Android SDK toolchain candy (sdkmanager/adb/aapt2/emulator + the API-36 system image under /opt/android-sdk)." +--- + + + +*Recipe card from the `charly-check` plugin (Commands — runtime CLI verbs).* + +# android-sdk — the Android SDK toolchain candy + +## Candy Properties + +| Property | Value | +|----------|-------| +| Install root | `/opt/android-sdk` | +| Requires | `@github.com/opencharly/layer-java-openjdk` (JDK 21) | +| Env | `ANDROID_HOME`, `ANDROID_SDK_ROOT` = `/opt/android-sdk` | +| System image | API-36 `google_apis_playstore` x86_64 (sdkmanager-fetched) | + +## What it installs + +From CachyOS/Arch packages under `/opt/android-sdk`: +`cmdline-tools` (`sdkmanager`/`avdmanager`), `platform-tools` (`adb`), +`build-tools` 36 (`aapt2`), `platform android-36`, and the `emulator`. +`apkeep` (the by-package-name app downloader the `charly check adb +install-app` verb drives) is installed from its upstream precompiled +x86_64 binary. The one component with no package anywhere — the API-36 +`google_apis_playstore` x86_64 system image — is fetched by `sdkmanager` +into a persistent cache and copied alongside the tools. + +## Usage + +Compose it in a box (a named box's `candy:` value is the box BODY): + +```yaml +android-dev: + candy: + base: cachyos-base + candy: + - '@github.com/opencharly/layer-android-sdk:v2026.xxx.yyyy' +``` + +The SDK lands at fixed paths under `/opt/android-sdk`, so it is verifiable +by probing those paths and running `adb version`. Pair it with an +emulator device (`kind: android`) and the `adb:`/`appium:` check verbs. + +## Verification + +`plan:` `check:` steps assert `/opt/android-sdk/cmdline-tools/latest/bin/sdkmanager`, +`.../platform-tools/adb`, `.../build-tools/36.0.0/aapt2`, `.../emulator/emulator`, +`.../platforms/android-36`, and the fetched system-image directory all exist, +that `adb version` reports the Android Debug Bridge banner, and that `apkeep` +resolves on PATH. + +## Related + +- [`/charly-check:android`](/recipes/check/android/) — the `kind: android` device + `target: android` deploy +- [`/charly-check:adb`](/recipes/check/adb/) — the `adb:` probe verb +- [`/charly-check:appium`](/recipes/check/appium/) — the `appium:` UI-automation verb diff --git a/src/content/docs/recipes/check/android-test-apps.md b/src/content/docs/recipes/check/android-test-apps.md new file mode 100644 index 00000000..4c6d855c --- /dev/null +++ b/src/content/docs/recipes/check/android-test-apps.md @@ -0,0 +1,55 @@ +--- +title: "android-test-apps" +description: "The Android test-apps candy — a committed F-Droid APK applied to a `kind: android` device through the `apk:` package format." +--- + + + +*Recipe card from the `charly-check` plugin (Commands — runtime CLI verbs).* + +# android-test-apps — Android fixture apps via the `apk:` format + +## Candy Properties + +| Property | Value | +|----------|-------| +| Installs into image | nothing (device-scoped) | +| `apk:` list | `tests/data/F-Droid.apk` (committed) | +| Applied by | a `target: android` deploy (skipped at image build) | +| Verified by | `adb:` `pm list packages` / `pidof` after the deploy | + +## What it does + +Carries the F-Droid client (`org.fdroid.fdroid`) as a **committed APK** +(`tests/data/F-Droid.apk`), pushed over the goadb sync protocol and +installed with `pm install`. It is the declarative counterpart to the +`charly check adb install-app` verb. The candy installs **nothing** into +the image — the `apk:` list is device-scoped and applied ONLY by a +`target: android` deploy (via the external `deploy:android` substrate, +venue-agnostic for an in-pod image device or a remote endpoint). + +## Usage + +Compose it in the box that backs a `kind: android` deploy: + +```yaml +android-fixtures: + candy: + base: cachyos-base + candy: + - '@github.com/opencharly/layer-android-test-apps:v2026.xxx.yyyy' + - '@github.com/opencharly/layer-android-apidemos:v2026.xxx.yyyy' +``` + +## Verification + +The `plan:` `check:` steps run at `context: [runtime]` after a +`target: android` deploy: `pm list packages` must contain +`org.fdroid.fdroid`, and launching it (`monkey … LAUNCHER`) must yield a +running PID — proving the install end to end over `adb`. + +## Related + +- [`/charly-check:android`](/recipes/check/android/) — the `kind: android` device + `apk:` format +- [`/charly-check:adb`](/recipes/check/adb/) — the `adb:` probe verb +- `layer-android-apidemos` — the sibling committed-APK fixture diff --git a/src/content/docs/recipes/check/android.md b/src/content/docs/recipes/check/android.md index 45c2a50f..e7e3080b 100644 --- a/src/content/docs/recipes/check/android.md +++ b/src/content/docs/recipes/check/android.md @@ -26,7 +26,7 @@ This sits ABOVE the device-interaction verbs: the `adb:` ([`/charly-check:adb`]( and `appium:` ([`/charly-check:appium`](/recipes/check/appium/)) declarative check verbs drive a running device; `kind: android` + `target: android` declaratively describe a device and the apps installed on it. The install machinery is shared — see "One installer -(R3)". +(R2)". ## `kind: android` — the device @@ -106,11 +106,11 @@ android-stack: - my-android-apps # layers whose apk: packages install onto the device ``` -`charly fleet add android-stack.device` resolves the device, gates on +`charly deploy add android-stack.device` resolves the device, gates on `sys.boot_completed`, and installs the `add_candy:` candies' `apk:` packages via the **external `deploy:android` substrate** (F1 — served out-of-process by candy/plugin-adb). Apps ride in on `add_candy:` (the same overlay mechanism -local/vm targets use) — there is no separate apk-list field. `charly fleet del` +local/vm targets use) — there is no separate apk-list field. `charly deploy del` best-effort `pm uninstall`s each `package:` id (replayed from the deploy's recorded reverse ops; the device/pod lifecycle is owned by the pod deploy). @@ -125,12 +125,12 @@ apps deploy onto the device. `target: android` is a **passthrough** hop in the deploy chain (the device shares its host pod's adb venue / the endpoint addr — there is no shell venue to "enter"), so `charly check live pod.android` runs the device's checks against the pod's published adb port. A pod's children can only -deploy AFTER `charly start` (the container doesn't exist at `charly fleet add` time), -so `charly fleet add --node-only` brings the pod up first and the children deploy +deploy AFTER `charly start` (the container doesn't exist at `charly deploy add` time), +so `charly deploy add --node-only` brings the pod up first and the children deploy afterwards by dotted path; `charly check run ` automates this (deploy pod → config → start → deploy nested children → check-live). -## One installer + one plugin (R3 / F1) +## One installer + one plugin (R2 / F1) candy/plugin-adb owns ALL Android device interaction — the `adb:` check verb, the `deploy:android` substrate, AND the goadb-backed `charly status` probe — so @@ -157,7 +157,7 @@ round trip remains in this leg: - **Plugin** (`candy/plugin-adb/deploy.go`, the `deploy:android` provider) gates on `sys.boot_completed`, installs each app with retry (reusing the SAME `install`/`install-app` method handlers the `adb:` verb dispatches), and returns - the `pm uninstall` teardown ops the host records + replays at `charly fleet del`. + the `pm uninstall` teardown ops the host records + replays at `charly deploy del`. So the apk format, the check verbs, and the deploy substrate can never drift on single/split/`.xapk` handling — they all flow through the one provider. @@ -211,7 +211,7 @@ ALL pure/portable and run plugin-side directly, returning a - `deploykit.ApkInstallStep` (`sdk/deploykit/steps.go`); `sdk/deploykit/install_build.go` — `compileApkStep` (the plugin-side preresolver reads this step; no deploy target executes it). - `sdk/loaderkit/load_unified.go` — loader wiring (mirrors every `kubernetes` site; the former `charly/unified.go` is DELETED, K-wave 2). -- `spec.Deploy` (the deploy node — the former `charly/deploy.go`'s `FleetNode` is DELETED, K-wave 2) with `target: android`; `charly/fleet_add_cmd.go` dispatch + +- `spec.Deploy` (the deploy node — the former `charly/deploy.go`'s `FleetNode` is DELETED, K-wave 2) with `target: android`; `charly/deploy_add_cmd.go` dispatch + `--node-only`; `sdk/deploykit/deploy_chain.go` / `charly/deploy_tree.go` passthrough. ## Related skills diff --git a/src/content/docs/recipes/check/appium.md b/src/content/docs/recipes/check/appium.md index 00e226d7..a17db2f5 100644 --- a/src/content/docs/recipes/check/appium.md +++ b/src/content/docs/recipes/check/appium.md @@ -38,7 +38,7 @@ the W3C escape hatch: `POST /session//execute/sync` with ### Authoring the `appium:` verb in a plan step The verb is the inline Op of a step — an ordered list item under the candy/box -`plan:` (deploy-context only — `context: [deploy]`); an Appium action that drives the +`plan:` (**live-mode only** — `context: [runtime]`); an Appium action that drives the UI is a `run:` step. The method name is the scalar value for a bare-method step (`appium: status`), or the `method:` key of the `appium:` map when the step carries appium-exclusive fields (`caps:`, `apk:`, `strategy:`, `selector:`, `text:`, @@ -52,7 +52,7 @@ validators) — those live INSIDE the `appium:` map. Only the shared matchers id: appium-up appium: status stdout: { contains: '"ready":true' } - context: [deploy] + context: [runtime] - run: open a W3C WebDriver session against the emulator id: open-session appium: @@ -79,7 +79,7 @@ validators) — those live INSIDE the `appium:` map. Only the shared matchers method: screenshot artifact: /tmp/post-tap.png artifact_min_bytes: 10000 - context: [deploy] + context: [runtime] - run: close the WebDriver session id: close appium: session-delete @@ -305,7 +305,7 @@ Override the session id for a single check with `session:`: method: screenshot artifact: /tmp/x.png session: 37e8f3c1-... # bypass the session file - context: [deploy] + context: [runtime] ``` ## Implementation diff --git a/src/content/docs/recipes/check/cdp.md b/src/content/docs/recipes/check/cdp.md index b71f255b..8705a4ca 100644 --- a/src/content/docs/recipes/check/cdp.md +++ b/src/content/docs/recipes/check/cdp.md @@ -37,13 +37,13 @@ cdp-exclusive field (`tab:`, `expression:`, `url:`, `selector:`, `text:`, `x:`, `artifact:`, `artifact_min_bytes:`, …) — those fields live INSIDE the `cdp:` map. The shared matchers (`stdout:`, `stderr:`, `exit_status:`) and `context:`/`id:`/`timeout:` stay siblings of the `cdp:` key. A query is a `check:` step; a navigation/click action -is a `run:` step. All `cdp:` steps are **deploy-context only** (they need a running -container), so author them with `context: [deploy]`. See [`/charly-check:check`](/recipes/check/check/) for the +is a `run:` step. All `cdp:` steps are **live-mode only** (they need a running +container), so author them with `context: [runtime]`. See [`/charly-check:check`](/recipes/check/check/) for the full method allowlist and YAML shape. Example: ```yaml - check: the page title is Dashboard - context: [deploy] + context: [runtime] cdp: method: eval tab: "1" @@ -124,7 +124,7 @@ tab ID between steps; reference subsequent steps as `tab: "1"`). ```yaml - check: a tab is open - context: [deploy] + context: [runtime] cdp: list # scalar sugar — bare method, no cdp-exclusive fields stdout: contains: example.com @@ -149,7 +149,7 @@ Uses HTTP API: `GET /json/close/`. ```yaml - check: the page text contains the marker - context: [deploy] + context: [runtime] cdp: method: text # cdp: html → HTML source; cdp: url → title and URL tab: "1" @@ -163,7 +163,7 @@ Uses CDP WebSocket: `Runtime.evaluate` with `document.body.innerText` / `documen ```yaml - check: a non-empty screenshot is captured - context: [deploy] + context: [runtime] cdp: method: screenshot tab: "1" @@ -207,7 +207,7 @@ CDP coordinates are **viewport-relative** (relative to Chrome's content area). V ```yaml - check: the sync button is located - context: [deploy] + context: [runtime] cdp: method: coords tab: "1" @@ -249,7 +249,7 @@ above, then author a `wl: click` step at those `x:`/`y:`: ```yaml - check: read the document title - context: [deploy] + context: [runtime] cdp: method: eval tab: "1" @@ -265,7 +265,7 @@ Uses CDP: `Runtime.evaluate`. Returns the result value (e.g. ```yaml - check: the heading appears - context: [deploy] + context: [runtime] cdp: method: wait tab: "1" @@ -421,7 +421,7 @@ then deliver the click via the `vnc:` verb at the reported desktop center: ```yaml - check: the sign-in button is located - context: [deploy] + context: [runtime] cdp: method: coords tab: "1" @@ -435,14 +435,14 @@ ID survives Google's same-tab navigations (email → password → result). ```yaml - check: the email field appears - context: [deploy] + context: [runtime] cdp: method: wait tab: "1" selector: "#identifierId" timeout: 30s - check: the email field is located (focus via vnc: at these coords) - context: [deploy] + context: [runtime] cdp: method: coords tab: "1" @@ -461,14 +461,14 @@ transition: ```yaml - check: the password challenge page is reached - context: [deploy] + context: [runtime] cdp: method: url tab: "1" stdout: contains: challenge/pwd - check: a verification screenshot is captured - context: [deploy] + context: [runtime] cdp: method: screenshot tab: "1" @@ -480,14 +480,14 @@ transition: ```yaml - check: the password field appears - context: [deploy] + context: [runtime] cdp: method: wait tab: "1" selector: input[type="password"] timeout: 15s - check: the password field is located (focus via vnc:, then vnc: type "$GMAIL_PASSWORD") - context: [deploy] + context: [runtime] cdp: method: coords tab: "1" @@ -539,7 +539,7 @@ The `cdp: spa-*` methods provide first-class support for interacting with Selkie ```yaml - check: the SPA is in a healthy state - context: [deploy] + context: [runtime] cdp: method: spa-status tab: "1" @@ -598,7 +598,7 @@ on an instance, then run `charly check live -i --filter cdp`: ```yaml - check: CDP is available on port 9222 - context: [deploy] + context: [runtime] cdp: status stdout: equals: ok @@ -608,7 +608,7 @@ on an instance, then run `charly check live -i --filter cdp`: method: open url: https://ip.me - check: the proxy IP is reflected by the page - context: [deploy] + context: [runtime] cdp: method: eval tab: "1" diff --git a/src/content/docs/recipes/check/check-sway-browser-vnc.md b/src/content/docs/recipes/check/check-sway-browser-vnc.md index c4ab2d6f..69cc6749 100644 --- a/src/content/docs/recipes/check/check-sway-browser-vnc.md +++ b/src/content/docs/recipes/check/check-sway-browser-vnc.md @@ -33,21 +33,21 @@ check-sway-browser-vnc-pod: plan: - check: CDP /json/version answers over the published HOST_PORT id: esbv-pod-http-cdp - context: [deploy] + context: [runtime] http: http: "http://127.0.0.1:${HOST_PORT:9222}/json/version" status: 200 - check: CDP enumerates the live debugging targets id: esbv-pod-cdp-list - context: [deploy] + context: [runtime] cdp: list - check: the Sway tree is reachable over the Wayland socket id: esbv-pod-wl-sway-tree - context: [deploy] + context: [runtime] wl: sway-tree - check: a terminal recording starts id: esbv-pod-record-start - context: [deploy] + context: [runtime] record: method: start record_name: check-term @@ -86,7 +86,7 @@ Note: `charly config ` persists `image: ` (it assumes deploy-key == image-name; see [`/charly-core:deploy`](/recipes/core/deploy/)). Because this bed's key (`check-sway-browser-vnc-pod`) differs from its image (`sway-browser-vnc`), set the operator ref to `sway-browser-vnc` in `~/.config/charly/charly.yml` (the check -runner / `charly fleet add` does this for you — `charly` "never clobbers +runner / `charly deploy add` does this for you — `charly` "never clobbers operator-authored refs"). ## Related Skills diff --git a/src/content/docs/recipes/check/check.md b/src/content/docs/recipes/check/check.md index bb1ba887..08595dab 100644 --- a/src/content/docs/recipes/check/check.md +++ b/src/content/docs/recipes/check/check.md @@ -120,6 +120,37 @@ feature run`. Every candy MUST ship a non-empty `description:` + at least one deterministic `check:` step (`charly box validate` enforces it); the live agent grader stays opt-in. Full detail: [`references/authoring-gotchas.md`](/recipes/check/check/authoring-gotchas/). +## The three-step bed shape — a gate that can FAIL without the change + +*This is the shape every `check:` bed the R10 gate selects should have, and the one this org's best beds use.* + +**A bed that only inspects the FINAL state cannot tell "my change worked" from "something else made it true" — and +cannot fail without the change, which is R7's real test.** The shape that can: + +1. **ASSERT THE ABSENCE — before the change.** *Probe the thing your change will produce, and assert it is NOT there + yet: `nothing-served-before-the-delivery`. If the probe already succeeds on the un-changed tree, the bed proves + nothing about your change.* +2. **PERFORM THE CHANGE.** *The `run:` step, or the deploy the bed exists to exercise.* +3. **ASSERT THE PRESENCE — after it, in terms ONLY the change could produce.** *`delivers-the-built-tree`, + `venue-serves-the-delivered-word`.* **The assertion must be specific enough that a coincidence does not satisfy it.** + +**A working example in this org:** `spec#245`'s `check-spec-delivery` bed, whose three steps are named exactly along this +shape. *Six PRs in one leg failed by omitting step 1.* **If you cannot write step 1, you have not decided what your change +produces — which is worth knowing before the gate runs, not after.** + +## The uppercase-token trap — a step that SKIPS is not a step that PASSES + +**A step's body is scanned for variables INCLUDING ITS COMMENTS, and an unresolvable UPPER-CASE token makes the step +SKIP rather than fail.** This is the single most expensive authoring trap in the check system, because a skipped step +reads as a satisfied one in the summary. + +**So:** +- **do not put an upper-case `${...}`-looking token in a step's body or in a comment inside it**, even to explain + something. *A comment is scanned.* +- **verify the step table says `PASS`, not `SKIP`**, after a run that you are quoting as evidence. `2 steps: 2 passed, + 0 skipped` is the line to look for; a bed that reports skips has not proven what you are claiming it proved. +- **when a variable genuinely is needed, use the bed's declared `var:` mechanism** so the value is resolvable at the + point the step runs. ## Quick Reference | Action | Command | Description | diff --git a/src/content/docs/recipes/check/check/authoring-gotchas.md b/src/content/docs/recipes/check/check/authoring-gotchas.md index 4e7c961f..1117941c 100644 --- a/src/content/docs/recipes/check/check/authoring-gotchas.md +++ b/src/content/docs/recipes/check/check/authoring-gotchas.md @@ -26,7 +26,7 @@ steps to the agent grader. | Stage | Who | Command | What | |---|---|---|---| -| **Specify** | you / an agent | hand-edit the candy's `plan:` list (or `charly box set candy..plan ...`) | Author the `description:` string + `plan:` steps on the CANDY that provides the behaviour (it bakes into every box that composes the candy — R3). | +| **Specify** | you / an agent | hand-edit the candy's `plan:` list (or `charly box set candy..plan ...`) | Author the `description:` string + `plan:` steps on the CANDY that provides the behaviour (it bakes into every box that composes the candy — R2). | | **Bind** | author (implicit) | `charly feature pending ` lists the agent-graded steps | Use a `check:` step (inline verb) → deterministic; use an `agent-check:` step (prose) → agent-graded. | | **Run** | you / CI | `charly box feature run ` / `charly check feature run ` | Execute the plan; per-step pass/fail + grader evidence. | | **Iterate** | you / an agent | edit + re-run, OR `charly check run ` (an `iterate:` bed) | Drive red→green by hand, or let the plateau-bounded AI loop write the code until the `check:` steps pass. | @@ -116,7 +116,7 @@ in P12a — core constructs `&AgentGrader{}` directly, so it lives in `kit`, rea core code), and `sdk/deploykit/description_collect.go` (`CollectDescriptions`; the former `charly/description_collect.go` is DELETED, K-wave 2) for the `charly feature list/pending/validate` surface. The `Runner.Grader` dispatch is `kit.RunPlan` (`sdk/kit/planrun.go`) directly — the former 1-line `charly/description_run.go` wrapper was dissolved in P12a. -Target resolution is shared with the harness loop and `charly check box`/`live` (R3). +Target resolution is shared with the harness loop and `charly check box`/`live` (R2). ## Authoring Gotchas (learned the hard way) @@ -268,10 +268,10 @@ them fails in `charly check box` because the mount isn't attached. file: /workspace filetype: directory -# ✓ context: [deploy] so it runs only against live containers +# ✓ context: [runtime] so it runs only against live deployments - check: the workspace directory exists id: workspace-dir - context: [deploy] + context: [runtime] file: file: /workspace filetype: directory @@ -367,23 +367,23 @@ the shell is a login shell — reproduced: `runuser -l user -s /bin/bash -n -l` prints the full NOPASSWD listing. This bit the earlier shipping form of the test; the sshd candy now uses `-u … --`. -Worked example: [`/charly-coder:sshd`](/recipes/coder/sshd/) ships exactly the `-u user --` pattern. Alternative: give the step `context: [deploy]` so it runs against a live container where you control the user-switch externally. +Worked example: [`/charly-coder:sshd`](/recipes/coder/sshd/) ships exactly the `-u user --` pattern. Alternative: give the step `context: [runtime]` so it runs against a live container where you control the user-switch externally. ### 12. `charly check box ` is ambiguous with multiple CalVer tags — use the full registry ref `charly check box` resolves its positional argument against local podman storage, not `charly.yml`. When the host has accumulated many CalVer tags for the same image (a normal consequence of iterative `charly box build` runs), the short form errors out: ``` -charly: error: ambiguous short name "openclaw-desktop" in local storage; - candidates: ghcr.io/opencharly/openclaw-desktop:latest, - ghcr.io/opencharly/openclaw-desktop:2026.109.1418, +charly: error: ambiguous short name "my-box" in local storage; + candidates: ghcr.io/opencharly/my-box:latest, + ghcr.io/opencharly/my-box:, ... Re-run with a full ref. ``` Use the fully-qualified registry ref: ```bash -charly check box ghcr.io/opencharly/openclaw-desktop:latest +charly check box ghcr.io/opencharly/my-box:latest ``` This is different from `charly box inspect`, `charly box build`, and `charly check live` (the live-service runner), which key off `charly.yml` and accept short names unambiguously. Only the disposable-container runner has this restriction because it does not consult `charly.yml` at all. @@ -413,31 +413,51 @@ when the pattern would also match the wrapping bash. The harness defense is a safety net, not a license to use the broken pattern deliberately. -### 13. A step is SIGKILLed at 90s unless it declares `timeout:` - -`ProbeNeverHang` (`sdk/kit/runner.go`) bounds every probe ATTEMPT at -`runnerProbeNeverHangFallback` = **90 seconds**. A step that runs longer is killed, -and the runner names the bound in the message — but the underlying exec-layer text is -still `process terminated by signal (signal: killed)`, which describes the mechanism -of death and not its cause. Read alone, it looks like the command crashed. - -What crosses 90s in practice: **installing charly from a published distro repo pulls -~190 packages** (podman, qemu, libvirt, gnupg, tailscale). On a 2-vCPU cloud-image VM -`dnf install` does not finish in time while `pacman -S` does — so two beds differing -only in package manager come out one green and one "killed", which invites a -distro-specific theory (repo layout, signing, cloud image) when the variable is -elapsed time against a shared floor. **Compare the step's duration to 90s before -theorising about the distro.** +### 13. A step is SIGKILLed at its never-hang bound unless it declares `timeout:` + +`ProbeNeverHang` (`sdk/kit/runner.go`) bounds every probe ATTEMPT. The +live `charly check` path sets that bound from the readiness table — +`cfg.ProbeTimeout = poll.ReadinessProvider().PerAttemptFor(PollLocal)` +(`candy/plugin-check/plugin_runner.go`), whose class fallback is +`readinessPerAttemptFallback` = **120 seconds** (`spec/poll/poll.go`). +The `runnerProbeNeverHangFallback` = 90s constant in `sdk/kit/runner.go` +is ONLY the bare-`NewRunner` guard (a test / a plugin); it is never the +bound on the real check paths. **Read the number out of the kill message +rather than assuming** — an actual run prints +`killed by the per-attempt never-hang bound of 2m0s`. A step that runs +longer is killed, and the underlying exec-layer text is still +`process terminated by signal (signal: killed)`, which describes the +mechanism of death and not its cause. Read alone, it looks like a crash. + +What crosses the bound in practice is any step whose own work is +minutes-long: + +- **Installing charly from a published distro repo pulls ~190 packages** + (podman, qemu, libvirt, gnupg, tailscale). On a 2-vCPU cloud-image VM + `dnf install` does not finish in time while `pacman -S` does — so two + beds differing only in package manager come out one green and one + "killed", which invites a distro-specific theory (repo layout, signing, + cloud image) when the variable is elapsed time against a shared floor. +- **A full nested-container acceptance loop** — e.g. `cbx-e2e-loop`, + which leases a real nested container via `local-container`, syncs a git + workdir and streams a command. Its own work is minutes-long: on + distro-cachyos the enclosing `check-live` bucket (129 checks incl. this + one) measures **2m39s idle and 3m07s under concurrent host load** — + both above the 120s default, so the step is killed by the bound on its + own duration, not by a wedge (before the bound was declared it was + killed at `2m0s`; with `timeout: 10m` it PASSes). A check bed's long + acceptance steps are a normal case for an authored bound — not a sign + of a hang. The fix is authored, not code: `#Op` carries `timeout?: #Duration`, and -`ProbeNeverHang` honours a longer authored value over the floor (the effective -ceiling becomes `declared + 30s`). Declaring it is USING the mechanism's own -parameter — not an R4 workaround: +`ProbeNeverHang` honours a longer authored value over the floor (the +effective ceiling becomes `declared + 30s`). Declaring it is USING the +mechanism's own parameter — not an R3 workaround: ```yaml - check: dnf install charly installs the package id: fedora-charly-installed - timeout: 10m # ~190 packages on 2 vCPUs; the 90s floor kills this + timeout: 10m # ~190 packages on 2 vCPUs; the floor kills this exit_status: 0 command: | sudo dnf install -y charly && diff --git a/src/content/docs/recipes/check/check/beds-and-r10.md b/src/content/docs/recipes/check/check/beds-and-r10.md index 021d52bc..e58b97ef 100644 --- a/src/content/docs/recipes/check/check/beds-and-r10.md +++ b/src/content/docs/recipes/check/check/beds-and-r10.md @@ -39,7 +39,7 @@ never by stripping the candy. 1. `charly box build --dev-local-pkg` — build the test artifact (pod beds only). The check-bed runner sets `--dev-local-pkg` automatically, so a bed bakes the **in-development** charly toolchain (built via the `charly generate-packages` plugin from the local binary + plugins) — never a stale published release. A bed thus always tests the code under development; a production box build downloads the released package. See [`/charly-tools:charly`](/recipes/tools/charly/) "Check-vs-production binary source" + [`/charly-internals:install-plan`](/recipes/internals/install-plan/) "Check-vs-production charly toolchain". 2. `charly check box ` — box-section + baked candy-section probes. -3. `charly fleet add ` — apply the bed (or `charly vm create` for vm beds). +3. `charly deploy add ` — apply the bed (or `charly vm create` for vm beds). 4. (pod beds) `charly config ` + `charly start `. 5. `charly check live ` — full three-section live probe pass. 6. `charly update ` — fresh-rebuild re-verification (R10 acceptance gate). @@ -184,7 +184,6 @@ bed name against the live tree before launching it. | `check-jupyter-pod` / `check-jupyter-ml-pod` | pod | `image: jupyter` / `image: jupyter-ml` | jupyter-mcp regression coverage; jupyter-ml spacy/quarto + GPU MCP probes | | `check-versa-pod` | pod | `image: versa` | versa OSM analytics + vector-tile + marimo MCP | | `check-android-emulator-pod` | pod | `image: android-emulator` | Android 14 emulator (/dev/kvm) + adb/appium | -| `check-openclaw-pod` / `check-openclaw-full-pod` / `check-openclaw-desktop-pod` | pod | `image: openclaw*` | minimal / maximal / streamed-desktop headless gateway | | `check-cachyos-gpu-vm` / `check-selkies-labwc-nvidia-vm` / `check-selkies-kde-nvidia-vm` | vm | `from: cachyos-gpu-vm` | VFIO GPU-passthrough + nested selkies NVENC streaming (`requires_exclusive: [nvidia-gpu]` — serialized) | | `check-arch-pacstrap-vm` / `check-arch-vm` / `check-cachyos-vm` / `check-debian-debootstrap-vm` / `check-ubuntu-debootstrap-vm` / `check-fedora-vm` | vm | `from: -vm` | the distro bootstrap-VM beds (pacstrap / debootstrap) | | `check-cross-pod-cdp` / `check-cross-vm-http` / `check-cross-local-http` / `check-cross-local-driver` | pod/vm/local | — | cross-deployment probing (pod→pod, host→pod/VM) | @@ -223,7 +222,7 @@ hardcodes that name — it flows from the `iterate.sandbox:` field through `ResolveIterateSandbox`, and prompts reference it via the `${TARGET_NAME}` substitution token. **The sandbox is an operator-provisioned per-host deploy** — the runner restarts-but-never-creates it: provision once with -`charly fleet add check-sandbox --disposable` + `charly start +`charly deploy add check-sandbox --disposable` + `charly start check-sandbox` (the ref must provide charly + nested podman + the configured AI CLI; the per-host overlay never ships with the repo). On a host without the entry, `charly check run ` fails fast with exactly that @@ -257,7 +256,7 @@ construction. `check-pod` ~110s idle but **842s measured under a concurrent roster** (one build → deploy → check → fresh-update → teardown cycle covering all four mechanisms) · `check-local-vm` ~45s · `check-sidecar-pod` ~180–290s · `check-k3s-vm` ~5–7 min · -`check-openclaw-full-pod` ~1414s · the heavy feature beds +the heavy feature beds (`check-sway-browser-vnc-pod` ~2477s ≈ 41 min incl. image build) longer. **These are load-dependent, and the idle figures mislead.** A bed's own newest @@ -279,7 +278,7 @@ libvirt domain / emulator it spawns outlives a single turn. (1) **Launch it as a harness-tracked background task** (`run_in_background`) — never foreground (the Bash tool's `timeout`, 120s default / 600s max, kills the call mid-`vm-create`, orphaning the domain) and -never a sleep/poll loop (the R4 bandaid). (2) **Let the completion notification +never a sleep/poll loop (the R3 bandaid). (2) **Let the completion notification drive the next step** — the harness re-invokes the launching session when the run exits, so the launcher must survive to completion to be notified: the persistent main session does; an ephemeral sub-agent (returns synchronously) and an idle @@ -303,10 +302,15 @@ use `--if-exists`, which is idempotent and still cleans managed metadata. Confir identity with `charly vm list`; see [`/charly-vm:vm`](/recipes/vm/vm/) "`charly vm destroy` — the DEPLOY name keys the domain" and [`/charly-internals:agents`](/recipes/internals/agents/) "The binding rule". -Final target and member teardown are recorded acceptance steps. In particular, a targetless group -records `cleanup-members`; a failed members-down operation fails the bed rather than leaving cleanup -to inference from a later host inventory. The group fresh-rebuild transition likewise records and -requires `rebuild-members-down` before bringing the members back up. +Final target and member teardown happen on the SUCCESS tail as recorded acceptance steps (a +targetless group records `cleanup-members`), **and** on every unwinding failure path through the +bed runner's ONE venue-teardown owner: a failed run disposes of its deployed target and its members +unless retention was explicitly requested (`--keep-on-failure`, `--keep`/`--keep-venue`, +`keep_venue:`, or the root's `ephemeral.keep_on_failure:`). On the success path a failed +members-down operation fails the bed; on the failure path it is reported as a warning so the +original step error survives. The SIGNAL path cannot tear down at all (nothing unwinds), so +`charly check stop` names the scoped destroy verb instead. The group fresh-rebuild transition +likewise records and requires `rebuild-members-down` before bringing the members back up. ### Golden snapshots: stop the keeper after capture @@ -461,7 +465,7 @@ explicit pin, so the guard never fires inside a bed. **Which verb/bed proves what (the project rulebook R7):** `charly check box` passes on zero-content stages too — it is not a substitute for the generated-artifact -checks (R8). For the R10 gate, pick the disposable bed whose kind matches +checks (R7). For the R10 gate, pick the disposable bed whose kind matches what you changed (`check-pod` for the combined box/candy/pod/deploy-target mechanism, `check-local`, `check-k3s-vm`, or a feature bed). `charly check run` on an `iterate:` bed is the multi-hour AI-iteration benchmark, never a quick @@ -491,11 +495,11 @@ The project rulebook R10 carries the mandate; this matrix is the authoritative d | Change class | Pre-flight | The R10 gate | Tier on a clean pass | Explicitly NOT required | |---|---|---|---|---| -| **Documentation-only change class** — `*.md` (`AGENTS.md` / `CLAUDE.md`, the marketplace corpus's `**/SKILL.md`, READMEs, CHANGELOG), comment-only code edits, or a submodule pointer bump to an all-documentation submodule commit; zero behavior change | markdown integrity, link checks | The non-runtime standards: adversarial consistency review, the R5 grep self-test, cross-reference validation, and command-safety gates | `documentation reviewed` | ANY bed run or image build — beds cannot fail on prose | +| **Documentation-only change class** — `*.md` (`AGENTS.md`, the marketplace corpus's `**/SKILL.md`, READMEs, CHANGELOG), comment-only code edits, or a submodule pointer bump to an all-documentation submodule commit; zero behavior change | markdown integrity, link checks | The non-runtime standards: adversarial consistency review, the R5 grep self-test, cross-reference validation, and command-safety gates | `documentation reviewed` | ANY bed run or image build — beds cannot fail on prose | | **Hook / workflow scripts** — `.claude/hooks/*.sh`, `.claude/workflows/*.js` | `bash -n` / async-body parse | Execute the changed script live: run the hook directly (paste its output); a workflow whose control flow changed runs against ONE bed matching the change. Prompt-string-only workflow edits: parse + the non-runtime standards | `fully tested and validated` | The full bed fan-out | | **Harness project configuration** — `AGENTS.md`, `.codex/**`, repo-native `.agents/**`, or an executable that provisions or validates those surfaces | Parse the changed configuration; run the project profile and static-validator checks; verify exact gitlink and linked-worktree provenance | Run the final-tree repository harness gate: execute each changed validator/provisioner directly, verify only the gitlinks dispatched by the change class at their recorded revisions, and run the committed developer-profile checks. A Git-provisioning change also proves its canonical-object reference and exact-gitlink behavior in a dedicated linked worktree. Record the exact approved commands and active managed sandbox available for this run. This proves repository-controlled behavior; never claim that it proves settings loaded by a newly launched harness process. The fresh validator independently decides whether the final-tree delta additionally requires a Charly R10 bed and runs it when required. | `fully tested and validated` | A forced restart/new session, alternate home/cache/workspace, or unrelated VM/container roster that cannot exercise repository configuration | | **`charly` Go code** | `go test ./...` + `go vet` + the R9 source build `scripts/bootstrap-charly.sh` (R9 freshness + `charly version` check on the worktree binary) | `charly check run ` for EACH bed whose kind matches a touched code path: box/candy/pod/deploy-target mechanism → `check-pod`; `target: local` → `check-local`; VM / kubernetes → `check-k3s-vm`; a feature surface → its feature bed. Cross-cutting loader / resolver / IR / unified-schema changes → run the matching beds as one `kind:check-roster` roster (`charly check run `, its `lanes` pool overlapping every bed) — in-spec for that class, not a scope override; a roster run that does not include every matching bed is a partial roster, never a green gate | `fully tested and validated` | Beds whose substrate the change cannot reach | -| **Contract / library module** — a Go module with NO `charly.yml` project, NO `main`/deployable target and therefore NO `disposable: true` entity (the `github.com/opencharly/spec` + `github.com/opencharly/sdk` contract modules; any standalone library repo) | none beyond the suite | Run the repo's OWN committed module CI (`.github/workflows/ci.yml`: `go build ./...` + `go test ./...` + `gofmt -l .` + `golangci-lint run ./...`) GREEN on the PR head — the module suite IS the gate, because no bed CAN exist (a bed that cannot fail on the change proves nothing). The suite must genuinely EXECUTE the changed paths (a test that would FAIL without the change), not merely compile them. The `no disposable target` premise is a negative claim: prove it with executed output (`git ls-files \| grep -c 'charly.yml'` → 0; `git grep -c 'disposable: true'` → no match). A change whose behaviour is observable only at a CONSUMER's live boundary names the consumer PR running that bed — the bed rides the consumer change (producer→consumer order, B6), never the library PR | `fully tested and validated` | A `charly check run` bed in the module repo — none can exist there; the consumer boundary bed belongs to the consumer PR | +| **Contract / library module** — a Go module with NO `main`/deployable target and therefore NO `disposable: true` entity (the `github.com/opencharly/spec` + `github.com/opencharly/sdk` contract modules; any standalone library repo). Shipping no `charly.yml` is NOT the discriminator: `spec` carries one holding only its `repo:`/`task:` maintenance manifest, and a task-only manifest is no bed venue | none beyond the suite | Run the repo's OWN committed module CI (`.github/workflows/ci.yml`: `go build ./...` + `go test ./...` + `gofmt -l .` + `golangci-lint run ./...`) GREEN on the PR head — the module suite IS the gate, because no bed CAN exist (a bed that cannot fail on the change proves nothing). The suite must genuinely EXECUTE the changed paths (a test that would FAIL without the change), not merely compile them. The `no disposable target` premise is a negative claim: prove it with executed output on the PR head — `git grep -nE '^[[:space:]]*disposable:' -- '*.yml' '*.yaml'` returns no match, and the root `charly.yml` is absent or declares no `box:`/`deploy:`/`check:` node. Key the grep to the ANCHORED key at line start: the bare string also sits in CHANGELOG prose and in Go string literals, and a bare `grep 'charly.yml'` also matches the `*.charly.yml.golden` `workflowkit` fixtures — either form makes the premise false-negative on `sdk`. A change whose behaviour is observable only at a CONSUMER's live boundary names the consumer PR running that bed — the bed rides the consumer change (producer→consumer order, B6), never the library PR | `fully tested and validated` | A `charly check run` bed in the module repo — none can exist there; the consumer boundary bed belongs to the consumer PR | | **Candy / box / pod / vm / kubernetes / local / android config** | `charly box validate` | Build + run a bed that composes the changed entity (a candy edit → a bed whose image stacks that candy); when no bed composes it, the R7 sequence on a disposable deploy: build → `charly check box` → deploy → `charly check live` → fresh `charly update` | `fully tested and validated` | Beds that do not compose the changed entity | | **`iterate:` / ai check config** | `charly box validate` | The affected `iterate:` bed run as specified (see "Flag discipline") | `fully tested and validated` | Unrelated beds | @@ -556,9 +560,9 @@ These are the standards referenced in the project rulebook's AI attribution tier 0. **Prove every high-risk assumption before you edit (RDD — Risk Driven Development)** — the proactive bookend to Standard 11's fresh-rebuild gate. Low-risk orientation ("what does layer X do") is a skill lookup (R0, zero risk); every high-risk assumption — including any a skill or the code merely *asserts*, and above all whether this layer composition at its latest available versions builds / deploys / runs together — is proven on a `disposable: true` bed first (`charly check` it). Never accept docs or code as ground truth for a high-risk decision; if the bed disagrees with a skill, the skill is stale — fix it. Standard 0 (validate forward, riskiest-first) and Standard 11 (re-verify on a fresh rebuild) are the two ends of the same loop. 1. **Build a real artifact** (R7) — `charly box build ` / `go build` / `charly vm build `. Not just `go test`. Not just `charly box generate`. -2. **Verify the emitted artifact's content** (R8) — `grep -c supervisord-conf .build//Containerfile` for any image that uses supervisord; `charly check libvirt domain-xml ` for a VM. -3. **Verify critical OCI / capability labels post-build** (R8) — `charly box labels --format init` (or any `ai.opencharly.` shorthand) prints the built ref's label and exits non-zero when absent; `charly box labels ` lists the whole capability contract ([`/charly-internals:capabilities`](/recipes/internals/capabilities/)). Empty / missing label → the detection path silently returned nil → regression. -4. **Deploy to a disposable target** (R10) — never experiment on a resource that doesn't carry `disposable: true`. If no suitable disposable target exists, create one first (`charly fleet add --disposable` or mark a VM `disposable: true` in `charly.yml` and `charly vm create`). The setup is part of the task. On a disposable target: `charly update ` (unattended). On anything else: confirm with the user before any irreversible destroy — except preempting a declared-`preemptible:` holder, which is standing-authorized (reversible: graceful stop + guaranteed restore). +2. **Verify the emitted artifact's content** (R7) — `grep -c supervisord-conf .build//Containerfile` for any image that uses supervisord; `charly check libvirt domain-xml ` for a VM. +3. **Verify critical OCI / capability labels post-build** (R7) — `charly box labels --format init` (or any `ai.opencharly.` shorthand) prints the built ref's label and exits non-zero when absent; `charly box labels ` lists the whole capability contract ([`/charly-internals:capabilities`](/recipes/internals/capabilities/)). Empty / missing label → the detection path silently returned nil → regression. +4. **Deploy to a disposable target** (R10) — never experiment on a resource that doesn't carry `disposable: true`. If no suitable disposable target exists, create one first (`charly deploy add --disposable` or mark a VM `disposable: true` in `charly.yml` and `charly vm create`). The setup is part of the task. On a disposable target: `charly update ` (unattended). On anything else: confirm with the user before any irreversible destroy — except preempting a declared-`preemptible:` holder, which is standing-authorized (reversible: graceful stop + guaranteed restore). 5. **Target must reach steady-state** — `charly status ` → `running`; `charly check libvirt info ` → state `running`; SPICE socket file exists and accepts a handshake. If the service start-limit is hit, the container is crashing — read `charly logs ` and reproduce in a disposable shell (`charly shell `, running the service command manually). 6. **Run the declarative test suite** — `charly check live ` full three-section pass against the live container (or `--uri` / `--host` remote equivalent for a remote target). 7. **Verify the deployed binary is the one you built** (R9) — `charly version` on the target matches the expected CalVer, and `charly status ` (detail `Image ref:` line; JSON `image_ref`) shows the running container's image ref carries THIS build's CalVer tag, not the prior one. Source-only changes (Syncthing, git push) do not update the deployed binary; you must build AND deploy on the target host. @@ -574,6 +578,49 @@ These are the standards referenced in the project rulebook's AI attribution tier than inferring it from a PASS. Same failure family as invoking a stale `/usr/bin/charly`: "the binary under test must be the one invoked" applies to every binary in the chain. + + **The compiled-in mirror of this standard.** The remedy above is stated for an + OUT-OF-PROCESS verb and does not generalise: a candy named in charly's + `compiled_plugins:` is emitted by `pluginsgen` as a `registerCompiledPlugin(...)` + call and resolved as a `require` pin, so the plugin is LINKED INTO `bin/charly` — + and no environment variable re-points a linked symbol. `CHARLY_PLUGIN_DIR` is read + only by the out-of-process loader (`charly/plugin_loader.go`) and is never + consulted for a compiled-in plugin; `CHARLY_REPO_OVERRIDE` re-points the candy + RESOLVER and the local plugin source, not the Go module graph. A bed run on a + stock binary therefore cannot fail on an unmerged compiled-in plugin AT ALL — the + same "proves nothing about your rebuild" failure this standard exists to catch, + and harder to notice, because the plugin genuinely is in the binary and the run + genuinely is a bed run. + + The sanctioned override is + `scripts/bootstrap-charly.sh --dev-plugin =` + (repeatable). `pluginsgen` re-points its ENTIRE read of that repo at the local + checkout and emits a SEPARATE `go.work.dev` selected only by an explicit `GOWORK=`, + so the committed `go.work`/`go.work.sum` stay byte-identical (a workspace's sum + file is keyed to its own path, so a dev build's lock lands in `go.work.dev.sum`); + a later run WITHOUT the flag deletes `go.work.dev`, so a stale dev workspace can + never resolve a local tree for a plain build. The build prints a `DEV BUILD` + banner on stderr and refuses `--install`. Before compilation the generator + validates both halves: the name must appear in `compiled_plugins:`, and the + checkout's `candy//go.mod` must declare module + `github.com/opencharly//candy/` — the path the generated + registration imports. + + Then assert the changed path EXECUTED rather than inferring it from a PASS — the + discipline above, against two traps that have each shipped a false green: + + - `go version -m ` reports the plugin's module as `(devel)` in a + `--dev-plugin` build and as the module-proxy tag in a release build. That is the + cheap discriminator between the two binaries, and it is necessary but NOT + sufficient: it proves the module GRAPH, not that the changed arm ran. + - Set-difference the two binaries' plugin symbol tables (`go tool nm`) — never + `grep` for the changed name with a package-anchored pattern (`.`). + A method's symbol carries its receiver between the package and the name — + `.(*T).Method`, e.g. + `github.com/opencharly/plugin-check/candy/plugin-check.(*bedRunState).snapshotStep` + — so an anchored pattern matches every plain function and no method at all: a + change confined to method bodies reads as absent, and a real regression reads + as clean. (An unanchored `` grep does find them — the trap is the anchor.) 9. **Verify runtime deps are installed via package management** (R9) — on the host: `charly doctor` (dependency status), or the host package manager directly (`rpm -q ` / `pacman -Q ` — host packages are not charly-managed resources, so the package manager IS their interface); inside a container: `charly cmd 'rpm -q '`. Manual installs do not count — they won't survive a fresh install on a synced host. Every runtime dep must live in `setup.sh` + the charly candy's `packaging:` section (`candy/charly/charly.yml`). 10. **Leave the target healthy, not paused/errored** — the final `charly status` (and `charly check libvirt info ` for a VM) is healthy. If the target is in a broken state during exploration, `charly update` it back to the committed config before continuing — never layer experiments on broken state. 11. **Re-verify on a fresh rebuild after committing the source-level fix** (R10) — `charly update ` one more time from clean, with the new source applied. Run standards 1–10 again against this fresh rebuild. **This is the acceptance gate.** A fix that works on a hand-patched target but not on a fresh rebuild is a regression waiting for the next unrelated rebuild to wipe your patch. Paste both the exploratory-pass output and the fresh-rebuild-pass output into the conversation — the user sees both. @@ -585,7 +632,7 @@ These are the standards referenced in the project rulebook's AI attribution tier `DeployExecutor` chain that lands probes inside the leaf's actual venue — `command: id` for a pod-in-VM leaf returns the inner pod's user, not the parent VM's. Live-check and AI-iteration-scoring chain construction go -through the same code path `charly fleet add` uses. +through the same code path `charly deploy add` uses. For deeply-nested paths, each segment adds one hop: ```bash @@ -594,7 +641,7 @@ charly check live check-vm.inner # → SSH + podman exec ch charly check live check-vm.inner.deeper # → SSH + 2× podman exec (3 hops) ``` -Same chain primitive (`NestedExecutor`) used everywhere — `charly fleet +Same chain primitive (`NestedExecutor`) used everywhere — `charly deploy add`, `charly check live`, `charly check run` (AI iteration scoring). **Exception — a pod leaf nested in a VM delegates its check to the guest.** Because @@ -618,7 +665,7 @@ probing") for the symmetric authoring surface in a bed's plan (venue-from-positi A green `go test ./...` run does not prove a cutover done — build, deploy, run, and test the live target every time. A post-`charly update` re-test must run against the freshly deployed container, not the prior one still resident from before the update (an `is not running` error on the new container means the update broke it, not that "tests pass in aggregate"). A service-start failure (`A dependency job for X failed` + immediate exit) is a real error to read (`charly logs`) and reproduce (`charly shell`), never a presumed transient. `disposable: true` is the sole destroy authorization — a `lifecycle: dev` tag and "it's a dev box" framing grant none; everything else needs user confirmation regardless of hostname. A fix verified only on a target hand-patched over an afternoon is unverified; re-run `charly update` from clean and re-verify before claiming success. A plan that said "one PR" gets no invented Phase 2. Docs and code are not proof for a high-risk assumption — prove it on a disposable bed first (Standard 0); conversely, don't bed-test a low-risk fact a skill already states — that is wasted effort. Risk, not documentation status, is the trigger. -If the container needs state that's only available in deploy (volumes, env, tunnel), author the step at `context: [deploy]`. If it needs something at build only (binary path, package presence), author at `context: [build]`. Both contexts must pass for the cutover to be real. +If the step needs state that's only available on a live deployment (volumes, env, tunnel), author it at `context: [runtime]` — the context `charly check live` activates. If it needs something at build only (binary path, package presence), author at `context: [build]`. Note that those two ARE the check engine's contexts: a `check:` step scoped `context: [deploy]` is active in NEITHER mode and never runs (`opencharly/opencharly#413`, `opencharly/plugin-check#111`); `deploy` keeps its meaning on a `run:` step, where it names the install timeline. Both active contexts must pass for the cutover to be real. **Confidence tier mapping:** The "fully tested and validated" confidence level in the project rulebook's AI-attribution table requires all the standards met — including the fresh-rebuild re-verification. Anything short of that ships at a lower confidence tier. diff --git a/src/content/docs/recipes/check/check/cross-deployment-probing.md b/src/content/docs/recipes/check/check/cross-deployment-probing.md index 8980868d..2afa9fb1 100644 --- a/src/content/docs/recipes/check/check/cross-deployment-probing.md +++ b/src/content/docs/recipes/check/check/cross-deployment-probing.md @@ -70,7 +70,7 @@ Two pieces compose it: position: a step in the `plan:` of member `M` runs on `M` (bare name), a step in the `plan:` of a nested child `C` of parent path `P` runs on `P.C` (dotted). There is no authored `on:`/`pod:` step field — both are retired; tree position is the sole source of - venue (`flattenFleetVenues` stamps it at load time). A `cdp:`/`vnc:`/`mcp:` step + venue (`FlattenVenuesByPosition` stamps it at load time). A `cdp:`/`vnc:`/`mcp:` step placed under a driver member connects to that member's CDP/VNC/MCP endpoint; a `command:` step runs in that member's venue. Members are brought up by the same deploy verbs and are never check-live'd (instruments, not subjects). A GROUP diff --git a/src/content/docs/recipes/check/check/live-probe-verbs.md b/src/content/docs/recipes/check/check/live-probe-verbs.md index 6976df5d..62113f77 100644 --- a/src/content/docs/recipes/check/check/live-probe-verbs.md +++ b/src/content/docs/recipes/check/check/live-probe-verbs.md @@ -219,13 +219,13 @@ auto-picks. plan: - check: the MCP server answers a ping id: mcp-ping - context: [deploy] + context: [runtime] mcp: ping timeout: 10s # optional; default 30s - check: the MCP server lists its notebook tools id: mcp-list-tools - context: [deploy] + context: [runtime] mcp: list-tools stdout: - contains: insert_cell # plaintext "name\tdescription" per line @@ -233,7 +233,7 @@ plan: - check: calling list_notebooks succeeds (no IsError) id: mcp-call-tool - context: [deploy] + context: [runtime] mcp: method: call tool: list_notebooks # required @@ -242,7 +242,7 @@ plan: - check: reading a resource returns a non-empty body id: mcp-read-resource - context: [deploy] + context: [runtime] mcp: method: read uri: file:///tmp/example.txt diff --git a/src/content/docs/recipes/check/check/verb-catalog.md b/src/content/docs/recipes/check/check/verb-catalog.md index c771f2bc..fb062ed9 100644 --- a/src/content/docs/recipes/check/check/verb-catalog.md +++ b/src/content/docs/recipes/check/check/verb-catalog.md @@ -140,7 +140,7 @@ schema; a scalar value is the verb's primary-field shorthand (`file: /x`, | `skip: true` | Always skip this check (reported but doesn't fail the run). | | `exclude_distro: [, ...]` | Skip the check when any of the image's `distro:` tags matches an entry. Use for probes that only apply on some distros (e.g. `file: /usr/bin/fastfetch` is valid on Fedora/Arch/Debian but fastfetch is dropped from Ubuntu 24.04's noble main). Matched against the image's full distro list (`["ubuntu:24.04", "ubuntu", "debian"]`), so either `ubuntu:24.04` or `ubuntu` matches. See `charly/checkspec.go:Op.ExcludeDistros` and `charly/checkrun.go:runOne`. | | `timeout: "5s"` | Per-check timeout (http, addr). | -| `context: [build\|deploy\|runtime]` | Which contexts the step runs in (a list). Build steps run in `charly check box`; deploy/runtime steps need a live deployment. | +| `context: [build\|deploy\|runtime]` | Which contexts the step runs in (a list). **The check engine activates exactly two of them**: `build` under `charly check box`, `runtime` under `charly check live` (`sdk/checkkit/checkkit.go:37`; `sdk/kit/runner.go:225`). An unscoped step with a plugin-envelope verb runs in BOTH. `deploy` is **not** a mode any check runner has: on a `check:`/`agent-check:` step it is a no-op in both modes (the step is skipped, so a plan relying on it asserts nothing — `opencharly/opencharly#413`, `opencharly/plugin-check#111`); it keeps its meaning on a `run:` step, where it names the install timeline. Use `[runtime]` for a live-only assertion and `[build]` for a build-artifact assertion. | | `eventually: "30s"` | POLL until the check passes, re-running it every `retry_interval` until this deadline. The FIRST pass wins and returns immediately; on failure the LAST attempt is reported, annotated `(after N attempts over D)`. Absent means the check runs exactly once. | | `retry_interval: "2s"` | Poll interval for `eventually:`. Default 1s. Clamped if it exceeds the deadline. | @@ -190,7 +190,7 @@ verb. One code per test. See [`references/authoring-gotchas.md`](/recipes/check/ |---------|-------------|--------------| | `candy` | `plan:` steps in the candy body, `candy//charly.yml` (build context) | `charly check box` + `charly check live` | | `box` | `plan:` steps in the box body, `charly.yml` (build context) | `charly check box` + `charly check live` | -| `deploy` | a `plan:` step with `context: [deploy]`, or a local `charly.yml` overlay step | `charly check live ` only (deploy-context steps need a running deployment with port mappings, volumes, and resolved runtime variables) | +| `deploy` | a `plan:` step in the deployment node's own `plan:` (a local `charly.yml` overlay step), or a step authored `context: [runtime]` | `charly check live ` only (these steps need a running deployment with port mappings, volumes, and resolved runtime variables). **Not** a step scoped `context: [deploy]`: the engine activates `build` (box mode) and `runtime` (live mode) only, so a `check:` step carrying `[deploy]` is skipped in both modes and asserts nothing (`opencharly/opencharly#413`) | The `ai.opencharly.description` label carries the collected plan steps from all three sections with `origin:` annotations (`candy:`, `box:`, `deploy-default`, diff --git a/src/content/docs/recipes/check/console-automation.md b/src/content/docs/recipes/check/console-automation.md index 26e481b2..3b5a9219 100644 --- a/src/content/docs/recipes/check/console-automation.md +++ b/src/content/docs/recipes/check/console-automation.md @@ -55,7 +55,7 @@ ECHOES the typed line, so waiting for the command text — or for the marker as SUBSTRING — passes the instant the command is typed, BEFORE it runs, certifying completion that never happened. So the engine types `command; echo ` and waits for a screen LINE whose trimmed text EQUALS the marker: only the shell's -OWN output produces that. It is a condition poll, never a sleep (R4). +OWN output produces that. It is a condition poll, never a sleep (R3). ## luks-unlock — the encrypted-install first boot @@ -79,7 +79,7 @@ single anchors with explicit DATA: node id; the OBSERVED outcome selects the branch. No transition → `next:`. - **while loop** — a transition pointing BACK to an earlier node is a loop, bounded by `flow_max_loops` (per node) and `flow_max_steps` (whole flow). A condition - that never becomes true FAILS naming `max_loops` — the R4-safe "repeat until". + that never becomes true FAILS naming `max_loops` — the R3-safe "repeat until". A node action may be a raw input (`key`/`combo`/`text`) or a shell `command:` (run in the open terminal, output OCR-read). The flow validates WITHOUT a device. diff --git a/src/content/docs/recipes/check/crabbox.md b/src/content/docs/recipes/check/crabbox.md index 89096ea8..73550da9 100644 --- a/src/content/docs/recipes/check/crabbox.md +++ b/src/content/docs/recipes/check/crabbox.md @@ -14,7 +14,7 @@ description: "the `crabbox:` check verb — probe the Crabbox CLI or its local c `crabbox:` probes the [Crabbox](https://github.com/openclaw/crabbox) CLI and its optional local Node.js/PostgreSQL coordinator, served out-of-process over go-plugin gRPC by `opencharly/plugin-crabbox`. -Install the CLI with [`/charly-tools:crabbox`](/recipes/tools/crabbox/) (opencharly/layer-crabbox) +Install the CLI with [`/charly-tools:crabbox-cli`](/recipes/tools/crabbox-cli/) (opencharly/layer-crabbox) and the coordinator with [`/charly-crabbox:crabbox-coordinator`](/recipes/crabbox/crabbox-coordinator/) (opencharly/pod-crabbox). @@ -34,7 +34,14 @@ and the coordinator with [`/charly-crabbox:crabbox-coordinator`](/recipes/crabbo |---|---| | In-venue CLI — credential-free | `version` (`crabbox --version`) `providers` (`crabbox providers`) `config` (`crabbox config show`) `doctor` (`crabbox doctor` — needs NO broker configured, or a REACHABLE one) | | Coordinator HTTP probe (host-side, port 8080) | `health` (`/v1/health`) `ready` (`/v1/ready`) | -| In-venue CLI — broker-backed (requires `crabbox login` in the venue) | `leases` (`crabbox status --all`) `usage` (`crabbox usage`) `events` (`crabbox events `) `logs` (`crabbox logs `) | +| In-venue CLI — broker-backed (requires `crabbox login` in the venue) | `leases` (`crabbox list` — the ID/NAME/STATE/TYPE/IP inventory) `usage` (`crabbox usage`) `events` (`crabbox events `) `logs` (`crabbox logs `) | + +Per-lease state is `crabbox status ` — *"Show lease state; add +`--wait` to block until ready"*. It is deliberately NOT this verb's `leases` +method: `status` is not an enumerator, and it has **no `--all` flag** (measured +on the pinned v0.78.0: `crabbox status --all` exits *"flag provided but not +defined: -all"*), so the earlier prose that documented `leases` as +`crabbox status --all` named a command that cannot run. All methods are read-only — there are no mutating methods in this first cut. @@ -47,6 +54,7 @@ All methods are read-only — there are no mutating methods in this first cut. | `timeout` | HTTP probe timeout (default 10s) | | `json_path` | dotted path into the response; stdout becomes that value | | `run_id` | run identifier for the `events`/`logs` methods | +| `provider` | the provider to select for the methods whose CLI command DEFINES `--provider` (`doctor`, `leases`) | ## Scalar shorthand @@ -68,3 +76,21 @@ broker — the venue must hold a prior `crabbox login` (shared-token: `crabbox login --url http://127.0.0.1:8080 --token-stdin`). `doctor` exits nonzero when a broker is configured but unreachable — gate it on coordinator readiness first. + +## Selecting a provider + +`provider:` is passed through as `--provider ` for the two methods whose CLI +command defines the flag — `doctor` and `leases` (`crabbox list`) — and nowhere +else, because attaching it to a command that does not define it is an argument +error, not a selection. Measured on the pinned v0.78.0: + +``` +$ crabbox doctor --provider local-container -> ok provider-selection provider=local-container source=flag selected=true +$ crabbox list --provider aws -> the ID/NAME/STATE/TYPE/IP inventory +$ crabbox usage --provider aws -> flag provided but not defined: -provider +$ crabbox providers --provider aws -> flag provided but not defined: -provider +``` + +Unset, the CLI keeps its own configured/ambient selection — which is what every +step got before this input existed, so an authored step that does not name a +provider behaves exactly as it did. diff --git a/src/content/docs/recipes/check/dbus.md b/src/content/docs/recipes/check/dbus.md index ee4590ee..dcd79529 100644 --- a/src/content/docs/recipes/check/dbus.md +++ b/src/content/docs/recipes/check/dbus.md @@ -36,12 +36,12 @@ when the step carries dbus-exclusive fields (`dest:`, `path:`, `member:`, `arg:` `text:`) — those live INSIDE the `dbus:` map. The shared matchers (`stdout:`, `stderr:`, `exit_status:`) and `description:` (the notify body, doubling as the step's report label) stay siblings of the `dbus:` key. All `dbus:` steps are -**deploy-context only** (they need a running session bus), so author them with -`context: [deploy]`. See [`/charly-check:check`](/recipes/check/check/) for the full YAML shape. Example: +**live-mode only** (they need a running session bus), so author them with +`context: [runtime]`. See [`/charly-check:check`](/recipes/check/check/) for the full YAML shape. Example: ```yaml - check: the notifications service is on the session bus - context: [deploy] + context: [runtime] dbus: list stdout: contains: org.freedesktop.Notifications @@ -72,7 +72,7 @@ exit 0 (run them as `run:` steps). All steps are deploy-context only. ```yaml - check: a desktop notification is delivered - context: [deploy] + context: [runtime] dbus: method: notify text: Build Complete # notification summary (dbus-exclusive, in the map) @@ -86,7 +86,7 @@ appears via the running notification daemon (swaync or mako). ```yaml - check: the notifications service reports its capabilities - context: [deploy] + context: [runtime] dbus: method: call dest: org.freedesktop.Notifications @@ -101,7 +101,7 @@ Calls an arbitrary D-Bus method on the session bus and returns its reply. ```yaml - check: the session bus has the expected services registered - context: [deploy] + context: [runtime] dbus: list stdout: contains: org.freedesktop.Notifications @@ -113,7 +113,7 @@ Lists all registered services on the venue's session bus. ```yaml - check: the notifications object exposes the Notify method - context: [deploy] + context: [runtime] dbus: method: introspect dest: org.freedesktop.Notifications diff --git a/src/content/docs/recipes/check/jetkvm.md b/src/content/docs/recipes/check/jetkvm.md index 033f4fff..bf536961 100644 --- a/src/content/docs/recipes/check/jetkvm.md +++ b/src/content/docs/recipes/check/jetkvm.md @@ -125,7 +125,7 @@ A ~15-screen wizard as a chain of `check:` steps pays that per screen; the drive pays it once. The recipe is DATA, supplied by a `kind: jetkvm` device entity — the plugin is -installer-agnostic (R3), so one plugin drives any text console. Example: +installer-agnostic (R2), so one plugin drives any text console. Example: ```yaml omarchy-kvm: diff --git a/src/content/docs/recipes/check/libvirt.md b/src/content/docs/recipes/check/libvirt.md index ba6f691f..4369284a 100644 --- a/src/content/docs/recipes/check/libvirt.md +++ b/src/content/docs/recipes/check/libvirt.md @@ -47,7 +47,7 @@ siblings of the `libvirt:` key: the shared matchers (`stdout:`, `stderr:`, `exit_status:`) AND the `target:` snapshot name (a genuinely shared `#Op` modifier the `snapshot/*` methods read). A query/probe is a `check:` step; an action that changes domain state (send-key, passwd, snapshot create/revert) is a `run:` step. -**`context: [deploy]`** — the verb needs a running VM; under `charly check +**`context: [runtime]`** — the verb needs a running VM; under `charly check box` (no running VM) it skips. Run a candy's baked `libvirt:` steps against a live VM deployment with `charly check live --filter libvirt`. @@ -158,13 +158,13 @@ probe is a `check:` step, a state-changing action is a `run:` step. Run with - check: the session lists the arch domain id: libvirt-domains-listed libvirt: list - context: [deploy] + context: [runtime] stdout: contains: arch - check: the domain reports a reachable guest agent id: libvirt-agent-reachable libvirt: info - context: [deploy] + context: [runtime] stdout: contains: "Agent: true" @@ -175,7 +175,7 @@ probe is a `check:` step, a state-changing action is a `run:` step. Run with method: screenshot artifact: /tmp/fb.png artifact_not_uniform: true - context: [deploy] + context: [runtime] # Keyboard injection via libvirt (alternate path to the `spice: key` verb). - run: switch to VT2 via a libvirt key chord @@ -191,7 +191,7 @@ probe is a `check:` step, a state-changing action is a `run:` step. Run with libvirt: method: qmp text: query-status - context: [deploy] + context: [runtime] stdout: contains: running @@ -201,7 +201,7 @@ probe is a `check:` step, a state-changing action is a `run:` step. Run with libvirt: method: guest/exec command: uname -a - context: [deploy] + context: [runtime] stdout: contains: Linux diff --git a/src/content/docs/recipes/check/openclaw.md b/src/content/docs/recipes/check/openclaw.md index 0b30c8a1..814fae88 100644 --- a/src/content/docs/recipes/check/openclaw.md +++ b/src/content/docs/recipes/check/openclaw.md @@ -1,6 +1,6 @@ --- title: "openclaw" -description: "the `openclaw:` check verb — probe a running OpenClaw 2.0 gateway (health/ready/startup via the /healthz /readyz /startupz HTTP probe endpoints, status/models/channels/version via the in-venue CLI), served out-of-process by plugin-openclaw." +description: "the `openclaw:` check verb — probe a running OpenClaw 2.0 gateway (health/ready/startup via the /healthz /readyz /startupz HTTP probe endpoints, status/models/channels/version via the in-venue CLI), served out-of-process by plugin-openclaw; the probe surface is verified against npm `openclaw@2026.9.8`." --- @@ -13,8 +13,9 @@ description: "the `openclaw:` check verb — probe a running OpenClaw 2.0 gatewa `openclaw:` probes a running [OpenClaw](https://openclaw.ai) 2.0 gateway, served out-of-process over go-plugin gRPC by `opencharly/plugin-openclaw`. +The probe surface below is verified against npm `openclaw@2026.9.8`. Install the gateway itself with [`/charly-openclaw:openclaw`](/recipes/openclaw/openclaw/) -(opencharly/pod-openclaw). +(opencharly/layer-openclaw). ## Why it is not the `http:` verb @@ -35,7 +36,7 @@ for what `http:` structurally cannot do: | Group | Methods | |---|---| -| HTTP probes (host-side) | `health` (`/healthz` liveness) `ready` (`/readyz` readiness) `startup` (`/startupz` startup) | +| HTTP probes (host-side) | `health` (`/healthz` — liveness only) `ready` (`/readyz` — readiness, and the endpoint that reports recorded terminal database failures) `startup` (`/startupz` — startup progress) | | In-venue CLI | `status` (`openclaw status --all`) `models` (`openclaw models status`) `channels` (`openclaw channels status`) `version` (`openclaw --version`) | All methods are read-only — there are no mutating methods in this first cut. diff --git a/src/content/docs/recipes/check/record.md b/src/content/docs/recipes/check/record.md index 1137750e..5f020595 100644 --- a/src/content/docs/recipes/check/record.md +++ b/src/content/docs/recipes/check/record.md @@ -59,8 +59,9 @@ record-exclusive fields (`record_name:`, `record_mode:`, `record_fps:`, the `record:` map. Only the shared matchers (`stdout:`, `stderr:`, `exit_status:`) and `context:`/`id:`/`timeout:` stay siblings. All `record:` steps need a running container, so author them with `context: [runtime]` — the live phase, where the -plugin resolves. (`context: [deploy]` is skipped in live mode; no context runs them -in the box phase, where the plugin is unavailable.) +plugin resolves. (`context: [deploy]` is a no-op in BOTH modes — the engine activates `build` for +box and `runtime` for live — and no context value makes a live-only verb resolvable +in the box phase, where its plugin is unavailable.) ```yaml - check: a terminal recording starts diff --git a/src/content/docs/recipes/check/spice.md b/src/content/docs/recipes/check/spice.md index e447d7ba..b3e9564b 100644 --- a/src/content/docs/recipes/check/spice.md +++ b/src/content/docs/recipes/check/spice.md @@ -67,7 +67,7 @@ the step carries spice-exclusive fields — those live INSIDE the `spice:` map: The artifact validators (`artifact_min_bytes:`, `artifact_min_dimensions:`, `artifact_not_uniform:`) are spice-exclusive too, so they live inside the `spice:` map; only the shared matchers (`stdout:`, `stderr:`, `exit_status:`) and -`context:`/`timeout:`/`id:` stay siblings of the `spice:` key. **`context: [deploy]`** +`context:`/`timeout:`/`id:` stay siblings of the `spice:` key. **`context: [runtime]`** — the verb needs a running VM; under `charly check box` (no running VM) it skips, and a SPICE-less deployment (e.g. a GPU desktop with no `` device) is reported N/A SKIP. @@ -85,7 +85,7 @@ Example — each step is an ordered list item under the candy/box `plan:`: - check: the SPICE server completes the handshake and enumerates channels id: spice-handshake spice: status - context: [deploy] + context: [runtime] stdout: - contains: ok - contains: "inputs: ready" @@ -95,7 +95,7 @@ Example — each step is an ordered list item under the candy/box `plan:`: method: screenshot artifact: /tmp/spice-shot.png artifact_not_uniform: true - context: [deploy] + context: [runtime] ``` Input injection is authored as `run:` steps (each one mutates guest state) — a @@ -116,7 +116,7 @@ console login sequence walks the form with `spice: key` / `spice: type` steps: ```yaml - check: SPICE video recording starts on the VM display id: spice-rec-start - context: [deploy] + context: [runtime] spice: method: record action: start @@ -124,11 +124,11 @@ console login sequence walks the form with `spice: key` / `spice: type` steps: fps: 5 - check: a desktop-visible action runs during the capture id: spice-rec-drive - context: [deploy] + context: [runtime] command: "notify-send 'demo' 'capturing' 2>/dev/null || true; sleep 3" - check: the recording stops and a real MJPEG stream lands on the HOST id: spice-rec-stop - context: [deploy] + context: [runtime] spice: method: record action: stop diff --git a/src/content/docs/recipes/check/transcode.md b/src/content/docs/recipes/check/transcode.md new file mode 100644 index 00000000..2e2c5af8 --- /dev/null +++ b/src/content/docs/recipes/check/transcode.md @@ -0,0 +1,92 @@ +--- +title: "transcode" +description: "The `transcode:` capture-evidence pipeline verb — transcode a captured MJPEG stream into an H.264 MP4 with the host's `ffmpeg`, served out-of-process by candy/plugin-media." +--- + + + +*Recipe card from the `charly-check` plugin (Commands — runtime CLI verbs).* + +# transcode — capture-evidence MJPEG to H.264 MP4 + +The `transcode:` pipeline verb converts a captured MJPEG stream into an +H.264/yuv420p MP4 with the **host's** `ffmpeg`. It is **NOT a host +`charly check` subcommand** — it is a declarative pipeline word served +out-of-process by its plugin (`candy/plugin-media`), parallel to the +`record:`/`spice:` capture verbs. The MJPEG artifact a capture session +flushes (e.g. `spice: record`) is already host-side, so the provider +reaches only the local filesystem and the host `ffmpeg` — no +reverse-channel venue machinery. + +**Served out-of-process — no host CLI subcommand.** The host dispatches +the `transcode:` word through the provider registry exactly like a +built-in (`ResolveVerb("transcode")` → the out-of-process gRPC provider +→ `Provider.Invoke` with the full `Op`), executing in the **evidence +phase** BEFORE venue teardown. Authoring is unchanged from a built-in +verb: you write `transcode: mp4`, never `plugin: transcode`. + +## Authoring a `transcode:` step + +The word is authored in an instrument's `pipeline:` list. The scalar form +is the `to` primary-field shorthand (`transcode: mp4` == +`transcode: {to: mp4}`); the exclusive fields live INSIDE the `transcode:` +map. + +```yaml +instrument: + - id: screen + phase: [live] + spice: {method: session, fps: 5} + pipeline: + - transcode: {to: mp4} # map form + - transcode: mp4 # scalar-sugar equal (primary field: to) +``` + +| Field | Meaning | +|-------|---------| +| `to` | container format; only `mp4` is supported (the default; empty/omitted means mp4) | +| `artifact` | host path the MP4 is written to; empty → derived from the source (`.mp4`) | +| `artifact_min_bytes` | post-transcode artifact-size assertion (the output MP4 must be at least N bytes) | +| `artifact_not_uniform` | SOURCE-frame motion assertion, evaluated on the SOURCE MJPEG frames (pre-encode) | + +The shared matchers (`exit_status`/`stdout`/`stderr`) and `timeout` stay +on core `#Op` and are self-evaluated by the provider against the ffmpeg +run. + +## Behavior + +The provider runs the one canonical invocation (even-dimension scale + +timescale pin for robustness): + +``` +ffmpeg -y -loglevel error -i -vf scale=trunc(iw/2)*2:trunc(ih/2)*2 \ + -c:v libx264 -pix_fmt yuv420p -video_track_timescale 1000 +``` + +**`artifact_not_uniform` runs on the SOURCE MJPEG frames (pre-encode), +NEVER on the transcoded output** — exact hashes of x264-encoded frames +are vacuous (QP noise). The provider splits the source stream into its +constituent JPEGs, decodes a stream-wide sample, and requires at least +two distinct frame signatures: identical frames FAIL honestly (a real +capture shows motion), differing frames PASS. + +**DEPENDENCY:** requires host `ffmpeg` with `libx264` + `yuv420p` +support. + +## Verification + +`plan:` `check:` runs the deterministic command form with the literal +`true` target (the plugin envelope is internal only; a live transcode +needs a session artifact). The live R10 witness is the cutover-A +nested-capture bed that produces a session MJPEG and transcodes it. + +## Cross-References + +- [`/charly-check:check`](/recipes/check/check/) — the check-step surface the `transcode:` word is + authored through, and the capture-evidence pipeline it runs in. +- [`/charly-check:record`](/recipes/check/record/) — the `record:` verb that produces the source + MJPEG artifact the transcode consumes. +- [`/charly-check:spice`](/recipes/check/spice/) — `spice: {method: record}` flushes the source + MJPEG the transcode consumes. +- [`/charly-internals:plugin`](/recipes/internals/plugin/) — the plugin/provider model (out-of-process + placement, the per-plugin CUE-schema contract). diff --git a/src/content/docs/recipes/check/vnc.md b/src/content/docs/recipes/check/vnc.md index aad8dd74..15d1077c 100644 --- a/src/content/docs/recipes/check/vnc.md +++ b/src/content/docs/recipes/check/vnc.md @@ -39,13 +39,13 @@ bare-method step (`vnc: status`), or the `method:` key of the `vnc:` map when th carries vnc-exclusive fields (`x:`, `y:`, `button:`, `text:`, `key:`, `artifact:`, `artifact_min_bytes:`, …) — those live INSIDE the `vnc:` map. Only the shared matchers (`stdout:`, `stderr:`, `exit_status:`) and `context:`/`id:`/`timeout:` stay siblings. -All `vnc:` steps are **deploy-context only** (they need a running deployment), so -author them with `context: [deploy]`. See [`/charly-check:check`](/recipes/check/check/) for the full YAML +All `vnc:` steps are **live-mode only** (they need a running deployment), so +author them with `context: [runtime]`. See [`/charly-check:check`](/recipes/check/check/) for the full YAML shape. Example: ```yaml - check: a non-empty VNC framebuffer is captured - context: [deploy] + context: [runtime] vnc: method: screenshot artifact: /tmp/vnc.png @@ -97,14 +97,14 @@ in `candy/plugin-vnc`. The host retains only the endpoint pre-resolution and ## Methods -Each method below is a `vnc:` plan step authored with `context: [deploy]`; run a +Each method below is a `vnc:` plan step authored with `context: [runtime]`; run a candy's baked steps with `charly check live --filter vnc` (add `-i ` for a specific instance). ### Screenshot ```yaml - check: a non-empty VNC framebuffer is captured - context: [deploy] + context: [runtime] vnc: method: screenshot artifact: /tmp/desktop.png # host path for the captured PNG @@ -162,7 +162,7 @@ Valid key names: Return, Escape, Tab, BackSpace, Delete, Home, End, Page_Up, Pag ### Status ```yaml - check: the VNC server reports its desktop and resolution - context: [deploy] + context: [runtime] vnc: status stdout: contains: "1920x1080" @@ -245,7 +245,7 @@ Some websites (notably Google sign-in) detect and block CDP-based input. VNC pro ```yaml # 1. Locate via cdp: coords — reports both viewport and desktop coords for '#identifierId' - check: the email field is located - context: [deploy] + context: [runtime] cdp: method: coords tab: "1" @@ -287,7 +287,7 @@ desktop `x:`/`y:`: ```yaml - check: the sync button is located - context: [deploy] + context: [runtime] cdp: method: coords tab: "1" @@ -316,13 +316,13 @@ VNC screenshots work correctly on NVIDIA headless for images using `sway-desktop Both the `vnc: screenshot` step and the `wl: screenshot` step (grim, always works) work on NVIDIA headless: ```yaml - check: a non-empty VNC framebuffer is captured (works with pixman + DPMS fix) - context: [deploy] + context: [runtime] vnc: method: screenshot artifact: /tmp/out.png artifact_min_bytes: 5000 - check: a non-empty Wayland screenshot is captured (grim) - context: [deploy] + context: [runtime] wl: method: screenshot artifact: /tmp/wl-out.png diff --git a/src/content/docs/recipes/coder/arch-coder.md b/src/content/docs/recipes/coder/arch-coder.md index c9166cfd..9be8f8ff 100644 --- a/src/content/docs/recipes/coder/arch-coder.md +++ b/src/content/docs/recipes/coder/arch-coder.md @@ -162,7 +162,6 @@ Conflicts with [`/charly-coder:fedora-coder`](/recipes/coder/fedora-coder/) / [` - [`/charly-coder:debian-coder`](/recipes/coder/debian-coder/) — deb-family sibling on Debian 13. - [`/charly-coder:ubuntu-coder`](/recipes/coder/ubuntu-coder/) — deb-family sibling on Ubuntu 24.04 (adopt mode). - [`/charly-coder:charly-arch`](/recipes/coder/charly-arch/) — slimmer Arch alternative with just the charly toolchain (no AI CLIs or DevOps tooling). -- [`/charly-openclaw:openclaw-desktop`](/recipes/openclaw/openclaw-desktop/) — adds a browser-streamed Wayland desktop (plus the openclaw gateway, AI CLIs, and a CPU ollama) with the same rootless charly toolchain. ## Related layers diff --git a/src/content/docs/recipes/coder/charly-arch.md b/src/content/docs/recipes/coder/charly-arch.md index ac39e4ce..5f0eead8 100644 --- a/src/content/docs/recipes/coder/charly-arch.md +++ b/src/content/docs/recipes/coder/charly-arch.md @@ -199,7 +199,6 @@ packages and scripts per distro. - [`/charly-distros:arch`](/recipes/distros/arch/) — parent base image - [`/charly-distros:charly-fedora`](/recipes/distros/charly-fedora/) — Fedora counterpart, same candies, same rootless posture - [`/charly-coder:fedora-coder`](/recipes/coder/fedora-coder/) — kitchen-sink dev sibling (adds coding CLIs + DevOps) -- [`/charly-openclaw:openclaw-desktop`](/recipes/openclaw/openclaw-desktop/) — streaming-desktop counterpart (charly toolchain + browser-accessible Wayland); shares the rootless-first posture - [`/charly-distros:githubrunner`](/recipes/distros/githubrunner/) — self-hosted GitHub Actions runner; same uid=1000 posture ## Related Commands diff --git a/src/content/docs/recipes/coder/charly-mcp.md b/src/content/docs/recipes/coder/charly-mcp.md index d5deedb5..1a2f1fcd 100644 --- a/src/content/docs/recipes/coder/charly-mcp.md +++ b/src/content/docs/recipes/coder/charly-mcp.md @@ -123,8 +123,7 @@ Six deploy-scope tests ship with the candy: | `mcp-charly-call-list-images` | MCP `call box.list.boxes` returns boxes — **proves the bind-mount OR auto-fallback is working** (matches "fedora" either way, since upstream opencharly/charly always has a `fedora` image) | All `mcp:` checks pass `mcp_name: charly` so they stay unambiguous on -boxes that also expose `jupyter` or `chrome-devtools` servers -(e.g. [`/charly-openclaw:openclaw-desktop`](/recipes/openclaw/openclaw-desktop/)). +boxes that also expose `jupyter` or `chrome-devtools` servers. ## Host networking caveat diff --git a/src/content/docs/recipes/coder/codex.md b/src/content/docs/recipes/coder/codex.md index 87ea6ebf..e0faf906 100644 --- a/src/content/docs/recipes/coder/codex.md +++ b/src/content/docs/recipes/coder/codex.md @@ -28,7 +28,6 @@ my-box: ## Used In Boxes -- `openclaw-full` (via `openclaw-full` metalayer) ## Related Candies - [`/charly-coder:nodejs`](/recipes/coder/nodejs/) — Required Node.js runtime parent dependency diff --git a/src/content/docs/recipes/coder/direnv.md b/src/content/docs/recipes/coder/direnv.md index eef5594e..b506e4d5 100644 --- a/src/content/docs/recipes/coder/direnv.md +++ b/src/content/docs/recipes/coder/direnv.md @@ -39,13 +39,16 @@ Provides the `direnv` binary AND the per-shell hook installation for automatic e ```yaml shell: init: | - eval "$(direnv hook ${SHELL_NAME})" # bash/zsh/sh — POSIX-style + eval "$(direnv hook ${SHELL_NAME})" # bash/zsh — POSIX-style fish: init: | direnv hook fish | source # fish — different syntax + sh: {} # sh opted OUT — direnv has no sh hook ``` -Container images get `/etc/profile.d/charly-direnv-.sh` and `/etc/fish/conf.d/charly-direnv.fish` emitted at `charly box build` time. `target: local` host deploys get a managed-block in `~/.bashrc` / `~/.zshrc` plus `~/.config/fish/conf.d/charly-direnv.fish` at `charly fleet add` time, only for shells the runtime probe finds. The fish hook lands in `~/.config/fish/conf.d/charly-direnv.fish` (its own conf.d drop-in), so it works without editing `~/.config/fish/config.fish`. +The emitter is VENUE-SHAPED. Container images get `/etc/profile.d/charly-direnv-.sh` (bash/zsh only) and `/etc/fish/conf.d/charly-direnv.fish` emitted at `charly box build` time; each POSIX drop-in is runtime-guarded to its own shell because `/etc/profile` sources every `*.sh` in every POSIX login shell. `target: local` host and `target: vm` guest deploys instead get a managed block in `~/.bashrc` / `~/.zshrc` plus `~/.config/fish/conf.d/charly-direnv.fish` written at `charly deploy add` time — for every shell the `shell:` block defines, with no per-host shell probe. The fish hook lands in the per-user conf.d drop-in (its own file), so it works without editing `~/.config/fish/config.fish`. + +**The plan asserts each venue's OWN shape.** The baked drop-ins are `context: [build]` assertions (`charly box build` artifacts); the deploy venue's wiring is one `context: [runtime]` assertion — the live mode's context, because a `check:` step scoped `context: [deploy]` is active in NEITHER check mode (`opencharly/opencharly#413`). That runtime step branches on the venue marker (`/etc/profile.d/charly-direnv-bash.sh`): an image venue must carry the baked drop-ins, a host/VM venue must carry the managed `~/.bashrc` / `~/.zshrc` blocks and the per-user fish drop-in, and the `sh:{}` opt-out must hold at both. An unscoped image-shaped assertion run in a `local:` venue is exactly the defect this shape prevents (`opencharly/layer-direnv#7`). The primary use case in OpenCharly is the `.secrets` workflow: `.envrc` calls `eval "$(charly secrets gpg env)"` which decrypts a GPG-encrypted `.secrets` file in memory and exports the variables — no plaintext on disk. No external `direnvrc` dependency needed. diff --git a/src/content/docs/recipes/coder/fedora-coder.md b/src/content/docs/recipes/coder/fedora-coder.md index 2407559a..59f3e696 100644 --- a/src/content/docs/recipes/coder/fedora-coder.md +++ b/src/content/docs/recipes/coder/fedora-coder.md @@ -11,8 +11,7 @@ description: "Kitchen-sink development box: coding + AI-coding CLIs + DevOps too The everyday-development counterpart to [`/charly-distros:charly-fedora`](/recipes/distros/charly-fedora/): all the coding + AI + DevOps tooling a developer needs in one box, no desktop, -no streaming. Distinct from `openclaw-desktop` (which adds the -browser-streamed Wayland desktop) — `fedora-coder` is headless and +no streaming. `fedora-coder` is headless and meant to be accessed via `ssh -p 2222` or `charly shell`. > **Location:** lives in the **`opencharly/distro-fedora`** repo (git submodule at @@ -85,8 +84,7 @@ normal `-p host:container` remapping (e.g. running `arch-coder` alongside No `uid:` / `gid:` / `user:` / `security:` override — inherits `1000/1000/user` from `defaults` and the candy-level security from -[`/charly-distros:container-nesting`](/recipes/distros/container-nesting/). Rootless-first by design (shares this -posture with [`/charly-openclaw:openclaw-desktop`](/recipes/openclaw/openclaw-desktop/)). +[`/charly-distros:container-nesting`](/recipes/distros/container-nesting/). Rootless-first by design. ## Resolved security posture (OCI label) @@ -134,8 +132,8 @@ includes `rpmfusion` explicitly. `supervisord`, `language-runtimes`, and `uv` all use system python3 from RPM, not the conda-forge pixi env, so none of them declares `require: python`. System Python is available via `language-runtimes` (`python3-devel` + -`python3-ramalama`). See the "Key Rules" note in the project rulebook (`AGENTS.md` / `CLAUDE.md`) ("don't declare -defensive deps"). +`python3-ramalama`). Don't declare a defensive dependency: a `require:` that nothing in +the candy uses is an unproven "to be safe" caution, not a need. **`uv` is a direct-download binary** (no pixi involvement). Lives at `/usr/local/bin/uv` and `/usr/local/bin/uvx`, extracted from the @@ -251,7 +249,6 @@ All four produce the same daily-dev surface (sshd on 2222, charly-mcp on 18765, ## Related Boxes -- [`/charly-openclaw:openclaw-desktop`](/recipes/openclaw/openclaw-desktop/) — sibling rootless-first power-user box; same security posture + container-nesting, but adds the streaming desktop. Prefer when you want browser-accessible GUI + dev tools. - [`/charly-distros:charly-fedora`](/recipes/distros/charly-fedora/) — minimal charly toolchain (no coding CLIs, no DevOps), also uid=1000 with sudo. - [`/charly-coder:charly-arch`](/recipes/coder/charly-arch/) — Arch Linux counterpart of charly-fedora. - [`/charly-distros:githubrunner`](/recipes/distros/githubrunner/) — self-hosted GitHub Actions runner; same uid=1000 posture. @@ -273,7 +270,7 @@ All four produce the same daily-dev surface (sshd on 2222, charly-mcp on 18765, - Building, deploying, or troubleshooting the `fedora-coder` box. - Picking the right power-user base image for a coding/dev workload (this - vs. `charly-fedora` vs. `charly-arch` vs. `openclaw-desktop`). + vs. `charly-fedora` vs. `charly-arch`). - Understanding the rootless-first architectural pattern shared by the four power-user boxes (kernel RCA belongs in [`/charly-distros:container-nesting`](/recipes/distros/container-nesting/); the composition that proves it works diff --git a/src/content/docs/recipes/coder/gemini.md b/src/content/docs/recipes/coder/gemini.md index 35df2ab0..0d9588af 100644 --- a/src/content/docs/recipes/coder/gemini.md +++ b/src/content/docs/recipes/coder/gemini.md @@ -28,12 +28,11 @@ my-box: ## Used In Boxes -- `openclaw-full` (via `openclaw-full` metalayer) ## Related Candies - [`/charly-coder:nodejs`](/recipes/coder/nodejs/) — required runtime dependency -- [`/charly-coder:claude-code`](/recipes/coder/claude-code/) — sibling AI CLI in openclaw-full and hermes-full -- [`/charly-coder:codex`](/recipes/coder/codex/) — sibling AI CLI in openclaw-full and hermes-full +- [`/charly-coder:claude-code`](/recipes/coder/claude-code/) — sibling AI CLI in hermes-full +- [`/charly-coder:codex`](/recipes/coder/codex/) — sibling AI CLI in hermes-full ## Related Commands - [`/charly-build:secrets`](/recipes/build/secrets/) — provision Gemini API credentials for the CLI diff --git a/src/content/docs/recipes/coder/gh.md b/src/content/docs/recipes/coder/gh.md index 9a50e524..7f5009de 100644 --- a/src/content/docs/recipes/coder/gh.md +++ b/src/content/docs/recipes/coder/gh.md @@ -82,7 +82,6 @@ my-box: ## Used In Boxes - [`/charly-coder:charly-arch`](/recipes/coder/charly-arch/), [`/charly-distros:charly-fedora`](/recipes/distros/charly-fedora/), [`/charly-coder:fedora-coder`](/recipes/coder/fedora-coder/) — power-user boxes that compose gh explicitly -- [`/charly-openclaw:openclaw-desktop`](/recipes/openclaw/openclaw-desktop/) — streaming-desktop sibling - Any box composing `hermes-full` ## Related Candies diff --git a/src/content/docs/recipes/coder/kimi.md b/src/content/docs/recipes/coder/kimi.md index 857895b1..7264a1a8 100644 --- a/src/content/docs/recipes/coder/kimi.md +++ b/src/content/docs/recipes/coder/kimi.md @@ -28,7 +28,7 @@ my-dev: ## Used In Boxes - No enabled boxes use this candy yet — composition into the AI-CLI metalayers - (`hermes-full`, `openclaw-full`) and the coder boxes is the named + (`hermes-full`) and the coder boxes is the named `@github`-pin follow-up once the candy carries a published tag (see [`/charly-build:reconcile`](/recipes/build/reconcile/)) diff --git a/src/content/docs/recipes/coder/language-runtimes.md b/src/content/docs/recipes/coder/language-runtimes.md index 38824745..f7593388 100644 --- a/src/content/docs/recipes/coder/language-runtimes.md +++ b/src/content/docs/recipes/coder/language-runtimes.md @@ -105,7 +105,7 @@ Python env). It installs `python3-devel` + `python3-ramalama` via RPM — Consequence for [`/charly-coder:fedora-coder`](/recipes/coder/fedora-coder/) (the biggest consumer): the whole `python` / `pixi` charly-layer chain stays out of the resolved candy set (because [`/charly-coder:uv`](/recipes/coder/uv/) and [`/charly-infrastructure:supervisord`](/recipes/infrastructure/supervisord/) likewise carry no python -dep). See the project rulebook "Key Rules" (`AGENTS.md` / `CLAUDE.md`) → *"Don't declare defensive deps"* for the +dep). See the project rulebook "Key Rules" (`AGENTS.md`) → *"Don't declare defensive deps"* for the general rule. If you genuinely need the pixi-python env (e.g. a candy that diff --git a/src/content/docs/recipes/coder/nodejs.md b/src/content/docs/recipes/coder/nodejs.md index ee15f485..db1421e3 100644 --- a/src/content/docs/recipes/coder/nodejs.md +++ b/src/content/docs/recipes/coder/nodejs.md @@ -42,6 +42,29 @@ binary on `/usr/local/bin` is on the default system PATH for every user (incl. root — Immich runs its pnpm build as root). Immich and other pnpm consumers use this pnpm to drive their build. +### The pin and a consumer's `allowBuilds` KEY FORM are a COUPLED PAIR + +pnpm >= 10 blocks a dependency's build/install scripts unless it is allowlisted, +and for a **git-specifier** dependency the KEY FORM of that allowlist entry is +version-coupled: the two forms fail on each other's pin, so no single form works +at both. MEASURED in the real build image (Fedora 43, node 22.22.2) against +pod-dsh's `dsh-web` profile — `opencharly/layer-nodejs#5`: + +| `allowBuilds` key form | pnpm `10.33.4` | pnpm `10.34.6` | +|---|---|---| +| bare name — `"@perrylink/dsh-github": true` | PASS | `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` | +| fully-qualified URL key — `"@perrylink/dsh-github@https://codeload.github.com///.git": true` | `ERR_PNPM_INVALID_VERSION_UNION` | PASS | + +A wrong pair hard-fails the consumer's profile install at IMAGE BUILD time. So +`PNPM_VERSION`, `PNPM_ALLOWBUILDS_GIT_KEY_FORM` and the two PROBED_* constants move +together, and the candy's own +`check: the pinned pnpm version's allowBuilds git-key form matches the recorded measurement` +makes a bump that forgets them RED instead of a hard-failed consumer build. Only the +two probed versions are accepted: a bump to any other pin must RE-MEASURE the form and +record it. (pod-dsh vendored its git-hosted plugins as prebuilt `file:` tarballs in +pod-dsh#28, so no git dep remains there today — the rule still binds any consumer +that pins one.) + ## Usage ```yaml diff --git a/src/content/docs/recipes/coder/oracle.md b/src/content/docs/recipes/coder/oracle.md index bd67c8b7..d84ad09d 100644 --- a/src/content/docs/recipes/coder/oracle.md +++ b/src/content/docs/recipes/coder/oracle.md @@ -28,11 +28,9 @@ my-box: ## Used In Boxes -- `openclaw-full` (via `openclaw-full` metalayer) ## Related Candies - [`/charly-coder:nodejs`](/recipes/coder/nodejs/) -- runtime dependency -- [`/charly-openclaw:openclaw-full`](/recipes/openclaw/openclaw-full/) -- parent metalayer that bundles oracle ## Related Commands - [`/charly-automation:openclaw-deploy`](/recipes/automation/openclaw-deploy/) -- gateway/skill configuration diff --git a/src/content/docs/recipes/core/charly-config.md b/src/content/docs/recipes/core/charly-config.md index 987e08a2..40d18cb4 100644 --- a/src/content/docs/recipes/core/charly-config.md +++ b/src/content/docs/recipes/core/charly-config.md @@ -15,9 +15,9 @@ description: "`charly config` commands, image deployment setup, quadlet generati This is the **single entry point** for **container** deployment setup. `charly start` requires `charly config` to have been run first in quadlet mode. -**Relationship to `charly fleet add`** — `charly config` remains the primary way to create/update a quadlet and provision secrets/volumes/sidecars for a container deploy. `charly fleet add ` (container target) wraps both `charly config` and `charly start` and additionally handles `--add-candy` overlay synthesis (an overlay Containerfile is built before the quadlet references the resulting overlay image). `charly fleet add host` bypasses `charly config` entirely — the host target has no quadlet; it writes systemd units directly (when `--with-services` is enabled) and records every action in the ledger at `~/.config/opencharly/installed/`. See [`/charly-core:deploy`](/recipes/core/deploy/) for the command family and [`/charly-local:local-deploy`](/recipes/local/local-deploy/) for host-target semantics. +**Relationship to `charly deploy add`** — `charly config` remains the primary way to create/update a quadlet and provision secrets/volumes/sidecars for a container deploy. `charly deploy add ` (container target) wraps both `charly config` and `charly start` and additionally handles `--add-candy` overlay synthesis (an overlay Containerfile is built before the quadlet references the resulting overlay image). `charly deploy add host` bypasses `charly config` entirely — the host target has no quadlet; it writes systemd units directly (when `--with-services` is enabled) and records every action in the ledger at `~/.config/opencharly/installed/`. See [`/charly-core:deploy`](/recipes/core/deploy/) for the command family and [`/charly-local:local-deploy`](/recipes/local/local-deploy/) for host-target semantics. -**`charly config` vs `charly settings` — common verb confusion.** `charly config ` configures an image for deployment (quadlet + secrets + volumes + data seed). `charly settings list` shows runtime config keys (secret_backend, vm.backend, etc.). A trailing `charly config show` parses as `charly config setup show` with `show` as the image positional — and errors with `image "show" is not available locally`. To inspect runtime configuration use `charly settings list`; to inspect a configured image's resolved deploy state use `charly box inspect ` or `charly fleet show `. +**`charly config` vs `charly settings` — common verb confusion.** `charly config ` configures an image for deployment (quadlet + secrets + volumes + data seed). `charly settings list` shows runtime config keys (secret_backend, vm.backend, etc.). A trailing `charly config show` parses as `charly config setup show` with `show` as the image positional — and errors with `image "show" is not available locally`. To inspect runtime configuration use `charly settings list`; to inspect a configured image's resolved deploy state use `charly box inspect ` or `charly deploy show `. ## Quick Reference @@ -264,12 +264,12 @@ Warning: port conflicts detected: Wrote /home/user/.config/containers/systemd/charly--.container ``` -The quadlet is still written with the conflicting port, so `charly start` will fail at bind time unless you either free the port, re-run `charly config` with a remap, or edit `charly.yml`. Detection uses a local `net.Listen` probe per published port at configure time. Handy for multi-instance deployments alongside a production fleet (e.g., running [`/charly-openclaw:openclaw-desktop`](/recipes/openclaw/openclaw-desktop/) as a test instance while [`/charly-selkies:selkies-labwc`](/recipes/selkies/selkies-labwc/) holds the canonical 3000/9222/9224/2222 range). +The quadlet is still written with the conflicting port, so `charly start` will fail at bind time unless you either free the port, re-run `charly config` with a remap, or edit `charly.yml`. Detection uses a local `net.Listen` probe per published port at configure time. Handy for multi-instance deployments alongside a production fleet (e.g., running [`/charly-distros:charly-fedora`](/recipes/distros/charly-fedora/) as a test instance while [`/charly-selkies:selkies-labwc`](/recipes/selkies/selkies-labwc/) holds the canonical 3000/9222/9224/2222 range). ## Deploy State All configuration is persisted to `~/.config/charly/charly.yml` in the compact -node-form — a `version:` stamp, an optional top-level `provides:` directive, and each +node-form — an optional top-level `provides:` directive, and each deploy as a name-first `: {: }` entry whose substrate-kind value carries the scalars, collections (`port:`/`volume:`/…), and `plan:` inline, with any nested/peer members as sibling child nodes (no `deploy:` map wrapper, no `target:` @@ -315,12 +315,12 @@ charly config my-app --bind workspace=/new/path ### Full instance removal -`charly remove -i ` is the complete teardown: it stops the container, deletes the quadlet file, and reloads systemd. `charly config remove` only disables the quadlet service (the quadlet file remains), and `charly fleet reset` removes the charly.yml entry — neither is a full removal on its own: +`charly remove -i ` is the complete teardown: it stops the container, deletes the quadlet file, and reloads systemd. `charly config remove` only disables the quadlet service (the quadlet file remains), and `charly deploy reset` removes the charly.yml entry — neither is a full removal on its own: ```bash charly remove -i # Complete teardown: stop container, delete quadlet, reload systemd charly config remove -i # Disable quadlet service only (quadlet file remains) -charly fleet reset -i # Remove charly.yml entry only +charly deploy reset -i # Remove charly.yml entry only ``` Run `charly config --update-all` after removing an instance so the clean state propagates to the remaining deployments. @@ -489,7 +489,7 @@ When `charly config ` runs, it automatically migrates any existing plaint 1. Scan `dc.Images[deployKey(image, instance)].Env` for names that match `meta.SecretAccepts` / `meta.SecretRequires` 2. For each match: copy the value to the credential store at the layer-declared `(service, key)` path (default `charly/secret/`), remove the entry from `dc.Env`, mark the deploy config dirty 3. On first mutation, back up `charly.yml` → `charly.yml.bak.` -4. Persist the cleaned deploy config via `SaveFleetConfig` +4. Persist the cleaned deploy config via `SaveDeployConfig` 5. Log each migrated entry on stderr: `"Migrated plaintext OPENROUTER_API_KEY from charly.yml to credential store (charly/api-key/openrouter)"` Idempotent — running on a clean host is a no-op. This gives pre-upgrade hosts an automatic one-time cleanup with a rollback point preserved. @@ -563,13 +563,13 @@ Kong `sep:"none"` on all `-e` flags means commas in values are preserved (no spl `normalizeNoProxy()` auto-converts semicolons to commas in `NO_PROXY`/`no_proxy` values during env resolution. Legacy semicolon values in charly.yml are auto-healed. -**NO_PROXY enrichment:** When `HTTP_PROXY` or `HTTPS_PROXY` is present, `charly config` automatically appends all deployed container hostnames to `NO_PROXY`. This is necessary because Chrome does not support CIDR ranges in NO_PROXY (unlike curl) — without explicit hostnames, Chrome routes internal traffic like `http://charly-immich-ml:2283` through the external proxy, causing Bad Gateway errors. Applied in both the main config path and `--update-all`. Source: `spec/hostenv/envfile.go` (`EnrichNoProxy`), `sdk/deploykit/fleet_derive.go` (`DeployedContainerNames`). +**NO_PROXY enrichment:** When `HTTP_PROXY` or `HTTPS_PROXY` is present, `charly config` automatically appends all deployed container hostnames to `NO_PROXY`. This is necessary because Chrome does not support CIDR ranges in NO_PROXY (unlike curl) — without explicit hostnames, Chrome routes internal traffic like `http://charly-immich-ml:2283` through the external proxy, causing Bad Gateway errors. Applied in both the main config path and `--update-all`. Source: `spec/hostenv/envfile.go` (`EnrichNoProxy`), `sdk/deploykit/deploy_derive.go` (`DeployedContainerNames`). **Tunnel persistence:** `charly config setup` automatically persists tunnel config from charly.yml back to charly.yml via `saveDeployState`. Tunnel is a deploy-time concern — see [`/charly-core:deploy`](/recipes/core/deploy/) for tunnel configuration. **Tunnel is charly.yml-only:** `labels.go:238` deliberately skips parsing the `ai.opencharly.tunnel` OCI image label. Tunnel config is ONLY sourced from `charly.yml`. New instances created with `charly config setup -i ` do NOT inherit tunnel config from the base image's charly.yml entry — you must manually add `tunnel: {provider: tailscale, private: all}` to the instance's charly.yml entry, then re-run `charly config setup` to regenerate the quadlet with `ExecStartPost=tailscale serve` commands. -Source: `spec/hostenv/envfile.go` (`normalizeNoProxy`), `sdk/deploykit/deploy_state.go` (`MergeEnvVars`, `SaveDeployState`), `sep:"none"` in `candy/plugin-fleet/fleet_cmd.go` + `candy/plugin-pod/pod_cmd.go` (the former `charly/config_image.go`/`shell.go`/`start.go` are DELETED, K-wave 2). +Source: `spec/hostenv/envfile.go` (`normalizeNoProxy`), `sdk/deploykit/deploy_state.go` (`MergeEnvVars`, `SaveDeployState`), `sep:"none"` in `candy/plugin-fleet/deploy_cmd.go` + `candy/plugin-pod/pod_cmd.go` (the former `charly/config_image.go`/`shell.go`/`start.go` are DELETED, K-wave 2). ## Cross-References diff --git a/src/content/docs/recipes/core/charly-status.md b/src/content/docs/recipes/core/charly-status.md index ccc0af3a..282fb12a 100644 --- a/src/content/docs/recipes/core/charly-status.md +++ b/src/content/docs/recipes/core/charly-status.md @@ -69,10 +69,10 @@ former `status-substrate` HostBuild seam is DELETED, K-wave 2). - `candy/plugin-status/nested_tree.go` — the declared-nested-tree pre-resolution (K5, relocated from charly/status_nested.go's buildStatusRootsTree): resolves the merged project + per-machine deploy tree directly (`HostBuild("resolved- - project")` + `deploykit.LoadFleetConfig`) into the wire-safe + project")` + `deploykit.LoadDeployConfig`) into the wire-safe `[]spec.StatusNestedNode` shape the overlay folds, including the `--nested` live-probe leg (`ResolveDeployChain` + `NestedExecutor`, the SAME primitive - `charly fleet add` / `charly check live parent.child` use). + `charly deploy add` / `charly check live parent.child` use). - `candy/plugin-status/command.go` (`hostStatusSubstrate`) — the generic `status-substrate` F10 forward is DELETED with `charly/status_substrate_host.go` (K-wave 2): `command:status` now `InvokeProvider(verb:status-fanout)` DIRECTLY over @@ -200,7 +200,7 @@ match keeps the synthesized declared row (`Source="nested"`). subprocesses. - **`charly status --nested`**: each child's LIVE venue is probed through the real multi-hop chain (`ResolveDeployChain` → `NestedExecutor`, the SAME primitive - `charly fleet add` and `charly check live parent.child` use — no bespoke nested dial) + `charly deploy add` and `charly check live parent.child` use — no bespoke nested dial) under a STRICT 4-second per-child context deadline. A timed-out / failing child renders `unreachable`; the table is NEVER blocked. The deadline is a context cancellation, never a sleep/retry loop. `--nested` also turns on live @@ -318,7 +318,7 @@ Authoritative direct queries (when you need the raw mount data): ```bash charly status --json # volumes[] carries the live mounts -charly fleet show +charly deploy show ``` ## Usage diff --git a/src/content/docs/recipes/core/charly-update.md b/src/content/docs/recipes/core/charly-update.md index e54412bb..d0d55e1a 100644 --- a/src/content/docs/recipes/core/charly-update.md +++ b/src/content/docs/recipes/core/charly-update.md @@ -11,11 +11,11 @@ description: "Update image and restart service with data sync — `charly update ## Overview -Redeploy the current artifact and restart the service — for EVERY deploy kind through ONE codepath. `charly update ` resolves the deploy via `ResolveTarget` and calls `LifecycleTarget.Rebuild` (`charly/unified_targets_*.go`); there is no per-kind update code. The unified contract is **redeploy the current artifact + restart by default; `--build` rebuilds the artifact first** — realized per substrate: pod → `deploy add → config → start` (`--build` rebuilds the image); vm → destroy→create the domain (reuse the qcow2 disk unless `--build`) **then re-apply the deploy node's layers idempotently** via the shared `deploy add` path (so a config change — a newly-added layer or nested pod — takes effect on the rebuilt guest, exactly like local/pod); local → re-apply layers idempotently. All three live substrates end in the SAME `charly fleet add ` layer-apply step. kubernetes has no live runtime to rebuild (apply it via `kubectl apply -k`), so `charly update ` errors uniformly. Data sync uses MERGE mode by default — adds new files without overwriting existing user modifications. +Redeploy the current artifact and restart the service — for EVERY deploy kind through ONE codepath. `charly update ` resolves the deploy via `ResolveTarget` and calls `LifecycleTarget.Rebuild` (`charly/unified_targets_*.go`); there is no per-kind update code. The unified contract is **redeploy the current artifact + restart by default; `--build` rebuilds the artifact first** — realized per substrate: pod → `deploy add → config → start` (`--build` rebuilds the image); vm → destroy→create the domain (reuse the qcow2 disk unless `--build`) **then re-apply the deploy node's layers idempotently** via the shared `deploy add` path (so a config change — a newly-added layer or nested pod — takes effect on the rebuilt guest, exactly like local/pod); local → re-apply layers idempotently. All three live substrates end in the SAME `charly deploy add ` layer-apply step. kubernetes has no live runtime to rebuild (apply it via `kubectl apply -k`), so `charly update ` errors uniformly. Data sync uses MERGE mode by default — adds new files without overwriting existing user modifications. **`charly update` does NOT auto-pull.** It redeploys the image already in local storage. To advance a deploy to a newer published image, `charly box pull ` first, then `charly update`; or `charly update --build` to rebuild locally. (This consistency with vm's reuse-disk default replaced the former pod-only auto-pull, so `charly update` behaves identically across kinds.) See [`/charly-core:deploy`](/recipes/core/deploy/) for the unified command family and [`/charly-local:local-deploy`](/recipes/local/local-deploy/) for host-target specifics. -**`charly update` obeys an EXPLICIT invocation on ANY target.** It does NOT refuse a non-`disposable: true` deploy — for a target that is neither disposable nor ephemeral it prints a one-line transparency note (`noteUpdateDisposability`, naming the deploy key + lifecycle, so the operator can catch a mistyped name) and proceeds with the rebuild. The `disposable:` flag stays load-bearing as the authorization for UNATTENDED autonomous destroy + rebuild (the project rulebook R10 (`AGENTS.md` / `CLAUDE.md`)) and for the check-runner's unattended fresh-rebuild (`validateCheckBeds`); it does NOT gate this explicitly-invoked verb. See [`/charly-internals:disposable`](/recipes/internals/disposable/). +**`charly update` obeys an EXPLICIT invocation on ANY target.** It does NOT refuse a non-`disposable: true` deploy — for a target that is neither disposable nor ephemeral it prints a one-line transparency note (`noteUpdateDisposability`, naming the deploy key + lifecycle, so the operator can catch a mistyped name) and proceeds with the rebuild. The `disposable:` flag stays load-bearing as the authorization for UNATTENDED autonomous destroy + rebuild (the project rulebook R10 (`AGENTS.md`)) and for the check-runner's unattended fresh-rebuild (`validateCheckBeds`); it does NOT gate this explicitly-invoked verb. See [`/charly-internals:disposable`](/recipes/internals/disposable/). ## Quick Reference diff --git a/src/content/docs/recipes/core/clean.md b/src/content/docs/recipes/core/clean.md index c9e08c9e..498bb491 100644 --- a/src/content/docs/recipes/core/clean.md +++ b/src/content/docs/recipes/core/clean.md @@ -1,6 +1,6 @@ --- title: "clean" -description: "Prune reusable build artifacts to defaults: retention (images, check runs) and sweep one-time makepkg leftovers — `charly clean`, keep_images/keep_check_runs, image-tag pruning, .check run cleanup." +description: "Prune reusable build artifacts to defaults: retention (images, check runs) and sweep one-time build-candy leftovers — `charly clean`, keep_images/keep_check_runs, image-tag pruning, .check run cleanup." --- @@ -39,7 +39,7 @@ opts in; third-party configs get no surprise pruning until they set a value. ## Commands ```bash -charly clean # apply retention now: prune images + check runs + makepkg leftovers +charly clean # apply retention now: prune images + check runs + build-candy leftovers charly clean --dry-run # print everything that WOULD be removed; touch nothing charly clean --images # only image-tag retention charly clean --check # only check-run retention @@ -50,12 +50,28 @@ charly clean --deep --dry-run # the safe default probe: report the would-remov charly clean --keep N # override the retention count for this run (0 = use defaults:) charly clean --invalidate '' # remove charly-labeled image tags matching the glob # (full ref or last segment; in-use skipped; runs ONLY this) +charly clean --cache # reclaim unreferenced blobs from every named charly cache (the + # content-addressed ArtifactStore's own GC); reports each store's live + # entries + the blobs/bytes it would reclaim; runs ONLY this category +charly clean --scopes # reap HUNG transient build scopes — the systemd user scopes + # buildah/podman put a build container into (runc-buildah-*.scope). + # A scope is stopped only when it has hung; a live one is left alone ``` -With neither `--images` nor `--check` nor `--deep`, the three DEFAULT categories run (images + -check + makepkg) — unchanged, `--deep` NEVER fires implicitly. `--keep N` overrides both the -image and check-run retention counts for the invocation (it does not affect `--deep`, which has -no keep-N — it purges every untagged image). +With **none** of `--images` / `--check` / `--deep` / `--cache` / `--scopes`, the **four** DEFAULT categories +run (image-tag + check-run + build-candy + scopes) — unchanged, and `--deep` and `--cache` NEVER fire +implicitly. `--scopes` IS in that list because it is itself a category flag: the test the code applies is +`anyCategory := images || check || deep || cacheGC || scopes`, so naming ANY one of the five suppresses the +default set and runs only what was named (plus, for `--deep`, the scope reap below). +**`--scopes` is a default and `--deep` implies it:** `cleanCategories` computes +`doScopes = scopes || deep || !anyCategory`, so a bare `charly clean` reaps hung build scopes +and `--deep` does too, while `--deep` on its own runs only the image half plus that scope reap — and +`--cache` on its own runs only the cache sweep, with `doScopes` false. +`--keep N` overrides both the image and check-run retention counts for the invocation (it does +not affect `--deep`, which has no keep-N — it purges every untagged image). +**Category names, from the engine's own header** (`retention.go`): *image-tag / build-candy / check-run +pruning*, plus the `--deep` store-wide purge and the `--cache` blob sweep. The middle one prunes +`.build/_candy/./` per candy (`pruneBuildCandyDirs`). **`--deep` — the store-wide untagged/dangling-image purge.** The default image-tag sweep above only ever touches images carrying the `ai.opencharly.box` label. A multi-stage build's @@ -195,7 +211,7 @@ importing only `sdk/kit` + `spec/spec`). `--deep` shares its engine with the def charly-labeled dangling sweep via `pruneDanglingImages`/`selectDanglingImages` (`candy/plugin-clean/retention.go`) parameterized by an `onlyCharly` bool: `pruneDanglingCharlyImages` (onlyCharly=true, the default sweep) and `pruneDeepDanglingImages` (onlyCharly=false, `--deep`) -are both thin wrappers over the ONE shared selection + removal engine (R3 — no duplicated +are both thin wrappers over the ONE shared selection + removal engine (R2 — no duplicated listing/removal logic between the two categories). The engine is reached two ways: `charly clean`'s own CLI calls `runRetention` in-package (no wire hop); the three OTHER callers reach `verb:retention` — the build command's post-build prune (`candy/plugin-box/box.go`'s diff --git a/src/content/docs/recipes/core/deploy.md b/src/content/docs/recipes/core/deploy.md index 8c19e8c6..e73004b0 100644 --- a/src/content/docs/recipes/core/deploy.md +++ b/src/content/docs/recipes/core/deploy.md @@ -1,6 +1,6 @@ --- title: "deploy" -description: "`charly fleet add`/`charly fleet del`, quadlet generation, volume backing, tunnels (Tailscale/Cloudflare), `add_candy:` overlay, or per-machine deploy overlays." +description: "`charly deploy add`/`charly deploy del`, quadlet generation, volume backing, tunnels (Tailscale/Cloudflare), `add_candy:` overlay, or per-machine deploy overlays." --- @@ -15,26 +15,26 @@ description: "`charly fleet add`/`charly fleet del`, quadlet generation, volume - **The substrate node at the edge** — `vm: {from: }` for a VM target, `pod: {image: }` for a pod target, `kubernetes: {from: }` for a cluster target, `local: {from: