Entwurfs-Panel mit MCP-Tool write_panel
- Andockbares Panel im Terminal-Fenster: Markdown-Rendering, Copy-Button, normale Selektion; in eigenes Fenster ablösbar und wieder andockbar (Splitter, panel-detached/panel-attached). - MCP-stdio-Server (app --mcp-panel) mit Tool write_panel; schreibt in die Datei aus AI_CONTROL_PANEL, Watcher zieht sie ins Panel. - Provisionierung je Pool: Server-Registrierung in .claude.json (alwaysLoad), Freigabe mcp__text-panel__write_panel in settings.json, Panel-Skill; bei App-Start (alle Pools) und Pool-Anlage. Alte tee-Freigaben werden entfernt. - Capability deckt panel-*-Fenster ab.
This commit is contained in:
@@ -186,10 +186,20 @@ pub fn term_start(
|
||||
.openpty(PtySize { rows, cols, pixel_width: 0, pixel_height: 0 })
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// Panel-Kanal: leere Datei anlegen (definierter Startzustand für den
|
||||
// Watcher) und ihren Pfad als AI_CONTROL_PANEL in die PTY geben — der Skill
|
||||
// schreibt seinen Entwurf dorthin.
|
||||
let panel_path = crate::panel_file(&project);
|
||||
if let Some(parent) = panel_path.parent() {
|
||||
let _ = std::fs::create_dir_all(parent);
|
||||
}
|
||||
let _ = std::fs::write(&panel_path, "");
|
||||
|
||||
let mut cmd = CommandBuilder::new("/bin/zsh");
|
||||
cmd.args(["-ic", &crate::claude_command(&paths)]);
|
||||
cmd.cwd(&cwd);
|
||||
cmd.env("TERM", "xterm-256color");
|
||||
cmd.env("AI_CONTROL_PANEL", &panel_path);
|
||||
if let Some(pool_dir) = crate::project_pool_dir(&project)? {
|
||||
cmd.env("CLAUDE_CONFIG_DIR", pool_dir);
|
||||
}
|
||||
@@ -246,6 +256,8 @@ pub fn term_start(
|
||||
let _ = app.emit_to(&label, "pty-exit", ());
|
||||
});
|
||||
|
||||
spawn_panel_watcher(window.app_handle().clone(), panel_path);
|
||||
|
||||
terminals.0.lock().unwrap().insert(
|
||||
window.label().to_string(),
|
||||
Session { writer, master: pty.master, killer },
|
||||
@@ -253,6 +265,60 @@ pub fn term_start(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Beobachtet die Panel-Datei des Projekts und schickt neuen Inhalt als
|
||||
/// `panel-update` an alle Fenster dieses Terminal-Prozesses (angedocktes Panel
|
||||
/// und ein evtl. abgelöstes Panel-Fenster). Pollt per mtime — kein notify-Crate,
|
||||
/// die Datei ändert sich nur, wenn ein Entwurf geschrieben wird. Der Thread
|
||||
/// endet mit dem Prozess (Fenster zu).
|
||||
fn spawn_panel_watcher(app: AppHandle, path: std::path::PathBuf) {
|
||||
std::thread::spawn(move || {
|
||||
let mtime = || std::fs::metadata(&path).and_then(|m| m.modified()).ok();
|
||||
let mut last = mtime();
|
||||
loop {
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
let now = mtime();
|
||||
if now != last {
|
||||
last = now;
|
||||
if let Ok(content) = std::fs::read_to_string(&path) {
|
||||
let _ = app.emit("panel-update", content);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Aktueller Panel-Inhalt (Erstbefüllung eines gerade geöffneten Panel-Fensters).
|
||||
#[tauri::command]
|
||||
pub fn panel_read(project: String) -> String {
|
||||
std::fs::read_to_string(crate::panel_file(&project)).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Löst das Panel in ein eigenes Fenster ab. Existiert es schon, kommt es nach
|
||||
/// vorn. `panel-detached` blendet das angedockte Panel im Terminal-Fenster aus.
|
||||
#[tauri::command]
|
||||
pub fn open_panel_window(app: AppHandle, project: String) -> Result<(), String> {
|
||||
let label = format!("panel-{project}");
|
||||
if let Some(w) = app.get_webview_window(&label) {
|
||||
let _ = w.set_focus();
|
||||
return Ok(());
|
||||
}
|
||||
let cfg = crate::terminal_config(&project)?;
|
||||
let (r, g, b) = theme_background(cfg.theme.as_deref().unwrap_or_default());
|
||||
let title = cfg.title.as_deref().unwrap_or(project.as_str());
|
||||
WebviewWindowBuilder::new(
|
||||
&app,
|
||||
&label,
|
||||
WebviewUrl::App(format!("panel.html?project={project}").into()),
|
||||
)
|
||||
.title(format!("{title} — Entwurf"))
|
||||
.inner_size(480.0, 640.0)
|
||||
.background_color(tauri::window::Color(r, g, b, 0xff))
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?;
|
||||
app.emit("panel-detached", ()).map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Debug: JS-Fehler aus dem Terminal-Fenster ins Dev-Log.
|
||||
#[tauri::command]
|
||||
pub fn term_log(window: tauri::WebviewWindow, msg: String) {
|
||||
|
||||
Reference in New Issue
Block a user