mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-08-15 11:43:31 +00:00
refactor: standardize Workspace Bundle terminology
This commit is contained in:
parent
c9152a39e9
commit
08e2209afa
42 changed files with 213 additions and 212 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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]:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Device-authenticated Cloud transport for Workforce Bundle installation."""
|
||||
"""Device-authenticated Cloud transport for Workspace Bundle installation."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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, ...],
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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=[],
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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' ? (
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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' }));
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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() ? (
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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: {},
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export interface WorkspaceAgentProfile {
|
|||
|
||||
export interface WorkspaceConfigurationDocument {
|
||||
apiVersion: 'eigent.ai/v1alpha1';
|
||||
kind: 'WorkforceBundle';
|
||||
kind: 'WorkspaceBundle';
|
||||
metadata: {
|
||||
id: string;
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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: {},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue