From 08e2209afad032af67ee2280198c680a27b5e445 Mon Sep 17 00:00:00 2001 From: 4pmtong Date: Tue, 11 Aug 2026 18:00:11 +0800 Subject: [PATCH] refactor: standardize Workspace Bundle terminology --- backend/app/agent/toolkit/terminal_toolkit.py | 14 +++---- .../controller/workspace_config_controller.py | 16 ++++---- backend/app/router.py | 2 +- backend/app/workspace_bundle/agent_plugins.py | 10 ++--- backend/app/workspace_bundle/authoring.py | 6 +-- backend/app/workspace_bundle/cloud.py | 2 +- backend/app/workspace_bundle/installer.py | 14 +++---- backend/app/workspace_bundle/runtime.py | 10 ++--- backend/app/workspace_bundle/secrets.py | 19 +++++----- backend/app/workspace_config/__init__.py | 12 +++--- backend/app/workspace_config/admission.py | 10 ++--- .../app/workspace_config/legacy_migration.py | 6 +-- backend/app/workspace_config/manifest.py | 18 ++++----- backend/app/workspace_config/models.py | 10 ++--- backend/app/workspace_config/resolver.py | 4 +- backend/app/workspace_git/configuration.py | 8 ++-- backend/main.py | 2 +- .../app/agent/factory/test_toolkit_safety.py | 6 +-- .../agent/toolkit/test_terminal_toolkit.py | 8 ++-- .../app/permission_policy/test_service.py | 6 +-- backend/tests/app/run_journal/test_store.py | 22 +++++------ .../app/workspace_bundle/test_authoring.py | 18 ++++----- .../app/workspace_bundle/test_installer.py | 18 ++++----- .../app/workspace_bundle/test_secrets.py | 4 +- .../test_workspace_bundle_runtime.py | 6 +-- .../app/workspace_config/test_admission.py | 6 +-- .../tests/app/workspace_config/test_models.py | 28 +++++++------- .../test_configuration_repository.py | 38 +++++++++---------- electron/main/workspaceSecrets/vault.ts | 2 +- .../AgentPluginImportWizard.tsx | 4 +- .../WorkspaceBundleInstallWizard.test.tsx | 10 ++--- .../WorkspaceBundleInstallWizard.tsx | 16 ++++---- .../EnvironmentRequirementsEditor.tsx | 2 +- .../WorkspaceBundleSaveDialog.test.tsx | 6 +-- .../WorkspaceBundleSaveDialog.tsx | 10 ++--- src/pages/Home/components/HomeHubToolbar.tsx | 2 +- src/service/workspaceBundleInstallApi.test.ts | 38 +++++++++---------- src/service/workspaceBundleInstallApi.ts | 4 +- src/service/workspaceConfigurationApi.test.ts | 2 +- src/service/workspaceConfigurationApi.ts | 2 +- .../electron/main/workspaceSecrets.test.ts | 2 +- .../hooks/useWorkspaceConfiguration.test.tsx | 2 +- 42 files changed, 213 insertions(+), 212 deletions(-) diff --git a/backend/app/agent/toolkit/terminal_toolkit.py b/backend/app/agent/toolkit/terminal_toolkit.py index 465601bc..14485880 100644 --- a/backend/app/agent/toolkit/terminal_toolkit.py +++ b/backend/app/agent/toolkit/terminal_toolkit.py @@ -16,6 +16,7 @@ import asyncio import logging import os import platform +import re import shlex import shutil import signal @@ -55,12 +56,9 @@ logger = logging.getLogger("terminal_toolkit") APP_VERSION = "1.0.2" -_SECRET_BROKER_ENVIRONMENT_KEYS = { - "EIGENT_WORKSPACE_SECRET_BROKER_ENDPOINT", - "EIGENT_WORKSPACE_SECRET_BROKER_CAPABILITY", - "EIGENT_WORKFORCE_SECRET_BROKER_ENDPOINT", - "EIGENT_WORKFORCE_SECRET_BROKER_CAPABILITY", -} +_SECRET_BROKER_ENVIRONMENT_KEY = re.compile( + r"^EIGENT_[A-Z0-9_]+_SECRET_BROKER_(?:ENDPOINT|CAPABILITY)$" +) _BUNDLE_RUNTIME_BASE_ENVIRONMENT_KEYS = { "APPDATA", @@ -92,7 +90,9 @@ _BUNDLE_RUNTIME_BASE_ENVIRONMENT_KEYS = { def is_secret_broker_environment_key(name: str) -> bool: - return name.strip().upper() in _SECRET_BROKER_ENVIRONMENT_KEYS + return bool( + _SECRET_BROKER_ENVIRONMENT_KEY.fullmatch(name.strip().upper()) + ) def is_control_plane_environment_key(name: str) -> bool: diff --git a/backend/app/controller/workspace_config_controller.py b/backend/app/controller/workspace_config_controller.py index bc656c1f..bd6cc194 100644 --- a/backend/app/controller/workspace_config_controller.py +++ b/backend/app/controller/workspace_config_controller.py @@ -42,7 +42,7 @@ from app.workspace_bundle import ( WorkspaceBundleCloudError, ) from app.workspace_config import ( - WorkforceBundleManifest, + WorkspaceBundleManifest, WorkspaceConfigError, assert_bundle_asset_safe, canonical_digest, @@ -130,7 +130,7 @@ def _default_document(space_id: str, name: str | None) -> dict[str, Any]: display_name = (name or "Workspace").strip() or "Workspace" return { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": _default_bundle_id(space_id), "name": display_name, @@ -176,7 +176,7 @@ def _base_document(space_id: str, name: str | None) -> tuple[dict, str | None]: ) if revision is None: return _default_document(space_id, name), None - document = WorkforceBundleManifest.model_validate( + document = WorkspaceBundleManifest.model_validate( revision.manifest ).canonical_payload() metadata = document.setdefault("metadata", {}) @@ -197,7 +197,7 @@ def _payload( "version": 0, "base_revision_id": base_revision_id, "document": document, - "document_digest": WorkforceBundleManifest.model_validate( + "document_digest": WorkspaceBundleManifest.model_validate( document ).digest, "persisted": False, @@ -329,7 +329,7 @@ def _prepared_asset_payload(asset: Any) -> dict[str, Any]: def _workspace_configuration_review( draft: WorkspaceConfigDraftRecord, ) -> dict[str, Any]: - manifest = WorkforceBundleManifest.model_validate(draft.document) + manifest = WorkspaceBundleManifest.model_validate(draft.document) base = WorkspaceBundleAuthoringService.review( manifest, mcp_config=read_mcp_config(), @@ -396,7 +396,7 @@ def _assert_cloud_prepared_assets_match( manifest_digest: str, cloud_revision: dict[str, Any], ) -> None: - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( cloud_revision.get("manifest", {}) ) base = WorkspaceBundleAuthoringService.review( @@ -600,7 +600,7 @@ async def put_workspace_configuration( ) journal = get_default_run_journal() try: - manifest = WorkforceBundleManifest.model_validate(body.document) + manifest = WorkspaceBundleManifest.model_validate(body.document) canonical = manifest.canonical_payload() existing = journal.get_workspace_config_draft(space_id) if existing is not None: @@ -766,7 +766,7 @@ async def upload_prepared_workspace_configuration_asset( draft=draft, descriptor=descriptor, ) - manifest = WorkforceBundleManifest.model_validate(draft.document) + manifest = WorkspaceBundleManifest.model_validate(draft.document) bundle_id = manifest.metadata.id revision_id = f"{bundle_id}@{manifest.metadata.revision}" cloud = _authoring_cloud(authorization) diff --git a/backend/app/router.py b/backend/app/router.py index aa759ea5..bfeda6e0 100644 --- a/backend/app/router.py +++ b/backend/app/router.py @@ -134,7 +134,7 @@ def register_routers(app: FastAPI, prefix: str = "") -> None: }, { "router": workspace_bundle_controller.router, - "tags": ["Workforce Bundles"], + "tags": ["Workspace Bundles"], "description": "Review-first local Bundle installation", "self_authenticated": True, }, diff --git a/backend/app/workspace_bundle/agent_plugins.py b/backend/app/workspace_bundle/agent_plugins.py index 82a33874..dd9bca78 100644 --- a/backend/app/workspace_bundle/agent_plugins.py +++ b/backend/app/workspace_bundle/agent_plugins.py @@ -1,4 +1,4 @@ -"""Agent Plugins v1.0.0 importer for reviewable Workforce Bundle drafts.""" +"""Agent Plugins v1.0.0 importer for reviewable Workspace Bundle drafts.""" from __future__ import annotations @@ -27,7 +27,7 @@ from app.run_journal.store import SQLiteRunJournal from app.workspace_bundle.authoring import WorkspaceBundleAuthoringService from app.workspace_config import ( SecretValueInManifestError, - WorkforceBundleManifest, + WorkspaceBundleManifest, assert_bundle_asset_safe, assert_manifest_secret_free, canonical_digest, @@ -161,7 +161,7 @@ class AgentPluginAsset: @dataclass(frozen=True) class AgentPluginImportResult: - manifest: WorkforceBundleManifest + manifest: WorkspaceBundleManifest assets: tuple[AgentPluginAsset, ...] source_metadata: dict[str, Any] warnings: tuple[AgentPluginImportWarning, ...] @@ -291,10 +291,10 @@ class AgentPluginImporter: excluded=excluded, semantic_executable_paths=semantic_executable_paths, ) - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": bundle_id or self._bundle_id(plugin_name), "name": plugin_name, diff --git a/backend/app/workspace_bundle/authoring.py b/backend/app/workspace_bundle/authoring.py index 976144a4..37d85058 100644 --- a/backend/app/workspace_bundle/authoring.py +++ b/backend/app/workspace_bundle/authoring.py @@ -1,11 +1,11 @@ -"""Secret-free review projection for authoring a Workforce Bundle.""" +"""Secret-free review projection for authoring a Workspace Bundle.""" from __future__ import annotations import re from typing import Any -from app.workspace_config import WorkforceBundleManifest, canonical_digest +from app.workspace_config import WorkspaceBundleManifest, canonical_digest from app.workspace_config.admission import LegacyEnvironmentImporter _SENSITIVE_ENV_NAME = re.compile( @@ -21,7 +21,7 @@ class WorkspaceBundleAuthoringService: @classmethod def review( cls, - manifest: WorkforceBundleManifest, + manifest: WorkspaceBundleManifest, *, mcp_config: dict[str, Any] | None = None, ) -> dict[str, Any]: diff --git a/backend/app/workspace_bundle/cloud.py b/backend/app/workspace_bundle/cloud.py index 4c78300a..7541db0f 100644 --- a/backend/app/workspace_bundle/cloud.py +++ b/backend/app/workspace_bundle/cloud.py @@ -1,4 +1,4 @@ -"""Device-authenticated Cloud transport for Workforce Bundle installation.""" +"""Device-authenticated Cloud transport for Workspace Bundle installation.""" from __future__ import annotations diff --git a/backend/app/workspace_bundle/installer.py b/backend/app/workspace_bundle/installer.py index 5d5ef8fc..c25bd39d 100644 --- a/backend/app/workspace_bundle/installer.py +++ b/backend/app/workspace_bundle/installer.py @@ -1,4 +1,4 @@ -"""Review-first local Workforce Bundle installation and materialization.""" +"""Review-first local Workspace Bundle installation and materialization.""" from __future__ import annotations @@ -31,7 +31,7 @@ from app.workspace_bundle.secrets import ( from app.workspace_config import ( ConfigPlacement, SecretValueInManifestError, - WorkforceBundleManifest, + WorkspaceBundleManifest, assert_bundle_asset_safe, canonical_digest, ) @@ -96,7 +96,7 @@ class WorkspaceBundleInstaller: manifest_value = revision.get("manifest") if not isinstance(manifest_value, dict): raise WorkspaceBundleInstallError("Bundle manifest is missing") - manifest = WorkforceBundleManifest.model_validate(manifest_value) + manifest = WorkspaceBundleManifest.model_validate(manifest_value) if ( manifest.metadata.id != bundle_id or manifest.revision_id != revision_id @@ -458,7 +458,7 @@ class WorkspaceBundleInstaller: ) cloud_version = int(cloud_installation["version"]) assets, executable_assets = await self._download_assets(proposal) - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( proposal.manifest ) lock_payload = { @@ -579,7 +579,7 @@ class WorkspaceBundleInstaller: ) if installed_bundle_id != proposal.bundle_id: raise WorkspaceBundleInstallError( - "Space already uses a different Workforce Bundle" + "Space already uses a different Workspace Bundle" ) if installed_revision_id == proposal.revision_id: local_materialization = ( @@ -725,7 +725,7 @@ class WorkspaceBundleInstaller: @staticmethod def _install_plan( - manifest: WorkforceBundleManifest, + manifest: WorkspaceBundleManifest, assets: list[dict[str, Any]], *, mcp_destinations: list[dict[str, Any]] | None = None, @@ -796,7 +796,7 @@ class WorkspaceBundleInstaller: async def _inspect_mcp_destinations( self, - manifest: WorkforceBundleManifest, + manifest: WorkspaceBundleManifest, assets: list[dict[str, Any]], ) -> list[dict[str, Any]]: assert self.cloud is not None diff --git a/backend/app/workspace_bundle/runtime.py b/backend/app/workspace_bundle/runtime.py index 38792438..b94d4d07 100644 --- a/backend/app/workspace_bundle/runtime.py +++ b/backend/app/workspace_bundle/runtime.py @@ -33,7 +33,7 @@ from app.workspace_bundle.mcp_destination import ( ) from app.workspace_config.models import ( EffectiveEnvironmentSpec, - WorkforceBundleManifest, + WorkspaceBundleManifest, WorkspaceLock, canonical_digest, ) @@ -361,7 +361,7 @@ class RuntimeEnvironmentAssembler: if revision is None: raise EnvironmentSetupRequiredError(["bundle_revision_missing"]) try: - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( spec.semantic_spec.get("bundle") ) except Exception as exc: @@ -724,13 +724,13 @@ class RuntimeEnvironmentAssembler: def _load_configuration_contract( self, root: Path, - manifest: WorkforceBundleManifest, + manifest: WorkspaceBundleManifest, ) -> WorkspaceLock: try: manifest_value = yaml.safe_load( self._read_limited(root / "workspace.yaml").decode("utf-8") ) - materialized_manifest = WorkforceBundleManifest.model_validate( + materialized_manifest = WorkspaceBundleManifest.model_validate( manifest_value ) lock_value = yaml.safe_load( @@ -807,7 +807,7 @@ class RuntimeEnvironmentAssembler: def _validate_declared_bindings( self, - manifest: WorkforceBundleManifest, + manifest: WorkspaceBundleManifest, proposal: WorkspaceBundleInstallProposalRecord, local_by_slot: dict[str, WorkspaceBundleLocalBindingRecord], secret_bindings: tuple[WorkspaceBundleSecretBindingRecord, ...], diff --git a/backend/app/workspace_bundle/secrets.py b/backend/app/workspace_bundle/secrets.py index 55c8a4d0..d10a72a9 100644 --- a/backend/app/workspace_bundle/secrets.py +++ b/backend/app/workspace_bundle/secrets.py @@ -21,15 +21,16 @@ def _capture_broker_environment( capability = environment.pop( "EIGENT_WORKSPACE_SECRET_BROKER_CAPABILITY", "" ) - legacy_endpoint = environment.pop( - "EIGENT_WORKFORCE_SECRET_BROKER_ENDPOINT", "" - ) - legacy_capability = environment.pop( - "EIGENT_WORKFORCE_SECRET_BROKER_CAPABILITY", "" - ) - if endpoint or capability: - return endpoint, capability - return legacy_endpoint, legacy_capability + # Strip any obsolete or vendor-specific broker authority as well. Only the + # Workspace keys above are accepted as the active authority, but no broker + # credential may leak into an agent child process. + for key in tuple(environment): + if re.fullmatch( + r"EIGENT_[A-Z0-9_]+_SECRET_BROKER_(?:ENDPOINT|CAPABILITY)", + key.strip().upper(), + ): + environment.pop(key, None) + return endpoint, capability _BROKER_ENDPOINT, _BROKER_CAPABILITY = _capture_broker_environment(os.environ) diff --git a/backend/app/workspace_config/__init__.py b/backend/app/workspace_config/__init__.py index 065a5dd3..a96dbc4c 100644 --- a/backend/app/workspace_config/__init__.py +++ b/backend/app/workspace_config/__init__.py @@ -14,8 +14,8 @@ from app.workspace_config.capabilities import ModelCapabilityRegistry from app.workspace_config.manifest import ( - load_workforce_manifest, - parse_workforce_manifest, + load_workspace_manifest, + parse_workspace_manifest, ) from app.workspace_config.models import ( ConfigPlacement, @@ -31,7 +31,7 @@ from app.workspace_config.models import ( ThinkingEffort, UnsafeCloudProjectionError, UnsupportedThinkingEffortError, - WorkforceBundleManifest, + WorkspaceBundleManifest, WorkspaceBundleReconfigurationPendingError, WorkspaceConfigError, WorkspaceLock, @@ -60,7 +60,7 @@ __all__ = [ "ThinkingEffort", "UnsafeCloudProjectionError", "UnsupportedThinkingEffortError", - "WorkforceBundleManifest", + "WorkspaceBundleManifest", "WorkspaceBundleReconfigurationPendingError", "WorkspaceLock", "WorkspaceConfigError", @@ -69,7 +69,7 @@ __all__ = [ "assert_manifest_secret_free", "canonical_digest", "canonical_json", - "load_workforce_manifest", + "load_workspace_manifest", "normalize_thinking_effort", - "parse_workforce_manifest", + "parse_workspace_manifest", ] diff --git a/backend/app/workspace_config/admission.py b/backend/app/workspace_config/admission.py index 4cbd746f..af75e1f2 100644 --- a/backend/app/workspace_config/admission.py +++ b/backend/app/workspace_config/admission.py @@ -36,7 +36,7 @@ from app.workspace_config.models import ( ResolvedConnectorBinding, ResolvedContextSource, ThinkingEffort, - WorkforceBundleManifest, + WorkspaceBundleManifest, WorkspaceBundleReconfigurationPendingError, canonical_digest, normalize_thinking_effort, @@ -58,7 +58,7 @@ _SECRET_ARG = re.compile( @dataclass(frozen=True) class EnvironmentAdmissionTemplate: - manifest: WorkforceBundleManifest + manifest: WorkspaceBundleManifest provider_capability: ProviderModelCapability runtime_capability_manifest: dict[str, Any] # None means the user did not override the installed Bundle layer. @@ -177,10 +177,10 @@ class LegacyEnvironmentImporter: "legacy_source_checksum": source_checksum, } ) - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": f"bundle_legacy_{identity[:24]}", "name": "Personal Default Bundle", @@ -313,7 +313,7 @@ class EnvironmentAdmissionService: raise ValueError( "Materialized Workspace Bundle revision is missing" ) - installed_manifest = WorkforceBundleManifest.model_validate( + installed_manifest = WorkspaceBundleManifest.model_validate( revision.manifest ) proposal = self.journal.get_active_workspace_bundle_proposal( diff --git a/backend/app/workspace_config/legacy_migration.py b/backend/app/workspace_config/legacy_migration.py index 7fa61810..4c0b75d4 100644 --- a/backend/app/workspace_config/legacy_migration.py +++ b/backend/app/workspace_config/legacy_migration.py @@ -61,7 +61,7 @@ class LegacyWorkspaceBundleMigration: self.output_path = ( self.root / "migrations" - / "personal-default-workforce-bundle-v1.json" + / "personal-default-workspace-bundle-v1.json" ) def run(self) -> LegacyMigrationResult: @@ -106,7 +106,7 @@ class LegacyWorkspaceBundleMigration: bindings = self._secret_bindings(servers) safe_payload = { "migration_version": _MIGRATION_VERSION, - "kind": "PersonalDefaultWorkforceBundleMigration", + "kind": "PersonalDefaultWorkspaceBundleMigration", "bundle_manifest": template.manifest.canonical_payload(), "runtime_capability_manifest": ( template.runtime_capability_manifest @@ -136,7 +136,7 @@ class LegacyWorkspaceBundleMigration: Exception ) as exc: # startup migration is intentionally fail-open logger.warning( - "Legacy Workforce Bundle migration degraded: %s", exc + "Legacy Workspace Bundle migration degraded: %s", exc ) return LegacyMigrationResult( status="degraded", diff --git a/backend/app/workspace_config/manifest.py b/backend/app/workspace_config/manifest.py index dffd82e6..2619afd9 100644 --- a/backend/app/workspace_config/manifest.py +++ b/backend/app/workspace_config/manifest.py @@ -12,7 +12,7 @@ # limitations under the License. # ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= -"""Safe parser for shareable Workforce Bundle manifests.""" +"""Safe parser for shareable Workspace Bundle manifests.""" from __future__ import annotations @@ -22,30 +22,30 @@ from typing import Any import yaml from app.workspace_config.models import ( - WorkforceBundleManifest, + WorkspaceBundleManifest, WorkspaceConfigError, assert_manifest_secret_free, ) -def parse_workforce_manifest(value: str | bytes) -> WorkforceBundleManifest: +def parse_workspace_manifest(value: str | bytes) -> WorkspaceBundleManifest: try: payload: Any = yaml.safe_load(value) except yaml.YAMLError as exc: - raise WorkspaceConfigError("invalid Workforce Bundle YAML") from exc + raise WorkspaceConfigError("invalid Workspace Bundle YAML") from exc if not isinstance(payload, dict): raise WorkspaceConfigError( - "Workforce Bundle manifest must be a YAML mapping" + "Workspace Bundle manifest must be a YAML mapping" ) # Run this before Pydantic so callers receive the typed privacy-boundary # error instead of a generic wrapped ValidationError. assert_manifest_secret_free(payload) - return WorkforceBundleManifest.model_validate(payload) + return WorkspaceBundleManifest.model_validate(payload) -def load_workforce_manifest(path: Path) -> WorkforceBundleManifest: +def load_workspace_manifest(path: Path) -> WorkspaceBundleManifest: if path.name != "workspace.yaml": raise WorkspaceConfigError( - "Workforce Bundle manifest must be named workspace.yaml" + "Workspace Bundle manifest must be named workspace.yaml" ) - return parse_workforce_manifest(path.read_text(encoding="utf-8")) + return parse_workspace_manifest(path.read_text(encoding="utf-8")) diff --git a/backend/app/workspace_config/models.py b/backend/app/workspace_config/models.py index fa8197e0..9220ca9e 100644 --- a/backend/app/workspace_config/models.py +++ b/backend/app/workspace_config/models.py @@ -12,7 +12,7 @@ # limitations under the License. # ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= -"""Immutable Workforce Bundle and environment materialization contracts.""" +"""Immutable Workspace Bundle and environment materialization contracts.""" from __future__ import annotations @@ -650,14 +650,14 @@ class BundleSpec(_StrictFrozenModel): return self -class WorkforceBundleManifest(_StrictFrozenModel): +class WorkspaceBundleManifest(_StrictFrozenModel): api_version: Literal["eigent.ai/v1alpha1"] = Field(alias="apiVersion") - kind: Literal["WorkforceBundle"] + kind: Literal["WorkspaceBundle"] metadata: BundleMetadata spec: BundleSpec @model_validator(mode="after") - def reject_secret_values(self) -> WorkforceBundleManifest: + def reject_secret_values(self) -> WorkspaceBundleManifest: assert_manifest_secret_free(self.canonical_payload()) return self @@ -896,7 +896,7 @@ class EffectiveEnvironmentSpec(_StrictFrozenModel): *, owner_type: Literal["run", "run_attempt"], owner_id: str, - manifest: WorkforceBundleManifest, + manifest: WorkspaceBundleManifest, semantic_spec: dict[str, Any], local_materialization: LocalMaterialization, permission_profile_revision: str, diff --git a/backend/app/workspace_config/resolver.py b/backend/app/workspace_config/resolver.py index 7e5d1b07..ae37bc09 100644 --- a/backend/app/workspace_config/resolver.py +++ b/backend/app/workspace_config/resolver.py @@ -23,7 +23,7 @@ from app.workspace_config.models import ( LocalMaterialization, ProviderModelCapability, ThinkingEffort, - WorkforceBundleManifest, + WorkspaceBundleManifest, canonical_digest, ) @@ -34,7 +34,7 @@ class EnvironmentConfigResolver: def resolve( self, *, - manifest: WorkforceBundleManifest, + manifest: WorkspaceBundleManifest, owner_type: Literal["run", "run_attempt"], owner_id: str, local_materialization: LocalMaterialization, diff --git a/backend/app/workspace_git/configuration.py b/backend/app/workspace_git/configuration.py index a8870f94..31469138 100644 --- a/backend/app/workspace_git/configuration.py +++ b/backend/app/workspace_git/configuration.py @@ -37,7 +37,7 @@ from app.run_journal import ( ) from app.workspace_config import ( ConfigPlacement, - WorkforceBundleManifest, + WorkspaceBundleManifest, WorkspaceLock, assert_manifest_secret_free, canonical_digest, @@ -92,7 +92,7 @@ class ConfigurationRepositoryService: *, space_id: str, space_root: Path, - manifest: WorkforceBundleManifest, + manifest: WorkspaceBundleManifest, placement: ConfigPlacement, created_by: str, lock_payload: dict[str, Any] | None = None, @@ -263,7 +263,7 @@ class ConfigurationRepositoryService: current_lock_payload = yaml.safe_load( workspace_lock_path.read_text(encoding="utf-8") ) - current_manifest = WorkforceBundleManifest.model_validate( + current_manifest = WorkspaceBundleManifest.model_validate( current_manifest_payload ) current_lock = WorkspaceLock.model_validate( @@ -397,7 +397,7 @@ class ConfigurationRepositoryService: @staticmethod def _default_lock( - manifest: WorkforceBundleManifest, + manifest: WorkspaceBundleManifest, ) -> dict[str, Any]: return { "apiVersion": "eigent.ai/lock/v1alpha1", diff --git a/backend/main.py b/backend/main.py index 88eab88a..23d181d9 100644 --- a/backend/main.py +++ b/backend/main.py @@ -183,7 +183,7 @@ async def startup_event(): ) if legacy_bundle_migration.status == "degraded": app_logger.warning( - "Legacy Workforce Bundle migration degraded without blocking " + "Legacy Workspace Bundle migration degraded without blocking " "startup: %s", legacy_bundle_migration.error, ) diff --git a/backend/tests/app/agent/factory/test_toolkit_safety.py b/backend/tests/app/agent/factory/test_toolkit_safety.py index 404c06a1..81e8be11 100644 --- a/backend/tests/app/agent/factory/test_toolkit_safety.py +++ b/backend/tests/app/agent/factory/test_toolkit_safety.py @@ -80,8 +80,8 @@ def test_mcp_process_environment_excludes_secret_broker_authority(): "EIGENT_WORKSPACE_SECRET_BROKER_CAPABILITY": ( "broker-secret" ), - "EIGENT_WORKFORCE_SECRET_BROKER_CAPABILITY": ( - "legacy-secret" + "EIGENT_OBSOLETE_SECRET_BROKER_CAPABILITY": ( + "obsolete-secret" ), "AUTHORIZATION": "consumer-authorization", "MCP_API_TOKEN": "consumer-secret", @@ -99,4 +99,4 @@ def test_mcp_process_environment_excludes_secret_broker_authority(): assert environment["AUTHORIZATION"] == "consumer-authorization" assert "EIGENT_WORKSPACE_SECRET_BROKER_ENDPOINT" not in environment assert "EIGENT_WORKSPACE_SECRET_BROKER_CAPABILITY" not in environment - assert "EIGENT_WORKFORCE_SECRET_BROKER_CAPABILITY" not in environment + assert "EIGENT_OBSOLETE_SECRET_BROKER_CAPABILITY" not in environment diff --git a/backend/tests/app/agent/toolkit/test_terminal_toolkit.py b/backend/tests/app/agent/toolkit/test_terminal_toolkit.py index cdcfaea9..ccf63fb7 100644 --- a/backend/tests/app/agent/toolkit/test_terminal_toolkit.py +++ b/backend/tests/app/agent/toolkit/test_terminal_toolkit.py @@ -142,10 +142,10 @@ class TestTerminalToolkit: "http://127.0.0.1:1234" ), "EIGENT_WORKSPACE_SECRET_BROKER_CAPABILITY": "broker-secret", - "EIGENT_WORKFORCE_SECRET_BROKER_ENDPOINT": ( + "EIGENT_OBSOLETE_SECRET_BROKER_ENDPOINT": ( "http://127.0.0.1:5678" ), - "EIGENT_WORKFORCE_SECRET_BROKER_CAPABILITY": "legacy-secret", + "EIGENT_OBSOLETE_SECRET_BROKER_CAPABILITY": "obsolete-secret", "AUTHORIZATION": "Bearer secret", "SERVICE_AUTHORIZATION": "Bearer service-secret", "NORMAL_API_KEY": "allowed-tool-secret", @@ -160,7 +160,7 @@ class TestTerminalToolkit: assert "EIGENT_LOCAL_CONTROL_CAPABILITY" not in environment assert "EIGENT_WORKSPACE_SECRET_BROKER_ENDPOINT" not in environment assert "EIGENT_WORKSPACE_SECRET_BROKER_CAPABILITY" not in environment - assert "EIGENT_WORKFORCE_SECRET_BROKER_ENDPOINT" not in environment - assert "EIGENT_WORKFORCE_SECRET_BROKER_CAPABILITY" not in environment + assert "EIGENT_OBSOLETE_SECRET_BROKER_ENDPOINT" not in environment + assert "EIGENT_OBSOLETE_SECRET_BROKER_CAPABILITY" not in environment assert "AUTHORIZATION" not in environment assert "SERVICE_AUTHORIZATION" not in environment diff --git a/backend/tests/app/permission_policy/test_service.py b/backend/tests/app/permission_policy/test_service.py index 914476e2..cf634fd6 100644 --- a/backend/tests/app/permission_policy/test_service.py +++ b/backend/tests/app/permission_policy/test_service.py @@ -12,7 +12,7 @@ from app.workspace_config import ( LocalMaterialization, ProviderModelCapability, ThinkingEffort, - parse_workforce_manifest, + parse_workspace_manifest, ) @@ -22,10 +22,10 @@ def _create_bound_attempt( run_id: str, permission_profile_revision: str, ): - manifest = parse_workforce_manifest( + manifest = parse_workspace_manifest( f""" apiVersion: eigent.ai/v1alpha1 -kind: WorkforceBundle +kind: WorkspaceBundle metadata: id: bundle_{run_id} name: Permission test diff --git a/backend/tests/app/run_journal/test_store.py b/backend/tests/app/run_journal/test_store.py index f0d012a2..851ae488 100644 --- a/backend/tests/app/run_journal/test_store.py +++ b/backend/tests/app/run_journal/test_store.py @@ -39,7 +39,7 @@ from app.workspace_config import ( LocalMaterialization, ProviderModelCapability, ThinkingEffort, - parse_workforce_manifest, + parse_workspace_manifest, ) @@ -90,10 +90,10 @@ def test_initializes_schema_and_durability_pragmas(journal): def _persist_environment_spec(journal, *, owner_id: str = "run-1"): - manifest = parse_workforce_manifest( + manifest = parse_workspace_manifest( """ apiVersion: eigent.ai/v1alpha1 -kind: WorkforceBundle +kind: WorkspaceBundle metadata: id: bundle_test name: Test Bundle @@ -157,10 +157,10 @@ def test_workspace_config_and_environment_spec_are_immutable(journal): def test_workspace_config_revision_lifecycle_uses_version_cas(journal): - manifest = parse_workforce_manifest( + manifest = parse_workspace_manifest( """ apiVersion: eigent.ai/v1alpha1 -kind: WorkforceBundle +kind: WorkspaceBundle metadata: id: bundle_lifecycle name: Lifecycle Bundle @@ -213,7 +213,7 @@ spec: def test_workspace_config_draft_autosave_uses_version_cas(journal): document = { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_working_copy", "name": "Working copy", @@ -287,7 +287,7 @@ def test_workspace_config_publish_is_atomic_and_idempotently_advances_draft( ): document = { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_publish", "name": "Publish", @@ -343,7 +343,7 @@ def test_workspace_config_publish_rejects_same_digest_wrong_revision_identity( ): document = { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_publish", "name": "Publish", @@ -394,7 +394,7 @@ def test_workspace_config_publish_rebases_concurrent_edit_to_next_revision( ): published_document = { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_publish", "name": "Published A", @@ -448,7 +448,7 @@ def test_workspace_config_publish_mismatch_rolls_back_every_local_fact( ): document = { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_publish", "name": "Publish", @@ -847,7 +847,7 @@ def test_v17_database_adds_agent_plugin_import_tables_without_losing_draft( path = tmp_path / "run-journal.sqlite3" document = { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_existing", "name": "Existing", diff --git a/backend/tests/app/workspace_bundle/test_authoring.py b/backend/tests/app/workspace_bundle/test_authoring.py index 33606800..b704ba38 100644 --- a/backend/tests/app/workspace_bundle/test_authoring.py +++ b/backend/tests/app/workspace_bundle/test_authoring.py @@ -5,14 +5,14 @@ import json import pytest from app.workspace_bundle import WorkspaceBundleAuthoringService -from app.workspace_config import WorkforceBundleManifest +from app.workspace_config import WorkspaceBundleManifest def test_save_review_extracts_requirement_names_without_local_values(): - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_review", "name": "Review", @@ -86,10 +86,10 @@ def test_save_review_extracts_requirement_names_without_local_values(): def test_save_review_keeps_non_env_secret_slots_when_legacy_env_is_not_object( legacy_environment, ): - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_review", "name": "Review", @@ -141,10 +141,10 @@ def test_save_review_keeps_non_env_secret_slots_when_legacy_env_is_not_object( def test_save_review_hardens_declared_environment_secret_without_value(): - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_review", "name": "Review", @@ -194,7 +194,7 @@ def test_save_review_hardens_declared_environment_secret_without_value(): def test_sensitive_environment_requirement_cannot_carry_example_value(): payload = { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle_review", "name": "Review", @@ -220,7 +220,7 @@ def test_sensitive_environment_requirement_cannot_carry_example_value(): } try: - WorkforceBundleManifest.model_validate(payload) + WorkspaceBundleManifest.model_validate(payload) except ValueError as exc: assert "cannot contain examples" in str(exc) else: diff --git a/backend/tests/app/workspace_bundle/test_installer.py b/backend/tests/app/workspace_bundle/test_installer.py index ad6394a6..e0f2f8cb 100644 --- a/backend/tests/app/workspace_bundle/test_installer.py +++ b/backend/tests/app/workspace_bundle/test_installer.py @@ -16,7 +16,7 @@ from app.workspace_bundle import ( ) from app.workspace_config import ( ConfigPlacement, - WorkforceBundleManifest, + WorkspaceBundleManifest, canonical_digest, ) from app.workspace_git import ConfigurationRepositoryService, GitBackend @@ -25,7 +25,7 @@ from app.workspace_git import ConfigurationRepositoryService, GitBackend def _manifest(revision: int = 1) -> dict: return { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle-research", "name": "Research Workforce", @@ -106,7 +106,7 @@ class FakeCloud: async def get_catalog_revision(self, bundle_id, revision_id): revision_number = int(str(revision_id).rsplit("@", 1)[1]) - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( _manifest(revision_number) ).canonical_payload() suffix = "" if revision_number == 1 else f"-v{revision_number}" @@ -287,7 +287,7 @@ def installer(tmp_path): def test_local_review_decision_does_not_require_cloud(tmp_path): with SQLiteRunJournal(tmp_path / "journal.sqlite3") as journal: - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( _manifest() ).canonical_payload() proposal = journal.put_workspace_bundle_install_proposal( @@ -626,7 +626,7 @@ async def test_required_local_values_block_before_cloud_and_optional_env_does_no ) async def get_catalog_revision(bundle_id, revision_id): - canonical = WorkforceBundleManifest.model_validate( + canonical = WorkspaceBundleManifest.model_validate( manifest ).canonical_payload() definition = json.dumps( @@ -809,7 +809,7 @@ async def test_registry_secret_mcp_cannot_be_approved_or_reported_ready( ] async def get_catalog_revision(bundle_id, revision_id): - canonical = WorkforceBundleManifest.model_validate( + canonical = WorkspaceBundleManifest.model_validate( manifest ).canonical_payload() return { @@ -874,7 +874,7 @@ async def test_proposal_rejects_mcp_definition_digest_mismatch(installer): cloud.contents["asset-mcp-private"] = content async def get_catalog_revision(bundle_id, revision_id): - canonical = WorkforceBundleManifest.model_validate( + canonical = WorkspaceBundleManifest.model_validate( manifest ).canonical_payload() return { @@ -923,7 +923,7 @@ async def test_unreadable_bound_value_blocks_all_cloud_side_effects(installer): } async def get_catalog_revision(bundle_id, revision_id): - canonical = WorkforceBundleManifest.model_validate( + canonical = WorkspaceBundleManifest.model_validate( manifest ).canonical_payload() return { @@ -1182,7 +1182,7 @@ def test_startup_reconciliation_exposes_interrupted_materialization(tmp_path): bundle_id="bundle-research", revision_id="bundle-research@1", config_placement="sidecar", - manifest=WorkforceBundleManifest.model_validate( + manifest=WorkspaceBundleManifest.model_validate( _manifest() ).canonical_payload(), assets=[], diff --git a/backend/tests/app/workspace_bundle/test_secrets.py b/backend/tests/app/workspace_bundle/test_secrets.py index e95f9a3b..c003cb17 100644 --- a/backend/tests/app/workspace_bundle/test_secrets.py +++ b/backend/tests/app/workspace_bundle/test_secrets.py @@ -295,8 +295,8 @@ def test_secret_broker_authority_is_removed_from_child_environment(): "PATH": "/usr/bin", "EIGENT_WORKSPACE_SECRET_BROKER_ENDPOINT": "http://127.0.0.1:1234", "EIGENT_WORKSPACE_SECRET_BROKER_CAPABILITY": "x" * 43, - "EIGENT_WORKFORCE_SECRET_BROKER_ENDPOINT": "legacy-endpoint", - "EIGENT_WORKFORCE_SECRET_BROKER_CAPABILITY": "legacy-capability", + "EIGENT_OBSOLETE_SECRET_BROKER_ENDPOINT": "obsolete-endpoint", + "EIGENT_OBSOLETE_SECRET_BROKER_CAPABILITY": "obsolete-capability", } captured = _capture_broker_environment(environment) diff --git a/backend/tests/app/workspace_bundle/test_workspace_bundle_runtime.py b/backend/tests/app/workspace_bundle/test_workspace_bundle_runtime.py index 380d45fe..91e2479b 100644 --- a/backend/tests/app/workspace_bundle/test_workspace_bundle_runtime.py +++ b/backend/tests/app/workspace_bundle/test_workspace_bundle_runtime.py @@ -36,7 +36,7 @@ from app.workspace_config import ( EnvironmentConfigResolver, LocalMaterialization, ResolvedContextSource, - WorkforceBundleManifest, + WorkspaceBundleManifest, ) from app.workspace_config.admission import LegacyEnvironmentImporter from app.workspace_config.admission import EnvironmentAdmissionService @@ -96,10 +96,10 @@ def _installed_spec( slot: f"slot://{slot}" for slot in mcp_secret_slots } contents["mcp/local.json"] = json.dumps(mcp_definition).encode() - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle-runtime", "name": "Runtime Bundle", diff --git a/backend/tests/app/workspace_config/test_admission.py b/backend/tests/app/workspace_config/test_admission.py index d4e02031..e364e6bc 100644 --- a/backend/tests/app/workspace_config/test_admission.py +++ b/backend/tests/app/workspace_config/test_admission.py @@ -8,7 +8,7 @@ import pytest from app.run_journal import SQLiteRunJournal from app.workspace_config import ( ThinkingEffort, - WorkforceBundleManifest, + WorkspaceBundleManifest, WorkspaceBundleReconfigurationPendingError, ) from app.workspace_config.admission import ( @@ -276,10 +276,10 @@ def test_admission_pins_current_space_permission_profile(tmp_path): def test_materialized_bundle_replaces_legacy_template_for_new_run(tmp_path): - manifest = WorkforceBundleManifest.model_validate( + manifest = WorkspaceBundleManifest.model_validate( { "apiVersion": "eigent.ai/v1alpha1", - "kind": "WorkforceBundle", + "kind": "WorkspaceBundle", "metadata": { "id": "bundle-team", "name": "Team Workspace", diff --git a/backend/tests/app/workspace_config/test_models.py b/backend/tests/app/workspace_config/test_models.py index 19cb7f9c..5946fc68 100644 --- a/backend/tests/app/workspace_config/test_models.py +++ b/backend/tests/app/workspace_config/test_models.py @@ -21,13 +21,13 @@ from app.workspace_config import ( assert_bundle_asset_safe, assert_manifest_secret_free, canonical_digest, - parse_workforce_manifest, + parse_workspace_manifest, ) from app.workspace_config.models import assert_cloud_projection_safe MANIFEST_YAML = """ apiVersion: eigent.ai/v1alpha1 -kind: WorkforceBundle +kind: WorkspaceBundle metadata: id: bundle_product_research name: Product Research Workforce @@ -96,8 +96,8 @@ def _capability() -> ProviderModelCapability: def test_manifest_is_strict_canonical_and_digest_stable(): - first = parse_workforce_manifest(MANIFEST_YAML) - reordered = parse_workforce_manifest( + first = parse_workspace_manifest(MANIFEST_YAML) + reordered = parse_workspace_manifest( MANIFEST_YAML.replace( " name: Product Research Workforce\n revision: 7", " revision: 7\n name: Product Research Workforce", @@ -113,14 +113,14 @@ def test_manifest_is_strict_canonical_and_digest_stable(): def test_legacy_manifest_canonical_payload_does_not_gain_environment_field(): - manifest = parse_workforce_manifest(MANIFEST_YAML) + manifest = parse_workspace_manifest(MANIFEST_YAML) assert "environment" not in manifest.canonical_payload()["spec"] def test_manifest_rejects_secret_value_even_inside_freeform_instructions(): with pytest.raises(SecretValueInManifestError, match="api_key"): - parse_workforce_manifest( + parse_workspace_manifest( MANIFEST_YAML.replace( "coordinator: bundle://instructions/coordinator.md", "api_key: sk-must-not-enter-a-bundle", @@ -224,7 +224,7 @@ def test_asset_preflight_preserves_safe_structured_assets( def test_manifest_allows_path_like_prose_and_requires_default_model(): - manifest = parse_workforce_manifest( + manifest = parse_workspace_manifest( MANIFEST_YAML.replace( " context:\n", " context:\n" @@ -235,7 +235,7 @@ def test_manifest_allows_path_like_prose_and_requires_default_model(): ) assert manifest.spec.context[0].content is not None with pytest.raises(ValidationError, match="default profile"): - parse_workforce_manifest( + parse_workspace_manifest( MANIFEST_YAML.replace(" default:\n", " custom:\n") ) @@ -250,7 +250,7 @@ def test_manifest_allows_path_like_prose_and_requires_default_model(): ], ) def test_manifest_allows_device_paths_inside_local_inline_prose(path): - parse_workforce_manifest( + parse_workspace_manifest( MANIFEST_YAML.replace( " context:\n", " context:\n" @@ -281,7 +281,7 @@ def test_cloud_projection_only_rejects_identifying_home_paths(): def test_manifest_rejects_physical_path_for_local_slot(): with pytest.raises(ValidationError, match="physical path"): - parse_workforce_manifest( + parse_workspace_manifest( MANIFEST_YAML.replace( " sharing: reference_only", " path: /Users/alice/private\n" @@ -292,7 +292,7 @@ def test_manifest_rejects_physical_path_for_local_slot(): def test_thinking_effort_aliases_are_normalized_and_unsupported_is_explicit(): - manifest = parse_workforce_manifest( + manifest = parse_workspace_manifest( MANIFEST_YAML.replace( "thinkingEffort: medium", "thinkingEffort: light" ) @@ -361,7 +361,7 @@ def test_capability_registry_maps_product_max_without_blind_forwarding(): def test_cloud_projection_redacts_local_paths_and_binding_ids(): - manifest = parse_workforce_manifest(MANIFEST_YAML) + manifest = parse_workspace_manifest(MANIFEST_YAML) local = LocalMaterialization( context_sources=( ResolvedContextSource( @@ -420,7 +420,7 @@ def test_cloud_projection_redacts_local_paths_and_binding_ids(): def test_cloud_projection_does_not_repeat_inline_bundle_path_instructions(): - manifest = parse_workforce_manifest( + manifest = parse_workspace_manifest( MANIFEST_YAML.replace( " context:\n", " context:\n" @@ -449,7 +449,7 @@ def test_cloud_projection_does_not_repeat_inline_bundle_path_instructions(): def test_cloud_projection_rejects_local_fields_in_semantic_capabilities(): - manifest = parse_workforce_manifest(MANIFEST_YAML) + manifest = parse_workspace_manifest(MANIFEST_YAML) spec = EnvironmentConfigResolver().resolve( manifest=manifest, owner_type="run", diff --git a/backend/tests/app/workspace_git/test_configuration_repository.py b/backend/tests/app/workspace_git/test_configuration_repository.py index 65b9cd56..79e70366 100644 --- a/backend/tests/app/workspace_git/test_configuration_repository.py +++ b/backend/tests/app/workspace_git/test_configuration_repository.py @@ -12,7 +12,7 @@ from app.run_journal import IdempotencyConflictError, SQLiteRunJournal from app.workspace_config import ( ConfigPlacement, SecretValueInManifestError, - parse_workforce_manifest, + parse_workspace_manifest, ) from app.workspace_git import ( ConfigurationRepositoryError, @@ -24,7 +24,7 @@ from app.workspace_git import ( MANIFEST = """ apiVersion: eigent.ai/v1alpha1 -kind: WorkforceBundle +kind: WorkspaceBundle metadata: id: bundle_local name: Local Workspace @@ -84,7 +84,7 @@ def test_sidecar_bootstrap_never_mutates_user_space( original = space / "private-notes.txt" original.write_text("never import me", encoding="utf-8") service, backend = _service(tmp_path, journal) - manifest = parse_workforce_manifest(MANIFEST) + manifest = parse_workspace_manifest(MANIFEST) first = service.bootstrap( space_id="space-1", @@ -132,7 +132,7 @@ def test_sidecar_bootstrap_commits_verified_bundle_assets(tmp_path, journal): result = service.bootstrap( space_id="space-1", space_root=space, - manifest=parse_workforce_manifest(MANIFEST), + manifest=parse_workspace_manifest(MANIFEST), placement=ConfigPlacement.SIDECAR, created_by="user-1", assets={ @@ -142,7 +142,7 @@ def test_sidecar_bootstrap_commits_verified_bundle_assets(tmp_path, journal): lock_payload={ "apiVersion": "eigent.ai/lock/v1alpha1", "bundleRevision": "bundle_local@1", - "manifestDigest": parse_workforce_manifest(MANIFEST).digest, + "manifestDigest": parse_workspace_manifest(MANIFEST).digest, "assets": [ { "ref": "bundle://instructions/coordinator.md", @@ -182,7 +182,7 @@ def test_same_bundle_revision_materializes_into_multiple_spaces( first_space.mkdir() second_space.mkdir() service, _ = _service(tmp_path, journal) - manifest = parse_workforce_manifest(MANIFEST) + manifest = parse_workspace_manifest(MANIFEST) first = service.bootstrap( space_id="space-1", @@ -218,7 +218,7 @@ def test_existing_space_materialization_rejects_placement_change_before_git( space = tmp_path / "space" space.mkdir() service, _ = _service(tmp_path, journal) - manifest = parse_workforce_manifest(MANIFEST) + manifest = parse_workspace_manifest(MANIFEST) service.bootstrap( space_id="space-1", space_root=space, @@ -263,7 +263,7 @@ def test_in_repo_commit_excludes_and_preserves_user_staged_changes( result = service.bootstrap( space_id="space-1", space_root=space, - manifest=parse_workforce_manifest(MANIFEST), + manifest=parse_workspace_manifest(MANIFEST), placement=ConfigPlacement.IN_REPO, created_by="user-1", ) @@ -284,7 +284,7 @@ def test_in_repo_requires_explicit_content_init(tmp_path, journal): space = tmp_path / "plain-folder" space.mkdir() service, _ = _service(tmp_path, journal) - manifest = parse_workforce_manifest(MANIFEST) + manifest = parse_workspace_manifest(MANIFEST) with pytest.raises( ConfigurationRepositoryError, @@ -328,7 +328,7 @@ def test_nested_repository_is_rejected_without_writing_child( service.bootstrap( space_id="space-1", space_root=child, - manifest=parse_workforce_manifest(MANIFEST), + manifest=parse_workspace_manifest(MANIFEST), placement=ConfigPlacement.IN_REPO, created_by="user-1", allow_content_repository_init=True, @@ -345,7 +345,7 @@ def test_secret_or_device_capability_in_lock_is_rejected_before_init( space = tmp_path / "space" space.mkdir() service, _ = _service(tmp_path, journal) - manifest = parse_workforce_manifest(MANIFEST) + manifest = parse_workspace_manifest(MANIFEST) with pytest.raises(SecretValueInManifestError): service.bootstrap( @@ -376,7 +376,7 @@ def test_lock_must_match_bundle_revision_before_git_init(tmp_path, journal): space = tmp_path / "space" space.mkdir() service, _ = _service(tmp_path, journal) - manifest = parse_workforce_manifest(MANIFEST) + manifest = parse_workspace_manifest(MANIFEST) with pytest.raises( ConfigurationRepositoryError, @@ -408,7 +408,7 @@ def test_replay_does_not_overwrite_manual_manifest_edit( space = tmp_path / "space" space.mkdir() service, _ = _service(tmp_path, journal) - manifest = parse_workforce_manifest(MANIFEST) + manifest = parse_workspace_manifest(MANIFEST) first = service.bootstrap( space_id="space-1", space_root=space, @@ -444,7 +444,7 @@ def test_bootstrap_recovers_exact_untracked_files_after_crash( space = tmp_path / "space" space.mkdir() service, backend = _service(tmp_path, journal) - manifest = parse_workforce_manifest(MANIFEST) + manifest = parse_workspace_manifest(MANIFEST) repository = tmp_path / "state" / "spaces" / "space-1" / "configuration" backend.init_repository(repository) manifest_path = repository / "workspace.yaml" @@ -502,7 +502,7 @@ def test_bootstrap_clears_owner_execute_for_non_executable_asset_recovery( space = tmp_path / "space" space.mkdir() service, backend = _service(tmp_path, journal) - manifest = parse_workforce_manifest(MANIFEST) + manifest = parse_workspace_manifest(MANIFEST) repository = tmp_path / "state" / "spaces" / "space-1" / "configuration" backend.init_repository(repository) content = b"public package data\n" @@ -558,7 +558,7 @@ def test_bundle_upgrade_preserves_user_edits_and_removes_only_clean_old_assets( space = tmp_path / "space" space.mkdir() service, backend = _service(tmp_path, journal) - first_manifest = parse_workforce_manifest(MANIFEST) + first_manifest = parse_workspace_manifest(MANIFEST) first_assets = { "instructions/coordinator.md": b"version one\n", "assets/obsolete.txt": b"remove on upgrade\n", @@ -587,7 +587,7 @@ def test_bundle_upgrade_preserves_user_edits_and_removes_only_clean_old_assets( ) edited_path = first.configuration_repository_root / "instructions/coordinator.md" edited_path.write_text("user edit\n", encoding="utf-8") - second_manifest = parse_workforce_manifest( + second_manifest = parse_workspace_manifest( MANIFEST.replace("revision: 1", "revision: 2") ) second_assets = {"instructions/coordinator.md": b"version two\n"} @@ -652,7 +652,7 @@ def test_revision_conflict_is_detected_before_git_mutation( space = tmp_path / "space" space.mkdir() service, _ = _service(tmp_path, journal) - original = parse_workforce_manifest(MANIFEST) + original = parse_workspace_manifest(MANIFEST) first = service.bootstrap( space_id="space-1", space_root=space, @@ -660,7 +660,7 @@ def test_revision_conflict_is_detected_before_git_mutation( placement=ConfigPlacement.SIDECAR, created_by="user-1", ) - conflicting = parse_workforce_manifest( + conflicting = parse_workspace_manifest( MANIFEST.replace("name: Local Workspace", "name: Changed Name") ) diff --git a/electron/main/workspaceSecrets/vault.ts b/electron/main/workspaceSecrets/vault.ts index 92d5bb7b..02733b7a 100644 --- a/electron/main/workspaceSecrets/vault.ts +++ b/electron/main/workspaceSecrets/vault.ts @@ -26,7 +26,7 @@ import type { } from './types'; const FORMAT_VERSION = 1; -const VAULT_FILE_NAME = 'workforce-secret-vault.v1.json'; +const VAULT_FILE_NAME = 'workspace-secret-vault.v1.json'; const MAX_VAULT_BYTES = 8 * 1024 * 1024; export const MAX_WORKSPACE_SECRET_BYTES = 64 * 1024; diff --git a/src/components/WorkspaceBundle/AgentPluginImportWizard.tsx b/src/components/WorkspaceBundle/AgentPluginImportWizard.tsx index 38297aec..d2713461 100644 --- a/src/components/WorkspaceBundle/AgentPluginImportWizard.tsx +++ b/src/components/WorkspaceBundle/AgentPluginImportWizard.tsx @@ -286,7 +286,7 @@ export function AgentPluginImportWizard({ /> Agent Plugin converted - {conversion.bundle_id}@{conversion.revision_id} is a local Workforce + {conversion.bundle_id}@{conversion.revision_id} is a local Workspace Bundle draft. It has not been published or installed elsewhere. @@ -311,7 +311,7 @@ export function AgentPluginImportWizard({

Import Agent Plugin

Import the Agent Plugins standard. Eigent reviews the package before - converting it to a local Workforce Bundle draft. + converting it to a local Workspace Bundle draft.

diff --git a/src/components/WorkspaceBundle/WorkspaceBundleInstallWizard.test.tsx b/src/components/WorkspaceBundle/WorkspaceBundleInstallWizard.test.tsx index 42741904..fe725b9f 100644 --- a/src/components/WorkspaceBundle/WorkspaceBundleInstallWizard.test.tsx +++ b/src/components/WorkspaceBundle/WorkspaceBundleInstallWizard.test.tsx @@ -99,8 +99,8 @@ import { WorkspaceBundleInstallWizard } from './WorkspaceBundleInstallWizard'; const manifest = { apiVersion: 'eigent.ai/v1alpha1', - kind: 'WorkforceBundle', - metadata: { id: 'research', name: 'Research workforce', revision: 1 }, + kind: 'WorkspaceBundle', + metadata: { id: 'research', name: 'Research workspace', revision: 1 }, spec: { instructions: {}, context: [], @@ -135,7 +135,7 @@ const review = { bundle: { id: 'research', workspace_id: 'author-space', - name: 'Research workforce', + name: 'Research workspace', visibility: 'public' as const, latest_published_revision_id: 'research@1', }, @@ -236,7 +236,7 @@ describe('WorkspaceBundleInstallWizard', () => { const user = userEvent.setup(); renderWizard({ initialHandle: 'research@1' }); - expect(await screen.findByText('Research workforce')).toBeInTheDocument(); + expect(await screen.findByText('Research workspace')).toBeInTheDocument(); expect(mocks.createSpace).not.toHaveBeenCalled(); expect(mocks.decide).not.toHaveBeenCalled(); @@ -785,7 +785,7 @@ describe('WorkspaceBundleInstallWizard', () => { ).toBeInTheDocument(); await user.click(screen.getByRole('button', { name: 'Retry' })); - expect(await screen.findByText('Research workforce')).toBeInTheDocument(); + expect(await screen.findByText('Research workspace')).toBeInTheDocument(); expect(mocks.fetchReview).toHaveBeenCalledTimes(2); }); diff --git a/src/components/WorkspaceBundle/WorkspaceBundleInstallWizard.tsx b/src/components/WorkspaceBundle/WorkspaceBundleInstallWizard.tsx index 8fa69d23..124973a0 100644 --- a/src/components/WorkspaceBundle/WorkspaceBundleInstallWizard.tsx +++ b/src/components/WorkspaceBundle/WorkspaceBundleInstallWizard.tsx @@ -337,7 +337,7 @@ function McpDestinationReview({ } const installSeedKey = (revisionId: string, actorId: string): string => - `eigent:workforce-bundle-install-seed:v1:${actorId}:${revisionId}`; + `eigent:workspace-bundle-install-seed:v1:${actorId}:${revisionId}`; function readInstallSeed( revisionId: string, @@ -564,7 +564,7 @@ export function WorkspaceBundleInstallWizard({ async (rawHandle: string) => { const parsed = parseWorkspaceBundleHandle(rawHandle); if (!parsed) { - setError('Use a published handle such as my-workforce@1.'); + setError('Use a published handle such as my-workspace@1.'); setRetryMode(null); return; } @@ -634,13 +634,13 @@ export function WorkspaceBundleInstallWizard({ const name = review.bundle?.name || review.revision.manifest.metadata.name || - 'Imported workforce'; + 'Imported workspace'; const spaceId = await createSpaceOnServer({ name, sourceType: 'blank', setActive: false, metadata: { - createdFrom: 'workforce_bundle_install', + createdFrom: 'workspace_bundle_install', bundleRevision: handle.revisionId, bundleInstallProposalId: proposalId, bundleInstallRequestId: requestId, @@ -963,10 +963,10 @@ export function WorkspaceBundleInstallWizard({

- Install Workforce Bundle + Install Workspace Bundle

- Review what the workforce can access, then configure required values + Review what the workspace environment can access, then configure required values and connections locally.

@@ -1010,8 +1010,8 @@ export function WorkspaceBundleInstallWizard({ setHandleInput(event.target.value)} - placeholder="research-workforce@1" - aria-label="Workforce Bundle share handle" + placeholder="research-workspace@1" + aria-label="Workspace Bundle share handle" />

Share this exact bundle_id@revision handle. - Recipients can paste it into Import Workforce Bundle to + Recipients can paste it into Import Workspace Bundle to review and install this immutable version.

diff --git a/src/pages/Home/components/HomeHubToolbar.tsx b/src/pages/Home/components/HomeHubToolbar.tsx index 2853a930..8ebb9ff1 100644 --- a/src/pages/Home/components/HomeHubToolbar.tsx +++ b/src/pages/Home/components/HomeHubToolbar.tsx @@ -255,7 +255,7 @@ export default function HomeHubToolbar({ onClick={() => navigate('/workspace-bundles/install')} > - Import Workforce Bundle + Import Workspace Bundle {isDesktop() ? ( diff --git a/src/service/workspaceBundleInstallApi.test.ts b/src/service/workspaceBundleInstallApi.test.ts index 77be35ac..a8751d9f 100644 --- a/src/service/workspaceBundleInstallApi.test.ts +++ b/src/service/workspaceBundleInstallApi.test.ts @@ -33,46 +33,46 @@ describe('workspace Bundle install API', () => { }); it('accepts only a canonical immutable share handle', () => { - expect(parseWorkspaceBundleHandle('research-workforce@12')).toEqual({ - bundleId: 'research-workforce', - revisionId: 'research-workforce@12', + expect(parseWorkspaceBundleHandle('research-workspace@12')).toEqual({ + bundleId: 'research-workspace', + revisionId: 'research-workspace@12', }); - expect(parseWorkspaceBundleHandle('research-workforce')).toBeNull(); - expect(parseWorkspaceBundleHandle('research-workforce@0')).toBeNull(); + expect(parseWorkspaceBundleHandle('research-workspace')).toBeNull(); + expect(parseWorkspaceBundleHandle('research-workspace@0')).toBeNull(); }); it('loads the published revision before creating a local proposal', async () => { - mocks.findBundle.mockResolvedValue({ id: 'research-workforce' }); + mocks.findBundle.mockResolvedValue({ id: 'research-workspace' }); mocks.getRevision.mockResolvedValue({ - id: 'research-workforce@1', - bundle_id: 'research-workforce', + id: 'research-workspace@1', + bundle_id: 'research-workspace', status: 'published', }); await fetchWorkspaceBundleInstallReview({ - bundleId: 'research-workforce', - revisionId: 'research-workforce@1', + bundleId: 'research-workspace', + revisionId: 'research-workspace@1', }); expect(mocks.getRevision).toHaveBeenCalledWith( - 'research-workforce', - 'research-workforce@1' + 'research-workspace', + 'research-workspace@1' ); expect(mocks.fetchPost).not.toHaveBeenCalled(); }); it('rejects a draft revision during the review-first read', async () => { - mocks.findBundle.mockResolvedValue({ id: 'research-workforce' }); + mocks.findBundle.mockResolvedValue({ id: 'research-workspace' }); mocks.getRevision.mockResolvedValue({ - id: 'research-workforce@1', - bundle_id: 'research-workforce', + id: 'research-workspace@1', + bundle_id: 'research-workspace', status: 'validated', }); await expect( fetchWorkspaceBundleInstallReview({ - bundleId: 'research-workforce', - revisionId: 'research-workforce@1', + bundleId: 'research-workspace', + revisionId: 'research-workspace@1', }) ).rejects.toThrow('Only published'); }); @@ -84,8 +84,8 @@ describe('workspace Bundle install API', () => { proposalId: 'p-1', requestId: 'r-1', spaceId: 'space-1', - bundleId: 'research-workforce', - revisionId: 'research-workforce@1', + bundleId: 'research-workspace', + revisionId: 'research-workspace@1', }); expect(mocks.fetchPost).toHaveBeenCalledWith( diff --git a/src/service/workspaceBundleInstallApi.ts b/src/service/workspaceBundleInstallApi.ts index 1cdebe5d..dc55fb53 100644 --- a/src/service/workspaceBundleInstallApi.ts +++ b/src/service/workspaceBundleInstallApi.ts @@ -149,14 +149,14 @@ export async function fetchWorkspaceBundleInstallReview( ); if (revision.status !== 'published') { throw new Error( - 'Only published Workforce Bundle versions can be installed.' + 'Only published Workspace Bundle versions can be installed.' ); } if ( revision.bundle_id !== handle.bundleId || revision.id !== handle.revisionId ) { - throw new Error('The Workforce Bundle version identity does not match.'); + throw new Error('The Workspace Bundle version identity does not match.'); } // Public install remains usable even if mutable owner metadata is not // readable by this account. The immutable revision is the authority. diff --git a/src/service/workspaceConfigurationApi.test.ts b/src/service/workspaceConfigurationApi.test.ts index a5565705..f484c744 100644 --- a/src/service/workspaceConfigurationApi.test.ts +++ b/src/service/workspaceConfigurationApi.test.ts @@ -27,7 +27,7 @@ import { const document: WorkspaceConfigurationDocument = { apiVersion: 'eigent.ai/v1alpha1', - kind: 'WorkforceBundle', + kind: 'WorkspaceBundle', metadata: { id: 'bundle-1', name: 'Bundle', revision: 1 }, spec: { instructions: {}, diff --git a/src/service/workspaceConfigurationApi.ts b/src/service/workspaceConfigurationApi.ts index 5e1f9e43..18b7ce8d 100644 --- a/src/service/workspaceConfigurationApi.ts +++ b/src/service/workspaceConfigurationApi.ts @@ -58,7 +58,7 @@ export interface WorkspaceAgentProfile { export interface WorkspaceConfigurationDocument { apiVersion: 'eigent.ai/v1alpha1'; - kind: 'WorkforceBundle'; + kind: 'WorkspaceBundle'; metadata: { id: string; name: string; diff --git a/test/unit/electron/main/workspaceSecrets.test.ts b/test/unit/electron/main/workspaceSecrets.test.ts index be5701ac..a0039796 100644 --- a/test/unit/electron/main/workspaceSecrets.test.ts +++ b/test/unit/electron/main/workspaceSecrets.test.ts @@ -105,7 +105,7 @@ describe('WorkspaceSecretVault', () => { expect(fs.statSync(store.rootDir).mode & 0o777).toBe(0o700); expect(fs.statSync(store.filePath).mode & 0o777).toBe(0o600); expect(fs.readdirSync(store.rootDir)).toEqual([ - 'workforce-secret-vault.v1.json', + 'workspace-secret-vault.v1.json', ]); expect(fsync).toHaveBeenCalledTimes(2); expect(store.resolve(result)).toBe('sentinel-super-secret'); diff --git a/test/unit/hooks/useWorkspaceConfiguration.test.tsx b/test/unit/hooks/useWorkspaceConfiguration.test.tsx index 8099575b..8d27da54 100644 --- a/test/unit/hooks/useWorkspaceConfiguration.test.tsx +++ b/test/unit/hooks/useWorkspaceConfiguration.test.tsx @@ -26,7 +26,7 @@ import { useWorkspaceConfiguration } from '@/hooks/useWorkspaceConfiguration'; const makeDocument = (name = 'Research'): WorkspaceConfigurationDocument => ({ apiVersion: 'eigent.ai/v1alpha1', - kind: 'WorkforceBundle', + kind: 'WorkspaceBundle', metadata: { id: 'bundle-1', name, revision: 1 }, spec: { instructions: {},