Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@ Win/macOS: tenbox-manager ──IPC v1──► tenbox-vm-runtime (WHVP / HVF)
- **LLM proxy** exists in two places: `src/daemon/llm_proxy.cpp` (Linux) and `src/manager/llm_proxy.cpp` (Windows); change both when the protocol changes.
- **RemoteSession** is single-instance per VM. Read `remote_webrtc.cpp`'s `force` takeover path before adding DataChannels.
- **macOS Caps Lock forwarding**: send Caps Lock as a tap (`down` then `up`) on each `flagsChanged` event; AppKit exposes it as a toggle state, but the guest input stack needs a full key press for every switch.
- **Agent data profile packages**: `TenBox.app` exports/imports Hermes/OpenClaw data without image changes by using a temporary shared folder and console-injected standard shell commands. Keep the gzip package format documented in `docs/agent-profile.md` and reject cross-agent imports.
- **Hermes profile scope**: export user/config/state data, not the reinstallable Hermes app checkout, virtualenv, local binaries, logs, or cache directories.
- **macOS Agent data UI**: `TenBox.app` exposes Agent data export/import from the VM toolbar/menu while a VM is running. It must not depend on preinstalled guest TenBox scripts.
- **macOS Agent data shares**: Agent tool temporary shared folders are runtime-only; do not persist operation or backup share tags into VM config.
- **macOS Agent share cleanup**: drop persisted `tenbox-agent-ops-*` and `tenbox-agent-backups-*` entries on config load/startup to clean old builds.
- **macOS Agent data panels**: show export/import file panels asynchronously from SwiftUI sheets; do not use blocking `runModal()` from button handlers.
- **macOS console commands**: Agent tool commands fail quickly if the VM shell does not echo the begin marker, and they wait for the temporary shared folder to become writable before reading or writing packages.
- **macOS app signing**: the app entitlement includes `com.apple.security.cs.disable-library-validation` so the hardened-runtime app can load the bundled Sparkle framework.
- **Static build** (`TENBOX_STATIC_FFMPEG=ON`) requires `/opt/tenbox-deps` (only present inside the CI/packaging container). Dev builds use system shared libs — keep `ON` off by default.
- **Release**: `docs/release.md` — VERSION bump → commit → push → tag → push tag. Always push commit before tag.

Expand Down
41 changes: 41 additions & 0 deletions docs/agent-profile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Agent Data Export and Import

TenBox.app exports and imports Hermes/OpenClaw Agent data without requiring
images to preinstall TenBox-specific scripts.

The macOS manager creates a temporary shared folder, then sends a short shell
command through the existing VM console channel. The command uses standard guest
tools such as `tar` and `gzip`.

## Package format

The exported package is a gzip tar archive:

```text
<vm>-<agent>-profile.tar.gz
├── manifest.json
└── files.tar.gz
```

`manifest.json` contains:

- `format`: `tenbox-agent-profile`
- `format_version`: `2`
- `agent_type`: `hermes` or `openclaw`
- `archive`: `files.tar.gz`

`files.tar.gz` contains the Agent data directory relative to the guest home:

- Hermes: `.hermes`
- OpenClaw: `.openclaw`

Excluded paths:

- Hermes: `.hermes/logs`, `.hermes/image_cache`, `.hermes/audio_cache`,
`.hermes/hermes-agent`, `.hermes/bin`, `.hermes/gateway.pid`,
`.hermes/gateway.lock`
- OpenClaw: `.openclaw/cache`, `.openclaw/.cache`, `.openclaw/workspace/.cache`

Import rejects packages whose `agent_type` does not match the selected Agent.
Before replacing existing data, it renames the current directory to
`*.pre-import-YYYYMMDDHHMMSS`.
19 changes: 19 additions & 0 deletions src/manager-macos/Bridge/VmConfigStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class VmConfigStore {

private let decoder = JSONDecoder()

private static func isAgentToolSharedFolderTag(_ tag: String) -> Bool {
tag.hasPrefix("tenbox-agent-ops-") || tag.hasPrefix("tenbox-agent-backups-")
}

// MARK: - Paths

func vmDirectory(for vmId: String) -> URL {
Expand All @@ -47,9 +51,24 @@ class VmConfigStore {
config.kernelPath = resolve(config.kernelPath)
config.initrdPath = resolve(config.initrdPath)
config.diskPath = resolve(config.diskPath)
config.sharedFolders.removeAll { Self.isAgentToolSharedFolderTag($0.tag) }
return config
}

func purgeAgentToolSharedFolders() {
let fm = FileManager.default
guard let items = try? fm.contentsOfDirectory(atPath: Self.vmsDirectory.path) else { return }
for item in items {
let url = configURL(for: item)
guard let data = try? Data(contentsOf: url),
var config = try? decoder.decode(VmConfig.self, from: data) else { continue }
let oldCount = config.sharedFolders.count
config.sharedFolders.removeAll { Self.isAgentToolSharedFolderTag($0.tag) }
guard config.sharedFolders.count != oldCount else { continue }
_ = writeConfig(vmId: item, config: config)
}
}

@discardableResult
func writeConfig(vmId: String, config: VmConfig) -> Bool {
guard let data = try? encoder.encode(config) else { return false }
Expand Down
2 changes: 2 additions & 0 deletions src/manager-macos/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ let package = Package(
"Bridge/VmProcessManager.swift",
"Services/ImageSourceService.swift",
"Services/LlmProxyService.swift",
"Services/AgentToolsService.swift",
"Views/LlmProxyView.swift",
"Views/AgentToolsView.swift",
],
resources: [
.copy("Resources/icon.png"),
Expand Down
2 changes: 2 additions & 0 deletions src/manager-macos/Resources/TenBox.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<dict>
<key>com.apple.security.hypervisor</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<false/>
</dict>
Expand Down
Loading
Loading