From c9c4fd941ea6a88f804b2355c9bd27cc7600a7d8 Mon Sep 17 00:00:00 2001 From: Riley Crane Date: Mon, 31 Aug 2026 22:26:30 -0700 Subject: [PATCH] feat(accumulator): vite+React lab UI at crates/buzz-accumulator/ui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ergonomics lab for the exploration client: a standalone SPA that talks to the daemon through vite's dev proxy (/api → 127.0.0.1:4640), so the daemon stays loopback-pure and zero-config. One screen, three panes: - Selection composer (channels/authors/kinds + window presets), with URL-shareable state (?channels=…&since=… and ?fold=…&v=…). - Explore: live zero-spend preview (count/chars/est tokens), the daily rhythm strip, and a paged browser of the matching events. - Folds board: create-from-current-selection, and per-fold cards with the priced loop — preflight ($0) → run pinned to the exact priced window → outcome (refusals salvage the model output visibly). - Artifact reader: Working Context / Log rendering with [event:id] citation chips that pin the source message into an evidence rail, plus a version scrubber. Deliberately its own pnpm workspace root: not in the repo workspace, invisible to just ci. Run: cd crates/buzz-accumulator/ui && pnpm install && pnpm dev (daemon running on :4640). Co-Authored-By: Claude Fable 5 Signed-off-by: Riley Crane --- crates/buzz-accumulator/ui/.gitignore | 2 + crates/buzz-accumulator/ui/index.html | 12 + crates/buzz-accumulator/ui/package.json | 24 + crates/buzz-accumulator/ui/pnpm-lock.yaml | 1163 +++++++++++++++++ .../buzz-accumulator/ui/pnpm-workspace.yaml | 6 + crates/buzz-accumulator/ui/src/App.tsx | 119 ++ crates/buzz-accumulator/ui/src/api.ts | 245 ++++ .../ui/src/components/ArtifactReader.tsx | 182 +++ .../ui/src/components/Explore.tsx | 198 +++ .../ui/src/components/FoldsBoard.tsx | 262 ++++ .../ui/src/components/SelectionComposer.tsx | 189 +++ crates/buzz-accumulator/ui/src/main.tsx | 22 + crates/buzz-accumulator/ui/src/styles.css | 468 +++++++ crates/buzz-accumulator/ui/tsconfig.json | 18 + crates/buzz-accumulator/ui/vite.config.ts | 16 + 15 files changed, 2926 insertions(+) create mode 100644 crates/buzz-accumulator/ui/.gitignore create mode 100644 crates/buzz-accumulator/ui/index.html create mode 100644 crates/buzz-accumulator/ui/package.json create mode 100644 crates/buzz-accumulator/ui/pnpm-lock.yaml create mode 100644 crates/buzz-accumulator/ui/pnpm-workspace.yaml create mode 100644 crates/buzz-accumulator/ui/src/App.tsx create mode 100644 crates/buzz-accumulator/ui/src/api.ts create mode 100644 crates/buzz-accumulator/ui/src/components/ArtifactReader.tsx create mode 100644 crates/buzz-accumulator/ui/src/components/Explore.tsx create mode 100644 crates/buzz-accumulator/ui/src/components/FoldsBoard.tsx create mode 100644 crates/buzz-accumulator/ui/src/components/SelectionComposer.tsx create mode 100644 crates/buzz-accumulator/ui/src/main.tsx create mode 100644 crates/buzz-accumulator/ui/src/styles.css create mode 100644 crates/buzz-accumulator/ui/tsconfig.json create mode 100644 crates/buzz-accumulator/ui/vite.config.ts diff --git a/crates/buzz-accumulator/ui/.gitignore b/crates/buzz-accumulator/ui/.gitignore new file mode 100644 index 0000000000..b947077876 --- /dev/null +++ b/crates/buzz-accumulator/ui/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ diff --git a/crates/buzz-accumulator/ui/index.html b/crates/buzz-accumulator/ui/index.html new file mode 100644 index 0000000000..976ed296c3 --- /dev/null +++ b/crates/buzz-accumulator/ui/index.html @@ -0,0 +1,12 @@ + + + + + + accumulator + + +
+ + + diff --git a/crates/buzz-accumulator/ui/package.json b/crates/buzz-accumulator/ui/package.json new file mode 100644 index 0000000000..8c2bab198e --- /dev/null +++ b/crates/buzz-accumulator/ui/package.json @@ -0,0 +1,24 @@ +{ + "name": "accumulator-ui", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "check": "tsc", + "preview": "vite preview" + }, + "dependencies": { + "@tanstack/react-query": "^5.90.5", + "react": "^19.1.0", + "react-dom": "^19.1.0" + }, + "devDependencies": { + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^5.0.0", + "typescript": "~5.8.3", + "vite": "^7.1.0" + } +} diff --git a/crates/buzz-accumulator/ui/pnpm-lock.yaml b/crates/buzz-accumulator/ui/pnpm-lock.yaml new file mode 100644 index 0000000000..526ef6efdb --- /dev/null +++ b/crates/buzz-accumulator/ui/pnpm-lock.yaml @@ -0,0 +1,1163 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@tanstack/react-query': + specifier: ^5.90.5 + version: 5.102.8(react@19.2.8) + react: + specifier: ^19.1.0 + version: 19.2.8 + react-dom: + specifier: ^19.1.0 + version: 19.2.8(react@19.2.8) + devDependencies: + '@types/react': + specifier: ^19.1.8 + version: 19.2.18 + '@types/react-dom': + specifier: ^19.1.6 + version: 19.2.5(@types/react@19.2.18) + '@vitejs/plugin-react': + specifier: ^5.0.0 + version: 5.2.0(vite@7.3.6) + typescript: + specifier: ~5.8.3 + version: 5.8.3 + vite: + specifier: ^7.1.0 + version: 7.3.6 + +packages: + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/code-frame/-/code-frame-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/compat-data/-/compat-data-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/core/-/core-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/generator/-/generator-7.29.8.tgz} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/helper-globals/-/helper-globals-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/helpers/-/helpers-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/parser/-/parser-7.29.8.tgz} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.29.7': + resolution: {integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.29.7': + resolution: {integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/template/-/template-7.29.7.tgz} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/traverse/-/traverse-7.29.8.tgz} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@babel/types/-/types-7.29.8.tgz} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/android-arm/-/android-arm-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/android-x64/-/android-x64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@jridgewell/remapping/-/remapping-2.3.5.tgz} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz} + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz} + + '@rollup/rollup-android-arm-eabi@4.63.1': + resolution: {integrity: sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.1.tgz} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.63.1': + resolution: {integrity: sha512-cQ4nFQABN5cDvDpbvJ7bMStCpnaVxynZrRMfUJYgxcIk9Sh54FIO1vtfkg0B69REjER77ioZ/ov+eAApx/KmLQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.1.tgz} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.63.1': + resolution: {integrity: sha512-FQNqd1lRy/0QhDk3xeRIkSBiCpXCiDnZO3YLVdcDKN1UBiKToNftCzcXYNLshmPDUMlu2TdeS8tGcsU6f3YF1Q==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.1.tgz} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.63.1': + resolution: {integrity: sha512-pvD16V939D3CloK0+qikpGaxiPrDUXTe7Y5cWOMkMSy7m1cawa8EGy/kXYi/G/cKAC4HDAbSnzCIk1WmsoOKXg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.1.tgz} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.63.1': + resolution: {integrity: sha512-pcFGeL2345VwdTnJhA6zLbew+YgWB0qBG2+dMtXjCicf6+rm6kO6cOoh5VnTe0ZMrMRgRyuHmCJxZWrIdzYuOw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.1.tgz} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.63.1': + resolution: {integrity: sha512-mRJlqSRulVzcKq/LKA6ICSIc3K/l4fzlVn/gePn2nXIHy8seRi5z/eeRE0d/XMBxcMldiXtQTSpRj0tkkC3g8Q==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.1.tgz} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': + resolution: {integrity: sha512-YDUNvVM85TI3g/1OpnqKP1h4NeW/j64DfWMf+G3M809xNk1bJSnpFp4sh83NpmVE5DXnkh8ULor4LTVZKoYLHw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.1.tgz} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.63.1': + resolution: {integrity: sha512-7Mcn71p9ZuQFAj+h+dhQXy/yeLePRS2yKRnmW1DijA9thKO5qap0GNOIQK4yQ6iP3SU0Mrb/yWo8h8vgRba8lw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.1.tgz} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.63.1': + resolution: {integrity: sha512-4YiLQTX6U4CSl0L9cluep9A9W6UmTfqBDc2/CH6wlu54pl4E7Jn3cOD8oxzvBDEGk/JMKgJ47C8g+radF7mwvg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.1.tgz} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.63.1': + resolution: {integrity: sha512-2ra8F7w8OquwZN9z2/fKFnli69wa8PLwaVzRMIPGb13ByMJwC28Fbp8YcVGoUhlYMTt7j5j9bNgpysrN2UM+vw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.1.tgz} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.63.1': + resolution: {integrity: sha512-Sy20ncyhjmBP0Ml+UvQbimjlk6VFgjW5uNP+qqwHB00mTE8Bl2C1TuHTlRwK2YoXeZbee5lP2XevBWVkAQAtSQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.1.tgz} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.63.1': + resolution: {integrity: sha512-noITLp8oNjYliPnGWmLyelIHwULGqbHloQHGw1rtxbWhTuWooRpnZarZQJ1y9EUC4szuCusCc+HEpUtxpIwYvA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.1.tgz} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.63.1': + resolution: {integrity: sha512-hlxxXd+F1mWiAcaFR7Sv9ZQT6m6UfI8+Vy/kFJzztq2pDMU/0wZ9sish0iszNZvsQDo8Gc0i5yuFEOz5dDf6fA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.1.tgz} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.63.1': + resolution: {integrity: sha512-EF7OpqQTQ/BvGqLzUi4rEHuagCV9MugAUXSHemwPW5vxZ75RR+jxO/2j95Ph2dalMpFHSVECjRoioHZgA9zOYA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.1.tgz} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.63.1': + resolution: {integrity: sha512-wQO3JesW9PRkwlabQ27y7sPfVOOTLRG73I4F2UYHG5PXun3J9U3y+b7ezVKSYbsvSKGQ1k1cq8Qlun4C9kLt3w==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.1.tgz} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.63.1': + resolution: {integrity: sha512-ouAGwhO6wHRXdnOVCOsB0tRFkA7nhNB2Nwax6oECXN0YiN8EYUTBAOudADOB1PI+yDL61TeNx/u7MVCzksNbkQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.1.tgz} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.63.1': + resolution: {integrity: sha512-q2R38Sn+1J8RxhfJ+T54wSWmyKXWec+9jgDfqO2AtArEqHO5R2aeayp5H5OYLr5UYDVGsVaZPEFUooMhYCdz5A==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.1.tgz} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.63.1': + resolution: {integrity: sha512-gfI5T24WLLuFfSKw7Go/zDXjAAV0fny0swTaDv+WjK7vqcw4cRhFfdsyKL1n+ukI+ooBxn3bVQnyrn06WpI50w==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.1.tgz} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.63.1': + resolution: {integrity: sha512-4h6XqthmB4Hspji84wvgk+ElodTsGj+dbZqHJHHtKxj4mYq0ANSEEPX9ys3moJueqsRjwpaJYH7874Itwnj2ow==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.1.tgz} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.63.1': + resolution: {integrity: sha512-dlfCOa87o1VAYegLQ9EKilx2JCeRofiyPGhTCmqnuXZ6bMPiycO1rq1+sKoulAp7pGLIsTIw+1x5R+zgh5LhhA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.1.tgz} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.63.1': + resolution: {integrity: sha512-cjkLbOlfcm3QGhMM1J5zaZjsw1GggbN6rw9UTSSRrPrR1KkcXnN7Uq9rPw34xImQ9VOY9GN+6u2Zj80B9ptkcw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.1.tgz} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.63.1': + resolution: {integrity: sha512-Li1KdUnWGE4N3e1F/B4RTB1ms+nG4WBgjByO46pkeBVX/2UBsY53xf5vK9WygVmnH3RwncIST7lkSdLSY6P9lg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.1.tgz} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.63.1': + resolution: {integrity: sha512-t4ZYOSoLTgwhuFMrmTMLx/+i1DQVK7HYqMc6kY46EApwi8X0nIVphzdNoThU3xt6n+N5urG1/gxBdCaKDLavfg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.1.tgz} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.63.1': + resolution: {integrity: sha512-RgroPfMmKlD1RzSDxvwgcPiy2HNQKoYV7OmwIXDsk73uKW5t6B/V8KIy27SMv/FNXFo/oSBtWc9J0X7t91ezZg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.1.tgz} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.63.1': + resolution: {integrity: sha512-at8QVep6S3h5Y6gSbdGU06bRY5WJkf6WUduM9YtvYMbYhB1MOFfUgc6kehitQXzOtMSaT70q7f9ydPhpqu821w==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.1.tgz} + cpu: [x64] + os: [win32] + + '@tanstack/query-core@5.102.8': + resolution: {integrity: sha512-ZNjkJ33CqvPNec/6lZBnHqLc3EVGPZ9ySLhYahU9TcuRFdmwXewuj0c4hwSWcGHqEUwcSrKeZ+oGcvPBqXcQcg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@tanstack/query-core/-/query-core-5.102.8.tgz} + + '@tanstack/react-query@5.102.8': + resolution: {integrity: sha512-TYBea4OuXWD7MhaSHq069TWbFe7rcwWN6kzT7JF0OKi1K6c1gTv2IzD6A6ExJsCMozdkqBWeuIUZmu4KQg0O5A==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@tanstack/react-query/-/react-query-5.102.8.tgz} + peerDependencies: + react: ^18 || ^19 + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@types/babel__core/-/babel__core-7.20.5.tgz} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@types/babel__generator/-/babel__generator-7.27.0.tgz} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@types/babel__template/-/babel__template-7.4.4.tgz} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@types/babel__traverse/-/babel__traverse-7.28.0.tgz} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@types/estree/-/estree-1.0.9.tgz} + + '@types/react-dom@19.2.5': + resolution: {integrity: sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@types/react-dom/-/react-dom-19.2.5.tgz} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.18': + resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@types/react/-/react-19.2.18.tgz} + + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + + baseline-browser-mapping@2.11.20: + resolution: {integrity: sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz} + engines: {node: '>=6.0.0'} + hasBin: true + + browserslist@4.28.8: + resolution: {integrity: sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/browserslist/-/browserslist-4.28.8.tgz} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + caniuse-lite@1.0.30001810: + resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/convert-source-map/-/convert-source-map-2.0.0.tgz} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/csstype/-/csstype-3.2.3.tgz} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/debug/-/debug-4.4.3.tgz} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + electron-to-chromium@1.5.416: + resolution: {integrity: sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz} + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/esbuild/-/esbuild-0.28.2.tgz} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/escalade/-/escalade-3.2.0.tgz} + engines: {node: '>=6'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/fdir/-/fdir-6.5.0.tgz} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/fsevents/-/fsevents-2.3.3.tgz} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/gensync/-/gensync-1.0.0-beta.2.tgz} + engines: {node: '>=6.9.0'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/js-tokens/-/js-tokens-4.0.0.tgz} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/jsesc/-/jsesc-3.1.0.tgz} + engines: {node: '>=6'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/json5/-/json5-2.2.3.tgz} + engines: {node: '>=6'} + hasBin: true + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/lru-cache/-/lru-cache-5.1.1.tgz} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/ms/-/ms-2.1.3.tgz} + + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/nanoid/-/nanoid-3.3.18.tgz} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-releases@2.0.54: + resolution: {integrity: sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/node-releases/-/node-releases-2.0.54.tgz} + engines: {node: '>=18'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/picocolors/-/picocolors-1.1.1.tgz} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/picomatch/-/picomatch-4.0.7.tgz} + engines: {node: '>=12'} + + postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/postcss/-/postcss-8.5.26.tgz} + engines: {node: ^10 || ^12 || >=14} + + react-dom@19.2.8: + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/react-dom/-/react-dom-19.2.8.tgz} + peerDependencies: + react: ^19.2.8 + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/react-refresh/-/react-refresh-0.18.0.tgz} + engines: {node: '>=0.10.0'} + + react@19.2.8: + resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/react/-/react-19.2.8.tgz} + engines: {node: '>=0.10.0'} + + rollup@4.63.1: + resolution: {integrity: sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/rollup/-/rollup-4.63.1.tgz} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/scheduler/-/scheduler-0.27.0.tgz} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/semver/-/semver-6.3.1.tgz} + hasBin: true + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/source-map-js/-/source-map-js-1.2.1.tgz} + engines: {node: '>=0.10.0'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/tinyglobby/-/tinyglobby-0.2.17.tgz} + engines: {node: '>=12.0.0'} + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/typescript/-/typescript-5.8.3.tgz} + engines: {node: '>=14.17'} + hasBin: true + + update-browserslist-db@1.3.2: + resolution: {integrity: sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + vite@7.3.6: + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/vite/-/vite-7.3.6.tgz} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, tarball: https://global.block-artifacts.com/artifactory/api/npm/square-npm/yallist/-/yallist-3.1.1.tgz} + +snapshots: + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.8': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.8 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + + '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + + '@babel/traverse@7.29.8': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true + + '@esbuild/openharmony-arm64@0.28.2': + optional: true + + '@esbuild/sunos-x64@0.28.2': + optional: true + + '@esbuild/win32-arm64@0.28.2': + optional: true + + '@esbuild/win32-ia32@0.28.2': + optional: true + + '@esbuild/win32-x64@0.28.2': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.3': {} + + '@rollup/rollup-android-arm-eabi@4.63.1': + optional: true + + '@rollup/rollup-android-arm64@4.63.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.63.1': + optional: true + + '@rollup/rollup-darwin-x64@4.63.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.63.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.63.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.63.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.63.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.63.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.63.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.63.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.63.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.63.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.63.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.63.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.63.1': + optional: true + + '@tanstack/query-core@5.102.8': {} + + '@tanstack/react-query@5.102.8(react@19.2.8)': + dependencies: + '@tanstack/query-core': 5.102.8 + react: 19.2.8 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.8 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.8 + + '@types/estree@1.0.9': {} + + '@types/react-dom@19.2.5(@types/react@19.2.18)': + dependencies: + '@types/react': 19.2.18 + + '@types/react@19.2.18': + dependencies: + csstype: 3.2.3 + + '@vitejs/plugin-react@5.2.0(vite@7.3.6)': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) + '@rolldown/pluginutils': 1.0.0-rc.3 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.6 + transitivePeerDependencies: + - supports-color + + baseline-browser-mapping@2.11.20: {} + + browserslist@4.28.8: + dependencies: + baseline-browser-mapping: 2.11.20 + caniuse-lite: 1.0.30001810 + electron-to-chromium: 1.5.416 + node-releases: 2.0.54 + update-browserslist-db: 1.3.2(browserslist@4.28.8) + + caniuse-lite@1.0.30001810: {} + + convert-source-map@2.0.0: {} + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + electron-to-chromium@1.5.416: {} + + esbuild@0.28.2: + optionalDependencies: + '@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 + + escalade@3.2.0: {} + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + js-tokens@4.0.0: {} + + jsesc@3.1.0: {} + + json5@2.2.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + ms@2.1.3: {} + + nanoid@3.3.18: {} + + node-releases@2.0.54: {} + + picocolors@1.1.1: {} + + picomatch@4.0.7: {} + + postcss@8.5.26: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + react-dom@19.2.8(react@19.2.8): + dependencies: + react: 19.2.8 + scheduler: 0.27.0 + + react-refresh@0.18.0: {} + + react@19.2.8: {} + + rollup@4.63.1: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.63.1 + '@rollup/rollup-android-arm64': 4.63.1 + '@rollup/rollup-darwin-arm64': 4.63.1 + '@rollup/rollup-darwin-x64': 4.63.1 + '@rollup/rollup-freebsd-arm64': 4.63.1 + '@rollup/rollup-freebsd-x64': 4.63.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.1 + '@rollup/rollup-linux-arm-musleabihf': 4.63.1 + '@rollup/rollup-linux-arm64-gnu': 4.63.1 + '@rollup/rollup-linux-arm64-musl': 4.63.1 + '@rollup/rollup-linux-loong64-gnu': 4.63.1 + '@rollup/rollup-linux-loong64-musl': 4.63.1 + '@rollup/rollup-linux-ppc64-gnu': 4.63.1 + '@rollup/rollup-linux-ppc64-musl': 4.63.1 + '@rollup/rollup-linux-riscv64-gnu': 4.63.1 + '@rollup/rollup-linux-riscv64-musl': 4.63.1 + '@rollup/rollup-linux-s390x-gnu': 4.63.1 + '@rollup/rollup-linux-x64-gnu': 4.63.1 + '@rollup/rollup-linux-x64-musl': 4.63.1 + '@rollup/rollup-openbsd-x64': 4.63.1 + '@rollup/rollup-openharmony-arm64': 4.63.1 + '@rollup/rollup-win32-arm64-msvc': 4.63.1 + '@rollup/rollup-win32-ia32-msvc': 4.63.1 + '@rollup/rollup-win32-x64-gnu': 4.63.1 + '@rollup/rollup-win32-x64-msvc': 4.63.1 + fsevents: 2.3.3 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + source-map-js@1.2.1: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + typescript@5.8.3: {} + + update-browserslist-db@1.3.2(browserslist@4.28.8): + dependencies: + browserslist: 4.28.8 + escalade: 3.2.0 + picocolors: 1.1.1 + + vite@7.3.6: + dependencies: + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.26 + rollup: 4.63.1 + tinyglobby: 0.2.17 + optionalDependencies: + fsevents: 2.3.3 + + yallist@3.1.1: {} diff --git a/crates/buzz-accumulator/ui/pnpm-workspace.yaml b/crates/buzz-accumulator/ui/pnpm-workspace.yaml new file mode 100644 index 0000000000..c20738fb2b --- /dev/null +++ b/crates/buzz-accumulator/ui/pnpm-workspace.yaml @@ -0,0 +1,6 @@ +# Deliberately its own workspace root: the lab is standalone tooling and must +# not join the repo-level pnpm workspace (or `just ci`'s desktop/web checks). +packages: + - "." +allowBuilds: + esbuild: true diff --git a/crates/buzz-accumulator/ui/src/App.tsx b/crates/buzz-accumulator/ui/src/App.tsx new file mode 100644 index 0000000000..1fe9ee3729 --- /dev/null +++ b/crates/buzz-accumulator/ui/src/App.tsx @@ -0,0 +1,119 @@ +import { useQuery } from "@tanstack/react-query"; +import { useState } from "react"; +import { api, type Selection, type TimeWindow } from "./api"; +import { ArtifactReader } from "./components/ArtifactReader"; +import { Explore } from "./components/Explore"; +import { FoldsBoard } from "./components/FoldsBoard"; +import { SelectionComposer } from "./components/SelectionComposer"; + +export type View = + | { kind: "explore" } + | { kind: "artifact"; fold: string; version: number }; + +/** Initial selection/window from URL query params, so a selection is + * shareable: `?channels=&authors=&kinds=9&since=`. */ +function fromUrl(): { selection: Selection; window: TimeWindow } { + const q = new URLSearchParams(location.search); + const list = (key: string) => + (q.get(key) ?? "").split(",").map((s) => s.trim()).filter(Boolean); + const num = (key: string) => { + const n = Number.parseInt(q.get(key) ?? "", 10); + return Number.isFinite(n) ? n : undefined; + }; + return { + selection: { + channels: list("channels"), + authors: list("authors"), + kinds: list("kinds") + .map((k) => Number.parseInt(k, 10)) + .filter((k) => Number.isFinite(k) && k >= 0), + }, + window: { since: num("since"), until_exclusive: num("until") }, + }; +} + +/** Initial view from `?fold=&v=`, so artifacts are shareable. */ +function viewFromUrl(): View { + const q = new URLSearchParams(location.search); + const fold = q.get("fold"); + const v = Number.parseInt(q.get("v") ?? "1", 10); + return fold && Number.isFinite(v) && v >= 1 + ? { kind: "artifact", fold, version: v } + : { kind: "explore" }; +} + +export function App() { + const initial = fromUrl(); + const [selection, setSelection] = useState(initial.selection); + const [window, setWindow] = useState(initial.window); + const [view, setView] = useState(viewFromUrl); + + const status = useQuery({ + queryKey: ["status"], + queryFn: api.status, + refetchInterval: 5000, + }); + + const s = status.data; + const dotClass = status.isError + ? "error" + : s?.connection === "connected" + ? "connected" + : ""; + + return ( + <> +
+

🐝 accumulator

+ + + {status.isError + ? "daemon unreachable — is it running on :4640?" + : s + ? `${s.connection} · ${s.total_events.toLocaleString()} events · ${ + s.folds + } folds · ${s.artifacts} artifacts${ + s.backfill_complete ? "" : " · backfilling…" + }` + : "connecting…"} + + {view.kind === "artifact" && ( + + )} +
+
+ +
+ {view.kind === "explore" ? ( + + ) : ( + + setView({ kind: "artifact", fold: view.fold, version: v }) + } + /> + )} +
+ +
+ + ); +} diff --git a/crates/buzz-accumulator/ui/src/api.ts b/crates/buzz-accumulator/ui/src/api.ts new file mode 100644 index 0000000000..8f53437f33 --- /dev/null +++ b/crates/buzz-accumulator/ui/src/api.ts @@ -0,0 +1,245 @@ +// Typed client for the daemon's loopback HTTP API (proxied at /api by vite). + +export type Selection = { + channels: string[]; + authors: string[]; + kinds: number[]; +}; + +/** Half-open run window; omitted bounds mean "everything up to now". */ +export type TimeWindow = { since?: number; until_exclusive?: number }; + +export type Status = { + relay: string; + pubkey: string; + started_at: number; + connection: string; + connected_at: number | null; + reconnect_attempts: number; + last_error: string | null; + last_event_at: number | null; + backfill_complete: boolean; + channels: Record; + total_events: number; + folds: number; + artifacts: number; + db_path: string; +}; + +export type Channel = { + id: string; + name: string | null; + channel_type: string; + backfill_cursor: number | null; + backfill_done: boolean; + active: boolean; + discovered_at: number; +}; + +export type Bucket = { day: number; count: number }; + +export type Preview = { + selection: Selection; + window: { since: number; until_exclusive: number }; + count: number; + total_chars: number; + oldest_ts: number | null; + newest_ts: number | null; + buckets: Bucket[]; +}; + +export type EventItem = { + id: string; + channel: string | null; + pubkey: string; + author_name: string | null; + kind: number; + created_at: number; + content: string; +}; + +export type PageCursor = { created_at: number; id: string }; + +export type EventsPage = { + window: { since: number; until_exclusive: number }; + count: number; + next: PageCursor | null; + events: EventItem[]; +}; + +export type FoldSpec = { + name: string; + selection: Selection; + schema: string; + model: string; + instructions: string; + meta?: unknown; +}; + +export type FoldRow = { + name: string; + spec: FoldSpec; + versions: number; + latest_version: number | null; + created_at: number; + updated_at: number; +}; + +export type WindowFit = { + model_window: number | null; + est_input_tokens: number; + fits: boolean | null; + headroom_tokens: number | null; +}; + +export type Estimate = { est_input_tokens: number; window_fit: WindowFit }; + +export type Preflight = + | { plan: "cached" } + | { plan: "stalled"; reason: string; pending: number } + | { + plan: "ready"; + shown: number; + pending: number; + truncated: boolean; + estimate: Estimate; + window: [number, number]; + }; + +export type Artifact = { + fold: string; + version: number; + output: string; + shown_ids: string[]; + coverage_since: number | null; + coverage_until: number | null; + selection: Selection; + channels: string[]; + model: string; + schema: string; + prompt_sha256: string; + truncated: boolean; + created_at: number; +}; + +export type ArtifactSummary = { + version: number; + created_at: number; + shown: number; + coverage_since: number | null; + coverage_until: number | null; + channels: string[]; + model: string; + schema: string; + truncated: boolean; +}; + +export type RunOutcome = + | { status: "cached" } + | { status: "stalled"; reason: string; pending: number } + | { status: "refused"; reason: string; model_output: string } + | { status: "unpublished"; reason: string; model_output: string } + | { + status: "folded"; + artifact: Artifact; + shown: number; + pending: number; + truncated: boolean; + }; + +const BASE = "/api"; + +async function request(path: string, init?: RequestInit): Promise { + const res = await fetch(BASE + path, init); + if (!res.ok) { + let message = `${res.status} ${res.statusText}`; + try { + const body = (await res.json()) as { error?: string }; + if (body.error) message = body.error; + } catch { + // non-JSON error body; keep the status line + } + throw new Error(message); + } + return (await res.json()) as T; +} + +function json(body: unknown): Pick { + return { + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), + }; +} + +function post(body: unknown): RequestInit { + return { method: "POST", ...json(body) }; +} + +export const api = { + status: () => request("/status"), + channels: () => request<{ channels: Channel[] }>("/channels"), + event: (id: string) => request(`/events/${id}`), + preview: (selection: Selection, window: TimeWindow) => + request("/select/preview", post({ selection, ...window })), + events: ( + selection: Selection, + window: TimeWindow, + limit: number, + after: PageCursor | null, + ) => + request( + "/select/events", + post({ selection, ...window, limit, after }), + ), + folds: () => request<{ folds: FoldRow[] }>("/folds"), + putFold: ( + name: string, + body: { + selection: Selection; + model: string; + instructions?: string; + meta?: unknown; + }, + ) => request<{ saved: FoldSpec }>(`/folds/${name}`, { method: "PUT", ...json(body) }), + deleteFold: (name: string) => + request<{ deleted: string }>(`/folds/${name}`, { method: "DELETE" }), + preflight: (name: string, window: TimeWindow) => + request(`/folds/${name}/preflight`, post(window)), + run: (name: string, window: TimeWindow) => + request(`/folds/${name}/run`, post(window)), + artifacts: (name: string) => + request<{ fold: string; artifacts: ArtifactSummary[] }>( + `/folds/${name}/artifacts`, + ), + artifact: (name: string, version: number) => + request(`/folds/${name}/artifacts/${version}`), +}; + +export function selectionIsRunnable(s: Selection): boolean { + return s.channels.length > 0 || s.authors.length > 0; +} + +export function shortId(id: string): string { + return id.slice(0, 8); +} + +export function fmtTime(ts: number): string { + return new Date(ts * 1000).toLocaleString(undefined, { + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }); +} + +export function fmtDay(ts: number): string { + return new Date(ts * 1000).toLocaleDateString(undefined, { + timeZone: "UTC", + month: "short", + day: "numeric", + }); +} + +export function fmtTokens(n: number): string { + return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : `${n}`; +} diff --git a/crates/buzz-accumulator/ui/src/components/ArtifactReader.tsx b/crates/buzz-accumulator/ui/src/components/ArtifactReader.tsx new file mode 100644 index 0000000000..559490c276 --- /dev/null +++ b/crates/buzz-accumulator/ui/src/components/ArtifactReader.tsx @@ -0,0 +1,182 @@ +import { useQuery } from "@tanstack/react-query"; +import { useState, type ReactNode } from "react"; +import { api, fmtTime, shortId } from "../api"; + +type Props = { + fold: string; + version: number; + onVersion: (v: number) => void; +}; + +/** Renders one artifact version: Working Context + Log with citation chips, + * a version scrubber, and a pinned-evidence rail. */ +export function ArtifactReader({ fold, version, onVersion }: Props) { + const [pinned, setPinned] = useState([]); + + const chain = useQuery({ + queryKey: ["artifacts", fold], + queryFn: () => api.artifacts(fold), + }); + const artifact = useQuery({ + queryKey: ["artifact", fold, version], + queryFn: () => api.artifact(fold, version), + }); + + const pin = (id: string) => + setPinned((p) => (p.includes(id) ? p : [id, ...p])); + + const a = artifact.data; + + return ( +
+
+ {fold} +
+ {chain.data?.artifacts.map((s) => ( + + ))} +
+
+ {a && ( +
+ {fmtTime(a.created_at)} · model {a.model} · {a.shown_ids.length} shown + {a.truncated ? " · chunked window" : ""} + {a.coverage_since !== null && a.coverage_until !== null && ( + <> + {" "} + · covers {fmtTime(a.coverage_since)} → {fmtTime(a.coverage_until)} + + )} +
+ )} + {artifact.isError && ( +
{(artifact.error as Error).message}
+ )} +
+
+ {a ? renderOutput(a.output, pin) : loading…} +
+
+

