fix: address AI review feedback for disinto-chat (#705)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/pr/smoke-init Pipeline was successful

This commit is contained in:
Claude 2026-04-12 00:46:45 +00:00
parent eada673493
commit 938cd319aa
5 changed files with 25 additions and 46 deletions

5
.gitignore vendored
View file

@ -32,3 +32,8 @@ docker/agents/bin/
# Generated docker-compose.yml (run 'bin/disinto init' to regenerate)
# Note: This file is now committed to track volume mount configuration
# docker-compose.yml
# Python bytecode
__pycache__/
*.pyc
*.pyo

View file

@ -1,7 +1,7 @@
# disinto-chat — minimal HTTP+WebSocket backend for Claude chat UI
# disinto-chat — minimal HTTP backend for Claude chat UI
#
# Small Debian slim base with Python runtime and websockets library.
# Chosen for simplicity and small image size (~100MB vs ~150MB for Go).
# Small Debian slim base with Python runtime.
# Chosen for simplicity and small image size (~100MB).
#
# Image size: ~100MB (well under the 200MB ceiling)
#
@ -10,11 +10,9 @@
FROM debian:bookworm-slim
# Install Python and websockets (no build-time network access needed)
# Install Python (no build-time network access needed)
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 \
python3-pip \
&& pip3 install --break-system-packages websockets \
&& rm -rf /var/lib/apt/lists/*
# Non-root user

View file

@ -165,35 +165,21 @@ class ChatHandler(BaseHTTPRequestHandler):
return
try:
# Spawn claude --print with streaming output
# Using stream-json format for structured parsing capability
# Spawn claude --print with text output format
proc = subprocess.Popen(
[CLAUDE_BIN, "--print", message, "--output-format", "stream-json"],
[CLAUDE_BIN, "--print", message],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=False,
bufsize=0, # Unbuffered for streaming
text=True,
)
# Read and stream response
response_parts = []
error_parts = []
# Read stdout in chunks
while True:
chunk = proc.stdout.read(4096)
if not chunk:
break
try:
response_parts.append(chunk.decode("utf-8"))
except UnicodeDecodeError:
response_parts.append(chunk.decode("utf-8", errors="replace"))
# Read response as text (Claude outputs plain text when not using stream-json)
response = proc.stdout.read()
# Read stderr (should be minimal, mostly for debugging)
if proc.stderr:
error_output = proc.stderr.read()
if error_output:
error_parts.append(error_output.decode("utf-8", errors="replace"))
print(f"Claude stderr: {error_output}", file=sys.stderr)
# Wait for process to complete
proc.wait()
@ -202,12 +188,6 @@ class ChatHandler(BaseHTTPRequestHandler):
if proc.returncode != 0:
self.send_error(500, f"Claude CLI failed with exit code {proc.returncode}")
return
# Combine response parts
response = "".join(response_parts)
# If using stream-json, we could parse and reformat here.
# For now, return as-is (HTMX will display it in the UI).
self.send_response(200)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.send_header("Content-Length", len(response.encode("utf-8")))

View file

@ -132,7 +132,7 @@
<div class="content">Welcome to disinto-chat. Type a message to start chatting with Claude.</div>
</div>
</div>
<form class="input-area" hx-post="/chat" hx-swap="none" hx-target="#messages">
<form class="input-area">
<textarea name="message" placeholder="Type your message..." required></textarea>
<button type="submit" id="send-btn">Send</button>
</form>
@ -161,13 +161,6 @@
return div.innerHTML.replace(/\n/g, '<br>');
}
// Handle HTMX swap for streaming responses
document.body.addEventListener('htmx:afterSwap', function(event) {
const newContent = event.detail.xhr.responseText;
// HTMX will handle the swap; we just need to scroll to bottom
messagesDiv.scrollTop = messagesDiv.scrollHeight;
});
// Send message handler
sendBtn.addEventListener('click', async () => {
const message = textarea.value.trim();
@ -183,13 +176,16 @@
textarea.value = '';
try {
// Use fetch for better control over streaming
const formData = new FormData();
formData.append('message', message);
// Use fetch with URLSearchParams for application/x-www-form-urlencoded
const params = new URLSearchParams();
params.append('message', message);
const response = await fetch('/chat', {
method: 'POST',
body: formData
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: params
});
if (!response.ok) {