Add bottom padding to terminal containers so FitAddon proposes one
fewer row, leaving visible space below Claude Code's mode indicator.
Previously the bottom status line (e.g. "bypass permissions on") was
clipped against the container edge in fullscreen TUI mode.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous fix wasn't enough: the NodeSource setup_22.x script runs its
own internal `apt-get update` without retries. When that hit the Ubuntu
mirror-sync issue (stale Packages.gz with mismatched hash), the script
silently bailed without configuring the NodeSource repo. The next
`apt-get install -y nodejs` then installed Ubuntu's default nodejs 18,
which ships without npm, breaking the `npm install -g pnpm` step.
Changes:
- Replace the `curl ... | bash -` NodeSource setup with manual GPG key +
repo file configuration, giving us direct control over apt-get update
retries.
- Add the same 5-attempt retry loop (with 10s sleep and lists cleanup)
to the Python 3 and Docker CLI steps, since both also do an
apt-get update and would hit the same failure mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two fixes for the v0.3.x initial build failures:
1. **Compute Version step**: When no tags match v0.3.*, `grep` returns
exit 1 which under `pipefail` killed the step before the empty-tag
fallback could run. Added `|| true` to the pipeline so the fallback
(`git rev-list --count HEAD`) runs correctly on first 0.3.x build.
2. **Dockerfile apt-get update**: Transient archive.ubuntu.com mirror
sync failures (stale Packages.gz with mismatched hash) broke the
GitHub CLI install step. Added a shell retry loop (5 attempts with
10s sleep, clearing /var/lib/apt/lists/* between retries) to both
the main system packages step and the GitHub CLI step, plus
Acquire::Retries=3 on the other apt-get update calls for transient
network failures.
Also includes the Cargo.lock 0.2.0 → 0.3.0 rev that went with the
previous version bump commit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## What's New in v0.3.0
### Claude Code Settings (TUI Mode, Effort, Focus, Caching)
- New per-project and global settings for Claude Code CLI behavior
- **TUI Fullscreen Mode**: Flicker-free alt-screen rendering via CLAUDE_CODE_NO_FLICKER
- **Effort Level**: Control reasoning depth (low/medium/high)
- **Focus Mode**: Collapse tool output to one-line summaries
- **Thinking Summaries**: Show Claude's thinking process
- **Session Recap**: Get context when returning to a session
- **Auto-Scroll Disabled**: Disable auto-scroll in fullscreen TUI
- **Env Scrub**: Strip credentials from subprocess environments
- **Prompt Caching (1h)**: Enable 1-hour prompt cache TTL
- New ClaudeCodeSettingsModal accessible from project config and global settings
- Settings injected as env vars and ~/.claude/settings.json via entrypoint
### Session Naming
- Name Claude Code terminal sessions with the -n flag
- Session names displayed in terminal tabs instead of project name
### Global Default Fallbacks
- Global SSH key path now used when per-project SSH path is not set
- Global git name/email now used when per-project values are not set
- New UI in Settings panel for SSH key directory, git name, and git email
### Relaxed Environment Variable Filter
- CLAUDE_CODE_* env vars now allowed in custom env vars for power users
- Only specific internal vars (CLAUDE_INSTRUCTIONS, MCP_SERVERS_JSON, etc.) blocked
### Documentation
- Updated README, HOW-TO-USE, and CLAUDE.md with all new features
- New "Claude Code Tips" section documenting built-in CLI features
(/focus, /recap, /color, /loop, /powerup, /team-onboarding, setup wizards)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds first-class support for Claude Code CLI features (2.1.71-2.1.110):
- New ClaudeCodeSettings struct with per-project and global defaults for
TUI mode, effort level, focus mode, thinking summaries, session recap,
auto-scroll, env scrub, and 1-hour prompt caching
- Settings injected as env vars (CLAUDE_CODE_NO_FLICKER, etc.) and
~/.claude/settings.json entries via entrypoint.sh merge block
- New ClaudeCodeSettingsModal component for configuring settings
- Session naming support (-n flag passed to claude CLI, shown in tabs)
- Relaxed reserved prefix filter: CLAUDE_CODE_* env vars now allowed in
custom env vars UI for power users
- Global SSH key path, git name, and git email now used as fallbacks
when per-project values are not set, with UI in SettingsPanel
- Fingerprint-based change detection triggers container recreation when
Claude Code settings change
- Updated README, HOW-TO-USE, and CLAUDE.md documentation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
For Bedrock Profile projects, SSO credentials are now checked and
refreshed on the host before the container starts, so the entrypoint
copies already-valid tokens. This eliminates the delay where users
had to wait for the terminal to open before being prompted to login.
The terminal-time fallback remains for mid-session credential expiry.
Also consolidates duplicated profile resolution logic into a shared
helper in aws_commands.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add STT section covering voice mode usage, hotkey (Ctrl+Shift+M), model
options, auto-start behavior, and transcription flow. Update Key Files
table with all STT-related files and fix outdated useVoice.ts reference.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously the STT container only started on-demand (mic button click or
manual start in settings). Now it auto-starts during app setup if
stt.enabled is true, matching the web terminal auto-start pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the native title attribute with a custom tooltip that appears
instantly on hover, displaying the shortcut in a styled kbd element.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Lifts useSTT hook from SttButton into TerminalView so both the hotkey
and the button share the same recording state. The hotkey keeps terminal
focus so after transcription the user just presses Enter. The button
also no longer steals focus via onMouseDown preventDefault.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Aligns the npm lockfile with the Cargo crate version to fix the Tauri
build version mismatch check.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cargo had resolved to 2.6.0 while npm had 2.7.0, causing the Tauri
build version check to fail.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a mic button to the terminal UI that captures speech, transcribes
it via a Faster Whisper sidecar container, and injects the text into
the terminal input. Includes settings panel for model selection
(tiny/small/medium), port config, and container lifecycle management.
- stt-container/: Dockerfile + FastAPI server for Whisper transcription
- Rust backend: STT container management, transcribe_audio IPC command
- Frontend: useSTT hook, SttButton, SttSettings, WAV encoder
- CI: Gitea Actions workflow for multi-arch STT image builds
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Manual workflow that deletes old Gitea and GitHub releases,
keeping only the N most recent versions. Defaults to dry-run
mode for safe preview before deletion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The mission-control (Flight Control) project is being closed upstream.
This embeds the project files directly in the repo under container/mission-control/,
bakes them into the Docker image at /opt/mission-control, and copies them into place
at container startup instead of git cloning from GitHub.
Also adds missing osc52-clipboard, audio-shim, and triple-c-sso-refresh to the
programmatic Docker build context in image.rs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds position:sticky to the topbar and tab bar so they stay pinned
at the top when the virtual keyboard opens on tablets. Also uses
100dvh (dynamic viewport height) so the layout properly shrinks
when the keyboard appears on mobile browsers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a dedicated input bar at the bottom that bypasses mobile IME
composition buffering — characters are sent immediately on each input
event instead of waiting for word boundaries. Also adds helper buttons
(Enter, Tab, Ctrl+C) and a floating scroll-to-bottom button that
appears when scrolled up from the terminal output.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds an axum HTTP+WebSocket server that runs alongside the Tauri app,
serving a standalone xterm.js-based terminal UI accessible from any
browser on the local network. Shares the existing ExecSessionManager
via Arc-wrapped stores, with token-based authentication and automatic
session cleanup on disconnect.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migrate env-var-based checks in container_needs_recreation() to label-based
checks. When a container snapshot is committed, Docker merges the image's env
vars with the container's, causing get_env() to return stale values and
triggering an infinite snapshot→recreate loop. Labels are immutable after
creation and immune to this merging behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The onScroll RAF optimization (only fire when atBottom changes) prevented
the button from showing because xterm's onScroll may not fire from wheel
events. Fix by setting isAtBottom(false) directly in the wheel handler
and removing the RAF guard to always schedule state updates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevent viewport jumping during Claude output by only re-enabling
auto-follow on user-initiated scrolls (wheel events within 300ms),
not on write-triggered xterm scroll events. Add a "Following/Paused"
toggle button in the top-right corner of the terminal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous fix checked isAtBottomRef inside the write callback, but
xterm's own scroll events during write processing could set the ref to
false (viewport desync), breaking auto-follow entirely.
Introduce a separate autoFollowRef that tracks user intent:
- Set to false only by explicit mouse wheel scroll-up (capture phase)
- Set to true when viewport reaches bottom or user clicks the button
- Write callback uses autoFollowRef so desync doesn't kill auto-follow
but user scroll-up correctly pauses it
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The shouldFollow flag was captured before term.write() but the callback
ran asynchronously — if the user scrolled up in between, the stale flag
forced the viewport back to bottom, preventing the button from appearing.
Check isAtBottomRef at callback time instead so user scroll-up is respected.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Auto-scroll viewport on new output when user is at bottom, debounce
scroll state updates to reduce re-renders, preserve scroll position
across resize reflows, and fix "Jump to Current" button by re-fitting
the terminal to clear viewport desync.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- help_commands.rs: fetch HOW-TO-USE.md from GitHub raw instead of Gitea
- DockerSettings.tsx: display GHCR image address in settings UI
- HOW-TO-USE.md: update registry description to ghcr.io
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Work VPN blocks repo.anhonesthost.net, breaking update checks and image
pulls. Move all user-facing distribution to GitHub (releases API) and
GHCR (container images) while keeping Gitea as the source of truth for
development and CI.
- CI: push container images to GHCR alongside Gitea registry
- App updates: switch releases API to api.github.com, filter by asset
filename instead of tag suffix for unified releases
- Image updates: switch registry to ghcr.io with anonymous token auth
- Container pull: point REGISTRY_IMAGE to ghcr.io/shadowdao/triple-c-sandbox
- Rename GiteaRelease/GiteaAsset structs to GitHubRelease/GitHubAsset
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New projects default to standard permission mode (Claude asks before acting).
Existing projects default to full permissions ON, preserving current behavior.
UI toggle uses red/caution styling to highlight the security implications.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reflects that this backend works with any OpenAI API-compatible endpoint
(LiteLLM, OpenRouter, vLLM, text-generation-inference, LocalAI, etc.),
not just LiteLLM. Includes serde aliases for backward compatibility with
existing projects.json files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the user highlights text in the terminal, a "Ctrl+Shift+C to copy"
hint appears in the status bar next to the project/terminal counts.
The hint disappears when the selection is cleared.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ctrl+C in the terminal sends SIGINT which cancels running Claude work.
This adds a custom key handler so Ctrl+Shift+C copies selected text to
the clipboard without interrupting the container.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The model field must be set and the model must be pre-pulled in Ollama
before the container will work. Updated README, HOW-TO-USE, and the
ProjectCard UI label/tooltip to reflect this.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Help dialog now fetches HOW-TO-USE.md live from the gitea repo on open,
falling back to the compile-time embedded copy when offline. Content is
cached for the session. Removes the ~600-line hardcoded markdown constant
from HelpDialog.tsx in favor of a single source of truth.
Adds a Table of Contents with anchor links for quick navigation and a new
troubleshooting entry for the "Failed to install Anthropic marketplace"
error with the jq fix. Markdown renderer updated to support anchor links
and header id attributes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite Tooltip to use React portal (createPortal to document.body) so
tooltips render above all UI elements regardless of ancestor overflow:hidden.
Also increased max-width from 220px to 280px for longer descriptions.
Expanded Backend tooltip to explain each option (Anthropic, Bedrock,
Ollama, LiteLLM) with practical context for new users.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The version comparison was only comparing the patch number, ignoring major
and minor versions. This meant 0.1.75 (patch=75) appeared "newer" than
0.2.1 (patch=1), and updates within 0.2.x were missed entirely.
Also fixed platform filtering to handle -mac suffix (previously only
filtered -win, so Linux users would see macOS releases too).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add circled ? help button in TopBar that opens a dialog with HOW-TO-USE.md content
- Create reusable Tooltip component with viewport-aware positioning
- Add 32 tooltip indicators across project config and settings panels
- Covers backend selection, Bedrock/Ollama/LiteLLM fields, Docker, AWS, MCP, and more
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix serde deserialization error: TypeScript sent "lit_llm" but Rust expected "lite_llm"
- Rename AuthMode enum to Backend across Rust and TypeScript (with serde alias for backward compat)
- Add container image update checking via registry digest comparison
- Improve Settings page: fix image address display spacing, remove per-project auth section
- Update UI labels from "Auth" to "Backend" throughout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create VERSION file (currently `0.2`) as the single source of truth for major.minor
- Add compute-version job that reads VERSION and counts commits since the last
matching v{major.minor}.N tag to derive the patch number
- Patch resets automatically when VERSION is bumped (no matching tags exist yet)
- Add create-tag job that tags the repo after all platform builds succeed,
so subsequent builds count from the new tag
- All platform jobs now consume the shared version instead of computing their own
- VERSION file changes trigger the build workflow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The computed build version was hardcoded as 0.1.${COMMIT_COUNT} across all
three platform jobs (Linux, macOS, Windows), producing 0.1.x releases even
though the source files were bumped to 0.2.0.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The horizontal button lists overflowed the viewable area of the card. Replace
with <select> dropdowns for both the main auth mode and the Bedrock sub-method.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove unused `any_docker_mcp()` function, add `#[allow(unused_imports)]`
and `#[allow(dead_code)]` annotations to suppress false-positive warnings.
Update README.md and HOW-TO-USE.md with Ollama and LiteLLM auth backend
documentation including best-effort compatibility notices.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add two new auth modes for projects alongside Anthropic and Bedrock:
- Ollama: connect to local or remote Ollama servers via ANTHROPIC_BASE_URL
- LiteLLM: connect through a LiteLLM proxy gateway to 100+ model providers
Both modes inject ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN env vars into
the container, with optional model override via ANTHROPIC_MODEL. LiteLLM
API keys are stored securely in the OS keychain. Config changes trigger
automatic container recreation via fingerprinting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SSO login was broken in containers due to three issues: the sso_session
indirection format not being resolved by Claude Code's AWS SDK, SSO
detection only checking sso_start_url (missing sso_session), and the
OAuth callback port not being accessible from inside the container.
This fix runs SSO login on the host OS (where the browser and ports work
natively) by having the container emit a marker that the Tauri app
detects in terminal output, triggering host-side `aws sso login`. The
entrypoint also inlines sso_session properties into profile sections and
injects awsAuthRefresh into Claude Code config for mid-session refresh.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rewrite HOW-TO-USE.md MCP section with a mode matrix (stdio/http x
manual/docker), four worked examples (filesystem, GitHub, custom HTTP,
database), and detailed explanations of networking, auto-pull, and
config injection
- Update README.md MCP architecture section with a mode table and
key behaviors including auto-pull and Docker DNS details
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Automatically pull missing Docker images for MCP servers before
starting containers, with progress streamed to the container
progress modal
- Add contextual mode descriptions to MCP server cards explaining
where commands run (project container vs separate MCP container)
- Clarify that HTTP+Docker URLs are auto-generated using the
container hostname on the project network, not localhost
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add reconcile_project_statuses command that checks actual Docker container
state on startup, preserving Running status for containers that are genuinely
still running and resetting stale statuses to Stopped
- Add is_container_running helper using Docker inspect API
- Frontend calls reconciliation after Docker is confirmed available
- Update TECHNICAL.md project structure, auth modes, and file listings to
match current codebase
- Update README.md and HOW-TO-USE.md with MCP servers, Mission Control,
file manager, bash shells, clipboard/audio shims, and progress modal docs
- Add workflow file self-triggers to CI path filters for build-app.yml
and build.yml
- Install Mission Control skills to ~/.claude/skills/ in entrypoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The find command included the starting directory in results (e.g., listing
"workspace" inside /workspace). Replace `-not -name "."` with `-mindepth 1`
which correctly excludes the starting path from output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces the inline Yes/No confirmation with a proper ConfirmRemoveModal
dialog, consistent with other modal patterns in the app (EnvVarsModal, etc.).
Supports Escape key and overlay click to dismiss.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds two new features for running project containers:
1. Bash Shell Tab: A "Shell" button on running projects opens a plain
bash -l session instead of Claude Code, useful for direct container
inspection, package installation, and debugging. Tab labels show
"(bash)" suffix to distinguish from Claude sessions.
2. File Manager: A "Files" button opens a modal file browser for
navigating container directories, downloading files to the host,
and uploading files from the host. Supports breadcrumb navigation
and works with any path including those outside mounted projects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When enabled, the entrypoint clones mission-control into ~/mission-control
(persisted on the home volume) and symlinks it to /workspace/mission-control.
Flight Control global and project instructions are programmatically appended
to CLAUDE.md. Container recreation is triggered on toggle change.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add double-click-to-rename on project names in the sidebar
- Replace window.confirm() with inline React confirmation for project
removal (confirm dialog didn't block in Tauri webview)
- Add serde(default) to skip_serializing fields in Rust models so
deserialization doesn't fail when frontend omits secret fields
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude Code's /voice command incorrectly detects containers running
on WSL2 hosts as unsupported WSL environments. Remove the mic button
from project cards and microphone settings from the settings panel,
but keep useVoice hook and MicrophoneSettings component for re-enabling
once the upstream issue is resolved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Relocates the voice/mic toggle from a floating overlay on the terminal
view to the project command row (alongside Stop, Terminal, Config) so
it no longer blocks access to the terminal window.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a dropdown in Settings to choose which audio input device to
use for voice mode. Enumerates devices via the browser's
mediaDevices API and persists the selection in AppSettings.
The useVoice hook passes the selected deviceId to getUserMedia().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enables Claude Code's /voice command inside Docker containers by
capturing microphone audio in the Tauri webview and streaming it
into the container via a FIFO pipe.
Container: fake rec/arecord shims read PCM from a FIFO instead of
a real mic. Audio bridge exec writes PCM from Tauri into the FIFO.
Frontend: getUserMedia() + AudioWorklet captures 16kHz mono PCM
and streams it to the container via invoke("send_audio_data").
UI: "Mic Off/On" toggle button in the terminal view.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Programs inside the container (e.g. Claude Code's "hit c to copy") can
now write to the host system clipboard. A shell script shim installed as
xclip/xsel/pbcopy emits OSC 52 escape sequences, which the xterm.js
frontend intercepts and forwards to navigator.clipboard.writeText().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When using AWS Profile auth (SSO) with Bedrock, expired SSO sessions
caused Claude Code to spin indefinitely. Three root causes fixed:
1. Mount host .aws at /tmp/.host-aws (read-only) and copy to
/home/claude/.aws in entrypoint, mirroring the SSH key pattern.
This gives AWS CLI writable sso/cache and cli/cache directories.
2. For Bedrock Profile projects, wrap the claude command in a bash
script that validates credentials via `aws sts get-caller-identity`
before launch. If SSO session is expired, runs `aws sso login`
with the auth URL visible and clickable in the terminal.
3. Non-SSO profiles with bad creds get a warning but Claude still
starts. Non-Bedrock projects are unaffected.
Note: existing containers need a rebuild to pick up the new mount path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move GitHub release sync into build-app.yml as a final sync-to-github
job that runs after all 3 platform builds complete. This eliminates the
race condition where sync-release.yml triggered before artifacts were
uploaded to Gitea. The old sync-release.yml is changed to manual-only.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DefaultHasher is not stable across Rust compiler versions or binary
rebuilds, causing unnecessary container recreations on every app update.
Replace with SHA-256 for deterministic, cross-build-stable fingerprints.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each MCP server can now run as its own Docker container on a dedicated
per-project bridge network, enabling proper isolation and lifecycle
management. SSE transport is removed (deprecated per MCP spec) with
backward-compatible serde alias. Docker socket access is auto-enabled
when stdio+Docker MCP servers are configured.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Model Context Protocol (MCP) server configuration support. Users can
define MCP servers globally (new sidebar tab) and enable them per-project.
Enabled servers are injected into containers as MCP_SERVERS_JSON env var
and merged into ~/.claude.json by the entrypoint.
Backend: McpServer model, McpStore (JSON + atomic writes), 4 CRUD commands,
container injection with fingerprint-based recreation detection.
Frontend: MCP sidebar tab, McpPanel/McpServerCard components, useMcpServers
hook, per-project MCP checkboxes in ProjectCard config.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show container start/stop/rebuild progress as a modal popup instead of
inline text that was never visible. Add optimistic status updates so the
status dot turns yellow immediately. Also add a "Jump to Current" button
in the terminal when scrolled away from the bottom.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Emit container-progress events from Rust at key milestones (checking
image, saving state, recreating, starting, stopping) and display them
in ProjectCard instead of the static "starting.../stopping..." text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reconcile stale transient statuses on app startup, add Force Stop button
for transient states, and harden stop_project_container error handling so
Docker failures don't leave projects permanently stuck.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add home volume (triple-c-home-{id}) for /home/claude to persist
.claude.json, .local, and other user-level state across restarts
- Add docker commit before recreation: when container_needs_recreation()
triggers, snapshot the container to preserve system-level changes
(apt/pip/npm installs), then create the new container from that snapshot
- On Reset/removal: delete snapshot image + both volumes for clean slate
- Remove commit from stop_project_container (stop/start preserves the
writable layer naturally; no commit needed)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace OnceLock with Mutex<Option<Docker>> in the Rust backend so
failed Docker connections are retried instead of cached permanently.
Add frontend polling (every 5s) when Docker is initially unavailable,
stopping once detected.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CLAUDE_INSTRUCTIONS env var was computed differently during container
creation (with port mapping docs + scheduler instructions appended) vs
the recreation check (bare merge only). This caused
container_needs_recreation() to always return true, triggering a full
recreate on every stop/start cycle.
Extract build_claude_instructions() helper used by both code paths so
the expected value always matches what was set at creation time.
Also add TODO.md noting planned tauri-plugin-updater integration for
seamless in-app updates on all platforms.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Act runner has Node 18 at /opt/acttoolcache/node/18.20.3/x64/bin/,
not at /usr/local/bin/. Use $(dirname "$(which node)") to find and
remove the actual binary location before installing Node 22.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Act runner has Node 18 at /usr/local/bin/node which takes
precedence over the apt-installed /usr/bin/node. Even after
running nodesource setup and apt-get install, the old Node 18
binary remained in the PATH. Now removes old binaries and uses
hash -r to force path re-lookup. Also removes package-lock.json
before npm install to ensure correct platform-specific bindings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Act runner has Node.js v18 pre-installed, so the check
`command -v node` passes and skips installing v22. Node 18 is
too old for dependencies like vitest, jsdom, and tailwindcss/oxide.
Now checks the major version and upgrades if < 22.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tailwindcss/oxide has platform-specific native bindings. The
package-lock.json was generated on a different platform, so npm ci
installs the wrong native binary. Switching to rm -rf node_modules
+ npm install lets npm resolve the correct platform-specific
optional dependency (e.g., @tailwindcss/oxide-linux-x64-gnu on
Linux, oxide-darwin-arm64 on macOS).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Gitea Act runner's Docker container does not reliably support
$GITHUB_PATH or sourcing ~/.cargo/env across steps. Both mechanisms
failed because the runner spawns a fresh shell for each step.
Adopted the same pattern that already works for the Windows job:
explicitly set PATH at the top of every step that calls cargo or
npx tauri. This is the most portable approach across all runner
environments (Act Docker containers, bare metal macOS, Windows).
Build history shows Linux succeeded through run#46 (JS-based
actions) and failed from run#49 onward (shell-based installs).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GITHUB_PATH only takes effect in subsequent steps, but rustup/rustc/cargo
are called within the same step. Adding `. "$HOME/.cargo/env"` immediately
after install puts cargo/rustup in PATH for the remainder of the step.
Fixed in both Linux and macOS jobs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Gitea Linux runner also lacks Node.js, causing actions/checkout@v4
(a JS action) to fail with "node: executable file not found in PATH".
Same fix as the macOS job: install Node.js via shell before any
JS-based actions run.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Linux app build: cargo was not in PATH for subsequent steps after
shell-based install. Fixed by adding $HOME/.cargo/bin to GITHUB_PATH
(persists across steps) and setting it in the job-level env. Also
removed the now-unnecessary per-step PATH override in the macOS job.
Container build: added QEMU setup and platforms: linux/amd64,linux/arm64
to produce a multi-arch manifest. The Dockerfile already uses
arch-aware commands (dpkg --print-architecture, uname -m) so it
builds natively on both architectures. This fixes the "no matching
manifest for linux/arm64/v8" error on Apple Silicon Macs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace JS-based GitHub Actions (dtolnay/rust-toolchain,
actions/setup-node) in the Linux job with shell commands that
check if Rust and Node.js are already present before installing.
All three jobs (Linux, macOS, Windows) now use the same pattern:
skip installation if the tool is already available on the runner.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The macOS Gitea runner lacks Node.js, causing actions/checkout@v4
(a JS action) to fail with "Cannot find: node in PATH". Fixed by
installing Node.js via Homebrew before checkout and replacing all
JS-based actions (setup-node, rust-toolchain, rust-cache) with
shell equivalents.
Also adds macOS section to BUILDING.md covering Xcode CLI tools,
universal binary targets, and Gatekeeper bypass instructions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Builds a universal binary (aarch64 + x86_64) targeting both Apple
Silicon and Intel Macs. Produces .dmg and .app.tar.gz artifacts,
uploaded to a separate Gitea release tagged with -mac suffix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CLAUDE.md provides guidance for Claude Code instances working in this
repo (build commands, architecture overview, key conventions).
HOW-TO-USE.md is a user-facing guide covering prerequisites, setup,
all application features, and troubleshooting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Intercept clipboard paste events containing images in the terminal,
upload them into the Docker container via bollard's tar upload API,
and inject the resulting file path into terminal stdin so Claude Code
can reference the image.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace fragile line-by-line reassembly heuristic with a simpler
approach: flatten the buffer by converting blank lines to spaces
(URL terminators) and stripping remaining newlines (PTY wraps),
then match URLs with a single regex on the flat string.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PTY may deliver a long URL across multiple chunks with enough delay
that the debounce fires between them, emitting a truncated URL. Fixed by:
1. Stripping trailing empty strings from split (artifact of trailing \n)
2. Deferring emission when the URL reaches the end of the buffer — a
confirmation timer (500ms) waits for more data before emitting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PTY hard-wraps long URLs (e.g. OAuth) with \r\n at column width, breaking
xterm.js link detection. This adds a UrlDetector that reassembles wrapped
URLs from the output stream and shows a non-intrusive floating toast with
an "Open" button. Auto-dismisses after 30s, no terminal layout impact.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduces a cron-based scheduler that lets Claude set up recurring and
one-time tasks inside containers. Tasks run as separate Claude Code agents
and persist across container recreation via the named volume.
New files:
- container/triple-c-scheduler: CLI for add/remove/enable/disable/list/logs/run/notifications
- container/triple-c-task-runner: cron wrapper with flock, logging, notifications, auto-cleanup
Key changes:
- Dockerfile: add cron package and COPY both scripts
- entrypoint.sh: timezone setup, cron daemon, crontab restore, env saving
- container.rs: init=true for zombie reaping, TZ env, scheduler instructions, timezone recreation check
- image.rs: embed scheduler scripts in build context
- app_settings.rs + types.ts: timezone field
- settings_commands.rs: detect_host_timezone via iana-time-zone crate
- SettingsPanel.tsx: timezone input with auto-detection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add per-project port mapping configuration (host:container port pairs with
TCP/UDP protocol) stored in project config and applied as Docker port
bindings at container creation. Port changes trigger automatic container
recreation via fingerprint detection.
- Create PortMappingsModal UI component following the same pattern as
EnvVarsModal, integrated into ProjectCard config panel.
- Inject port mapping details into CLAUDE_INSTRUCTIONS so Claude inside the
container knows which ports are available for testing services.
- Update default global instructions for new installs to encourage use of
subagents for long-running and parallel tasks.
- Replace app icons with new v2 sun logo design for better visibility at
small sizes (taskbar/dock).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
API key auth only provides short-lived session tokens (8hrs or until
session restart) with no refresh mechanism, unlike OAuth which persists
via .credentials.json. Remove the non-functional API key settings UI
and all supporting code (frontend state, Tauri commands, keyring
storage, container env var injection, and fingerprint-based recreation
checks) to avoid user confusion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both match arms now return None, so Rust needs an explicit type
annotation for the Option<String>.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the three auth modes (Login, API Key, Bedrock) with two
(Anthropic, Bedrock). The Anthropic mode uses OAuth via `claude login`
inside the terminal, which generates and stores its own API key in the
persistent config volume. The separate API Key mode is removed because
Claude Code now requires interactive approval of externally-provided
keys, making the injected ANTHROPIC_API_KEY approach unreliable.
Old projects stored as "login" or "api_key" are automatically migrated
to "anthropic" via serde aliases.
Also fix the Windows taskbar icon showing as a black square by loading
icon.png instead of icon.ico for the runtime window icon.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The container was only recreated when the auth mode changed, not when
the API key value itself changed. This meant saving a new key required
a manual container rebuild. Now we store a hash of the API key as a
Docker label and compare it on start, so a key change automatically
recreates the container (preserving the claude config volume).
Also adds a note to the global AWS settings UI that changes require a
container rebuild.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The app crashed on startup because the image-ico Tauri feature was
missing, causing Image::from_bytes to panic when decoding icon.ico.
Added the feature flag and replaced env_logger with fern to log to both
stderr and <data_dir>/triple-c/logs/triple-c.log. A panic hook captures
crash details with backtraces. Store init and icon loading errors are now
logged before failing so future issues are diagnosable from the log file.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Windows taskbar icon by loading icon.ico instead of icon.png (ICO contains
multiple sizes native to Windows taskbar/title bar/alt-tab)
- Add "Container must be stopped to change settings" warning banner in config panel
- Move per-project Environment Variables and Claude Instructions into modal dialogs
for more editing space, with buttons in the config panel to open them
- Move global Claude Instructions into a modal in Settings panel
- Add default global Claude instruction recommending git initialization
- Add global environment variables support (full stack: Rust model, TS types,
container creation with merge logic where project overrides global for same key,
fingerprinting for recreation checks, and Settings UI with modal)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>