The C# worker failed with 'entry file not found: Main.cs' because the
dispatcher resolved the working directory against the DEFAULT workflow
repo instead of the tenant's currently-selected one, and never ensured
the selected repo was cloned on the executing host. This left the worker
working in a directory whose code files did not exist.
- WorkflowSourceFactory.ResolveCopiesRoot now anchors a relative
WorkflowSource:CopiesRoot to the content root (not the process CWD), so
a worker started from a container/different CWD still lands on the same
wizard root as the control plane.
- ForgejoWorkflowRepoService takes IWebHostEnvironment and uses
ResolveCopiesRoot the same way.
- TaskDispatcher.ResolveWorkerRootForTenantAsync resolves the tenant's
SELECTED repo from WorkflowRepoStore, and calls EnsureCloneAsync to
materialize that repo on the executing host before resolving the working
directory. EnsureClone is a no-op once the clone exists, so repeated
dispatches stay cheap; failures are logged and swallowed so the resolved
path still surfaces a deterministic error if the repo is genuinely missing.
Adds regression tests: TaskDispatcherWorkingDirTests.