Commit graph

25 commits

Author SHA1 Message Date
464c576b79 MCP v2 PR-1: policy engine + audit log + Config/Audit/Policy panel tabs
Foundation for Claude-drives-the-workspace writes. Nothing wired
end-to-end yet (App.tsx dispatcher comes next); this lands the
machinery + UI.

mcp_policy.rs (new) — three-tier allow/ask/deny policy with
deny-first precedence and a compiled-in non-overridable hard-deny
list (10 patterns covering rm -rf /, fork bombs, mkfs on device, dd
to raw disk, /etc/passwd overwrite, curl|sh, chmod -R 777 /, etc.).
Shell-operator-aware glob matcher mirroring Claude Code's Bash(*)
syntax. Restrictive default — empty policy means every non-hard-
denied call falls to Ask. Persisted to mcp-policy.json in
app_config_dir. Includes a PolicyClassifier scaffold (no-op) for a
future v2.1 LLM-classifier hook. 1152 lines incl. ~100 unit + fuzz
tests covering the matchers and lookalike negatives.

mcp.rs — TileService now holds AppHandle + Arc<PendingActions>
(oneshot registry keyed by uuid). New async dispatch_action helper
runs the policy check, emits "mcp://request" for the frontend to
handle, awaits a oneshot reply (30s timeout), then emits "mcp://
audit" with the outcome regardless. set_label tool wired through
this path as the demo for PR-1b's dispatcher.

commands.rs / lib.rs — new Tauri commands mcp_action_reply,
mcp_policy_load, mcp_policy_save; PendingActions registered as
managed state.

McpPanel.tsx — refactored into Config / Audit / Policy tabs.
AuditTab listens on mcp://audit, keeps a 200-entry ring with
ok/denied/failed chips. PolicyTab edits the allow/ask/deny buckets
(stacked vertically — three columns overflowed the panel) and shows
the hard-deny rules read-only at the bottom with "Cannot be
disabled" badges. Themed scrollbar on mcp-body to match xterm panes.

Caveat: set_label calls from Claude will currently time out — the
App.tsx side that listens on mcp://request and replies via
mcp_action_reply lands in PR-1b.

