refactor: standardize Workspace Bundle terminology

This commit is contained in:
4pmtong 2026-08-11 18:00:11 +08:00
parent c9152a39e9
commit 08e2209afa
42 changed files with 213 additions and 212 deletions

View file

@ -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:

View file

@ -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)

View file

@ -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,
},

View file

@ -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,

View file

@ -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]:

View file

@ -1,4 +1,4 @@
"""Device-authenticated Cloud transport for Workforce Bundle installation."""
"""Device-authenticated Cloud transport for Workspace Bundle installation."""
from __future__ import annotations

View file

@ -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

View file

@ -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, ...],

View file

@ -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)

View file

@ -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",
]

View file

@ -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(

View file

@ -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",

View file

@ -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"))

View file

@ -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,

View file

@ -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,

View file

@ -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",

View file

@ -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,
)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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",

View file

@ -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:

View file

@ -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=[],

View file

@ -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)

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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")
)

View file

@ -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;

View file

@ -286,7 +286,7 @@ export function AgentPluginImportWizard({
/>
<CardTitle>Agent Plugin converted</CardTitle>
<CardDescription>
{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.
</CardDescription>
</CardHeader>
@ -311,7 +311,7 @@ export function AgentPluginImportWizard({
<h1 className="text-heading-2xl font-semibold">Import Agent Plugin</h1>
<p className="mt-2 max-w-2xl text-body-sm text-ds-text-neutral-muted-default">
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.
</p>
</header>

View file

@ -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);
});

View file

@ -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({
<header>
<h1 className="text-heading-2xl font-semibold">
Install Workforce Bundle
Install Workspace Bundle
</h1>
<p className="mt-2 text-body-sm text-ds-text-neutral-muted-default">
Review what the workforce can access, then configure required values
Review what the workspace environment can access, then configure required values
and connections locally.
</p>
</header>
@ -1010,8 +1010,8 @@ export function WorkspaceBundleInstallWizard({
<Input
value={handleInput}
onChange={(event) => setHandleInput(event.target.value)}
placeholder="research-workforce@1"
aria-label="Workforce Bundle share handle"
placeholder="research-workspace@1"
aria-label="Workspace Bundle share handle"
/>
<Button type="submit" disabled={busyKey === 'review'}>
{busyKey === 'review' ? (

View file

@ -53,7 +53,7 @@ export function EnvironmentRequirementsEditor({
<p className="max-w-2xl text-body-xs text-ds-text-neutral-muted-default">
Declare names and safe documentation only. Secret values, tokens, and
local environment values are never stored in or shared with a
Workforce Bundle.
Workspace Bundle.
</p>
<Button
type="button"

View file

@ -54,7 +54,7 @@ const draft: WorkspaceConfigurationDraft = {
updated_at: 1,
document: {
apiVersion: 'eigent.ai/v1alpha1',
kind: 'WorkforceBundle',
kind: 'WorkspaceBundle',
metadata: { id: 'bundle-1', name: 'Research', revision: 1 },
spec: {
instructions: { coordinator: 'bundle://instructions/coordinator.md' },
@ -298,11 +298,11 @@ describe('WorkspaceBundleSaveDialog', () => {
fireEvent.click(screen.getByRole('button', { name: 'Publish version' }));
expect(
await screen.findByLabelText('Published Workforce Bundle handle')
await screen.findByLabelText('Published Workspace Bundle handle')
).toHaveTextContent('bundle-1@1');
expect(screen.getByText('Shareable install handle')).toBeInTheDocument();
expect(
screen.getByText(/paste it into Import Workforce Bundle/i)
screen.getByText(/paste it into Import Workspace Bundle/i)
).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Copy share handle' }));

View file

@ -230,7 +230,7 @@ export function WorkspaceBundleSaveDialog({
const totalAssetBytes = selectedAssetBytes + preparedAssetBytes;
const assetLimitError = review
? totalAssetCount > MAX_ASSET_COUNT
? `A Workforce Bundle can contain at most ${MAX_ASSET_COUNT} assets.`
? `A Workspace Bundle can contain at most ${MAX_ASSET_COUNT} assets.`
: totalAssetBytes > MAX_TOTAL_ASSET_BYTES
? 'Selected assets exceed the 128 MiB total Bundle limit.'
: Object.values(assetFiles).some(
@ -284,7 +284,7 @@ export function WorkspaceBundleSaveDialog({
try {
if (totalAssetCount > MAX_ASSET_COUNT) {
throw new Error(
`A Workforce Bundle can contain at most ${MAX_ASSET_COUNT} assets.`
`A Workspace Bundle can contain at most ${MAX_ASSET_COUNT} assets.`
);
}
const selected = manualAssetPaths.map((path) => {
@ -558,7 +558,7 @@ export function WorkspaceBundleSaveDialog({
}}
>
<DialogHeader
title="Save Workforce Bundle"
title="Save Workspace Bundle"
subtitle="Review the portable configuration before creating an immutable version."
/>
<DialogContentSection className="space-y-4 overflow-y-auto">
@ -864,7 +864,7 @@ export function WorkspaceBundleSaveDialog({
</p>
<p
className="mt-1 font-mono text-body-sm"
aria-label="Published Workforce Bundle handle"
aria-label="Published Workspace Bundle handle"
>
{publishedHandle}
</p>
@ -880,7 +880,7 @@ export function WorkspaceBundleSaveDialog({
</Button>
<p className="mt-2 text-body-xs text-ds-text-neutral-muted-default">
Share this exact <code>bundle_id@revision</code> 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.
</p>
<p className="mt-2 text-body-xs text-ds-text-neutral-muted-default">

View file

@ -255,7 +255,7 @@ export default function HomeHubToolbar({
onClick={() => navigate('/workspace-bundles/install')}
>
<PackagePlus className="h-4 w-4 shrink-0" aria-hidden />
Import Workforce Bundle
Import Workspace Bundle
</Button>
{isDesktop() ? (

View file

@ -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(

View file

@ -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.

View file

@ -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: {},

View file

@ -58,7 +58,7 @@ export interface WorkspaceAgentProfile {
export interface WorkspaceConfigurationDocument {
apiVersion: 'eigent.ai/v1alpha1';
kind: 'WorkforceBundle';
kind: 'WorkspaceBundle';
metadata: {
id: string;
name: string;

View file

@ -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');

View file

@ -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: {},