Conversation
Process-extension runners are cached per extension id and the cache ignored the arguments of every call after the first. The workspace folder is baked into each runner at construction, so after the workspace is moved in Settings (which updates paths at runtime, without a restart) workflow process nodes such as Mesh Optimizer kept writing their output into the previous workspace, where the viewer can no longer find it. Remember the arguments each runner was built with and replace the runner when they differ; identical arguments keep reusing the warm worker as before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
After moving the workspace folder in Settings → Storage, workflow process nodes keep writing their output into the previous workspace folder until the app is restarted. The built-in Mesh Optimizer writes to
<old workspace>/Workflows/and Mesh Exporter to<old workspace>/Exports/, and Python process nodes are handed the oldworkspaceDirtoo. The workflow resolves a node's scene URL against the current workspace, so the result never appears in the viewer, and if the old folder was moved away it is silently recreated.Why it triggers
extensions:runProcessreads the currentworkspaceDirfrom settings on every call and passes it togetProcessRunner/getPythonProcessRunner. But the runner registry is keyed only by extension id and ignores the arguments once a runner exists:The JS runner bakes
workspaceDirinto its worker'sworkerData, and the Python runner stores it on the instance and sends it with every spawn, so the workspace of the first run wins. Storage settings apply paths at runtime (api:updatePaths, no restart) and nothing terminates the runners on that path. #136 fixed this shape for extension installs and reloads by terminating runners, but a path change was never covered.Fix
Remember the arguments each cached runner was built with. When a call's arguments differ, terminate the old runner and build a fresh one. Identical arguments keep returning the same warm runner, so a JS worker is still reused across runs.
Verification
New
electron/main/process-runner.test.mjs, esbuild-bundled the same way ascopy-runtime.test.mjs. Node stands in for the Python interpreter, so the test needs no Python install.a JS process runner follows the workspace after it moves: fails before, passes after.a Python process runner follows the workspace after it moves: fails before, passes after.unchanged arguments keep reusing the same warm runner: passes before and after. It asserts that the same runner instance comes back and that its worker's module state carries over (run count1then2). That proves the change doesn't widen into respawning a worker on every call.Fail-before output, with the source reverted and the test kept. It is verbatim except that the local temp/checkout path prefix is replaced with
<tmp>/<repo>:After the fix:
Whole suite (
npm run test:node), unmodifieddevcompared with this branch:dev*.test.mjsnpx eslint .The 5 skips were already there on
dev. No Python touched.🤖 Generated with Claude Code