mirror of
https://github.com/block/buzz.git
synced 2026-10-30 05:51:46 +00:00
Seeding a project's first canvas read `resources/project-canvas-template` from disk at activation time, resolved from the running executable's directory in dev builds. That directory is the cargo target directory — shared across worktrees, rewritten by sibling builds, and deleted wholesale by toolchain cleanups. When it disappeared under a running app the first-ever activation of `buzz-bugs` failed with `inspect project canvas path: No such file or directory (os error 2)` and could not self-heal. Make the seed bytes part of the binary and drop the on-disk copy, so no runtime lookup exists to go stale. This follows `resources/pocket-voices`, which already embeds 7.6 MB of `.wav` through `include_bytes!` and is deliberately absent from `bundle.resources`. The template is consumed only as seed bytes: agents author canvases from `CANVASES/index.json` → `sourcePath`, never from the template, so the disk copy had no remaining consumer. - New `project_canvas_package/template.rs` embeds the tree with `include_dir!` and walks it into a path-keyed map, running every key through `validate_relative_path` and skipping `.DS_Store` exactly as the on-disk scan does. The validated package is cached in a `OnceLock` so the SHA-256 over 2.7 MB runs once per process, and validation happens on the blocking task rather than the command's async caller. - `build.rs` gains `cargo:rerun-if-changed=resources/project-canvas-template`. `include_dir!` expands to one `include_bytes!` per file, so rustc notices edits but not a file added or removed; without this line the binary can ship a stale file list. - `scan_package` splits into `ensure_package_dir` + `validate_package_files`. The latter is now the single validation gate for both disk-read and embedded packages — there is no second, weaker path for the template. `prepare_snapshot`, `seed_if_missing`, `get_or_activate`, and `activate` take `Option<&ValidatedPackage>`; `accept_agent_update` still passes `None` so an agent update can never seed a canvas that does not exist. - Delete `template_path`/`template_path_from`, the `AppHandle` parameter they forced onto two commands, and `bundle.resources` in `tauri.conf.json`. With no on-disk copy there is no second source of truth to go stale, and the `.app` bundle shrinks by 2.7 MB. - `ensure_package_dir` replaces `ensure_no_symlink` + `Path::is_dir()` with one non-following `symlink_metadata`, so an absent directory is named instead of dying unnamed inside the metadata call. Strictly stronger: the symlink check still runs on non-following metadata, and the directory test now reads off that metadata rather than a link-following `is_dir()`. Tests: `bundled_template_seeds_a_valid_snapshot` and `first_activation_seeds_the_validated_template` repoint at the embedded package and an in-memory map. New `bundled_template_contains_the_expected_tree` compares the embedded key set against a test-time walk of the source tree, `bundled_template_paths_are_package_safe` asserts every key is relative and traversal-free, `missing_package_directory_names_the_path` pins the new error ordering, and `package_root_symlink_is_rejected` covers the package root itself, which no existing test did. Each was checked falsifiable: dropping one embedded file fails the first two, restoring the old ordering fails the third, and removing the symlink arm fails the fourth. Verified: Tauri suite passes 3077 tests, clippy -D warnings, rustfmt, and the file-size gate are clean. `cargo build --bin buzz-desktop` emits no `resources/` directory next to the executable, so the built binary has no on-disk template to read. A live canvas open was not exercised — that needs an interactive `just staging` session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Matt Toohey <contact@matttoohey.com>
91 lines
2.5 KiB
JSON
91 lines
2.5 KiB
JSON
{
|
|
"$schema": "https://schema.tauri.app/config/2",
|
|
"productName": "Buzz",
|
|
"version": "0.5.20",
|
|
"identifier": "xyz.block.buzz.app",
|
|
"build": {
|
|
"beforeDevCommand": {
|
|
"script": "exec ./node_modules/.bin/vite",
|
|
"cwd": "..",
|
|
"wait": false
|
|
},
|
|
"devUrl": "http://localhost:1420",
|
|
"beforeBuildCommand": "pnpm build",
|
|
"frontendDist": "../dist"
|
|
},
|
|
"app": {
|
|
"windows": [
|
|
{
|
|
"title": "",
|
|
"width": 800,
|
|
"height": 600,
|
|
"maximized": true,
|
|
"visible": false,
|
|
"transparent": false,
|
|
"titleBarStyle": "Overlay",
|
|
"hiddenTitle": true,
|
|
"dragDropEnabled": false,
|
|
"trafficLightPosition": {
|
|
"x": 16,
|
|
"y": 25
|
|
},
|
|
"backgroundThrottling": "disabled",
|
|
"minWidth": 800,
|
|
"minHeight": 500
|
|
}
|
|
],
|
|
"macOSPrivateApi": true,
|
|
"security": {
|
|
"csp": "default-src 'self'; base-uri 'self'; form-action 'none'; frame-ancestors 'none'; frame-src buzz-canvas: http://buzz-canvas.localhost; object-src 'none'; script-src 'self' 'wasm-unsafe-eval' https://cdn.jsdelivr.net/npm/@mediapipe/; style-src 'self' 'unsafe-inline'; font-src 'self' data:; connect-src 'self' ipc: http://ipc.localhost buzz-media: http://buzz-media.localhost https: http: wss: ws:; img-src 'self' buzz-media: http://buzz-media.localhost data: blob: https: http:; media-src 'self' buzz-media: http://buzz-media.localhost data: blob: https: http:; worker-src 'self' blob:"
|
|
}
|
|
},
|
|
"plugins": {
|
|
"updater": {
|
|
"endpoints": []
|
|
},
|
|
"deep-link": {
|
|
"desktop": {
|
|
"schemes": ["buzz"]
|
|
}
|
|
}
|
|
},
|
|
"bundle": {
|
|
"active": true,
|
|
"targets": "all",
|
|
"externalBin": [
|
|
"binaries/buzz-acp",
|
|
"binaries/buzz-agent",
|
|
"binaries/buzz-backend-kubernetes",
|
|
"binaries/buzz-dev-mcp",
|
|
"binaries/git-credential-nostr",
|
|
"binaries/buzz"
|
|
],
|
|
"icon": [
|
|
"icons/32x32.png",
|
|
"icons/128x128.png",
|
|
"icons/128x128@2x.png",
|
|
"icons/icon.icns",
|
|
"icons/icon.ico"
|
|
],
|
|
"macOS": {
|
|
"infoPlist": "Info.plist",
|
|
"entitlements": "Entitlements.plist",
|
|
"dmg": {
|
|
"background": "icons/dmg-background.png",
|
|
"windowSize": {
|
|
"width": 660,
|
|
"height": 532
|
|
},
|
|
"appPosition": {
|
|
"x": 191,
|
|
"y": 330
|
|
},
|
|
"applicationFolderPosition": {
|
|
"x": 469,
|
|
"y": 330
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|