forked from Rockachopa/Timmy-time-dashboard
Clean up generated files and fix 6 dashboard bugs (#142)
* chore: gitignore local/generated files and remove from tracking Remove user-specific files (MEMORY.md, user_profile.md, prompts.py) from source control. Add patterns for credentials, backups, and generated content to .gitignore. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve 6 dashboard bugs — chat, /bugs, /swarm/events, WebSocket, marketplace, sidebar 1. Chat non-functional: CSRF middleware silently blocked HTMX POSTs. Added CSRF token transmission via hx-headers in base.html. 2. /bugs → 500: Route missing template vars (total, stats, filter_status). 3. /swarm/events → 500: Called .event_type.value on a plain str (SparkEvent.event_type is str, not enum). Also fixed timestamp and source field mismatches in the template. 4. WebSocket reconnect loop: No WS endpoint existed at /swarm/live, only an HTTP GET. Added @router.websocket("/live") using ws_manager. 5. Marketplace "Agent not found": Nav links /marketplace/ui matched the /{agent_id} catch-all. Added explicit /marketplace/ui route with enriched template context. 6. Agents sidebar "LOADING...": /swarm/agents/sidebar endpoint was missing. Added route returning the existing sidebar partial. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: restore src/timmy/prompts.py to source control prompts.py is imported by timmy.agent and is production code, not a user-local file. Re-add to tracking and remove from .gitignore. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Trip T <trip@local> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
b615595100
commit
3bf7187482
17
.gitignore
vendored
17
.gitignore
vendored
@@ -17,6 +17,10 @@ env/
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
discord_credentials.txt
|
||||
|
||||
# Backup / temp files
|
||||
*~
|
||||
|
||||
# SQLite — never commit databases or WAL/SHM artifacts
|
||||
*.db
|
||||
@@ -55,6 +59,19 @@ src/data/
|
||||
*.swo
|
||||
.claude/
|
||||
|
||||
# Local content — user-specific or generated
|
||||
MEMORY.md
|
||||
memory/self/user_profile.md
|
||||
TIMMYTIME
|
||||
introduction.txt
|
||||
messages.txt
|
||||
morning_briefing.txt
|
||||
markdown_report.md
|
||||
data/timmy_soul.jsonl
|
||||
scripts/migrate_to_zeroclaw.py
|
||||
src/infrastructure/db_pool.py
|
||||
workspace/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
|
||||
52
MEMORY.md
52
MEMORY.md
@@ -1,52 +0,0 @@
|
||||
# Timmy Hot Memory
|
||||
|
||||
> Working RAM — always loaded, ~300 lines max, pruned monthly
|
||||
> Last updated: 2026-02-26
|
||||
|
||||
---
|
||||
|
||||
## Current Status
|
||||
|
||||
**Agent State:** Operational
|
||||
**Mode:** Development
|
||||
**Active Tasks:** 0
|
||||
**Pending Decisions:** None
|
||||
|
||||
---
|
||||
|
||||
## Standing Rules
|
||||
|
||||
1. **Sovereignty First** — No cloud dependencies
|
||||
2. **Local-Only Inference** — Ollama on localhost
|
||||
3. **Privacy by Design** — Telemetry disabled
|
||||
4. **Tool Minimalism** — Use tools only when necessary
|
||||
5. **Memory Discipline** — Write handoffs at session end
|
||||
|
||||
---
|
||||
|
||||
## Agent Roster
|
||||
|
||||
| Agent | Role | Status |
|
||||
|-------|------|--------|
|
||||
| Timmy | Core | Active |
|
||||
|
||||
---
|
||||
|
||||
## User Profile
|
||||
|
||||
**Name:** Not
|
||||
|
||||
|
||||
## Key Decisions
|
||||
|
||||
(none yet)
|
||||
|
||||
---
|
||||
|
||||
## Pending Actions
|
||||
|
||||
- [ ] Learn user's name
|
||||
|
||||
---
|
||||
|
||||
*Prune date: 2026-02-25*
|
||||
@@ -1,43 +0,0 @@
|
||||
# User Profile
|
||||
|
||||
> Learned information about the user. Updated continuously.
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Name:** Not
|
||||
**Location:** (unknown)
|
||||
**Occupation:** (unknown)
|
||||
**Technical Level:** (to be assessed)
|
||||
|
||||
## Interests & Expertise
|
||||
|
||||
- (to be learned from conversations)
|
||||
|
||||
## Preferences
|
||||
|
||||
### Communication
|
||||
- Response style: (default: concise, technical)
|
||||
- Detail level: (default: medium)
|
||||
- Humor: (default: minimal)
|
||||
|
||||
### Tools
|
||||
- Auto-tool usage: (default: minimal)
|
||||
- Confirmation required for: shell commands, file writes
|
||||
|
||||
### Memory
|
||||
- Personalization: Enabled
|
||||
- Context retention: 20 messages (working), 100 (short-term)
|
||||
|
||||
## Important Facts
|
||||
|
||||
- (to be extracted from conversations)
|
||||
|
||||
## Relationship History
|
||||
|
||||
- First session: 2026-02-25
|
||||
- Total sessions: 1
|
||||
- Key milestones: (none yet)
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-02-27*
|
||||
@@ -47,28 +47,41 @@ async def api_list_agents():
|
||||
|
||||
|
||||
@router.get("/marketplace")
|
||||
async def marketplace_json(request: Request):
|
||||
"""Marketplace JSON API (backward compat)."""
|
||||
return await api_list_agents()
|
||||
|
||||
|
||||
@router.get("/marketplace/ui", response_class=HTMLResponse)
|
||||
async def marketplace_ui(request: Request):
|
||||
"""Marketplace page — returns JSON for API requests, HTML for browser."""
|
||||
# Check if client wants JSON (common test clients don't set Accept header)
|
||||
accept = request.headers.get("accept", "")
|
||||
# Return JSON if Accept header indicates JSON OR if no preference (default to JSON for API)
|
||||
if "application/json" in accept or accept == "*/*" or not accept:
|
||||
return await api_list_agents()
|
||||
|
||||
# Browser request - return HTML
|
||||
"""Marketplace HTML page."""
|
||||
try:
|
||||
brain = BrainClient()
|
||||
tasks = await brain.get_pending_tasks(limit=20)
|
||||
except Exception:
|
||||
tasks = []
|
||||
|
||||
|
||||
# Enrich agents with fields the template expects
|
||||
enriched = []
|
||||
for agent in AGENT_CATALOG:
|
||||
a = dict(agent)
|
||||
a.setdefault("status", a.get("default_status", "active"))
|
||||
a.setdefault("tasks_completed", 0)
|
||||
a.setdefault("total_earned", 0)
|
||||
enriched.append(a)
|
||||
|
||||
active = sum(1 for a in enriched if a["status"] == "active")
|
||||
|
||||
return templates.TemplateResponse(
|
||||
request,
|
||||
"marketplace.html",
|
||||
{
|
||||
"agents": AGENT_CATALOG,
|
||||
"agents": enriched,
|
||||
"pending_tasks": tasks,
|
||||
"message": "Personas deprecated — use Brain Task Queue",
|
||||
"page_title": "Agent Marketplace",
|
||||
"active_count": active,
|
||||
"planned_count": 0,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@ import json
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Request
|
||||
from fastapi import APIRouter, Request, WebSocket, WebSocketDisconnect
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
||||
from spark.engine import spark_engine
|
||||
from dashboard.templating import templates
|
||||
from infrastructure.ws_manager.handler import ws_manager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -31,13 +32,13 @@ async def swarm_events(
|
||||
if agent_id:
|
||||
events = [e for e in events if e.agent_id == agent_id]
|
||||
if event_type:
|
||||
events = [e for e in events if e.event_type.value == event_type]
|
||||
events = [e for e in events if e.event_type == event_type]
|
||||
|
||||
# Prepare summary and event types for template
|
||||
summary = {}
|
||||
event_types = set()
|
||||
for e in events:
|
||||
etype = e.event_type.value
|
||||
etype = e.event_type
|
||||
event_types.add(etype)
|
||||
summary[etype] = summary.get(etype, 0) + 1
|
||||
|
||||
@@ -60,7 +61,7 @@ async def swarm_live(request: Request):
|
||||
"""Live swarm activity page."""
|
||||
status = spark_engine.status()
|
||||
events = spark_engine.get_timeline(limit=20)
|
||||
|
||||
|
||||
return templates.TemplateResponse(
|
||||
request,
|
||||
"swarm_live.html",
|
||||
@@ -69,3 +70,34 @@ async def swarm_live(request: Request):
|
||||
"events": events,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@router.websocket("/live")
|
||||
async def swarm_ws(websocket: WebSocket):
|
||||
"""WebSocket endpoint for live swarm updates."""
|
||||
await ws_manager.connect(websocket)
|
||||
try:
|
||||
while True:
|
||||
await websocket.receive_text()
|
||||
except WebSocketDisconnect:
|
||||
ws_manager.disconnect(websocket)
|
||||
|
||||
|
||||
@router.get("/agents/sidebar", response_class=HTMLResponse)
|
||||
async def agents_sidebar(request: Request):
|
||||
"""Sidebar partial showing agent status for the home page."""
|
||||
from config import settings
|
||||
|
||||
agents = [
|
||||
{
|
||||
"id": "default",
|
||||
"name": settings.agent_name,
|
||||
"status": "idle",
|
||||
"type": "local",
|
||||
"capabilities": "chat,reasoning,research,planning",
|
||||
"last_seen": None,
|
||||
}
|
||||
]
|
||||
return templates.TemplateResponse(
|
||||
request, "partials/swarm_agents_sidebar.html", {"agents": agents}
|
||||
)
|
||||
|
||||
@@ -89,7 +89,9 @@ async def mission_control(request: Request):
|
||||
|
||||
@router.get("/bugs", response_class=HTMLResponse)
|
||||
async def bugs_page(request: Request):
|
||||
return templates.TemplateResponse(request, "bugs.html", {"bugs": []})
|
||||
return templates.TemplateResponse(request, "bugs.html", {
|
||||
"bugs": [], "total": 0, "stats": {}, "filter_status": None,
|
||||
})
|
||||
|
||||
|
||||
@router.get("/self-coding", response_class=HTMLResponse)
|
||||
|
||||
@@ -15,6 +15,14 @@
|
||||
<link rel="stylesheet" href="/static/style.css?v=5" />
|
||||
{% block extra_styles %}{% endblock %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.3/dist/htmx.min.js" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var match = document.cookie.match(/csrf_token=([^;]+)/);
|
||||
if (match) {
|
||||
document.body.setAttribute('hx-headers', JSON.stringify({"X-CSRF-Token": match[1]}));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/marked@15.0.7/marked.min.js"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/dompurify@3.2.4/dist/purify.min.js"></script>
|
||||
</head>
|
||||
|
||||
@@ -63,14 +63,14 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for event in events %}
|
||||
<tr class="event-row" data-type="{{ event.event_type.value }}">
|
||||
<td class="event-time">{{ event.timestamp[11:19] }}</td>
|
||||
<tr class="event-row" data-type="{{ event.event_type }}">
|
||||
<td class="event-time">{{ event.created_at[11:19] }}</td>
|
||||
<td>
|
||||
<span class="mc-badge mc-badge-{{ event.event_type.value.split('.')[0] }}">
|
||||
{{ event.event_type.value }}
|
||||
<span class="mc-badge mc-badge-{{ event.event_type.split('.')[0] }}">
|
||||
{{ event.event_type }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ event.source }}</td>
|
||||
<td>{{ event.agent_id or '-' }}</td>
|
||||
<td>
|
||||
{% if event.task_id %}
|
||||
<a href="/swarm/events?task_id={{ event.task_id }}">{{ event.task_id[:8] }}...</a>
|
||||
|
||||
Reference in New Issue
Block a user