pixelweaver 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (392) hide show
  1. package/.env.development +1 -0
  2. package/.github/workflows/ci.yml +22 -0
  3. package/.github/workflows/publish.yml +18 -0
  4. package/.prettierignore +5 -0
  5. package/.prettierrc +16 -0
  6. package/.python-version +1 -0
  7. package/.rlsbl/bases/.github/workflows/ci.yml +21 -0
  8. package/.rlsbl/bases/.github/workflows/publish.yml +18 -0
  9. package/.rlsbl/bases/.rlsbl/changes/unreleased.jsonl +0 -0
  10. package/.rlsbl/bases/.rlsbl/hooks/post-release.sh +8 -0
  11. package/.rlsbl/bases/.rlsbl/hooks/pre-checks.sh +5 -0
  12. package/.rlsbl/bases/.rlsbl/hooks/pre-release.sh +8 -0
  13. package/.rlsbl/bases/.rlsbl/lint/go.toml +17 -0
  14. package/.rlsbl/bases/.rlsbl/lint/npm.toml +19 -0
  15. package/.rlsbl/bases/.rlsbl/lint/python.toml +25 -0
  16. package/.rlsbl/bases/CHANGELOG.md +5 -0
  17. package/.rlsbl/bases/LICENSE +21 -0
  18. package/.rlsbl/changes/.validated +1 -0
  19. package/.rlsbl/changes/0.1.0.jsonl +85 -0
  20. package/.rlsbl/changes/0.1.0.md +13 -0
  21. package/.rlsbl/changes/unreleased.jsonl +0 -0
  22. package/.rlsbl/config.json +6 -0
  23. package/.rlsbl/hashes.json +14 -0
  24. package/.rlsbl/hooks/post-release.sh +8 -0
  25. package/.rlsbl/hooks/pre-checks.sh +5 -0
  26. package/.rlsbl/hooks/pre-release.sh +8 -0
  27. package/.rlsbl/lint/go.toml +17 -0
  28. package/.rlsbl/lint/npm.toml +19 -0
  29. package/.rlsbl/lint/python.toml +25 -0
  30. package/.rlsbl/releases/unreleased.toml +0 -0
  31. package/.rlsbl/releases/v0.1.0.toml +3 -0
  32. package/.rlsbl/version +1 -0
  33. package/.selfdoc/hashes/hashes.json +146 -0
  34. package/.strictcli/schema.json +227 -0
  35. package/CHANGELOG.md +17 -0
  36. package/CLAUDE.md +100 -0
  37. package/LICENSE +21 -0
  38. package/README.md +116 -0
  39. package/assets/icon.png +0 -0
  40. package/docs/_README.md +117 -0
  41. package/docs/cli-config.md +35 -0
  42. package/docs/cli-dev.md +21 -0
  43. package/docs/cli-diagnose.md +12 -0
  44. package/docs/cli-index.md +30 -0
  45. package/docs/cli-list.md +18 -0
  46. package/docs/cli-mcp.md +18 -0
  47. package/docs/cli-new.md +26 -0
  48. package/docs/cli-open.md +21 -0
  49. package/docs/cli-serve.md +21 -0
  50. package/docs/cli-stop.md +12 -0
  51. package/docs/gen-index.md +36 -0
  52. package/docs/index.md +13 -0
  53. package/docs/server-src-pixelweaver-__main__.md +12 -0
  54. package/docs/server-src-pixelweaver-autosave.md +12 -0
  55. package/docs/server-src-pixelweaver-bridge.md +12 -0
  56. package/docs/server-src-pixelweaver-cli.md +12 -0
  57. package/docs/server-src-pixelweaver-config.md +12 -0
  58. package/docs/server-src-pixelweaver-connections.md +12 -0
  59. package/docs/server-src-pixelweaver-main.md +12 -0
  60. package/docs/server-src-pixelweaver-mcp_bridge.md +12 -0
  61. package/docs/server-src-pixelweaver-mcp_drawing_tools.md +12 -0
  62. package/docs/server-src-pixelweaver-mcp_export_tools.md +12 -0
  63. package/docs/server-src-pixelweaver-mcp_frame_tools.md +12 -0
  64. package/docs/server-src-pixelweaver-mcp_history_tools.md +12 -0
  65. package/docs/server-src-pixelweaver-mcp_layer_tools.md +12 -0
  66. package/docs/server-src-pixelweaver-mcp_lock.md +12 -0
  67. package/docs/server-src-pixelweaver-mcp_project_tools.md +12 -0
  68. package/docs/server-src-pixelweaver-mcp_read_tools.md +12 -0
  69. package/docs/server-src-pixelweaver-mcp_registry.md +12 -0
  70. package/docs/server-src-pixelweaver-mcp_resources.md +12 -0
  71. package/docs/server-src-pixelweaver-mcp_server.md +12 -0
  72. package/docs/server-src-pixelweaver-protocol.md +12 -0
  73. package/docs/server-src-pixelweaver-state.md +12 -0
  74. package/docs/server-src-pixelweaver-storage.md +12 -0
  75. package/docs/server-src-pixelweaver-websocket.md +12 -0
  76. package/docs/server-src-pixelweaver.md +12 -0
  77. package/e2e/app-launch.test.ts +35 -0
  78. package/e2e/menus.test.ts +26 -0
  79. package/e2e/tools.test.ts +27 -0
  80. package/e2e/undo-redo.test.ts +11 -0
  81. package/eslint.config.js +62 -0
  82. package/index.html +13 -0
  83. package/package.json +48 -0
  84. package/playwright.config.ts +19 -0
  85. package/plugins/builtin/.gitkeep +0 -0
  86. package/plugins/builtin/advanced-fill-tool.ts +146 -0
  87. package/plugins/builtin/circle-tool.ts +186 -0
  88. package/plugins/builtin/diamond-tool.ts +182 -0
  89. package/plugins/builtin/dither-tool.ts +186 -0
  90. package/plugins/builtin/drawing-primitives-plugin.ts +362 -0
  91. package/plugins/builtin/drawing-utils.test.ts +495 -0
  92. package/plugins/builtin/drawing-utils.ts +431 -0
  93. package/plugins/builtin/effects/blur.ts +97 -0
  94. package/plugins/builtin/effects/color-effects.ts +278 -0
  95. package/plugins/builtin/effects/flip.ts +83 -0
  96. package/plugins/builtin/effects/glow.ts +118 -0
  97. package/plugins/builtin/effects/outline.ts +110 -0
  98. package/plugins/builtin/effects/rotate.ts +357 -0
  99. package/plugins/builtin/effects/scale.ts +258 -0
  100. package/plugins/builtin/effects/shadow.ts +111 -0
  101. package/plugins/builtin/effects/sharpen.ts +102 -0
  102. package/plugins/builtin/effects.test.ts +715 -0
  103. package/plugins/builtin/eraser-tool.ts +23 -0
  104. package/plugins/builtin/eyedropper-tool.ts +83 -0
  105. package/plugins/builtin/fill-tool.ts +93 -0
  106. package/plugins/builtin/gradient-tool.ts +204 -0
  107. package/plugins/builtin/gradient.test.ts +142 -0
  108. package/plugins/builtin/importers/aseprite-importer-plugin.ts +174 -0
  109. package/plugins/builtin/importers/aseprite-parser.ts +497 -0
  110. package/plugins/builtin/importers/piskel-importer-plugin.ts +222 -0
  111. package/plugins/builtin/importers/sky-spec-plugin.ts +409 -0
  112. package/plugins/builtin/line-tool.ts +267 -0
  113. package/plugins/builtin/make-stroke-tool.ts +271 -0
  114. package/plugins/builtin/noise-dither.test.ts +151 -0
  115. package/plugins/builtin/noise-tool.ts +131 -0
  116. package/plugins/builtin/pattern-stamp-tool.ts +162 -0
  117. package/plugins/builtin/pencil-tool.ts +25 -0
  118. package/plugins/builtin/rect-tool.ts +179 -0
  119. package/plugins/builtin/selection-tool.ts +388 -0
  120. package/plugins/builtin/selection.test.ts +195 -0
  121. package/plugins/builtin/tool-plugins.test.ts +529 -0
  122. package/public/favicon.svg +7 -0
  123. package/public/sw.js +91 -0
  124. package/pyproject.toml +49 -0
  125. package/scripts/eslint-wave-a-list.sh +24 -0
  126. package/scripts/eslint-wave-a-status.sh +25 -0
  127. package/scripts/fix-index-signature-access.py +127 -0
  128. package/scripts/fix-unchecked-index.py +128 -0
  129. package/scripts/fix-unchecked-vars.py +127 -0
  130. package/scripts/fix-wave-a-bangs.py +36 -0
  131. package/scripts/fix-wave-a-templates.py +108 -0
  132. package/scripts/fix-wave-b-void-expr.py +167 -0
  133. package/scripts/generate-command-params.py +540 -0
  134. package/scripts/migrate-single-frame-to-multi.py +171 -0
  135. package/scripts/smoke-test.sh +77 -0
  136. package/selfdoc.json +10 -0
  137. package/server/README.md +0 -0
  138. package/server/src/pixelweaver/__init__.py +1 -0
  139. package/server/src/pixelweaver/__main__.py +4 -0
  140. package/server/src/pixelweaver/autosave.py +114 -0
  141. package/server/src/pixelweaver/bridge.py +127 -0
  142. package/server/src/pixelweaver/cli.py +199 -0
  143. package/server/src/pixelweaver/config.py +24 -0
  144. package/server/src/pixelweaver/connections.py +54 -0
  145. package/server/src/pixelweaver/main.py +271 -0
  146. package/server/src/pixelweaver/mcp_bridge.py +189 -0
  147. package/server/src/pixelweaver/mcp_drawing_tools.py +178 -0
  148. package/server/src/pixelweaver/mcp_export_tools.py +291 -0
  149. package/server/src/pixelweaver/mcp_frame_tools.py +423 -0
  150. package/server/src/pixelweaver/mcp_history_tools.py +106 -0
  151. package/server/src/pixelweaver/mcp_layer_tools.py +64 -0
  152. package/server/src/pixelweaver/mcp_lock.py +37 -0
  153. package/server/src/pixelweaver/mcp_project_tools.py +302 -0
  154. package/server/src/pixelweaver/mcp_read_tools.py +163 -0
  155. package/server/src/pixelweaver/mcp_registry.py +247 -0
  156. package/server/src/pixelweaver/mcp_resources.py +312 -0
  157. package/server/src/pixelweaver/mcp_server.py +234 -0
  158. package/server/src/pixelweaver/protocol.py +219 -0
  159. package/server/src/pixelweaver/state.py +267 -0
  160. package/server/src/pixelweaver/storage.py +293 -0
  161. package/server/src/pixelweaver/websocket.py +282 -0
  162. package/server/tests/__init__.py +0 -0
  163. package/server/tests/conftest.py +17 -0
  164. package/server/tests/test_api.py +96 -0
  165. package/server/tests/test_bridge.py +161 -0
  166. package/server/tests/test_health.py +9 -0
  167. package/server/tests/test_integration.py +86 -0
  168. package/server/tests/test_mcp_bridge.py +293 -0
  169. package/server/tests/test_mcp_lock.py +34 -0
  170. package/server/tests/test_mcp_registry.py +679 -0
  171. package/server/tests/test_mcp_resources.py +648 -0
  172. package/server/tests/test_protocol.py +125 -0
  173. package/server/tests/test_state.py +87 -0
  174. package/server/tests/test_storage.py +306 -0
  175. package/server/tests/test_websocket.py +275 -0
  176. package/src/App.svelte +107 -0
  177. package/src/app.css +215 -0
  178. package/src/lib/animation/AnimationPreviewPanel.svelte +667 -0
  179. package/src/lib/animation/animation-commands.test.ts +228 -0
  180. package/src/lib/animation/animation-commands.ts +540 -0
  181. package/src/lib/animation/animation-preview-panel-plugin.ts +25 -0
  182. package/src/lib/animation/animation-preview.svelte.ts +151 -0
  183. package/src/lib/animation/clipboard.ts +134 -0
  184. package/src/lib/animation/frame-model.svelte.ts +437 -0
  185. package/src/lib/animation/frame-model.test.ts +314 -0
  186. package/src/lib/animation/frame-selection.svelte.ts +77 -0
  187. package/src/lib/animation/frame-tags.svelte.ts +238 -0
  188. package/src/lib/animation/frame-tags.test.ts +136 -0
  189. package/src/lib/animation/import.test.ts +141 -0
  190. package/src/lib/animation/import.ts +112 -0
  191. package/src/lib/animation/spritesheet-export.test.ts +239 -0
  192. package/src/lib/animation/spritesheet-export.ts +314 -0
  193. package/src/lib/canvas/CanvasViewport.svelte +216 -0
  194. package/src/lib/canvas/canvas-init-plugin.ts +178 -0
  195. package/src/lib/canvas/canvas-renderer.ts +408 -0
  196. package/src/lib/canvas/canvas-state.svelte.ts +232 -0
  197. package/src/lib/canvas/canvas-state.test.ts +139 -0
  198. package/src/lib/canvas/input-handler.ts +221 -0
  199. package/src/lib/canvas/input-plugin.ts +150 -0
  200. package/src/lib/canvas/onion-skin.ts +94 -0
  201. package/src/lib/canvas/pixel-buffer.test.ts +249 -0
  202. package/src/lib/canvas/pixel-buffer.ts +151 -0
  203. package/src/lib/canvas/render-state.svelte.ts +18 -0
  204. package/src/lib/canvas/shape-preview-state.svelte.ts +36 -0
  205. package/src/lib/canvas/tile-mode.test.ts +53 -0
  206. package/src/lib/canvas/tile-mode.ts +92 -0
  207. package/src/lib/canvas/viewport-utils.ts +24 -0
  208. package/src/lib/canvas/zoom-utils.ts +31 -0
  209. package/src/lib/color/.gitkeep +0 -0
  210. package/src/lib/color/color-commands.ts +87 -0
  211. package/src/lib/color/color-state.svelte.ts +98 -0
  212. package/src/lib/color/color-state.test.ts +91 -0
  213. package/src/lib/color/color-utils.test.ts +220 -0
  214. package/src/lib/color/color-utils.ts +243 -0
  215. package/src/lib/color/palette-state.svelte.ts +127 -0
  216. package/src/lib/color/palette-state.test.ts +154 -0
  217. package/src/lib/color/palette.ts +79 -0
  218. package/src/lib/core/bootstrap.ts +66 -0
  219. package/src/lib/core/command-params.generated.ts +1549 -0
  220. package/src/lib/core/command-params.ts +20 -0
  221. package/src/lib/core/command-runner.ts +79 -0
  222. package/src/lib/core/commands.ts +134 -0
  223. package/src/lib/core/dispatcher.test.ts +548 -0
  224. package/src/lib/core/dispatcher.ts +361 -0
  225. package/src/lib/core/index.test.ts +7 -0
  226. package/src/lib/core/notification-state.svelte.ts +119 -0
  227. package/src/lib/core/plugin-api.ts +210 -0
  228. package/src/lib/core/plugin-discovery.test.ts +53 -0
  229. package/src/lib/core/plugin-discovery.ts +65 -0
  230. package/src/lib/core/plugin-loader.test.ts +159 -0
  231. package/src/lib/core/plugin-loader.ts +240 -0
  232. package/src/lib/core/plugin-types.ts +286 -0
  233. package/src/lib/core/registries.svelte.ts +74 -0
  234. package/src/lib/core/tool-options-state.svelte.ts +61 -0
  235. package/src/lib/dock/DockLayout.svelte +375 -0
  236. package/src/lib/dock/TabAddMenu.svelte +90 -0
  237. package/src/lib/dock/dock-persistence.ts +46 -0
  238. package/src/lib/dock/dock-plugin.ts +49 -0
  239. package/src/lib/dock/dock-presets.ts +156 -0
  240. package/src/lib/dock/dock-state.svelte.ts +77 -0
  241. package/src/lib/dock/dock-types.ts +2 -0
  242. package/src/lib/dock/dockview-theme.css +226 -0
  243. package/src/lib/dock/dockview-theme.ts +17 -0
  244. package/src/lib/dock/header-action-renderer.ts +77 -0
  245. package/src/lib/edit/clipboard-state.ts +34 -0
  246. package/src/lib/export/download.ts +201 -0
  247. package/src/lib/export/png-metadata.ts +181 -0
  248. package/src/lib/history/ActionLogPanel.svelte +418 -0
  249. package/src/lib/history/action-log-panel-plugin.ts +24 -0
  250. package/src/lib/history/action-log.svelte.ts +172 -0
  251. package/src/lib/history/action-log.test.ts +168 -0
  252. package/src/lib/history/history-commands.ts +403 -0
  253. package/src/lib/history/macros.svelte.ts +320 -0
  254. package/src/lib/history/macros.test.ts +224 -0
  255. package/src/lib/history/replay-engine.test.ts +241 -0
  256. package/src/lib/history/replay-engine.ts +149 -0
  257. package/src/lib/history/spec-format.test.ts +250 -0
  258. package/src/lib/history/spec-format.ts +210 -0
  259. package/src/lib/iso/SeamCheckerPanel.svelte +251 -0
  260. package/src/lib/iso/iso-math.test.ts +77 -0
  261. package/src/lib/iso/iso-math.ts +77 -0
  262. package/src/lib/iso/seam-checker-panel-plugin.ts +25 -0
  263. package/src/lib/iso/seam-checker.test.ts +126 -0
  264. package/src/lib/iso/seam-checker.ts +93 -0
  265. package/src/lib/iso/tessellation.ts +67 -0
  266. package/src/lib/layers/compositor.test.ts +193 -0
  267. package/src/lib/layers/compositor.ts +175 -0
  268. package/src/lib/layers/layer-commands.test.ts +263 -0
  269. package/src/lib/layers/layer-commands.ts +429 -0
  270. package/src/lib/layers/layer-tree.svelte.ts +516 -0
  271. package/src/lib/layers/layer-tree.test.ts +383 -0
  272. package/src/lib/layers/layer-types.ts +56 -0
  273. package/src/lib/leveleditor/LevelEditorViewport.svelte +1808 -0
  274. package/src/lib/leveleditor/MapPropertiesPanel.svelte +266 -0
  275. package/src/lib/leveleditor/TilePickerPanel.svelte +324 -0
  276. package/src/lib/leveleditor/depth-sort.test.ts +70 -0
  277. package/src/lib/leveleditor/depth-sort.ts +39 -0
  278. package/src/lib/leveleditor/level-editor-commands.ts +353 -0
  279. package/src/lib/leveleditor/level-editor-viewport-plugin.ts +25 -0
  280. package/src/lib/leveleditor/map-properties-panel-plugin.ts +25 -0
  281. package/src/lib/leveleditor/map-state.svelte.ts +372 -0
  282. package/src/lib/leveleditor/map-state.test.ts +243 -0
  283. package/src/lib/leveleditor/tile-picker-panel-plugin.ts +25 -0
  284. package/src/lib/leveleditor/tile-source-registry.svelte.ts +91 -0
  285. package/src/lib/leveleditor/tiled-export.test.ts +144 -0
  286. package/src/lib/leveleditor/tiled-export.ts +374 -0
  287. package/src/lib/pywebview.d.ts +15 -0
  288. package/src/lib/recovery/.gitkeep +0 -0
  289. package/src/lib/recovery/idb-store.ts +118 -0
  290. package/src/lib/recovery/recovery-manager.test.ts +321 -0
  291. package/src/lib/recovery/recovery-manager.ts +115 -0
  292. package/src/lib/recovery/recovery-plugin.ts +55 -0
  293. package/src/lib/recovery/recovery-state.svelte.ts +21 -0
  294. package/src/lib/recovery/sw-plugin.ts +18 -0
  295. package/src/lib/recovery/sw-register.ts +17 -0
  296. package/src/lib/save/directory-format.ts +42 -0
  297. package/src/lib/save/project-snapshot.ts +139 -0
  298. package/src/lib/save/recent-projects.ts +56 -0
  299. package/src/lib/save/save-state.svelte.ts +35 -0
  300. package/src/lib/save/storage.ts +167 -0
  301. package/src/lib/save/zip-format.ts +45 -0
  302. package/src/lib/shortcuts/.gitkeep +0 -0
  303. package/src/lib/shortcuts/ShortcutEditorPanel.svelte +690 -0
  304. package/src/lib/shortcuts/default-bindings.ts +61 -0
  305. package/src/lib/shortcuts/shortcut-editor-panel-plugin.ts +25 -0
  306. package/src/lib/shortcuts/shortcut-init.ts +380 -0
  307. package/src/lib/shortcuts/shortcut-manager.test.ts +466 -0
  308. package/src/lib/shortcuts/shortcut-manager.ts +281 -0
  309. package/src/lib/shortcuts/shortcut-state.svelte.ts +78 -0
  310. package/src/lib/shortcuts/shortcuts-plugin.ts +17 -0
  311. package/src/lib/sync/patch-applicator.ts +300 -0
  312. package/src/lib/sync/patch-types.ts +65 -0
  313. package/src/lib/sync/project-manager.ts +108 -0
  314. package/src/lib/sync/sync-init.ts +152 -0
  315. package/src/lib/sync/sync-plugin.ts +19 -0
  316. package/src/lib/sync/sync-state.svelte.ts +56 -0
  317. package/src/lib/sync/ws-client.test.ts +604 -0
  318. package/src/lib/sync/ws-client.ts +574 -0
  319. package/src/lib/tools/.gitkeep +0 -0
  320. package/src/lib/ui/.gitkeep +0 -0
  321. package/src/lib/ui/AboutDialog.svelte +113 -0
  322. package/src/lib/ui/ColorPicker.svelte +761 -0
  323. package/src/lib/ui/ContextMenu.svelte +216 -0
  324. package/src/lib/ui/ExportDialog.svelte +747 -0
  325. package/src/lib/ui/FrameStrip.svelte +854 -0
  326. package/src/lib/ui/LayerPanel.svelte +810 -0
  327. package/src/lib/ui/MenuBar.svelte +590 -0
  328. package/src/lib/ui/NewProjectDialog.svelte +803 -0
  329. package/src/lib/ui/PluginManagerPanel.svelte +475 -0
  330. package/src/lib/ui/PromptDialog.svelte +252 -0
  331. package/src/lib/ui/RecoveryDialog.svelte +295 -0
  332. package/src/lib/ui/ResizeDialog.svelte +416 -0
  333. package/src/lib/ui/StatusBar.svelte +145 -0
  334. package/src/lib/ui/ToolbarPanel.svelte +488 -0
  335. package/src/lib/ui/animation-menu-commands.ts +194 -0
  336. package/src/lib/ui/command-palette/CommandPalette.svelte +232 -0
  337. package/src/lib/ui/command-palette/command-palette-plugin.ts +30 -0
  338. package/src/lib/ui/command-palette/command-palette-state.svelte.ts +190 -0
  339. package/src/lib/ui/command-palette/command-palette.test.ts +129 -0
  340. package/src/lib/ui/dialog-state.svelte.ts +70 -0
  341. package/src/lib/ui/edit-commands.ts +271 -0
  342. package/src/lib/ui/file-commands.ts +275 -0
  343. package/src/lib/ui/file-open.ts +99 -0
  344. package/src/lib/ui/help-commands.ts +93 -0
  345. package/src/lib/ui/image-commands.ts +181 -0
  346. package/src/lib/ui/layer-menu-commands.ts +420 -0
  347. package/src/lib/ui/menu-builder.ts +224 -0
  348. package/src/lib/ui/notifications/NotificationBanner.svelte +137 -0
  349. package/src/lib/ui/notifications/notification-plugin.ts +29 -0
  350. package/src/lib/ui/notifications/notification-state.svelte.ts +9 -0
  351. package/src/lib/ui/plugin-manager-panel-plugin.ts +26 -0
  352. package/src/lib/ui/plugin-state.svelte.ts +62 -0
  353. package/src/lib/ui/select-commands.ts +75 -0
  354. package/src/lib/ui/theme-plugin.ts +18 -0
  355. package/src/lib/ui/theme.svelte.ts +45 -0
  356. package/src/lib/ui/theme.test.ts +51 -0
  357. package/src/lib/ui/toolbar-config.ts +90 -0
  358. package/src/lib/ui/toolbar-plugin.ts +39 -0
  359. package/src/lib/ui/view-commands.ts +629 -0
  360. package/src/lib/variants/BisectionExportDialog.svelte +500 -0
  361. package/src/lib/variants/VariantPanel.svelte +822 -0
  362. package/src/lib/variants/bisection-export.test.ts +113 -0
  363. package/src/lib/variants/bisection-export.ts +148 -0
  364. package/src/lib/variants/palette-extraction.test.ts +111 -0
  365. package/src/lib/variants/palette-extraction.ts +84 -0
  366. package/src/lib/variants/palette-interpolation.test.ts +113 -0
  367. package/src/lib/variants/palette-interpolation.ts +87 -0
  368. package/src/lib/variants/palette-swap.test.ts +101 -0
  369. package/src/lib/variants/palette-swap.ts +114 -0
  370. package/src/lib/variants/variant-commands.ts +594 -0
  371. package/src/lib/variants/variant-panel-plugin.ts +27 -0
  372. package/src/lib/variants/variant-randomizer.ts +101 -0
  373. package/src/lib/variants/variant-state.svelte.ts +166 -0
  374. package/src/lib/variants/variant-state.test.ts +138 -0
  375. package/src/main.ts +14 -0
  376. package/src/vite-env.d.ts +3 -0
  377. package/svelte.config.js +2 -0
  378. package/todo/.done/audit-design-decisions.md +812 -0
  379. package/todo/.done/audit-implementation-plan.md +1235 -0
  380. package/todo/.done/happy-path-polish.md +177 -0
  381. package/todo/.done/pixelweaver-full-build.md +937 -0
  382. package/todo/.done/server-multi-frame-design.md +405 -0
  383. package/todo/.done/typed-dispatcher-design.md +435 -0
  384. package/todo/.done/unified-toolbar-and-action-system.md +323 -0
  385. package/todo/.obsolete/comprehensive-audit-obsolete-items.md +33 -0
  386. package/todo/.obsolete/tauri-desktop-bundle.md +424 -0
  387. package/todo/comprehensive-audit.md +1085 -0
  388. package/tsconfig.app.json +26 -0
  389. package/tsconfig.json +7 -0
  390. package/tsconfig.node.json +20 -0
  391. package/uv.lock +1167 -0
  392. package/vite.config.ts +32 -0
