Update dashboard, kb, memory +4 more (+28 ~18 -1)

This commit is contained in:
Echo
2026-02-06 14:25:10 +00:00
parent 7f64d5054a
commit 19d178268a
6767 changed files with 1346472 additions and 1282 deletions

View File

@@ -30,6 +30,8 @@ class TaskBoardHandler(SimpleHTTPRequestHandler):
self.handle_refresh_index()
elif self.path == '/api/git-commit':
self.handle_git_commit()
elif self.path == '/api/pdf':
self.handle_pdf_post()
else:
self.send_error(404)
@@ -129,6 +131,72 @@ class TaskBoardHandler(SimpleHTTPRequestHandler):
except Exception as e:
self.send_json({'error': str(e)}, 500)
def handle_pdf_post(self):
"""Convert markdown to PDF (text-based, not image) using venv script."""
try:
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length).decode('utf-8')
data = json.loads(post_data)
markdown_content = data.get('markdown', '')
filename = data.get('filename', 'document.pdf')
if not markdown_content:
self.send_json({'error': 'No markdown content'}, 400)
return
# Call PDF generator script in venv
venv_python = BASE_DIR / 'venv' / 'bin' / 'python3'
pdf_script = TOOLS_DIR / 'generate_pdf.py'
if not venv_python.exists():
self.send_json({'error': 'Venv Python not found'}, 500)
return
if not pdf_script.exists():
self.send_json({'error': 'PDF generator script not found'}, 500)
return
# Prepare input JSON
input_data = json.dumps({
'markdown': markdown_content,
'filename': filename
})
# Call script with stdin
result = subprocess.run(
[str(venv_python), str(pdf_script)],
input=input_data.encode('utf-8'),
capture_output=True,
timeout=30
)
if result.returncode != 0:
# Error from script
error_msg = result.stderr.decode('utf-8', errors='replace')
try:
error_json = json.loads(error_msg)
self.send_json(error_json, 500)
except:
self.send_json({'error': error_msg}, 500)
return
# PDF bytes from stdout
pdf_bytes = result.stdout
# Send as file download
self.send_response(200)
self.send_header('Content-Type', 'application/pdf')
self.send_header('Content-Disposition', f'attachment; filename="{filename}"')
self.send_header('Content-Length', str(len(pdf_bytes)))
self.end_headers()
self.wfile.write(pdf_bytes)
except subprocess.TimeoutExpired:
self.send_json({'error': 'PDF generation timeout'}, 500)
except Exception as e:
self.send_json({'error': str(e)}, 500)
def do_GET(self):
if self.path == '/api/status':
self.send_json({'status': 'ok', 'time': datetime.now().isoformat()})
@@ -193,15 +261,15 @@ class TaskBoardHandler(SimpleHTTPRequestHandler):
# Parse uncommitted into structured format
# Format: XY PATH where XY is 2 chars (index + working tree status)
# Examples: "M file" (staged), " M file" (unstaged), "?? file" (untracked)
# Examples: "M AGENTS.md" (staged), " M tools.md" (unstaged), "?? file" (untracked)
# The format varies: sometimes 1 space after status, sometimes 2
uncommitted_parsed = []
for line in uncommitted:
if len(line) >= 3:
status = line[:2].strip()
# Path starts at position 3 for most cases, but we use lstrip
# to handle edge cases where there's no separator space
filepath = line[2:].lstrip().strip()
uncommitted_parsed.append({'status': status, 'path': filepath})
if len(line) >= 2:
status = line[:2].strip() # Get 2 chars and strip whitespace
filepath = line[2:].strip() # Get everything after position 2 and strip
if filepath: # Only add if filepath is not empty
uncommitted_parsed.append({'status': status, 'path': filepath})
self.send_json({
'branch': branch,