c71e54a35fe9cb19ff117faa0149bba03ba813cd
93
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2de00b3c55 |
Fix review findings: secrets in snapshots, URL spoofing, migration data loss
Adversarial review of the branch produced findings across four areas. This addresses them, plus the Windows CI environment. Secrets. commit_container_snapshot baked the container's full env into the per-project snapshot image, so the shared OAuth token — and the AWS keys, git token and gateway master key — outlived revocation and were readable via docker inspect. Verified against Engine 29.6 that a commit body's config merges over the container's: keys cannot be dropped but can be overwritten, so all of them now commit as KEY=. clear_claude_token additionally rewrites images from earlier builds and reports honestly when a tag could not be rewritten. The recommendation to move the token out of env entirely was not taken, with reasoning: apiKeyHelper is a different auth method that outranks CLAUDE_CODE_OAUTH_TOKEN rather than a transport for it, and no file-based delivery exists. The durable exposure — the image — is what is closed here. Separately noted, not fixed: entrypoint.sh captures the token into the scheduler's .env inside the persisted volume. URL spoofing. Three call sites reached openUrl with container-controlled strings, one of which the review missed (the WebLinksAddon handler). The sign-in URL was scraped from container output with a longest-match tie-break and no userinfo check, so claude.ai@evil.tld rendered as "claude.ai…" in a truncating element. There is now one sanitizer in front of every sink — scheme allowlist, no userinfo, C0/C1 and quote rejection, host allowlist for the sign-in case, first-match — and the origin renders un-truncated. The toast is keyed so a changed URL remounts, closing a bait-and-switch where the user read one URL and clicked another. Migration. The rollback pin was best-effort: a tag failure was logged and the migration continued past remove_container, after which the final commit overwrote the only copy of the old system layer. It now aborts before anything destructive and reads the tag back. /var was destroyed while the ordinary recreate path preserves it — making the "safe" alternative to Reset more destructive than Reset's alternative; data-bearing subtrees are now detected and disclosed in the pre-flight rather than copied, since tarring a live database onto a different base's packages is a corruption risk. resume_migration now verifies the migration-state label instead of reporting success for a container that never swapped. dismiss actually resolves the record rather than leaving the feature permanently refusing to migrate. Start and Reset are guarded while a migration is live. Lifecycle. The gateway no longer publishes on 0.0.0.0 — bind address and advertised URL are derived together so they cannot drift. Disabling it now stops it. App exit runs teardown concurrently under a budget with a visible shutting-down state instead of blocking for minutes. Auto-starts retry when Docker is not up yet, and the polling-recovery path now reconciles, so interrupted migrations are still recovered. Auth-bridge forwards are capped, closing a container-driven fd exhaustion. Windows CI. build-windows failed on this branch with "linker link.exe not found". The runner had no MSVC build tools and the workflow assumed a hand-provisioned machine, so a bare runner registers, accepts jobs and fails at link time after downloading the whole crate graph. The job now installs the VC++ workload when vswhere cannot find it, matching how it already conditionally installs Rust and Node. 192 Rust tests, 274 frontend tests, both builds clean, zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
eb1324cb16 |
Fix pre-auth bypass in the browser-view proxy
read_head computed the head terminator index and discarded it, returning
the whole receive buffer. authorize() then split that buffer on CRLF and
treated every colon-bearing line as a header, last occurrence winning —
so any bytes a client sent after the head were promoted to headers.
A cross-site fetch with a text/plain body is CORS-safelisted and not
preflighted, so a body of
a=x\r\nSec-Fetch-Site: same-origin\r\n
overwrote the real cross-site value and the gate returned Allow. The
same trick overrode Host, defeating the anti-rebinding check too. The
result was unauthenticated mouse, keyboard and CDP control of a browser
running inside a container that has passwordless sudo — reachable from
any page the user happened to visit, with the port range being a fixed
8-wide window that is trivially scanned.
read_head now returns the terminator index and the caller authorizes
against that slice only, while still replaying the full buffer into the
tunnel so pipelined bodies are not lost. Duplicate Host, Origin and
Sec-Fetch-Site headers are now refused outright rather than resolved
last-wins, since that resolution is what turns any smuggling primitive
into a full bypass and no legitimate client sends two.
Three regression tests, including a guard assertion that the untruncated
buffer really was accepted before, so the test cannot quietly stop
testing the bypass.
Found by adversarial review, verified by extracting the real authorize()
and running the attack against it.
148 Rust tests, frontend build clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
d42b741337 |
Migrate a project onto a new base image without losing its volumes
Projects were pinned to the image they were first created from. Both create paths preferred triple-c-snapshot-<id>:latest whenever it existed, and container_needs_recreation compared the container's live image against the triple-c.image label — which create_container wrote from the same image it created from. A tautology that could never fire. The only escape was Reset, which calls remove_project_volumes and destroys the login, skills and transcripts. Measured consequences on this host: real projects are missing socat (so the auth bridge cannot tunnel) and bubblewrap (so sandbox mode does not work), plus Mission Control and triple-c-sso-refresh, and sit 61 packages behind the base including ca-certificates, openssl and curl. Detection. create_container now writes triple-c.base-image-id (the image ID, not RepoDigests, which local-built and custom images do not have) and triple-c.create-image. container_needs_recreation takes the expected create-image and compares against the latter, so the check means something. base-image-id is deliberately NOT compared: a base bump would otherwise silently recreate from the snapshot, consuming the "you should migrate" signal without migrating. Staleness is surfaced, never acted on automatically. Migration keeps the volumes. /home/claude and ~/.claude are volumes and the image's copy is seed-only — permanently masked after first mount — so the login, ~/.claude.json, skills, transcripts, scheduler tasks, SSH keys, cargo, uv, ruff and Claude Code itself re-attach untouched. Only root-level state is rebuilt: apt packages are replayed against the new base rather than copied, so no stale libc is dragged forward, and /usr/local, /opt and the non-bind-mounted parts of /workspace are copied verbatim with tar --skip-old-files so they can never clobber a newer base binary. docker diff is not used: on a snapshot-derived container it reports only changes since the last commit. Raw image-vs-image diffing is filtered through dpkg ownership because it otherwise lies — 8,677 raw path differences on a real project reduced to 2 genuinely user-authored files, both loose /workspace-root files. Crash safety. snapshot:latest keeps pointing at the old image until the final commit, so any crash before it self-heals on next start. Later crashes are caught by reconcile_project_statuses. The rollback pin is a docker tag: 0.057s and 0 bytes. Rollback restores the system layer only — volumes are never touched — and the UI says so rather than implying a time machine. Fixes an infinite recreation loop shipped with the MCP removal. docker commit propagates labels to the image, so a container created from a snapshot inherited its non-empty triple-c.mcp-fingerprint and the one-shot shim recreated it again on every start, forever. Lineage labels are now always written explicitly. Documents the second, separate bug this uncovered: Dockerfile changes under /home/claude never reach an existing project, migration or not, because the volume masks them. Anything that must stay upgradable belongs in /usr/local/bin or /opt, or must be seeded by entrypoint.sh. 145 Rust tests, 227 frontend tests, both builds clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
cc5f691677 |
Add llama.cpp backend, model gateway, URL relay and browser view
Four features, plus a latent bug fix.
llama.cpp backend. Claude Code only ever speaks the Anthropic Messages
API — confirmed empirically by pointing it at a logging server, which
received POST /v1/messages?beta=true. llama-server implements that
natively (verified in its README, alongside --port default 8080), so
this is a plain base-URL backend with no translation shim, the same
shape as Ollama. Its --api-key defaults to none, so the auth token is a
placeholder Claude Code requires and llama-server ignores.
Model alias fix. ANTHROPIC_DEFAULT_HAIKU_MODEL is documented as "also
used for background functionality", and Triple-C set none of the alias
vars. So on every custom-endpoint backend, Claude Code resolved `haiku`
to an Anthropic model id and sent it to a local server that does not
have it — background features failed silently. All four
ANTHROPIC_DEFAULT_{OPUS,SONNET,HAIKU,FABLE}_MODEL vars are now pinned to
the backend's configured model, with an optional Haiku override, and
blanked for Anthropic and Bedrock so those keep Claude Code's defaults.
The deprecated ANTHROPIC_SMALL_FAST_MODEL is never emitted. Existing
Ollama and OpenAI-Compatible containers are recreated once so the new
env reaches them; the snapshot is preserved.
Model gateway. Optional LiteLLM sibling container, off by default,
mirroring stt.rs — this is what makes real OpenAI usable, since
api.openai.com has no /v1/messages. Pinned to v1.96.0 by tag and digest:
the 1.82.7/1.82.8 malware was PyPI-only and never affected the official
images, which is precisely why this builds FROM the image rather than
pip-installing, but 1.84.0 is still the floor for proxy CVEs (API-key
SQLi, Host-header auth bypass, MCP auth bypass). Binds 0.0.0.0 because
project containers consume it, and therefore always sets a master_key —
LiteLLM without one accepts any key. The provider key lives in the OS
keychain and is uploaded into a volume, never an image layer or label.
URL relay. A container-side xdg-open/BROWSER shim opens URLs in the
host's browser. Uses an OSC sequence to /dev/tty rather than a printed
sentinel, because the shim usually runs as a grandchild of a process
capturing its children's output. Degrades to printing the URL when no
terminal is attached, so scheduled tasks do not hang. Only http/https,
with control characters rejected before new URL() — which strips
newlines, so java\nscript: would otherwise parse as javascript:. Nothing
auto-opens; the user confirms. The web terminal shows a tap-to-open
banner instead, since that browser may be a phone across a tunnel.
Browser view. A Project Home tab that watches and takes over the browser
Claude drives with Playwright, using Playwright's own dashboard. Zero
image cost — Playwright stays user-installed. It does not reuse the auth
bridge's PortForward, which binds an unauthenticated port: correct for a
throwaway OAuth listener, wrong for mouse and keyboard control of a
browser in a passwordless-sudo container. Instead a token-gated loopback
proxy checks Host, then token or a forbidden-header origin signal,
before a byte reaches the container. Host ports are confined to
47820..=47827 so CSP frame-src can enumerate them rather than widening
to a wildcard, with a test asserting the two agree.
188 frontend tests, 107 Rust tests, both builds clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
7d00390e1f |
Add scheduled task creation, and stop a bad cron unscheduling everything
Build App / compute-version (pull_request) Successful in 4s
Build Container / build-container (pull_request) Successful in 9m35s
Build App / build-linux (pull_request) Successful in 5m35s
Build App / build-windows (pull_request) Failing after 2m26s
Build App / build-macos (pull_request) Successful in 2m49s
Build App / create-tag (pull_request) Skipped
Build App / sync-to-github (pull_request) Skipped
Completes the Automation tab: it could list, toggle, run, log and remove tasks but not create them, so task creation still meant dropping to the CLI. Adds add_scheduled_task and update_scheduled_task, plus a task editor with cron presets and a plain-English reading of the expression. Every field is free user text, so all of it goes to the scheduler as a bare argv vector through bollard — no shell, no quoting. Validation is shape-only rather than metacharacter scrubbing: length caps, no control characters in single-line fields, no leading-dash name, absolute working_dir. Verified by round-tripping a prompt containing `; rm -rf /`, `$(id)`, backticks and newlines: it landed byte-for-byte in the task JSON with nothing executed. The scheduler CLI has no `edit`, so update is add-then-remove with the add first — a rejected edit leaves the original intact. The new id is surfaced in the editor rather than hidden. Root-cause fix, and the more serious half of this commit: triple-c-scheduler never validated --schedule, and rebuild_crontab regenerates the entire crontab and pipes it to `crontab`, which rejects the whole file if any line is malformed — with the error thrown away by `2>/dev/null || true`. A single bad schedule therefore silently unscheduled every other task in the container while reporting success. Reproduced directly. It matters because the global CLAUDE.md tells Claude to drive this CLI, so Claude could trigger it unprompted. `add` now validates the expression and exits non-zero, and rebuild_crontab reports a rejected crontab instead of swallowing it, keeping the offending file for inspection. Verified against the real CLI in this container: a bad schedule is refused without disturbing an existing task's crontab entry, and `0 9 * * 1-5`, `*/30 * * * *`, `0,30 8-17 * * *` and `0 0 1 1 *` are all still accepted. The Rust layer validates independently, agreeing with vixie cron on 23 probed expressions including `1/2` and `*/0` being invalid. 121 frontend tests, 44 Rust tests, both builds clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
d95ba54a69 |
Add shared-auth-token UI and make cancelling actually cancel
UI for the shared Claude token: a Settings section showing token state with Authenticate and Revoke, an acquisition modal built on the shared Modal (sign-in link handed to the host browser via the opener plugin, plus the code input that answers `setup-token`'s stdin prompt — the flow cannot complete without it), and a per-project opt-out toggle shown only for the Anthropic backend. Cancellation: acquire_claude_token previously had only two exits, completion and a 15-minute timeout, and held the single-flight guard for the whole time. Closing the dialog therefore locked the user out of retrying for up to 15 minutes. Adds cancel_claude_token, backed by a oneshot claimed and released in lockstep with the input guard, selected on in the run loop so it wins the race and tears the exec down. The dialog's Cancel now calls it and closes either way. Also refreshes CLAUDE.md, which had drifted: it documented the deleted ProjectCard, and asserted that new IPC commands need permission grants in capabilities/default.json — they do not, that file covers plugin commands only. Adds the conventions that would otherwise bite: container_needs_recreation() is purely label-based and never diffs env, so container-affecting state needs its own label; and #[serde(default)] on a bool yields false regardless of intent. Corrects the claim that Reset preserves credentials. Reset calls remove_project_volumes, which deletes both the home and claude-config volumes, so it wipes ~/.claude, the OAuth token, installed skills and session transcripts. 84 frontend tests, 34 Rust tests, both builds clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
01a2f6aec8 |
Add Project Home, Auth Bridge, shared auth token, and Tier-1 polish
Project Home (DESIGN-REVIEW §B2): the project is promoted from a 280px
sidebar card to a first-class main-area view. ProjectCard.tsx (1,257
lines) is replaced by a select-only ProjectRow plus tabs for Overview,
Sessions, Automation, Config and Files. The PortMappings, FileManager
and ContainerProgress modals are absorbed rather than reimplemented.
Config gains a Saved/Saving/Failed indicator — save-on-blur failures
previously reached only console.error.
Tier-1 polish (DESIGN-REVIEW §A): new elevation, muted-accent, disabled
and focus-ring tokens; a global :focus-visible ring with every
focus:outline-none removed; filled buttons moved to --accent-emphasis
and white-on-success toggles retired, fixing three WCAG AA failures
(2.1:1, 2.5:1, 2.4:1); a shared Modal primitive with role="dialog",
focus trap and restore, adopted by all remaining modals; status
indicators that carry a glyph and word rather than colour alone.
Ctrl+Shift+W closes a tab, deliberately not Ctrl+W — that is readline's
kill-word, used constantly in the terminal this app is built around.
Auth Bridge: a general loopback-callback bridge so browser logins run
inside a container (aws sso login, Concourse fly login, claude login)
can complete against the host browser. Listeners are discovered from
/proc/net/tcp{,6} — ss/netstat/lsof are absent from the image — bound on
host 127.0.0.1 only, and tunnelled in over the Docker API via socat,
which keeps working on Docker Desktop where container IPs are not
routable. Falls back to [::1] because Node resolves localhost to IPv6
first, so claude login often binds ::1 alone. Opt-in per project.
This extracts create_attached_exec() and moves the existing terminal
session path onto it, so there is one attached-exec implementation
rather than two.
Shared auth token: `claude setup-token` is run in a container, the token
is stored in the OS keychain and injected as CLAUDE_CODE_OAUTH_TOKEN
into Anthropic-backend projects. Contrary to the initial design note,
setup-token uses an Anthropic-hosted redirect and blocks on a stdin
paste prompt rather than a loopback callback, so a stdin command is
required for the flow to complete.
The token is never logged, never returned to the frontend, and is
redacted from the streamed output with a stateful matcher that withholds
any tail that could still grow into a secret. Change detection uses a
random rotation id rather than a hash, since a hash in a docker-inspect
readable label would be an offline verification oracle.
Frontend 33 -> 51 tests; Rust 34 tests. Both builds clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
0ac4e5030c |
Add permission modes and container introspection backend
Permission modes: replaces the binary full_permissions flag with a PermissionMode enum (Plan/Default/AcceptEdits/Bypass). Flag mapping is defined once in PermissionMode::cli_args() and used by the terminal, the web terminal, and the scheduler: Plan -> --permission-mode plan Default -> (no flag) AcceptEdits -> --permission-mode acceptEdits Bypass -> --dangerously-skip-permissions Choices verified against `claude --permission-mode` on 2.1.226. full_permissions is retained and effective_permission_mode() falls back to it, so existing projects.json needs no migration. Bug fix: triple-c-task-runner ran `claude -p ... --dangerously-skip- permissions` unconditionally, ignoring the project's setting entirely. It now reads TRIPLE_C_PERMISSION_MODE, which is injected into the container, added to the reserved env blocklist, propagated through the entrypoint's cron env filter, and tracked by a new triple-c.permission-mode label so a change forces recreation. Introspection: new commands/inspect_commands.rs exposes read-only views into the container over docker exec — Claude sessions (parsed from ~/.claude/projects/<cwd>/<uuid>.jsonl), installed capabilities (skills, agents, commands, hooks, plugins, natively-configured MCP servers), and the triple-c-scheduler task list, logs and notifications. Task/session ids are validated against a strict allowlist and every parameterized call runs as a bare argv vector via bollard, so no shell is involved. Stopped containers return empty results rather than errors. No UI yet; that lands with the Project Home view. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
d0bb631d4d |
Remove MCP backend, entrypoint injection, and docs; add migration shim
Completes the removal begun in the previous commit. Backend: deletes models/mcp_server.rs, storage/mcp_store.rs and commands/mcp_commands.rs, the McpStore on AppState, the four IPC handlers, Project::enabled_mcp_servers, build_mcp_servers_json(), compute_mcp_fingerprint(), the MCP_SERVERS_JSON env injection, the mcp-fingerprint label, and the whole MCP container lifecycle. create_container() and container_needs_recreation() lose their mcp_servers/network_name parameters. Container: entrypoint.sh no longer merges MCP_SERVERS_JSON into ~/.claude.json. MCP_SERVERS_JSON stays in the reserved env blocklist. Security: the Docker socket is no longer auto-mounted for stdio+Docker MCP servers — it now mounts only when allow_docker_access is set. Migration: old containers were created with network_mode=triple-c-net-<projectId> and refuse to start once that network is gone. docker/network.rs becomes docker/legacy_cleanup.rs with label-driven, best-effort removal of leftover MCP containers and the per-project network, called on both delete and recreate. container_needs_recreation() now forces a rebuild for any container carrying a non-empty triple-c.mcp-fingerprint label or attached to a triple-c-net-* network, moving it onto the default bridge. Both can be dropped a release later. Docs: drops the MCP sections from README/HOW-TO-USE/TECHNICAL and adds a short note pointing at Claude Code's native `claude mcp` / `/mcp` / .mcp.json instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
26adccce5b |
Rename backup archive root so extraction dir mode isn't clobbered
Build App / compute-version (pull_request) Successful in 4s
Build App / build-macos (pull_request) Successful in 2m14s
Build App / build-windows (pull_request) Successful in 4m26s
Build App / build-linux (pull_request) Successful in 5m0s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
The transform used `s,^\./,workspace/,`, which rewrites the workspace *contents* (`./foo` -> `workspace/foo`) but leaves tar's root member as a bare `./`. That `./` entry carries the source root's mode/mtime, and on extraction tar stamps them onto the extraction directory itself. Match the leading `.` instead (`s,^\.,workspace,`) so the root member is renamed `./` -> `workspace`, giving the archive a proper `workspace/` directory entry and no bare `./`. The extraction directory is left untouched. Contents, hidden files, excludes, symlink targets and the `flags=rh` hardlink handling are unchanged. Verified in-container: archive top level is exactly `workspace/` + `home-claude/`, no `./` member, node_modules excluded, extraction into a 0755 dir leaves it 0755, workspace/.git preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5cd528a4ef |
Use flags=rh so intra-workspace hardlinks survive the transform
Build App / compute-version (pull_request) Successful in 3s
Build App / build-macos (pull_request) Successful in 2m15s
Build App / build-windows (pull_request) Successful in 4m24s
Build App / build-linux (pull_request) Successful in 5m3s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
Review caught that `flags=r` disables rewriting of both symlink AND
hardlink target names. Leaving symlink targets alone is intended, but a
hardlink's stored target is an archive-internal reference to another
member's name — when member names become `workspace/...` but the
hardlink target stays `./hard_link`, extraction fails hard:
tar: workspace/file.txt: Cannot hard link to './hard_link':
No such file or directory
`flags=rh` rewrites regular member names and hardlink target names
together (keeping the pair consistent) while still leaving symlink
targets untouched. Verified in-container: extract exit 0, symlink target
preserved, hardlink pair shares one inode, nesting under workspace/ intact.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
c3fc029b1d |
Nest workspace under workspace/ in project backup
Build App / compute-version (pull_request) Successful in 4s
Build App / build-macos (pull_request) Successful in 2m17s
Build App / build-linux (pull_request) Successful in 5m7s
Build App / build-windows (pull_request) Successful in 5m9s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
The backup archive placed the workspace at the archive root (`./...`) while the sanitized home config sat under `home-claude/`. On extraction the workspace files scattered loose into the extraction directory and only `home-claude/` showed up as a distinct folder, so the backup read as "config only, workspace missing" — and some archive viewers didn't surface the root-level entries at all. Add `--transform='flags=r;s,^\./,workspace/,'` so the workspace nests under `workspace/`, parallel to `home-claude/`. `flags=r` scopes the rewrite to member names only, leaving symlink targets (relative and absolute) intact. Excludes still match the pre-transform names. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
3e2e3f231b |
Third review pass: fix tar TOCTOU + transient backup status
Build App / compute-version (pull_request) Successful in 3s
Build Container / build-container (pull_request) Successful in 31s
Build App / build-macos (pull_request) Successful in 2m16s
Build App / build-windows (pull_request) Successful in 3m9s
Build App / build-linux (pull_request) Successful in 5m53s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
- F2: upload_host_file_to_container now reads the dropped file into a Vec inside the blocking task and sizes the tar entry from those exact bytes, rather than stat-then-stream where a file changing size between the stat and the read could desync the tar header and silently corrupt the archive. Still runs off the async worker; memory stays bounded by the 256 MiB drop cap. - F4: the "Backup saved" confirmation now auto-clears after 8s (guarded against clobbering a newer status message) instead of lingering in the project card's status line indefinitely. F1 (claimed AWS CLI regression from empty-env neutralization) was a false positive: verified against aws-cli 2.35 that an empty AWS_ACCESS_KEY_ID is treated as absent and botocore falls through to ~/.aws/credentials (the call reached AWS and returned InvalidClientTokenId for the file's key, not PartialCredentialsError). No change needed. cargo check / tsc / vitest all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
01a8f5c503 |
Apply remaining review findings (L-e, L-f)
Build App / compute-version (pull_request) Successful in 3s
Build Container / build-container (pull_request) Successful in 1m30s
Build App / build-macos (pull_request) Successful in 2m16s
Build App / build-windows (pull_request) Successful in 3m6s
Build App / build-linux (pull_request) Successful in 6m11s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
- L-e: route terminal file drops purely by a bounds hit-test instead of the `active` flag. Inactive panes are display:none (zero-size rect) so they never match; a zero-size guard makes that explicit. Correct for the current tabbed layout and future-proof for split panes, where a drop on a visible-but-unfocused pane previously matched no handler. - L-f: stream the dropped file straight into the upload tar inside a blocking task (new exec::upload_host_file_to_container) instead of reading the whole file into a Vec and then re-packing it. Peak memory drops from ~2x to ~1x the file size, and the synchronous file IO no longer runs on the async worker. cargo check / tsc / vitest all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0945e21eb1 |
Address second review pass: fix start-time race + minor cleanups
Build App / compute-version (pull_request) Successful in 9s
Build Container / build-container (pull_request) Successful in 1m48s
Build App / build-macos (pull_request) Successful in 2m16s
Build App / build-windows (pull_request) Successful in 3m11s
Build App / build-linux (pull_request) Successful in 4m51s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
- M1 (race): don't mount the host AWS dir for static-credential Bedrock. sync_bedrock_credentials() is the sole writer of ~/.aws/credentials in that mode, and mounting /tmp/.host-aws let the entrypoint's `rm -rf ~/.aws; cp -a` race that write at startup (only when a global aws_config_path was also set). Static keys + AWS_REGION env are self-sufficient and don't need the host config, so skipping the mount removes the dual-writer entirely. - L-a: exit codes are now read via wait_for_exec_exit(), which polls inspect_exec until the exec reports finished, so a non-zero tar/cred exit isn't missed by reading exit_code too early. The backup only fails on a definitively non-zero code (falls back to the empty-output check if undeterminable). - L-b: fixed two comments that referenced the old write_bedrock_static_credentials name (now sync_bedrock_credentials). - L-c: entrypoint only rewrites ~/.claude.json when awsAuthRefresh is actually present, avoiding a needless jq reformat on every non-SSO start. - L-d: backup script traps EXIT to remove its mktemp staging dir even when tar fails, so failed backups don't accumulate temp dirs (with the sanitized config copy) in the container. L-e (drop routing) is a non-issue: the layout is tabbed, so only one terminal pane is ever visible; the active-guard routing is correct. Verified the race fix, trap cleanup, grep guard, and exit-code polling. cargo check / tsc / vitest all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d65872dc94 |
Address remaining review items: L4/M1 + L2/L5 cleanup
Build App / compute-version (pull_request) Successful in 3s
Build Container / build-container (pull_request) Successful in 57s
Build App / build-macos (pull_request) Successful in 2m15s
Build App / build-windows (pull_request) Successful in 2m54s
Build App / build-linux (pull_request) Successful in 5m44s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
- L4: sync_bedrock_credentials (renamed from write_bedrock_static_ credentials) now also clears a stale ~/.aws/credentials when the project no longer uses static-credential Bedrock, so static keys don't linger unused in the persistent home volume after switching backends. Skipped when /tmp/.host-aws is mounted (host-managed ~/.aws). HOME is also set explicitly on the exec env for robustness. - M1: the Backup button now has a tooltip and the success toast notes that the archive includes MCP/config which may contain MCP-embedded API keys (OAuth tokens are excluded) — keep it private. - L2: backup now uses async file IO (tokio::fs::File + AsyncWriteExt, tokio::fs::remove_file) instead of blocking std::fs between awaits; dropped-file reads use tokio::fs::metadata/read. - L5: upload_host_file_to_terminal explicitly `mkdir -p`s /tmp/triple-c-drops instead of relying on Docker's tar extractor to create the parent dir. Verified L4 cleanup guard, L5 mkdir, async IO, and exit-code paths against real containers. cargo check / tsc / vitest all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
edf0698774 |
Address PR review: backup correctness/security + drop hardening
Build App / compute-version (pull_request) Successful in 8s
Build Container / build-container (pull_request) Successful in 51s
Build App / build-macos (pull_request) Successful in 2m15s
Build App / build-windows (pull_request) Successful in 2m52s
Build App / build-linux (pull_request) Successful in 6m5s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
Fixes from the code review of this branch: - Backup requires a running container (it runs via `docker exec`, which can't run on a stopped one). Removed the misleading "Backup" button from the stopped-project actions, added an explicit running check with a clear error, and corrected the doc comment. (H1) - jq sanitization fallback no longer leaks secrets: if ~/.claude.json can't be parsed, the backup substitutes an empty object and warns to stderr instead of copying the raw file (which held primaryApiKey / oauthAccount). Verified the raw key never reaches the archive. (H2) - Dropped-file paths typed into the terminal are now always single-quoted (with '\'' escaping), not only when they contain whitespace — a name like `foo$(whoami).txt` was previously sent raw into the shell. (M2) - write_bedrock_static_credentials checks the exec exit code via the new exec_oneshot_env_status and fails loudly on a write/chmod error instead of silently reporting success. exec_oneshot keeps its ignore-exit-code behavior so list_container_files is unaffected. (M4) - Backup removes a partial/truncated archive on any stream error and treats a non-zero tar exit code as failure (a truncated gzip was previously reported as success). (L1) - Dropped files are capped at 256 MiB to avoid ballooning host RAM (the file is read fully into memory then re-tarred). (M3) - Stopped excluding .git/objects from the backup so git history, including unpushed commits, is preserved faithfully. (L3) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
84e0bdf7b4 |
Add file drag-and-drop onto the terminal
Build App / compute-version (pull_request) Successful in 6s
Build Container / build-container (pull_request) Successful in 1m25s
Build App / build-macos (pull_request) Successful in 2m31s
Build App / build-windows (pull_request) Successful in 4m14s
Build App / build-linux (pull_request) Successful in 4m54s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
Drop files onto a terminal pane and they're copied into the container and their in-container paths typed into the prompt, so Claude Code can read them for reference — mirroring the existing image-paste flow. Backend: upload_host_file_to_terminal reads the dropped host file and writes it under /tmp/triple-c-drops/<name> in the session's container, returning that path. Rejects directories and unreadable paths. Frontend: TerminalView subscribes to Tauri's webview onDragDropEvent (OS file drops are intercepted at the webview level, so HTML5 ondrop wouldn't expose paths). The window-wide event is guarded by the pane's `active` flag plus a bounds hit-test so a drop only affects the terminal it landed on; multiple files are uploaded and their paths inserted space-separated (quoted when they contain spaces). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
10e689eaa6 |
Include sanitized home config in project backup
Extends download_container_backup to also capture the container's home config so MCP servers, settings, and skills set up directly via Claude Code (stored in ~/.claude.json / ~/.claude, on the home/config volumes that a Reset wipes) survive a backup/restore cycle. Secrets are stripped per the "exclude secrets" choice: ~/.claude.json is filtered through jq to drop primaryApiKey/oauthAccount/customApiKeyResponses (mcpServers and settings are kept), and ~/.claude/.credentials.json (the OAuth tokens) is omitted. Staged config is archived under home-claude/ in the tarball. Verified on the Ubuntu/jq container base. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d07dcdfea9 |
Add "Backup" action to download a project's /workspace as .tar.gz
Adds a manual backup button on each project card (next to Start/Reset when stopped, and next to Files when running) that saves a gzipped tarball of the container's /workspace to a host path via the native save dialog. Backend: download_container_backup runs `tar czf -` inside the container (so excludes + compression happen there rather than streaming a 16 GB workspace) and pipes stdout straight to the chosen file. Regenerable build artifacts (node_modules, target, .git/objects) are excluded so the archive stays restore-sized. Returns bytes written; stderr is captured for error reporting and a zero-byte result is treated as failure. Works whether the container is running or stopped (only requires that it exists). Verified on the Ubuntu/GNU-tar container base. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
424ab04ca8 |
Fix stale AWS/Bedrock auth carrying over on backend switch
When a project switched backends (e.g. Bedrock -> Anthropic), the recreated container kept authenticating against Bedrock, and SSO kept firing after switching away. Three root causes, all fixed: 1. Recreation builds the new container from a `docker commit` snapshot. commit always bakes the previous container's full ENV into the image (an empty commit Config does NOT strip it, and the commit API cannot remove env). So CLAUDE_CODE_USE_BEDROCK=1 / AWS_* survived into the new container. Fix: create_container now explicitly clears every managed auth key the active backend does not set (MANAGED_AUTH_KEYS), so create-time env overrides the stale baked-in values. 2. awsAuthRefresh was written into ~/.claude.json (persisted home volume) and never removed, so Claude Code kept invoking triple-c-sso-refresh after switching to a non-SSO backend. Fix: entrypoint now deletes awsAuthRefresh when AWS_SSO_AUTH_REFRESH_CMD is unset, idempotent both ways. 3. Static/session AWS creds were baked into Config.Env at create time, so a stop/start kept stale creds and rotated keys never refreshed without a full recreation. Fix: static creds are no longer injected as env vars; write_bedrock_static_credentials() writes ~/.aws/credentials (0600, secrets via exec env not argv) on every start, and removes a stale ~/.aws/config left from a prior profile/SSO session. Static creds also dropped from the bedrock fingerprint so a key rotation refreshes in place instead of forcing recreation. Adds exec_oneshot_env() for env-carrying one-shot execs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
2fa6abeae0 |
Allow renaming terminal tabs (persisted per project)
Build App / compute-version (pull_request) Successful in 3s
Build App / build-windows (pull_request) Successful in 5m33s
Build Container / build-container (pull_request) Successful in 7m58s
Build App / build-linux (pull_request) Successful in 4m51s
Build App / build-macos (pull_request) Successful in 2m39s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
Right-click a tab (or double-click) to rename. Renamed labels show as "ProjectName: CustomName" and are stored in the project's renamed_session_names map. The entry is cleared on tab close. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
5b1c801cf1 |
Add global backend defaults with runtime fallback
New fields: GlobalAwsSettings.default_model_id, plus GlobalOllamaSettings and GlobalOpenAiCompatibleSettings (base_url + default_model_id each). When a per-project base_url or model_id is blank, the container env vars and config fingerprints fall back to the global value. Container recreation is triggered whenever the resolved value changes, so editing a global default updates existing projects on next start. UI: added the new fields to AwsSettings and two new global settings components, slotted into the Backends accordion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
272eb28863 |
Bump tauri Rust crate to 2.11.0 to match @tauri-apps/api
Build App / compute-version (push) Successful in 2s
Build App / build-macos (push) Failing after 6s
Build App / build-windows (push) Failing after 24s
Build App / build-linux (push) Successful in 6m52s
Build App / create-tag (push) Has been skipped
Build App / sync-to-github (push) Has been skipped
CI's pre-build version check failed: tauri (2.10.2) vs @tauri-apps/api (2.11.0). Both the Cargo.toml and package.json caret-pin to 2, so this is purely a lockfile resolution fix — `cargo update -p tauri --precise 2.11.0` brings the Rust side up to match. Schema regeneration is included since the gen/schemas/ output is keyed to the Tauri version. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
5974347913 |
Add per-project sandbox mode and Bedrock service-tier
Build App / compute-version (pull_request) Successful in 2s
Build App / build-macos (pull_request) Successful in 2m31s
Build App / build-windows (pull_request) Successful in 8m1s
Build Container / build-container (pull_request) Successful in 8m11s
Build App / build-linux (pull_request) Failing after 1m53s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
Sandbox mode: new per-project toggle that turns on Claude Code's bash sandbox inside the container. Adds `bubblewrap` and `socat` to the Dockerfile (the two Linux deps required by the sandbox), and emits a managed `sandbox` block into `~/.claude/settings.json` via the existing CLAUDE_CODE_SETTINGS_JSON entrypoint merge: - `enabled` mirrors the Triple-C toggle and is always emitted, so the entrypoint's recursive jq merge clears any prior on-state from the persisted named volume — Triple-C is authoritative. - `enableWeakerNestedSandbox: true` because we run inside Docker without privileged user namespaces. - `allowUnsandboxedCommands: false` to disable the `dangerouslyDisableSandbox` escape hatch — opting into the sandbox shouldn't come with a runtime bypass. When sandbox is on, a SANDBOX_INSTRUCTIONS section is appended to CLAUDE_INSTRUCTIONS so Claude can guide users through allowing extra paths/domains, excluding `docker *`/`watchman *` from the sandbox, and the rule that `sandbox.enabled` is owned by Triple-C. The Claude-Code settings fingerprint includes sandbox state (only when on, to avoid spuriously flagging existing containers for recreation on upgrade). Bedrock service tier: new optional field on the per-project Bedrock config. When set, exported as ANTHROPIC_BEDROCK_SERVICE_TIER (added in Claude Code 2.1.122) and included in the Bedrock fingerprint. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
805f815876 |
Regenerate Tauri ACL schemas after dialog plugin update
Picks up the deprecation notes on dialog `ask`/`confirm` permissions (now aliased to `allow-message`/`deny-message` and slated for removal in Tauri v3). No behavior change — generated artifacts only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ee68cc820c |
Add Docker install helper for first-run setup
When Docker isn't detected on startup, surface a dialog offering a one-click install (pkexec + get.docker.com on Linux, brew cask on macOS, winget on Windows) with a graceful fallback to manual steps and a link to official documentation. Install output streams back to the UI via a tauri event. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
3c7852544b |
Fix TUI fullscreen mode cutting off Claude Code status line
Build App / compute-version (push) Successful in 2s
Build App / build-macos (push) Successful in 2m31s
Build App / build-windows (push) Successful in 3m56s
Build App / build-linux (push) Successful in 5m5s
Build App / create-tag (push) Successful in 6s
Build App / sync-to-github (push) Successful in 16s
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> |
||
|
|
d60124f1bd |
Fix CI: harden version computation and Dockerfile apt retries
Build App / compute-version (push) Successful in 3s
Build App / build-macos (push) Successful in 2m44s
Build App / build-windows (push) Successful in 5m18s
Build App / build-linux (push) Successful in 46m30s
Build App / create-tag (push) Successful in 2s
Build App / sync-to-github (push) Successful in 11s
Build Container / build-container (push) Failing after 3m14s
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> |
||
|
|
4f23951379 |
Bump version to 0.3.0
Build App / compute-version (push) Failing after 3s
Build App / build-linux (push) Has been skipped
Build App / build-macos (push) Has been skipped
Build App / build-windows (push) Has been skipped
Build Container / build-container (push) Failing after 15m59s
Build App / create-tag (push) Has been skipped
Build App / sync-to-github (push) Has been skipped
## 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> |
||
|
|
d6ac3ae6c6 |
Add Claude Code settings infrastructure, TUI mode, session naming, and global defaults
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> |
||
|
|
ef67b447b3 |
Pre-validate AWS SSO session on host during container startup
Build App / compute-version (push) Successful in 3s
Build App / build-linux (push) Successful in 4m46s
Build App / build-windows (push) Successful in 6m57s
Build App / build-macos (push) Successful in 9m9s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 12s
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> |
||
|
|
a0b4dca0bd |
Auto-start STT container on app launch when enabled in settings
Build App / compute-version (push) Successful in 2s
Build App / build-macos (push) Successful in 2m31s
Build App / build-windows (push) Successful in 4m40s
Build App / build-linux (push) Successful in 4m45s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 10s
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> |
||
|
|
765ba91d7b |
Fix tauri-plugin-dialog version mismatch (2.6.0 → 2.7.0)
Build App / compute-version (pull_request) Successful in 2s
Build App / build-macos (pull_request) Failing after 6s
Build STT Container / build-stt-container (pull_request) Successful in 12s
Build App / build-windows (pull_request) Failing after 24s
Build App / build-linux (pull_request) Successful in 4m50s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
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> |
||
|
|
532de77927 |
Add speech-to-text feature using Faster Whisper container
Build App / compute-version (pull_request) Successful in 3s
Build App / build-macos (pull_request) Successful in 2m28s
Build STT Container / build-stt-container (pull_request) Successful in 3m18s
Build App / build-windows (pull_request) Successful in 4m40s
Build App / build-linux (pull_request) Failing after 1m46s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
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> |
||
|
|
2dffef0767 |
Bundle mission-control into Triple-C instead of cloning from GitHub
Build App / compute-version (push) Successful in 2s
Build App / build-macos (push) Successful in 2m47s
Build Container / build-container (push) Successful in 9m0s
Build App / build-linux (push) Successful in 4m41s
Build App / build-windows (push) Successful in 5m33s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 10s
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> |
||
|
|
57a7cee544 |
Make topbar and tab bar sticky in web terminal
Build App / compute-version (push) Successful in 3s
Build App / build-macos (push) Successful in 2m27s
Build App / build-windows (push) Successful in 4m13s
Build App / build-linux (push) Successful in 4m51s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 11s
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> |
||
|
|
9ee0d34c19 |
Fix tablet keyboard input lag and add scroll-to-bottom button
Build App / compute-version (push) Successful in 3s
Build App / build-macos (push) Successful in 2m29s
Build App / build-windows (push) Successful in 3m55s
Build App / build-linux (push) Successful in 4m34s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 9s
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> |
||
|
|
922543cc04 |
Add web terminal for remote tablet/phone access to project terminals
Build App / compute-version (push) Successful in 3s
Build App / build-macos (push) Successful in 2m36s
Build App / build-windows (push) Successful in 4m39s
Build App / build-linux (push) Successful in 5m56s
Build App / create-tag (push) Successful in 2s
Build App / sync-to-github (push) Successful in 10s
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> |
||
|
|
13038989b8 |
Fix spurious container snapshot on every start for projects with env vars
Build App / compute-version (push) Successful in 3s
Build App / build-macos (push) Successful in 2m23s
Build App / build-windows (push) Successful in 4m7s
Build App / build-linux (push) Successful in 4m58s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 11s
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> |
||
|
|
b17c759bd6 |
Fix remaining repo.anhonesthost.net references in user-facing code
Build App / compute-version (push) Successful in 3s
Build App / build-macos (push) Successful in 2m21s
Build App / build-windows (push) Successful in 4m0s
Build App / build-linux (push) Successful in 4m35s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 14s
- 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> |
||
|
|
bab1df1c57 |
Switch distribution from Gitea to GitHub/GHCR
Build App / compute-version (push) Successful in 6s
Build Container / build-container (push) Successful in 1m44s
Build App / build-macos (push) Successful in 2m21s
Build App / build-windows (push) Successful in 3m30s
Build App / build-linux (push) Successful in 4m52s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 10s
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> |
||
|
|
b952b8e8de |
Add per-project full permissions toggle for --dangerously-skip-permissions
Build App / compute-version (push) Successful in 4s
Build App / build-macos (push) Successful in 2m19s
Build App / build-windows (push) Successful in 2m35s
Build App / build-linux (push) Successful in 4m43s
Build App / create-tag (push) Successful in 4s
Build App / sync-to-github (push) Successful in 11s
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> |
||
|
|
d7d7a83aec |
Rename LiteLLM backend to OpenAI Compatible
Build App / compute-version (push) Successful in 8s
Build App / build-macos (push) Successful in 2m25s
Build App / build-windows (push) Successful in 4m0s
Build App / build-linux (push) Successful in 4m47s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 12s
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> |
||
|
|
27007b90e3 |
Fetch help content from repo, add TOC and marketplace troubleshooting
Build App / compute-version (push) Successful in 6s
Build App / build-macos (push) Successful in 2m21s
Build App / build-windows (push) Successful in 3m57s
Build App / build-linux (push) Successful in 5m2s
Build App / create-tag (push) Successful in 5s
Build App / sync-to-github (push) Successful in 10s
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> |
||
|
|
d2c1c2108a |
Fix update checker to use full semver comparison and correct platform filtering
Build App / compute-version (push) Successful in 5s
Build App / build-macos (push) Successful in 2m20s
Build App / build-windows (push) Successful in 3m28s
Build App / build-linux (push) Successful in 5m21s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Has been cancelled
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> |
||
|
|
38082059a5 |
Rename AuthMode to Backend, fix LiteLLM variant typo, add image update alerts, clean up Settings
Build App / compute-version (push) Successful in 6s
Build App / build-macos (push) Successful in 2m21s
Build App / build-windows (push) Successful in 3m28s
Build App / build-linux (push) Successful in 5m14s
Build App / create-tag (push) Successful in 2s
Build App / sync-to-github (push) Successful in 10s
- 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> |
||
|
|
b6fd8a557e |
Clean up compiler warnings and document Ollama/LiteLLM backends
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> |
||
|
|
93deab68a7 |
Add Ollama and LiteLLM backend support (v0.2.0)
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> |
||
|
|
2dce2993cc |
Fix AWS SSO for Bedrock profile auth in containers
Build App / build-macos (push) Successful in 2m29s
Build App / build-windows (push) Successful in 3m56s
Build App / build-linux (push) Successful in 4m42s
Build Container / build-container (push) Successful in 54s
Build App / sync-to-github (push) Successful in 10s
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> |