@@ -0,0 +1,424 @@
1
+ # Tauri Desktop Bundle: Production-Ready Self-Contained App
2
+
3
+ ## Current State
4
+
5
+ The Tauri 2 wrapper exists at `src-tauri/` and consists of:
6
+
7
+ - **`src/lib.rs`** (~179 lines): A sidecar manager that spawns the Python FastAPI server via `uv run pixelweaver serve`, polls `GET /health` over raw TCP every 500ms (10s timeout), and kills the child process on app exit. Falls back to "offline mode" if the server cannot be started, and reuses an existing server if one is already running on port 7779.
8
+ - **`tauri.conf.json`**: Minimal config -- product name, window size (1280x800), icons, CSP disabled, no resource declarations, no updater.
9
+ - **`Cargo.toml`**: Tauri 2.10.3 with `tauri-plugin-log` (debug only) and `tauri-plugin-shell`.
10
+ - **`capabilities/default.json`**: Core defaults plus `shell:allow-spawn` and `shell:allow-execute`.
11
+ - **Server (`server/pyproject.toml`)**: Python >=3.13, FastAPI + uvicorn + websockets + Pillow + MCP. Entry point: `pixelweaver.cli:main`. Build backend: `uv_build`. CORS already allows `tauri://localhost` and `https://tauri.localhost` origins.
12
+
13
+ **What is missing:**
14
+
15
+ | Gap | Impact |
16
+ |-----|--------|
17
+ | Requires `uv` on user's PATH | Non-developers cannot run the app |
18
+ | Requires Python (via uv) to already be available or downloadable | First launch fails without network awareness |
19
+ | `spawn_server()` locates `server/` via cwd heuristics | Breaks in production bundle (cwd is unpredictable) |
20
+ | No bootstrap / first-launch flow | User sees a blank window or error |
21
+ | No error handling UX | Failures are silent (logged to stderr) |
22
+ | No crash recovery | Server crash = dead app until manual restart |
23
+ | No restart IPC command | No way to restart the server without restarting the entire app |
24
+ | No auto-updater | Users must manually download new versions |
25
+ | No build pipeline for bundling resources | Cannot produce distributable artifacts |
26
+ | Never been tested as a production build | Unknown issues lurk |
27
+
28
+ ## Goal
29
+
30
+ A self-contained desktop application that artists and designers can download, double-click, and use with zero prerequisites. No terminal. No `uv`. No Python knowledge. First-time setup happens automatically with a visible progress screen.
31
+
32
+ ## Architecture: Bundled uv Approach
33
+
34
+ ### What Ships in the Bundle
35
+
36
+ The Tauri resource system (`bundle.resources` in `tauri.conf.json`) copies specified files into the app bundle at build time. Tauri's `resource_dir()` API locates them at runtime.
37
+
38
+ | Bundle path | Contents | Size |
39
+ |-------------|----------|------|
40
+ | `resources/uv` (or `resources/uv.exe` on Windows) | Platform-specific uv binary | ~15 MB |
41
+ | `resources/server/pyproject.toml` | Dependency declarations + entry point | <1 KB |
42
+ | `resources/server/uv.lock` | Locked dependency versions | ~50 KB |
43
+ | `resources/server/src/pixelweaver/` | Python source code | ~100 KB |
44
+
45
+ ### Venv Lives Outside the Bundle
46
+
47
+ The bundle is read-only (especially on macOS where `.app` contents are code-signed and immutable). The Python virtual environment must live in user-writable space.
48
+
49
+ | Item | Location |
50
+ |------|----------|
51
+ | Virtual environment | `<app_data_dir>/python/.venv/` |
52
+ | Copied project files | `<app_data_dir>/python/pyproject.toml`, `uv.lock`, `src/` |
53
+ | Lock hash (for update detection) | `<app_data_dir>/python/uv.lock` (compared against bundled copy) |
54
+
55
+ `app_data_dir()` resolves to platform-appropriate paths:
56
+
57
+ | Platform | Path |
58
+ |----------|------|
59
+ | macOS | `~/Library/Application Support/com.pixelweaver.app/python/` |
60
+ | Linux | `~/.local/share/com.pixelweaver.app/python/` |
61
+ | Windows | `C:\Users\<user>\AppData\Roaming\com.pixelweaver.app\python\` |
62
+
63
+ ### uv Binary Per Platform
64
+
65
+ A build script downloads the correct binary from uv's GitHub releases before `tauri build`.
66
+
67
+ | Platform | Binary name | Archive |
68
+ |----------|------------|---------|
69
+ | macOS arm64 | `uv-aarch64-apple-darwin` | `.tar.gz` |
70
+ | macOS x86_64 | `uv-x86_64-apple-darwin` | `.tar.gz` |
71
+ | Linux x86_64 | `uv-x86_64-unknown-linux-gnu` | `.tar.gz` |
72
+ | Windows x86_64 | `uv-x86_64-pc-windows-msvc.exe` | `.zip` |
73
+
74
+ ### Python Caching
75
+
76
+ uv caches Python toolchains globally at `~/.local/share/uv/python/` (macOS/Linux) or `%LOCALAPPDATA%\uv\python\` (Windows). If the user has other uv-managed projects, the Python 3.13 interpreter may already be cached, making first-launch faster.
77
+
78
+ ---
79
+
80
+ ## Phase 1: Bootstrap Flow (First Launch)
81
+
82
+ **Effort: Medium** -- Rust bootstrap module + frontend setup screen component.
83
+
84
+ ### Step-by-Step Flow
85
+
86
+ 1. User opens the app (double-click).
87
+ 2. Rust checks: does `<app_data_dir>/python/.venv/bin/python` (or `.venv/Scripts/python.exe` on Windows) exist?
88
+ 3. **No** -- emit `bootstrap:start` event to the webview via Tauri's event system.
89
+ 4. WebView renders a setup screen with progress text and a spinner.
90
+ 5. Rust copies `pyproject.toml` + `uv.lock` + `src/` from `resource_dir()` to `<app_data_dir>/python/`.
91
+ 6. Rust runs:
92
+ ```
93
+ <resource_dir>/uv sync --frozen --directory <app_data_dir>/python/
94
+ ```
95
+ - `--frozen` prevents lockfile modification -- it installs exactly what is locked.
96
+ - uv auto-downloads Python 3.13 (version from `requires-python` in pyproject.toml) to its global cache if not already present.
97
+ - uv creates `.venv/` and installs all dependencies.
98
+ - Duration: 10-15 seconds depending on network speed and whether Python is cached.
99
+ 7. Rust captures stdout/stderr from the `uv sync` process and emits `bootstrap:progress` events with human-readable messages.
100
+ 8. WebView displays progressive status: "Downloading Python...", "Installing dependencies...", "Almost ready..."
101
+ 9. `uv sync` exits with code 0.
102
+ 10. Rust spawns the server:
103
+ ```
104
+ <resource_dir>/uv run --directory <app_data_dir>/python/ pixelweaver serve --port 7779
105
+ ```
106
+ 11. Rust polls `GET /health` every 500ms, 10s timeout (existing logic, relocated).
107
+ 12. Emit `bootstrap:complete` -- webview transitions to the main application.
108
+
109
+ **Total first-launch time:** 10-15 seconds. This happens exactly once (unless deps change in an update).
110
+
111
+ ### Implementation Details
112
+
113
+ - Use `tauri::path::PathResolver` to get `resource_dir()` and `app_data_dir()`.
114
+ - The copy step should use recursive directory copying with proper error handling for permission issues.
115
+ - The `uv sync` command should be spawned with `Stdio::piped()` on both stdout and stderr so that progress can be streamed.
116
+ - Parse uv's output to extract meaningful progress phases (downloading, resolving, installing).
117
+
118
+ ---
119
+
120
+ ## Phase 2: Warm Start (Subsequent Launches)
121
+
122
+ **Effort: Low** -- Conditional check before the existing spawn logic.
123
+
124
+ ### Flow
125
+
126
+ 1. Rust checks: `.venv/bin/python` exists in `<app_data_dir>/python/`? **Yes.**
127
+ 2. Rust checks: SHA-256 hash of bundled `uv.lock` == SHA-256 hash of `<app_data_dir>/python/uv.lock`? **Yes** (same app version).
128
+ 3. Skip bootstrap entirely.
129
+ 4. Spawn server using the bundled uv binary:
130
+ ```
131
+ <resource_dir>/uv run --directory <app_data_dir>/python/ pixelweaver serve --port 7779
132
+ ```
133
+ 5. Poll `/health`, timeout 10s.
134
+ 6. App is live in **1-2 seconds**.
135
+
136
+ ### Notes
137
+
138
+ - The hash comparison is cheap (read two small files, compute SHA-256).
139
+ - If the hashes match, there is no network call, no `uv sync`, no delay.
140
+ - The existing `check_health` / reuse-existing-server logic should be preserved as a fallback.
141
+
142
+ ---
143
+
144
+ ## Phase 3: Update Flow
145
+
146
+ **Effort: Low** -- Lockfile hash comparison triggers incremental re-sync.
147
+
148
+ When a new version of the app ships with updated Python code or dependencies:
149
+
150
+ 1. On launch, Rust detects that the bundled `uv.lock` hash differs from the installed copy in `<app_data_dir>/python/`.
151
+ 2. Rust copies the updated `pyproject.toml`, `uv.lock`, and `src/` from `resource_dir()` to `<app_data_dir>/python/`, overwriting the previous versions.
152
+ 3. Rust runs `uv sync --frozen --directory <app_data_dir>/python/` (incremental -- only installs changed/added deps, removes stale ones).
153
+ 4. Starts the server as usual.
154
+
155
+ **If only Python source changed** (no dependency changes): `uv sync` is a near-instant no-op (~100ms), and the updated source files in `<app_data_dir>/python/src/` are picked up directly by the next server start.
156
+
157
+ ---
158
+
159
+ ## Phase 4: Server Restart IPC
160
+
161
+ **Effort: Low** -- One Tauri IPC command + a frontend overlay.
162
+
163
+ ### Rust Side
164
+
165
+ A single Tauri command exposed to the webview:
166
+
167
+ ```rust
168
+ #[tauri::command]
169
+ fn restart_server(state: State<SidecarProcess>) -> Result<(), String> {
170
+ kill_sidecar(&state);
171
+ spawn_server(&state)?;
172
+ wait_for_healthy()?;
173
+ Ok(())
174
+ }
175
+ ```
176
+
177
+ Registered via `.invoke_handler(tauri::generate_handler![restart_server])` in the builder.
178
+
179
+ ### Use Cases
180
+
181
+ - Configuration changes that require a server restart.
182
+ - Feature flag toggles.
183
+ - Manual crash recovery (user clicks "Restart Server").
184
+
185
+ ### Frontend Side
186
+
187
+ - A "Reconnecting..." overlay component that appears when the WebSocket connection drops.
188
+ - The overlay disappears when the server is back and the WebSocket reconnects.
189
+ - The existing `ws-client.ts` already implements exponential backoff reconnection logic (`calculateBackoff`, `scheduleReconnect`, `reconnectAttempts`), so the reconnection itself is handled. The overlay just needs to react to connection state.
190
+
191
+ ---
192
+
193
+ ## Phase 5: Auto-Crash Recovery
194
+
195
+ **Effort: Low** -- Process watcher + automatic restart loop.
196
+
197
+ ### Flow
198
+
199
+ 1. Rust monitors the sidecar child process. When using `Child`, check `try_wait()` periodically or use a dedicated watcher thread.
200
+ 2. If the child process exits unexpectedly (non-zero exit or signal), emit a `server:crashed` event to the webview.
201
+ 3. WebView shows the "Reconnecting..." overlay (same component as Phase 4).
202
+ 4. Rust automatically calls `spawn_server()` + `wait_for_healthy()`.
203
+ 5. On success, emit `server:ready` -- webview reconnects via `ws-client.ts` auto-reconnect.
204
+
205
+ ### Retry Limits
206
+
207
+ - Maximum 3 automatic restarts within a 60-second sliding window.
208
+ - If the limit is exceeded, emit `server:fatal` and show an error screen with:
209
+ - Last N lines of stderr from the server process.
210
+ - A "Try Again" button (resets the retry counter).
211
+ - A "Report Bug" button (copies diagnostics to clipboard or opens an issue URL).
212
+
213
+ ### Implementation
214
+
215
+ A background thread (or `tokio` task if async is adopted) that calls `child.try_wait()` in a loop with a short sleep (e.g., 1s). When the process is gone, it triggers the restart logic. The retry counter and timestamp window are tracked in shared state.
216
+
217
+ ---
218
+
219
+ ## Phase 6: Auto-Updater
220
+
221
+ **Effort: Medium** -- Plugin setup + update server/endpoint configuration.
222
+
223
+ ### Setup
224
+
225
+ 1. Add `tauri-plugin-updater = "2"` to `src-tauri/Cargo.toml`.
226
+ 2. Initialize the plugin in `lib.rs`: `.plugin(tauri_plugin_updater::Builder::new().build())`.
227
+ 3. Configure the updater in `tauri.conf.json`:
228
+ ```json
229
+ "plugins": {
230
+ "updater": {
231
+ "endpoints": ["https://releases.pixelweaver.com/updates/{{target}}/{{current_version}}"],
232
+ "pubkey": "<public key for signature verification>"
233
+ }
234
+ }
235
+ ```
236
+ 4. The endpoint can be a static file host (S3, GitHub Releases) serving update manifests, or a dynamic server.
237
+
238
+ ### Update Flow
239
+
240
+ 1. On launch (after the server is running), the frontend checks for updates via the updater plugin API.
241
+ 2. If an update is available, show a non-intrusive notification: "Update available. Restart to apply?"
242
+ 3. User confirms -- download new bundle, apply, restart.
243
+ 4. After restart, the bootstrap system (Phase 3 update flow) handles any Python dependency changes automatically.
244
+
245
+ ### Signing
246
+
247
+ - Updates must be signed. Tauri's updater verifies signatures against the configured public key.
248
+ - The build pipeline generates signed update bundles using `tauri signer`.
249
+
250
+ ---
251
+
252
+ ## Error Handling
253
+
254
+ | Failure | User-Facing Behavior |
255
+ |---------|---------------------|
256
+ | No network on first launch | Setup screen shows: "Internet connection required for first-time setup. Please connect and click Retry." with a Retry button. |
257
+ | `uv sync` fails (bad deps, build error) | Setup screen shows the last 20 lines of stderr in a scrollable text area, plus a "Copy Error" button and a "Report Bug" button. |
258
+ | Server won't start (health check timeout) | After 10s timeout, show last stderr lines from the server process, a Retry button, and a "Report Bug" button. |
259
+ | Server crashes mid-session | Auto-restart up to 3 times in 60s (Phase 5). If limit exceeded, show error screen with diagnostics. |
260
+ | Disk full | `uv sync` or file copy fails -- show the OS error message with clear context ("Not enough disk space to complete setup"). |
261
+ | Port 7779 already in use | Detect `EADDRINUSE` in server stderr. Options: (a) try the next port (7780, 7781, ...) and pass it to the frontend via a Tauri event, or (b) show an error asking the user to close the other application. Option (a) is better UX. |
262
+ | Corrupted venv | If the venv exists but `uv run` fails, delete `<app_data_dir>/python/` and re-run the full bootstrap. Show a "Repairing installation..." message. |
263
+
264
+ ---
265
+
266
+ ## Rust Module Structure
267
+
268
+ The current monolithic `lib.rs` should be split into focused modules:
269
+
270
+ | File | Responsibility | Approx. Lines |
271
+ |------|---------------|---------------|
272
+ | `src-tauri/src/main.rs` | Entry point (existing, minimal -- just calls `pixelweaver_lib::run()`) | ~5 |
273
+ | `src-tauri/src/lib.rs` | Tauri builder setup, plugin registration, IPC handler registration, run loop with exit cleanup | ~60 |
274
+ | `src-tauri/src/sidecar.rs` | `spawn_server()`, `kill_sidecar()`, `check_health()`, `wait_for_healthy()`, `SidecarProcess` state, process watcher thread | ~120 |
275
+ | `src-tauri/src/bootstrap.rs` | `needs_bootstrap()`, `needs_update()`, `run_bootstrap()`, file copying, `uv sync` execution, progress event emission | ~150 |
276
+
277
+ Total: ~335 lines of Rust. The current 179 lines grow to accommodate bootstrap, update detection, crash recovery, and restart IPC, but the logic is straightforward.
278
+
279
+ ---
280
+
281
+ ## Frontend Changes
282
+
283
+ Two new lightweight Svelte 5 components:
284
+
285
+ ### BootstrapScreen.svelte
286
+
287
+ - Displayed during first launch (Phase 1) and update re-sync (Phase 3).
288
+ - Listens for `bootstrap:start`, `bootstrap:progress`, `bootstrap:complete`, and `bootstrap:error` Tauri events.
289
+ - Shows a centered card with the PixelWeaver logo, a progress message, and a CSS spinner.
290
+ - On error, switches to an error state with stderr output and action buttons.
291
+ - Conditionally rendered at the app root, above/instead-of the main workspace.
292
+
293
+ ### ReconnectOverlay.svelte
294
+
295
+ - Displayed when the WebSocket connection drops (crash recovery, restart IPC).
296
+ - Listens for `server:crashed`, `server:ready`, and `server:fatal` Tauri events.
297
+ - Semi-transparent overlay on top of the workspace (the canvas remains visible but non-interactive).
298
+ - Shows "Reconnecting..." with a spinner during recovery, or an error screen if recovery fails.
299
+ - Can also be triggered manually by the restart IPC flow.
300
+
301
+ Both components are small (50-100 lines each) and use the existing design tokens (`--bg-*`, `--text-*`, `--accent`).
302
+
303
+ ---
304
+
305
+ ## Build Pipeline
306
+
307
+ There is currently no build script for the Tauri production bundle. A `scripts/tauri-build` script (or Makefile target) is needed.
308
+
309
+ ### Build Steps
310
+
311
+ 1. **Download the platform-appropriate `uv` binary** from GitHub releases to `src-tauri/resources/uv` (or `uv.exe`). Pin to a specific uv version for reproducibility.
312
+ 2. **Make it executable**: `chmod +x src-tauri/resources/uv` (macOS/Linux).
313
+ 3. **Copy the server directory**: Copy `server/pyproject.toml`, `server/uv.lock`, and `server/src/` to `src-tauri/resources/server/`.
314
+ 4. **Run `tauri build`**: Produces the platform-specific bundle (.dmg, .AppImage, .msi).
315
+
316
+ ### CI Configuration
317
+
318
+ For CI (GitHub Actions or similar), run the build per-platform:
319
+
320
+ | Runner | Target | Artifact |
321
+ |--------|--------|----------|
322
+ | macos-14 (arm64) | aarch64-apple-darwin | `.dmg` |
323
+ | macos-13 (x86_64) | x86_64-apple-darwin | `.dmg` |
324
+ | ubuntu-latest | x86_64-unknown-linux-gnu | `.AppImage`, `.deb` |
325
+ | windows-latest | x86_64-pc-windows-msvc | `.msi`, `.exe` |
326
+
327
+ ### tauri.conf.json Changes
328
+
329
+ Add the `resources` key to declare bundled files:
330
+
331
+ ```json
332
+ "bundle": {
333
+ "active": true,
334
+ "targets": "all",
335
+ "resources": {
336
+ "resources/uv": "uv",
337
+ "resources/server/": "server/"
338
+ },
339
+ ...
340
+ }
341
+ ```
342
+
343
+ This tells Tauri to include these files in the app bundle and makes them accessible via `resource_dir()` at runtime.
344
+
345
+ ---
346
+
347
+ ## Platform-Specific Notes
348
+
349
+ ### macOS
350
+
351
+ - The bundled `uv` binary must have its executable bit set before bundling. Tauri preserves file permissions.
352
+ - The `.app` bundle is **read-only when code-signed**, which is why the venv must live outside it in `app_data_dir()`.
353
+ - Distribution outside the Mac App Store requires **notarization** via `xcrun notarytool`. The Tauri build pipeline supports this with `--sign` and notarization config.
354
+ - The webview origin is `tauri://localhost` -- already in the server's CORS allow list.
355
+ - Gatekeeper may quarantine the app on first launch; notarization resolves this.
356
+
357
+ ### Linux
358
+
359
+ - **AppImage** is the best format for self-contained distribution -- it is a single file that runs on most distros.
360
+ - `.deb` packages also work and install to `/usr/lib/`.
361
+ - The bundled `uv` binary must be the glibc-linked variant (not musl) to match common desktop distros.
362
+ - The webview origin is `https://tauri.localhost` -- already in the server's CORS allow list.
363
+ - Some distros may require WebKitGTK to be installed; this is a Tauri system requirement, not specific to this bundling work.
364
+
365
+ ### Windows
366
+
367
+ - `.msi` installer is the standard distribution format. `.exe` (NSIS) is also available.
368
+ - The `uv` binary is `uv.exe`; the venv structure uses `.venv\Scripts\` instead of `.venv/bin/`.
369
+ - All path logic in Rust must use `std::path::PathBuf` (never hardcoded slashes) to handle this transparently.
370
+ - **Windows Defender SmartScreen** shows a warning for unsigned apps. Signing with an EV certificate eliminates this. Without signing, users see "Windows protected your PC" and must click "More info" then "Run anyway".
371
+ - The webview origin is `https://tauri.localhost` -- already in the server's CORS allow list.
372
+
373
+ ---
374
+
375
+ ## CORS Configuration
376
+
377
+ The FastAPI server's CORS middleware (`server/src/pixelweaver/main.py`) already uses a regex that matches all three Tauri webview origins:
378
+
379
+ ```python
380
+ allow_origin_regex=r"^(tauri|https?)://(tauri\.)?localhost(:\d+)?$"
381
+ ```
382
+
383
+ This covers:
384
+ - `tauri://localhost` (macOS)
385
+ - `https://tauri.localhost` (Windows, Linux)
386
+ - `http://localhost:<port>` (dev mode)
387
+
388
+ **No CORS changes are needed.** This is noted here so future developers do not accidentally narrow the regex.
389
+
390
+ ---
391
+
392
+ ## Files That Will Change
393
+
394
+ | File | Action | Phase |
395
+ |------|--------|-------|
396
+ | `src-tauri/src/lib.rs` | Refactor: extract sidecar logic to `sidecar.rs`, add bootstrap orchestration, register IPC handlers | 1, 4 |
397
+ | `src-tauri/src/sidecar.rs` | Create: `spawn_server`, `kill_sidecar`, `check_health`, `wait_for_healthy`, `SidecarProcess`, process watcher | 1, 5 |
398
+ | `src-tauri/src/bootstrap.rs` | Create: `needs_bootstrap`, `needs_update`, `run_bootstrap`, file copy, `uv sync` runner, progress events | 1, 2, 3 |
399
+ | `src-tauri/tauri.conf.json` | Edit: add `bundle.resources`, add `plugins.updater` config | 1, 6 |
400
+ | `src-tauri/Cargo.toml` | Edit: add `tauri-plugin-updater`, possibly `sha2` for hash comparison | 1, 6 |
401
+ | `src-tauri/capabilities/default.json` | Edit: add permissions for event emission, updater, and resource access if needed | 1, 6 |
402
+ | `src/lib/components/BootstrapScreen.svelte` | Create: first-launch setup UI with progress and error states | 1 |
403
+ | `src/lib/components/ReconnectOverlay.svelte` | Create: server restart/crash overlay | 4, 5 |
404
+ | `src/App.svelte` (or equivalent root) | Edit: conditionally render BootstrapScreen and ReconnectOverlay | 1, 4 |
405
+ | `scripts/tauri-build` | Create: build script that fetches uv, copies server, runs `tauri build` | Build |
406
+
407
+ ---
408
+
409
+ ## Effort Summary
410
+
411
+ | Phase | Description | Effort | Dependencies |
412
+ |-------|-------------|--------|-------------|
413
+ | Phase 1 | Bootstrap flow (first launch) | Medium | None |
414
+ | Phase 2 | Warm start (subsequent launches) | Low | Phase 1 |
415
+ | Phase 3 | Update flow (new app versions) | Low | Phase 1 |
416
+ | Phase 4 | Server restart IPC | Low | Phase 1 (sidecar refactor) |
417
+ | Phase 5 | Auto-crash recovery | Low | Phase 4 (restart logic) |
418
+ | Phase 6 | Auto-updater | Medium | Phase 3 (update detection) |
419
+ | Build pipeline | Scripts + CI for per-platform builds | Medium | Phase 1 (resource layout) |
420
+ | Testing | Manual testing on all target platforms | Medium | All phases |
421
+
422
+ Phases 1-3 form the critical path. Phases 4-5 are quick wins once the sidecar module is extracted. Phase 6 and the build pipeline can proceed independently once Phase 1 is complete.
423
+
424
+ **Total estimated effort:** 3-5 focused sessions, with Phase 1 + build pipeline being the largest chunk.