refactor: enhance artifact system, security, and terminal command handling

- Add basic HTTP authentication (express-basic-auth)
- Improve artifact tool with better source type handling (command_output, file, text)
- Update agent prompt with clearer artifact usage patterns
- Refactor tmux command execution to use execFile for safer argument handling
- Add UI cancellation capability for in-progress operations
- Switch session dumps to use util.inspect for better formatting
- Update artifact tool schema to require title parameter first

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Mohamed Boudra
2025-10-20 21:04:29 +02:00
co-authored by Claude
parent f832c43a11
commit 7d0a587619
10 changed files with 245 additions and 88 deletions
+8
View File
@@ -380,6 +380,14 @@
background-color: #f59e0b;
}
.send-button.cancelling {
background-color: #ef4444;
}
.send-button.cancelling:hover:not(:disabled) {
background-color: #dc2626;
}
.send-button:disabled {
background-color: #444;
color: #999;
+43 -8
View File
@@ -1,5 +1,5 @@
import { useState, useEffect, useRef } from "react";
import { Mic, Send, Radio } from "lucide-react";
import { Mic, Send, Radio, X } from "lucide-react";
import { useWebSocket } from "./hooks/useWebSocket";
import { createAudioPlayer } from "./lib/audio-playback";
import { createAudioRecorder, type AudioRecorder } from "./lib/audio-capture";
@@ -399,12 +399,47 @@ function App() {
}
};
const handleCancel = async () => {
console.log("[App] Cancelling operations...");
// Stop audio playback
audioPlayerRef.current.stop();
setIsPlayingAudio(false);
// Clear streaming state
setCurrentAssistantMessage("");
// Reset processing state
setIsProcessingAudio(false);
// Send abort request to server
ws.send({
type: "session",
message: {
type: "abort_request",
},
});
addLog("info", "Operations cancelled");
};
// Compute if we're processing an already sent request (not including recording)
const isInProgress =
isProcessingAudio || isPlayingAudio || currentAssistantMessage.length > 0;
const handleButtonClick = async (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
if (userInput.trim()) {
if (isRecording) {
// Stop recording and send the audio
await handleToggleRecording();
} else if (isInProgress) {
// Cancel processing/playback of already sent request
await handleCancel();
} else if (userInput.trim()) {
handleSendMessage();
} else {
// Start recording
await handleToggleRecording();
}
};
@@ -649,15 +684,15 @@ function App() {
<button
type="button"
onClick={handleButtonClick}
disabled={!ws.isConnected || isProcessingAudio}
className={`send-button ${isRecording ? "recording" : ""} ${
isProcessingAudio ? "processing" : ""
disabled={!ws.isConnected}
className={`send-button ${isInProgress ? "cancelling" : ""} ${
isRecording ? "recording" : ""
} ${userInput.trim() ? "has-text" : ""}`}
>
{isRecording ? (
{isInProgress ? (
<X size={20} />
) : isRecording ? (
<span className="recording-indicator" />
) : isProcessingAudio ? (
<span className="processing-indicator" />
) : userInput.trim() ? (
<Send size={20} />
) : (