State files updated by dashboard/heartbeat/cron jobs, plus new KB
captures (samsung firmware todo, scout song reel, weekly youtube notes).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three fixes that together restore the planning UX:
- Dashboard reopen showed only a 500-char truncated excerpt of the last
assistant message. Backend now reads the Claude session JSONL directly
and returns full per-turn history; frontend iterates and renders all
bubbles, falling back to last_text_excerpt when the JSONL is missing.
- Phases never advanced because the agent ran /plan-* skills inline as
tool calls and the marker protocol was loose. Tightened the planning
prompt (mandatory PHASE_STATUS marker on the last line of every turn,
ban on inline phase invocation), and the frontend now auto-calls
/plan/advance when phase_ready=true.
- The phase strip never showed visual state because data-phase values
("office-hours") didn't match orchestrator phase names ("/office-hours").
Added normalizePhase + cleanup of PHASE_STATUS markers from rendered
bubbles.
Also bumps eco.py session-content truncation from 2k to 20k so /eco
session views aren't cut mid-response either.
Bumps last_text_excerpt fallback in planning_session.py from 500 to
50_000 so even when the JSONL is unavailable, the bubble isn't sliced
mid-word.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hash fragments never reach the server so they're lost during login
redirects. ?file= survives the ?next= flow; #hash still works for
direct access when already logged in.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The reverse proxy strips /echo/ before Python, so next=/workspace.html.
Both the JS redirect and the server-side already-logged-in path now
prepend /echo to produce a valid public URL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pass current path as ?next= when bouncing unauthenticated requests
to /echo/login; after successful auth, JS reads and validates the
param (must start with /echo/, not /echo/login) before redirecting.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fonturile inter-*.woff2 și tokens.css nu mai sunt referențiate —
Inter se încarcă din Google Fonts, tokens.css a fost înlocuit
de professional-theme.css în romfast-website (fișier greșit în repo).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Systemd user units get a minimal PATH that omits ~/.local/bin where
the claude binary lives, causing plan/respond to 500 on every call.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
_resolve_planning_key searches all active sessions by slug regardless of
adapter, so respond/finalize/cancel/advance work even when planning was
initiated from Discord or Telegram.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tailscale Serve mapează /echo/* → 127.0.0.1:8088 (dashboard) și / →
:18789 (alt backend). Browser-ul calling /api/ralph/status (relative cu
absolute path la root domain) ajungea la 18789 care nu are endpoint Ralph
→ 502 Bad Gateway.
Fix: toate cele 6 URL-uri (5x fetch + 1x EventSource) folosesc acum prefix
/echo/api/ralph/* pentru a respecta routing-ul tailscale. Pattern consistent
cu workspace.html și index.html (verificat manual).
Endpoints atinse: /status, /<slug>/log, /<slug>/prd, /<slug>/stop,
/<slug>/rollback, /stream (SSE).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dashboard/api.py: adaug link "Ralph" (lucide bot icon) în NAV_HTML între
Workspace și KB. Pagina ralph.html se injectează corect cu nav-ul (verificat
live via curl pe :8088/ralph.html).
tests/test_e2e_planning_walkthrough.py (nou): 4 teste integration care
simulează scripted exact ce face un user pe Discord:
- click Planifică pe game-library cu UI scope → 4 faze (incl design-review)
- /office-hours → ceo → eng → design → final-plan.md stub scris pe disk
- "Dau drumul" → status approved + final_plan_path în approved-tasks.json
- description fără UI keywords → 3 faze (skip design)
- /cancel mid-planning → status revert pending, state cleared
- mesaj fără planning state → cade pe Claude main chat (NU orchestrator)
Subprocess `claude -p` mock-uit; testează tot wire-up-ul router → orchestrator
→ session și schema approved-tasks.json. Nu consumă credite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces 5s polling on /echo/ralph.html with EventSource streaming and adds
a rollback control for the running Ralph cards.
Server (dashboard/handlers/ralph.py):
- /api/ralph/stream — Server-Sent Events. Emits `event: status` whenever a
signature over the projects' state changes (poll filesystem at 2s); emits
`event: heartbeat` every 30s to keep proxies happy. Disables proxy
buffering via X-Accel-Buffering:no.
- /api/ralph/<slug>/rollback (POST) — runs `git revert --no-edit HEAD` in
the project; falls back to `git reset --hard HEAD~1` only if revert
reports conflict. After rolling back the commit, decrements `passes` on
the last user story marked complete in prd.json (atomic temp+rename
write, same pattern as ralph_dag.py). Returns
`{success, message, reverted_commit, story_reverted, method}`.
- _ralph_validate_slug tightened to a strict regex (alphanum + dash +
underscore, ≤64 chars) plus explicit ../, /, \ rejection. All previously
accepted slugs still pass; URL-encoded traversal and shell metachars
now blocked before the filesystem is touched.
- _ralph_collect_status / _ralph_signature factored out of
handle_ralph_status so the SSE loop can reuse them and detect changes
cheaply.
Server (dashboard/api.py):
- HTTPServer → ThreadingHTTPServer with daemon_threads=True. SSE is a
long-lived response; without threading a single client would block all
other dashboard endpoints.
- /api/ralph/stream (GET) and /api/ralph/<slug>/rollback (POST) wired
into the dispatch.
Client (dashboard/ralph.html):
- EventSource('/api/ralph/stream') with permanent fallback to 5s polling
when readyState=CLOSED (no server, CORS blocked, browser without SSE).
- Indicator badge: 🟢 Live (SSE), ⏱ Polling (fallback), Offline.
- Rollback button (undo-2 icon) on running cards; native confirm() with
message: "Asta va da git revert HEAD pe <slug> și va decrementa ultima
story trecută. Continui?"
Tests (tests/test_dashboard_ralph_endpoint.py, +20 cases):
- Strict slug validator: underscore allowed, >64 rejected, special chars
/ backslash / URL-encoded traversal rejected.
- _ralph_collect_status + _ralph_signature: stable when nothing changes,
flips when project added or `passes` toggles.
- Rollback: invalid slug → 400, non-git project → 400, real two-commit
repo revert succeeds and decrements last passing story (US-002 goes
passes:false while US-001 stays passes:true), no-passing-stories case
succeeds with story_reverted=None, response shape contract, atomic
helper leaves no .tmp file behind.
- API routing smoke: confirms ThreadingHTTPServer + stream + rollback
references present in dashboard/api.py.
39/39 tests pass on tests/test_dashboard_ralph_endpoint.py. Pre-existing
failures in test_dashboard_constants.py::test_base_dir_is_echo_core (the
worktree dir is `echo-core-realtime`, not `echo-core`) and
test_dashboard_unified_index.py::test_index_has_all_panels are unrelated
to this change and reproduced on master.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restructurare Ralph QC loop pe smart gate dispatcher tag-driven (în loc de
5 faze fixe), DAG dependsOn cu propagare blocked, retry guard 3-strike, rate
limit detection, plus dashboard live cu polling 5s.
Changes:
- tools/ralph_prd_generator.py: parametru optional final_plan_path; când e
furnizat, invocă Claude Opus pe final-plan.md pentru extragere user stories
cu schema extinsă (tags, dependsOn, acceptanceCriteria 3-5). Backward compat
păstrat — fără final_plan_path, fallback la heuristic-ul vechi.
- tools/ralph/prd-template.json: schema W3 (tags[], dependsOn[], retries,
failed, blocked, failureReason, requiresDesignReview).
- tools/ralph/prompt.md: 4 faze (impl, base quality, smart gates, commit) +
dispatcher pe story.tags. Tags vide → run-all-gates fallback (safe default).
- tools/ralph_dag.py (nou): tag validation heuristic anti-silent-regression
(force ui dacă diff atinge .vue/.tsx/.html/.css/.scss; force db pentru
migrations sau .sql; force vercel dacă există vercel.json) + topological
sort cu blocked propagation + atomic prd.json updates.
- tools/ralph/ralph.sh: --max-turns 30, DAG-aware story selection, retry
counter cu auto-fail la 3, rate limit detection (sleep 30min + 1 retry),
CLI subcommands prin tools/ralph_dag.py helper.
- dashboard/handlers/ralph.py (nou): /api/ralph/status + /<slug>/log + /prd
+ /stop. Defensive vs corrupt prd.json. Sandbox-ed PID kill.
- dashboard/ralph.html (nou): live cards 3/2/1 col responsive, polling 5s,
drawer pentru log/PRD viewer, status colors (--status-running/blocked/
failed/complete declarate inline), Lucide icons cu aria-labels.
- dashboard/api.py: mount /api/ralph/* (GET status/log/prd, POST stop).
- tests/: 72 teste noi (smart gates, DAG, retry, dashboard endpoint).
Note arhitecturale:
- Polling 5s ales peste SSE/WebSocket (suficient pentru iter Ralph 8-15min)
- Tag validation rulează POST-iter pe diff git pentru anti-silent-regression
- Rate limit retry: 1 dată per rulare, apoi mark failed=rate_limited
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Referințele vechi ~/clawd și gitea.romfast.ro/romfast/clawd rămase
din migrarea OpenClaw au fost corectate în index.html și files.html.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>