Evidence

+ {pinned.length === 0 && ( +
+ Click a citation chip to pin the source message here — every + claim is one click from its evidence. +
+ )} + {pinned.map((id) => ( + setPinned((p) => p.filter((x) => x !== id))} + /> + ))} +
+
+
+ ); +} + +function EvidenceCard({ id, onClose }: { id: string; onClose: () => void }) { + const ev = useQuery({ + queryKey: ["event", id], + queryFn: () => api.event(id), + retry: false, + }); + return ( +
+
+ + {ev.data ? ( + <> + {ev.data.author_name ?? shortId(ev.data.pubkey)}{" "} + · {fmtTime(ev.data.created_at)} + + ) : ( + {shortId(id)}… + )} + + +
+
+ {ev.isError + ? `not in the mirror: ${(ev.error as Error).message}` + : (ev.data?.content ?? "loading…")} +
+
+ ); +} + +const CITATION = /\[event:([0-9a-f]{64})\]/g; + +/** Minimal renderer for the artifact's markdown-shaped output: headings, + * list items, paragraphs — with `[event:]` turned into citation chips. */ +function renderOutput(output: string, pin: (id: string) => void): ReactNode { + const blocks: ReactNode[] = []; + let list: ReactNode[] = []; + let key = 0; + + const flushList = () => { + if (list.length > 0) { + blocks.push(
    {list}
); + list = []; + } + }; + + for (const line of output.split("\n")) { + const trimmed = line.trim(); + if (trimmed.startsWith("- ") || trimmed.startsWith("* ")) { + list.push(
  • {inline(trimmed.slice(2), pin)}
  • ); + continue; + } + flushList(); + if (trimmed.startsWith("## ")) { + blocks.push(

    {inline(trimmed.slice(3), pin)}

    ); + } else if (trimmed.startsWith("# ")) { + blocks.push(

    {inline(trimmed.slice(2), pin)}

    ); + } else if (trimmed.length > 0) { + blocks.push(

    {inline(trimmed, pin)}

    ); + } + } + flushList(); + return blocks; +} + +function inline(text: string, pin: (id: string) => void): ReactNode[] { + const out: ReactNode[] = []; + let last = 0; + let key = 0; + CITATION.lastIndex = 0; + let m = CITATION.exec(text); + while (m !== null) { + if (m.index > last) out.push(text.slice(last, m.index)); + const id = m[1]; + if (id) { + out.push( + , + ); + } + last = m.index + m[0].length; + m = CITATION.exec(text); + } + if (last < text.length) out.push(text.slice(last)); + return out; +} diff --git a/crates/buzz-accumulator/ui/src/components/Explore.tsx b/crates/buzz-accumulator/ui/src/components/Explore.tsx new file mode 100644 index 0000000000..4356eace0d --- /dev/null +++ b/crates/buzz-accumulator/ui/src/components/Explore.tsx @@ -0,0 +1,198 @@ +import { useInfiniteQuery, useQuery } from "@tanstack/react-query"; +import { useState } from "react"; +import { + api, + fmtDay, + fmtTime, + fmtTokens, + selectionIsRunnable, + shortId, + type Bucket, + type PageCursor, + type Selection, + type TimeWindow, +} from "../api"; + +type Props = { selection: Selection; window: TimeWindow }; + +/** Selection preview: stats, daily rhythm, and the actual matching events. */ +export function Explore({ selection, window }: Props) { + const runnable = selectionIsRunnable(selection); + + const preview = useQuery({ + queryKey: ["preview", selection, window], + queryFn: () => api.preview(selection, window), + enabled: runnable, + }); + + const events = useInfiniteQuery({ + queryKey: ["events", selection, window], + queryFn: ({ pageParam }) => api.events(selection, window, 50, pageParam), + initialPageParam: null as PageCursor | null, + getNextPageParam: (last) => last.next, + enabled: runnable, + }); + + if (!runnable) { + return ( +
    + Pick at least one channel or author on the left to preview a selection. +
    + Everything here is free — no model is called until you press Run on a + fold. +
    + ); + } + + const p = preview.data; + const allEvents = events.data?.pages.flatMap((page) => page.events) ?? []; + + return ( +
    + {preview.isError && ( +
    {(preview.error as Error).message}
    + )} + {p && ( +
    +
    +
    {p.count.toLocaleString()}
    +
    events
    +
    +
    +
    {p.total_chars.toLocaleString()}
    +
    chars
    +
    +
    +
    ~{fmtTokens(Math.ceil(p.total_chars / 4))}
    +
    est. input tokens
    +
    + {p.oldest_ts !== null && p.newest_ts !== null && ( +
    +
    + {fmtTime(p.oldest_ts)} → {fmtTime(p.newest_ts)} +
    +
    span
    +
    + )} +
    + )} + + {p && p.buckets.length > 0 && } + + {allEvents.map((ev) => ( + + ))} + {events.hasNextPage && ( + + )} + {events.data && allEvents.length === 0 && ( +
    No events match this selection.
    + )} +
    + ); +} + +function EventRow({ + id, + author, + time, + content, +}: { + id: string; + author: string; + time: number; + content: string; +}) { + const [expanded, setExpanded] = useState(false); + return ( +
    setExpanded((e) => !e)} + > +
    + {author} + {fmtTime(time)} + {shortId(id)} +
    +
    {content}
    +
    + ); +} + +/** Daily activity histogram. Single series: one hue, gaps filled with + * zero-height days so rhythm (and silence) is visible. */ +function RhythmStrip({ buckets }: { buckets: Bucket[] }) { + const DAY = 86_400; + const first = buckets[0]; + const last = buckets[buckets.length - 1]; + if (!first || !last) return null; + + const byDay = new Map(buckets.map((b) => [b.day, b.count])); + const days: Bucket[] = []; + for (let d = first.day; d <= last.day; d += DAY) { + days.push({ day: d, count: byDay.get(d) ?? 0 }); + } + // Beyond ~a year of days, group whole weeks so bars stay visible. + const perWeek = days.length > 366; + const cells: Bucket[] = perWeek + ? Array.from({ length: Math.ceil(days.length / 7) }, (_, i) => ({ + day: days[i * 7]?.day ?? 0, + count: days + .slice(i * 7, i * 7 + 7) + .reduce((acc, b) => acc + b.count, 0), + })) + : days; + + const w = 800; + const h = 64; + const gap = 2; + const bw = Math.max(1, w / cells.length - gap); + const max = Math.max(1, ...cells.map((c) => c.count)); + + return ( +
    +
    + ACTIVITY BY {perWeek ? "WEEK" : "DAY"} · {fmtDay(first.day)} –{" "} + {fmtDay(last.day)} +
    + + {cells.map((c, i) => { + const bh = Math.max(c.count > 0 ? 2 : 0, (c.count / max) * (h - 4)); + return ( + + + {fmtDay(c.day)}: {c.count} events + + + ); + })} + +
    + ); +} diff --git a/crates/buzz-accumulator/ui/src/components/FoldsBoard.tsx b/crates/buzz-accumulator/ui/src/components/FoldsBoard.tsx new file mode 100644 index 0000000000..c9fea79165 --- /dev/null +++ b/crates/buzz-accumulator/ui/src/components/FoldsBoard.tsx @@ -0,0 +1,262 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useState } from "react"; +import { + api, + fmtTime, + fmtTokens, + selectionIsRunnable, + type FoldRow, + type Preflight, + type RunOutcome, + type Selection, +} from "../api"; + +type Props = { + selection: Selection; + onOpenArtifact: (fold: string, version: number) => void; +}; + +export function FoldsBoard({ selection, onOpenArtifact }: Props) { + const folds = useQuery({ queryKey: ["folds"], queryFn: api.folds }); + + return ( +
    +

    Folds

    + + {folds.isError && ( +
    {(folds.error as Error).message}
    + )} + {folds.data?.folds.length === 0 && ( +
    + No folds yet. Compose a selection, then create one above — runs are + always priced before they spend. +
    + )} + {folds.data?.folds.map((f) => ( + + ))} +
    + ); +} + +function CreateFold({ selection }: { selection: Selection }) { + const qc = useQueryClient(); + const [name, setName] = useState(""); + const [model, setModel] = useState("haiku"); + const [instructions, setInstructions] = useState(""); + + const create = useMutation({ + mutationFn: () => + api.putFold(name.trim(), { + selection, + model, + ...(instructions.trim() ? { instructions } : {}), + }), + onSuccess: () => { + setName(""); + setInstructions(""); + qc.invalidateQueries({ queryKey: ["folds"] }); + }, + }); + + const ready = name.trim().length > 0 && selectionIsRunnable(selection); + + return ( +
    +
    + + setName(e.target.value)} + /> +
    +
    + + +
    +
    + +