Co-authored by Sonnet (policy engine, backend plumbing, panel UI)
and Haiku (hard-deny fuzz test suite); integration + bug fixes here.
2026-05-26 12:05:31 +01:00
799f507c3c MCP: persistent port/token + mcp-remote shim recipe for Claude Code
Port (default 47821) and bearer token now persist to mcp.json with
OS-picked fallback if the port is taken; new Regenerate button in the
panel rotates the token and restarts the running server. rmcp's
DNS-rebinding host allowlist is disabled so WSL gateway IPs can
connect (bearer-auth handles the gatekeeping); the auth middleware
only enforces on /mcp paths so OAuth-discovery clients don't see a
Bearer challenge on /.well-known/* probes.

Claude Code's HTTP-MCP client currently tries OAuth and ignores
static `headers` auth (anthropics/claude-code#17152, #46879), so the
panel + README config snippet now uses `npx mcp-remote` as a stdio
shim that proxies the HTTP endpoint with the bearer baked in.
2026-05-26 11:05:13 +01:00
112d7dd5b5 Use ReadResourceResult::new — struct is non-exhaustive 2026-05-25 21:34:25 +01:00
83d8932c98 Add MCP server (v1 read-only): toggle, per-pane gate, panel UI 2026-05-25 21:31:49 +01:00
dbd6c163c3 Lock in keyring-core and windows-native-keyring-store from password feature build 2026-05-25 20:24:41 +01:00
b462f9f3bf Acknowledge SpawnSpec::Ssh host_id in build_command pattern 2026-05-25 20:10:31 +01:00
1c243b3f3f Save SSH passwords in Windows Credential Manager and auto-type at prompt 2026-05-25 20:08:31 +01:00
872fb0e80e Add SSH connections: saved hosts manager and hierarchical shell picker 2026-05-25 19:47:37 +01:00
4e5bc7e081 Scope opener plugin to http/https/mailto so clicks open the browser 2026-05-25 19:47:24 +01:00
a24f7de7df Make URLs in terminal output clickable via xterm web-links + tauri-plugin-opener 2026-05-25 19:13:08 +01:00
234a0b74a1 Add PowerShell as a selectable shell in the distro dropdown 2026-05-25 19:13:03 +01:00
29b15f19c1 Route terminal clipboard through tauri-plugin-clipboard-manager; bump to 0.2.3
navigator.clipboard.readText() triggers WebView2's "Allow clipboard access?"
permission prompt on every paste. The plugin goes through IPC + the OS
clipboard directly, so the prompt never fires.

Wired the Rust plugin, granted clipboard-manager:allow-{read,write}-text in
the capabilities manifest, swapped XtermPane's copy/paste handler to use
the plugin's readText/writeText.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 23:27:43 +01:00
e94d2499d1 Add tauri-plugin-clipboard-manager dependency
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 23:12:52 +01:00
661a76951b Pick up Cargo.lock 0.2.2 bump from tauri build 2026-05-22 22:28:18 +01:00
1720b60499 Bump version to 0.2.2
Changes since 0.2.1:
- Keyboard shortcuts: Ctrl+K palette + Ctrl+Shift+E/O/W for
  split-right / split-down / close, Ctrl+Shift+B per-pane and
  Ctrl+Shift+Alt+B global broadcast, Ctrl+Shift+Arrow for spatial
  pane navigation
- New panes default to WSL home (~) instead of inherited Windows cwd
- Resize artifacts: rAF-throttle gutter drag, debounce PTY resize,
  skip resizePane when cols/rows haven't actually changed (kills the
  idle-flap loop that surfaced with many panes)
- Minimum pane size (180px) enforced on both split and gutter drag
- 2px gap around each leaf so per-pane borders read as distinct
  rectangles instead of a continuous grid

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:24:57 +01:00
7d1f1f4b9a Default new panes to WSL home (~) instead of inherited Windows cwd
Previously: spawn_wsl(cwd=None) passed no --cd to wsl.exe, so each
pane inherited the launcher's cwd — which is typically
C:\Users\<user>, surfacing inside WSL as /mnt/c/Users/<user>. Annoying
because the first thing you do in a new pane is `cd ~`.

Now: if the caller didn't specify a cwd, we explicitly pass `--cd ~`
so the pane lands in the WSL user's home. Existing panes keep their
saved cwd from the workspace.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:43:38 +01:00
9aa0c5a828 Pick up Cargo.lock 0.2.1 bump from tauri build 2026-05-22 21:14:10 +01:00
31bc4859cf Bump version to 0.2.1
Changes since 0.2.0:
- Fix broadcast no-op (useEffect deps captured stale orch ref, so paneIds
  got silently unregistered on every click → broadcastFrom found no peers)
- Flat-list layout architecture: render leaves as siblings keyed by id,
  position via absolute boxes. PTYs survive any tree reshape.
- Drag a pane's toolbar onto another pane to swap them
- Idle reporting moved out of toast spam into a "N idle" titlebar badge
  + red pane border + red "idle" status text
- Themed terminal scrollbars
- Global 📡 broadcast toggle in the titlebar
- Presets preserve existing panes' shells (only kill what overflows the
  preset's slot count, with a confirm dialog)
- React 18 frontend (Svelte version retired to svelte-archive branch)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:10:50 +01:00
3060169214 Bump version to 0.2.0 (first React-based release)
v0.1.0 was the Svelte version, preserved on branch svelte-archive.
v0.2.0 marks the React rewrite: same features, dramatically more
reliable interactions (no more fighting prop reactivity through the
recursive Pane chain), plus scrollbar theming and the global
broadcast toggle in the titlebar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 18:31:46 +01:00
e3e23b55ba Pick up Cargo.lock version bump from pnpm tauri build
cargo auto-rewrote the tiletopia entry from 0.0.1 to 0.1.0 during
the M5 release build; manually updating Cargo.toml in M5 didn't
touch the lockfile. Committing so the release tag points at a
clean tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 13:46:27 +01:00
dd1cf282e6 M5 ship infrastructure: icon, version, release script, README
- scripts/make-icon.py: generates a 1024x1024 source.png — dark
  rounded square + 2x2 tile grid with one active-blue tile and one
  broadcast-orange tile (matches the in-app accent colors).
  Regenerated all desktop icon sizes via 'pnpm tauri icon';
  pruned iOS/Android/UWP outputs.
- Version bump 0.0.1 -> 0.1.0 across package.json, Cargo.toml,
  tauri.conf.json. First real release.
- scripts/release.sh: takes vX.Y.Z, sanity-checks (clean tree,
  on main, in sync, tag matches package.json, installer exists,
  tag not already present), tags + pushes, uploads NSIS .exe to
  Forgejo via tea releases create --asset.
- README rewritten: Install section pointing at Forgejo releases,
  Using-it cheatsheet for all M2-M4 features (splits, broadcast,
  palette, etc.), Develop/Test/Release triplet for the WSL<->Windows
  workflow, icon regen instructions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 13:38:29 +01:00
64b90ebddb Add M3: APPDATA persistence + presets + per-pane distro/label
Backend:
- save_workspace / load_workspace Tauri commands writing to
  %APPDATA%\com.megaproxy.tiletopia\workspace.json with atomic
  tmp+rename. Path from app.path().app_config_dir() (no dirs crate).

Layout helpers:
- tree.ts: changeDistro (with id swap to force XtermPane remount via
  {#key}), changeLabel, presetSingle / TwoColumns / ThreeColumns /
  TwoRows / TwoByTwo.
- New ops.ts with PaneOps interface bundling split / close /
  setDistro / setLabel / distros, drilled through Pane chain
  instead of individual callbacks.

UI:
- LeafPane: in-toolbar editable label (click to rename, Enter
  saves, Esc cancels) and distro chip popover. Picking a different
  distro respawns the pane.
- App.svelte: migrated from localStorage to APPDATA via the new
  Tauri commands, debounced 500ms. One-time localStorage migration
  on boot. Split inherits parent's distro+cwd. Titlebar preset
  buttons with confirm when replacing >1 pane.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:55:46 +01:00
efcdf6a9ce Add M2 splits-tree layout
- src/lib/layout/tree.ts: pure helpers + types (newLeaf, splitLeaf,
  closeLeaf, replaceById, serialize/deserialize with shape-checking).
- SplitNode.svelte: flex container with pointer-captured gutter drag.
- LeafPane.svelte: per-pane toolbar (split-right ⇥, split-down ⇣,
  close ×) over the existing XtermPane.
- Pane.svelte: recursive dispatcher between SplitNode and LeafPane,
  keyed on leaf.id so swaps unmount XtermPane cleanly (kills PTY).
- App.svelte: tree-as-state with split/close handlers, auto-save to
  localStorage on every \$effect tick. Titlebar shows clickable distro
  buttons setting the default for new panes; existing panes keep theirs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:44:35 +01:00
c226f40816 Stop tracking Tauri-generated src-tauri/gen/
These JSON schemas are regenerated on every cargo build from
src-tauri/capabilities/. Same convention as claude-usage-widget.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:32:05 +01:00
b352f8f049 Initial scaffold from M1 spike (tiletopia)
Tauri 2 + Svelte 5 + xterm.js + portable-pty. Single full-window
WSL terminal pane with clickable distro picker. M1 verified manually
on Windows: window opens, xterm.js renders, claude TUI works,
resize reflows cleanly.

Graduated from ~/claude/ideas/wsl-mux/ per the approved plan at
~/.claude/plans/imperative-coalescing-feigenbaum.md. See memory.md
for decisions, open TODOs, and the M2-M5 roadmap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:31:29 +01:00