Related Issue
None filed yet. This is Eigent's side of Env Hub, which turns finished agent tasks into Harbor environments. The connector is eigent-ai/open-connector#5 (the env_hub provider), and Env Hub itself is eigent-ai/harbor-hub#158.
Description
A completed Task gets two actions next to Copy and feedback, in both the default event-native timeline (NarrativeTimeline) and the rollback renderer (UserQueryGroup).
Save as Harbor task
- Writes the Task as a Harbor task folder under
Downloads/eigent-harbor-tasks, built only from what Eigent already recorded. Nothing leaves the machine and no model is called.- The workspace is the Space at the Content Repository commit before the Task, without build caches, secrets, or binaries the Task never named. Each file left out is listed with its reason.
instruction.mdis the user's own words; workspace paths become/app.- The verifier and solution are placeholders, to be written by Env Hub.
- Backend:
GET /runs/{run_id}/git/harbor-tasksays whether the Task can be saved;POSTsaves it (backend/app/harbor_task/exporter.py). The Git backend can list a commit's tree (GitBackend.tree_entries). - The saved folder opens through a new IPC channel,
reveal-harbor-task, that only allows that folder (electron/main/harborTasks.ts).
Submit to Env Hub
- Shown only where the Connector Gateway offers Env Hub (
env_hub). The check runs once per app session, so cards that can't use it show nothing. - If Env Hub isn't connected, a toast offers to open its connector in Settings → Connectors. For this,
openSettings('connectors', { connectorTarget })is new. - Otherwise the local backend bundles the saved task with the conversation: the user's messages and answers and the agent's replies, with secrets redacted (
POST .../harbor-task/bundle,backend/app/harbor_task/bundle.py). A confirmation then shows what will be uploaded and its size. Nothing is sent until the user confirms. - On confirm:
env_hub.create_uploadreturns a one-time upload URL.- The local backend PUTs the bytes straight to that URL (
.../bundle/upload). It allows https only (http only for localhost), PUT only, and upload headers only, and the bytes never pass through the connector. env_hub.submit_conversionstarts the conversion.
- The button follows the conversion every 20 s while the card is shown, and the last conversion per Task is remembered on this computer. When the environment is ready, the button says so and opens it.
executeConnectorActioninsrc/api/connectors.tsunwraps the gateway's reply and throws its message and code.
Also
useRunHarborTaskAvailabilityis shared by both buttons, with one request per Task in flight.- The
authStoremock inchatStore.feedbackIdentity.test.tsxcan now be called as the hook it stands for. - Copy is in all 11 locales: the
harbor-task-*keys and 26 Env Hub keys (submit-to-env-hub,env-hub-*).
Also fixed: a Git Run whose Space folder is gone
Found while testing this. When a Space's folder is moved or deleted, finishing a Git Run that ended in it fails, and startup retries every terminal Run, so the same Run fails at every launch. WorkspaceGitLifecycle.finalize_run now checks that the worktree folder exists first. If it is gone, the Run is skipped as workspace_missing with an info log. Nothing is persisted, so the Run is finished at a later startup if the folder comes back (backend/app/workspace_git/lifecycle.py, test test_a_run_whose_space_folder_is_gone_is_skipped_not_failed).
UI
- Primitives:
Button(variant="ghost",size="sm",buttonContent="icon-only"),DsIcon,ConfirmModal(confirmVariant="primary") and sonner toasts. - Icons: lucide
CloudUpload,CloudCheck,CloudAlertandLoader2. - No raw colours or new tokens.
check:design-tokenspasses.
Testing Evidence
Automated (on current main):
- New frontend tests:
SubmitToEnvHubButton.test.tsx(6) covers these cases:- Hidden without the provider.
- Connect first.
- Nothing sent before confirming, then upload and convert.
- Cancel sends nothing.
- Following a conversion until it's ready, then opening it.
- A failed submit offers to submit again.
- Other focused frontend tests:
SaveAsHarborTaskButton.test.tsx, the TimelineModes tests,chatStore.feedbackIdentityand the settings tests. Altogether 12 files and 191 tests passed. - ChatBox and store suites:
test/unit/components/ChatBoxandtest/unit/storepass with the default env and withVITE_CHATBOX_EVENT_BUS=false. The exception is the same 9 tests that already fail onmain:QueuedBox.test.tsx(6) andinstallationStore.test.ts(3). - Backend:
tests/app/harbor_task,tests/app/controller/test_workspace_git_controller.pyandtests/app/workspace_git(with the Run fix): 290 passed.ruffpasses on the changed files. - Static checks:
npm run type-check, ESLint on the changed files,check:i18n,check:design-tokensandgit diff --checkpass.
End to end, outside the app: the same flow was run against Env Hub staging through a local open-connector gateway with the env_hub provider. It covered OAuth connect, create_upload, a direct PUT, submit_conversion, get_conversion and get_environment, and the environment passed its gates.
In the app: to be tested by hand. Save as Harbor task works on its own; Submit to Env Hub needs an eigent_server whose Connector Gateway offers env_hub (open-connector#5). Screenshots of both buttons, the confirmation and the toasts in light and dark themes will be added before this leaves draft.
- I have included human-verified testing evidence in this PR.
- This PR includes frontend/UI changes, and I attached screenshot(s) or screen recording(s).
- No frontend/UI changes in this PR.
What is the purpose of this pull request?
- Bug fix
- New Feature
- Documentation update
- Other
Contribution Guidelines Acknowledgement
- I have read and agree to the Eigent Contribution Guideline
🤖 Generated with Claude Code
Activity
3This pull request is a draft
Merging is unavailable until it is marked ready for review.