74 Commits

Author SHA1 Message Date
chahinebrini
df698c9dff feat(agenthub): Rollenwechsel, agent-setup + Push-Channel
roleService haelt roles.*.preferredAgent (Routing-Autoritaet fuer asks,
Watchdog, start) und agents.*.role (Health/Board/MCP-Discovery) konsistent —
bisher konnte nur eine Seite gesetzt werden und der Roster lief auseinander.
Dazu agent-setup-Kommando, Push-Channel im MCP und Selbstheilung im
remoteClient.

Build clean, 304 Tests in 55 Dateien gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113SC5FkaMxcRzXHDBsHmdJ
2026-08-02 21:38:47 +02:00
chahinebrini
908a043ac5 fix(work): bereits gehaltene Task wird genannt statt verschwiegen
Vom CEO gefunden: TSK-0293 stand auf in_progress bei codex — und codex tat
nichts. Ursache: `findAddressedOpenTask` sucht ausschliesslich Tasks mit
Status `open`. Haelt ein Agent bereits eine in_progress-Task (typisch nach
einem Session-Neustart), greift der Busy-Guard und der Loop liefert NICHTS
zurueck. Der Agent wartet dann auf neue Arbeit, die nie kommt, waehrend seine
eigene Task unbearbeitet liegt — und von aussen sieht es aus, als sei er tot.

`resolvePending` liefert jetzt `heldTask`, und alle drei Wege sagen es dem
Agenten deutlich:
  - `agenthub start <agent>`: "DU HAELTST BEREITS <id>" ganz oben
  - `agenthub work` (CLI): nennt die Task und beendet sich, statt zu warten
  - `agenthub_work` (MCP): gibt Task samt Body zurueck statt zu blockieren

Tests: 295 → 297.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 21:45:15 +02:00
chahinebrini
1250359e6d fix(hub): Check-in adressiert wie der Work-Loop (Titel-Präfix + Handoff)
Der Check-in prüfte nur `assignedTo`, `findAddressedOpenTask` dagegen
Titel-Präfix `<name>:`, Handoff-Empfänger UND `assignedTo`. Folge: `agenthub
start codex` meldete "AKTUELL: nichts offen", während TSK-0268 mit
`codex:`-Präfix offen lag — der Work-Loop hätte sie unmittelbar danach
geclaimt. Zwei Wahrheiten über dieselbe Frage.

Jetzt nutzt der Check-in dieselbe Adressierungslogik.

Tests: 293 → 295.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 19:18:02 +02:00
chahinebrini
4be0826a6f fix(hub): delivered-Nachrichten bleiben im Check-in sichtbar
`delivered` heißt nur "einmal ausgeliefert", nicht "gelesen" — abgeschlossen
ist eine Nachricht erst mit read/acked. Der Check-in filterte aber auf
`unread` und ließ damit jede Nachricht fallen, die irgendwo schon einmal
aufgetaucht war (etwa beim Session-Start), ohne dass der Agent sie je
beantwortet hätte.

Real aufgefallen an einer Architekten-Korrektur an kimi: Status `delivered`,
im pending-Block unsichtbar — die Korrektur wäre still verlorengegangen.
Genau der Fehlermodus, gegen den der Kanal gebaut wurde.

Tests: 292 → 294.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 19:12:23 +02:00
chahinebrini
a6f640242a fix(hub): beantwortete Asks über den Check-in-Kanal nachliefern
Realer Fall heute: kimi stellte ASK-0004 um 16:43 und blockierte in
`agenthub_ask(wait:true)`. Der Wait läuft nach 300 s aus. Der Architekt
brauchte für die Architekturentscheidung 18 Minuten — danach war kimi
dormant, das korrekt emittierte `ask`-Event lief ins Leere, und ein Mensch
musste den Agenten wecken.

Dieselbe Taubheit wie in TSK-0274, nur an einer anderen Stelle: dormant =
unerreichbar. Deshalb wandert die Antwort jetzt in den pending-Block —
`resolvePending` liefert beantwortete eigene Fragen mit, sodass sie beim
nächsten Hub-Kontakt (task_log, checkin, start) ankommt, egal wie lange der
Architekt gebraucht hat.

Tests: 290 → 292.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 19:09:41 +02:00
chahinebrini
1f3126b3b5 feat(hub): Check-in-Kanal + Review bindet den Agenten — der Wurzelfix (TSK-0274/0273, DEC-0035)
WURZEL: Ein Agent empfängt SSE-Events ausschließlich, solange er in
agenthub_work blockiert. Während er einen Task AUSFÜHRT, ist er vollständig
taub — kein Reopen, kein Cancel, keine Nachricht erreicht ihn. Ein echter
Interrupt in einen laufenden Agenten-Turn existiert nicht. Heartbeat,
Watchdog, Polling-Fallback und Presence-Tracking waren allesamt Umgehungen
dieser einen Tatsache; deshalb kam das Problem jede Session zurück.

LÖSUNG — der einzige reale Kanal: die Momente, in denen der Agent von sich
aus mit dem Hub spricht.

- checkinService.resolvePending(): zustandslos aus Tasks + Messages
  abgeleitet, nichts, was ein Neustart verliert. Erkennt, dass dem Agenten
  die Arbeit entzogen wurde (reopen/cancel/fremder Claim), und liefert
  ungelesene Nachrichten + offene Zuweisungen mit.
- agenthub_task_log gibt den pending-Block zurück; der Tool-Text macht ihn
  verbindlich (pending.interrupted ⇒ sofort aufhören, nicht einreichen).
- Neu: agenthub_checkin(agent, taskId) für lange Strecken ohne Log-Zeile,
  plus GET /agents/:agent/pending.
- resolvePending degradiert auf reinen Namensvergleich, wenn keine Config da
  ist — ein Check-in darf nie an Konfiguration scheitern.

DEC-0035: `review` bindet den Agenten wie `in_progress`. Vorher galt er in
der Sekunde des Einreichens als frei, griff sich die nächste Task, und ein
Reopen prallte danach am Ein-Task-Guard ab (so ging der Reopen von TSK-0218
verloren). Der Loop bleibt aktiv — wach warten, nichts Neues anfangen.

Außerdem: in_progress → open erlaubt, damit der Architekt eine festhängende
Arbeit überhaupt entziehen kann (vorher 400, Agent blieb dauerhaft blockiert).

SICHTBARKEIT: /health und /agent-health zeigen pro Agent pendingCount
(wartende Tasks) und deafForSec (wie lange ohne Check-in bei laufender
Arbeit). Ungelesene Nachrichten stehen separat — der dreistellige
Altbestand einzelner Agenten hätte das Signal sonst erschlagen.

Tests: 279 → 290. tests/singleClaim (b) auf den neuen Vertrag umgeschrieben
(+ (b2): ein Reopen gewinnt gegen die nächste Task).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 18:05:08 +02:00
chahinebrini
6d088648da feat(hub): Korrektheits- und Realtime-Härtung — Alias, Lifecycle, Presence, Architekten-Pulse (TSK-0242/0245/0249)
Drei vom Architekten abgenommene Tasks, gebündelt als Checkpoint:

- TSK-0242: Agent-Alias-Mapping (kimi-ah → kimi kanonisiert, Rollen → preferredAgent),
  reopenTask räumt claimedBy ab, fsWatch reindiziert direkte Datei-Edits,
  work-Default 300s → 50s, task_list mit Limit.
- TSK-0245: zwei Agent-Klassen (dispatch loop|architect). Watchdog mahnt
  architekt-getriebene Agenten nur noch EINMAL statt im Minutentakt;
  `task dispatch` startet sie explizit, `task record` trägt extern
  erledigte Arbeit mit origin=external nach.
- TSK-0249: Lifecycle wird serverseitig erzwungen (open→review scheitert mit
  klarer Meldung), claimedBy/doneBy überleben bis done, Presence pro Agent,
  Review-Watchdog, GET /architect/pulse (1.4 kB statt 34 kB, since-Cursor,
  omitted statt stillem Abschneiden), unbekannter Agent → 400 statt 500.

Alle Punkte live am laufenden Hub nachgemessen, nicht aus Agenten-Logs übernommen.
Tests: 242 → 279 grün, tsc sauber.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 17:48:24 +02:00
chahinebrini
9dfbf3f657 fix(work): single-claim semantics — max 1 in_progress claim per agent, next auto-claim only after review/done, server-side double-claim guard (TSK-0237)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 02:29:13 +02:00
chahinebrini
f5680c6982 feat(server): agent-health page + realtime auto-wake — SSE Last-Event-ID replay (durable SQLite event log), polling fallback wake on assign/message, /agent-health with reachability ampel + test-message delivery tracking + transport badge (TSK-0230)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 01:20:20 +02:00
chahinebrini
7bf52a0be3 feat(server): watchdog re-notify, agent health ampel, architect budget visibility
- Watchdog (configurable, ~60s): re-emits SSE + unread reminder + board
  warn log for unclaimed assigned tasks (3min high/critical, 10min else);
  alerts the architect on silent in_progress tasks (>15min, no auto-reassign);
  per-task cooldown against alert spam.
- GET /health (status/version/uptime/counts + per-agent traffic light) with
  lastSeen stamped on announce/claim/review/log/message; board sidebar shows
  the agent ampel; new 'agenthub health' CLI command.
- Budget: architect coordination actions (reviews, handoffs, messages,
  approvals) surface as estimated activity tokens + an 'actions' counter.
- Version bump 0.10.2 (single source: src/version.ts).
2026-07-23 17:52:37 +02:00
chahinebrini
9551c90597 fix(realtime): discovery self-heal, polling fallback, message ack semantics, CRLF SSE parser
- probe configured server URL (~1s) before remote commands; on failure
  re-discover via LAN discovery, persist and use the resolved URL
- poll tryClaim/trySurfaceMessages every ~4s during the SSE wait in CLI
  work and MCP waitForTask — a lost SSE frame costs seconds, never sleep
- work/MCP no longer auto-mark messages read: surfacing sets delivered,
  explicit ack/read required; loops still wake only on unread (no spin)
- parseSSEBuffer accepts CRLF frame separators and joins multi data: lines
- bump version to 0.10.1 (package.json, CLI --version, MCP server)
2026-07-23 16:53:33 +02:00
chahinebrini
97db2358bb fix(board): kpi chips strictly one line — nowrap, compact durations (5d/3h/25m), no prefix 2026-07-22 19:10:31 +02:00
chahinebrini
6e81500b74 feat(ui): shared v2 header on all pages (logo, project cell, gradient button) 2026-07-22 17:30:09 +02:00
chahinebrini
964ddff2f2 feat(board): drop budget über-tabs, Verlauf chart lives in donut card as third tab 2026-07-22 17:19:55 +02:00
chahinebrini
5dd5806640 fix(board): card overlap via grid-auto-rows max-content + review cards get ring design 2026-07-22 17:11:19 +02:00
chahinebrini
b09e4c78d2 feat(board): replace v1 monolith with modular v2 glass dashboard 2026-07-20 17:44:45 +02:00
chahinebrini
30b889acd9 feat(board): v2 sidebar with tabbed budget card, throughput chart, live feed 2026-07-20 17:31:58 +02:00
chahinebrini
9553461130 feat(board): v2 kpi cards (area chart, capped chips, done bar) 2026-07-20 17:28:04 +02:00
chahinebrini
e5071f8750 feat(board): v2 header, splash screen, logo route 2026-07-20 17:26:25 +02:00
chahinebrini
4c46e361a9 feat(board): v2 glass design system css 2026-07-20 17:23:54 +02:00
chahinebrini
a34d0ea870 feat(board): v2 viewmodel helpers + logo asset 2026-07-20 06:00:31 +02:00
chahinebrini
08667637e6 fix(agenthub): TSK-0007 — FTS5 duplicate-on-update + claimTask race-guard
- core/index.ts: the FTS5 'search' table has no UNIQUE on id, so INSERT OR
  REPLACE appended a new row every update and the search JOIN returned an id
  N times. Now delete-then-insert by id -> exactly one FTS row per entity.
- taskService.claimTask: race-guarded — only an OPEN task can be claimed;
  same-agent re-claim is an idempotent no-op; a task claimed by another agent or
  past open is refused. getTask+updateTask are sync, so within the single-thread
  event loop the read-check-write is effectively atomic (first claim wins).
- routes.ts (spec 'nicht brechen'): PATCH in_progress surfaces a lost/non-open
  claim as a clean 400 instead of 500, so the board drag reverts gracefully and
  a second agent can't clobber the first's claim.
- tests: +coreCorrectness.test.ts (no FTS dup after updates; concurrent claims
  -> one wins; idempotent re-claim; refuse non-open) + server.test.ts route guard

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 01:24:34 +02:00
chahinebrini
f0c7be25f4 feat(agenthub): TSK-0118 — Ask primitive for autonomous decision-routing
- New Ask entity (ASK-####): schema + counter + paths(EntityType 'asks') +
  events(AgentHubEventType 'ask') + fsWatch(WATCHED + toEvent). Generic entities
  table, no migration.
- askService: createAsk routes to config.roles.architect.preferredAgent, NEVER
  the CEO (a to='ceo' is rerouted); answerAsk / escalateAsk (escalatedTo='ceo',
  single channel) / getAsk / listAsks. Authority-policy JSDoc.
- Asks kept OUT of FTS5: Index.upsert gains a { fts?: boolean } option; askService
  upserts with fts:false, so 'memory search' never returns asks.
- routes: POST/GET /asks, GET /asks/:id, POST /asks/:id/{answer,escalate}, each
  emitChange type:'ask'.
- CLI 'ask <q> --from [--task][--wait][--timeout]' (SSE reconnect wait until
  status!=pending) + ask list/answer/escalate; remoteClient ask methods.
- MCP agenthub_ask (wait via waitForTask, now woken by 'ask' events) +
  agenthub_ask_list/answer/escalate; agenthub_work architect branch surfaces
  pending asks ({reviews,asks,messages}).
- Unattended mode (invocation flag): work.ts ctx + CLI 'work --unattended' +
  agenthub_work schema + LOOP reminder ('call agenthub_ask instead of pausing').
- tests: +askService.test.ts (routing/answer/escalate/list/FTS-exclusion),
  +ask-wait.test.ts (routes roundtrip + SSE wait: answer resolves, no-answer
  times out cleanly)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 01:19:42 +02:00
chahinebrini
941c20d12a fix(agenthub): TSK-0119 — implementer stays reachable after a review submit (dormancy fix)
- work.ts: the CLI work loop now wakes on architect follow-up MESSAGES, not just
  tasks. drainAgentMessages() surfaces + marks-read the agent's inbox; wired into
  waitAndClaim (SSE message events) and as an upfront check in workAgent. reopen +
  next-assign already wake via task events; a plain message no longer leaves the
  re-armed loop dormant.
- mcp/server.ts: implementer agenthub_work LOOP reminder now explicitly instructs
  re-arming after agenthub_task_review so the architect's approval/reopen/message
  wakes it (waitForTask already wakes on task+message).
- tests: work.test.ts +message-wake +reopen-wake

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 01:08:59 +02:00
chahinebrini
2c2193ec55 feat(agenthub): TSK-0074 — automatic agent progress logging to a task live console
- routes PATCH /tasks/🆔 uniformly appendTaskLog + publishLog for every status
  transition (claim/review/done/cancel/reopen) and on assign; best-effort, never
  fails the mutation. No double-emission (log rides the 'log' channel; fsWatch
  only watches .md so the .log append is not re-emitted).
- MCP agenthub_task_log tool + remoteClient.appendTaskLog + CLI 'task log <id>
  --text [--agent][--level]'
- agenthub_work LOOP reminder: 'Report meaningful progress with agenthub_task_log'
- taskDetail: Live Console panel — historic lines via readTaskLog + live tail via
  the named task-log SSE event filtered to this task id
- tests: +taskLog-live.test.ts (PATCH->one log event, no double change, historic
  render, POST /log, remoteClient)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 01:02:04 +02:00
chahinebrini
3f1fb76a84 feat(agenthub): TSK-0120 — split messaging from /activity into a /messages conversation view
- MessageSchema: status enum unread|delivered|read|acked + replyTo (additive, RW-compatible)
- messageService: listInbox transitions unread->delivered on fetch (agent-scoped);
  markMessageDelivered (idempotent, never downgrades); ackMessage(cwd,id,by?)
- routes: GET /messages HTML branch -> renderMessagesHtml; GET /messages/:id;
  POST /messages/:id/ack (mirror of /read, emits message/updated status=acked)
- server/messages.ts: 2-column conversation view (list grouped by pair + unread badge,
  thread bubbles aligned by ?as=, replyTo indentation, TSK pill, live via /events)
- activity.ts: drop message rows (tasks-only hard separation)
- ui-shared: HeaderPage +messages + nav link
- CLI: message ack <id> [--by], message reply <parentId> --from --text [--task];
  remoteClient ackMessage + getMessage
- tests: +message-receipts.test.ts, server.test.ts activity/messages/receipt-chain

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 00:56:16 +02:00
chahinebrini
7922eeb8e8 chore(agenthub): snapshot pre-existing orphaned WIP (single-instance/mDNS + claimedBy + message-read) as batch baseline 2026-07-12 00:46:47 +02:00
chahinebrini
1749f1c58c feat(board): v2 — drop handoffs/decisions panels, tabbed+throttled company donut, real-vs-estimated agent bars with FLIP reorder, session/total reset, fixed-height scrollable columns
codex TSK-0097 board redesign v2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 21:11:38 +02:00
chahinebrini
0884032db1 feat(board): session batch — delete + unified fixed header + in-card live console + reviewer field + 3/4 kanban token-insights redesign
Delete endpoint + trash UI, shared header across all pages, task-log SSE + in-card console, reviewer separate from assignee (board+team), codex board redesign (3/4 kanban + company half-donuts + per-agent bars + square cards).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 20:43:42 +02:00
chahinebrini
ef957bc2f6 feat(team): event-driven delegation pulse (meaningful, not decorative)
The green pulse now visualises real task flow instead of looping randomly:
- delegation (task → in_progress/reassigned) fires a green pulse architect→agent
  and the agent card turns 'active' (green ring + badge);
- review submission (→ review) fires an amber pulse agent→architect and the
  card enters the 'reviewing' state.
Pulses are one-shot, created per transition (SSE-driven, deduped against a
baseline snapshot) and removed on arrival, which lights the destination node.
At rest only the connectors breathe faintly. Active state recoloured green to
match the pulse. Verified: delegation→down+active, review→up+reviewing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 04:19:36 +02:00
chahinebrini
7ca6c859f2 feat(board+team): interactive board, animated team tree, token budget, mDNS, realtime architect review + codex/kimi autostart
Board (/board):
- Drag an AGENT chip onto a task card to (re)assign it (realtime-notified).
- Drag a task card to a column to change status; open→in_progress auto-assigns
  from the title's "<agent>:" prefix — no manual agent picking.
- "+ New task" composer (agent dropdown removed; agent comes from the title).
- Live Cost & Budget panel.

Team (/team): live SSE sync of busy state + always-on ambient animation
(connector shimmer, idle glow) that brightens to a busy pulse when an agent
works. Org-chart hierarchy stays.

Token accounting: new budgetService/rosterService + GET /budget and /agents.
Real doneTokens + time-on-task estimate capped at 45 min/task (avoids the
wall-clock overcount that produced multi-million-token totals), blended
per-model EUR cost + optional budget bars. All estimates flagged "~".

Autostart: `agent setup` writes deterministic SessionStart hooks for Codex
(~/.codex/config.toml) and Kimi (~/.kimi-code/config.toml), not just Claude
Code. Verified: both auto-enter the agenthub_work loop.

Realtime architect review: agenthub_work is role-aware — architect/reviewer
blocks on SSE and wakes when a task hits review (no manual watcher re-arm).

mDNS: server advertises agenthub.local (bonjour-service) so the hub is
reachable in a browser on the LAN without an IP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 03:23:48 +02:00
chahinebrini
caf60ea939 fix(memory): FTS5-safe search-term quoting — "TSK-0037"-style queries no longer crash (TSK-0043)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 01:52:57 +02:00
chahinebrini
8b17baae96 fix(sse): /events keepalive heartbeat — keeps idle agenthub_work alive across short MCP client timeouts (TSK-0042)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 01:52:46 +02:00
chahinebrini
10f3184ea2 feat(board): task-detail transparency — activity log + decisions & reasoning + token/duration badges; cards stay slim (TSK-0041)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 01:52:32 +02:00
chahinebrini
caa009b66a feat(board): lean board + /activity page (TSK-0032 rework, realtime folded in)
codex reworked the board per the user's "keep it simple": /board now shows only
the compact KPI cards + the kanban (half-donut removed), with realtime SSE folded
in (TSK-0030). Recent Activity + Done Archive moved to a new /activity page; nav is
Board · Team · Activity · Decisions. team.ts / ui-shared.ts touched for nav + a
tier data-role hook. Tests green (133). The /team + /activity 500s seen on review
were a local better-sqlite3 ABI mismatch (native module rebuilt for Node 24), not a
code bug — all pages 200 after rebuild.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 05:43:25 +02:00
chahinebrini
986639a5f3 TSK-0028: AgentHub UI foundation + /team page
- Add src/server/ui-shared.ts: design tokens, agentAvatar(), statusPill(),
  escapeHtml(), liveTimerJs(), pageHeader(). No emojis, no deps.
- Add src/server/team.ts: role hierarchy renderer (architect -> implementer/
  reviewer/tester) with per-agent free/busy state derived from in-progress tasks.
- Wire GET /team route in src/server/routes.ts.
- Add tests/team.test.ts and tests/ui-shared.test.ts.

Build: npm run build clean. Tests: 132 passed (was 122).
2026-06-29 00:24:39 +02:00
chahinebrini
78bbebf435 feat(task): agenthub task assign — architect addresses an open task to an agent
Closes the addressing gap that left a waiting `agenthub work` blocked: the
remaining Win tasks were titled "Win L2: …" / unassigned, so they matched
no agent and the daemon waited forever.

`agenthub task assign <id> --agent <name>` sets assignedTo WITHOUT claiming
(status stays open) and fires task/updated — so an agent's blocked `work`
re-checks, matches via assignedTo, and auto-claims it. The architect can now
route a specific open task to a specific agent and have its daemon pick it up.

- taskService.assignTask; PATCH /tasks/:id handles assignedTo-without-status;
  remoteClient.assignTask; CLI `task assign`.
- test: assign keeps status open + sets assignedTo; start/work then claims it
  via the assignedTo match. 122/122 green.

Bump 0.5.0 -> 0.6.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 00:12:50 +02:00
chahinebrini
ec378131e4 feat(watch): --await-review — architect review-queue notifier
Closes the architect-side gap: the auto-claim daemon wakes implementers on
new tasks, but the architect had no signal when an implementer submitted.

`agenthub watch --await-review` exits (after printing) the moment a task
enters `review` — including any task already in review on connect (initial
check) — so the architect can run it in the background and be re-invoked by
the harness the instant a submission needs a verdict.

- watch.ts: awaitReview option, initial fetchReviewTasks() check + SSE exit
  on task→review.
- index.ts: --await-review flag.
- tests: returns immediately on already-pending review; exits on a review
  transition while watching. 121/121 green.

Bump 0.4.0 -> 0.5.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 18:53:40 +02:00
chahinebrini
d2b26cc64c feat: agenthub work — auto-claim daemon (TSK-0018)
The missing autonomy step: an implementer no longer needs a human prompt
per task. `agenthub work --agent <name> --role <role>` announces, then:
  - claims an already-open task addressed to the agent immediately, or
  - blocks on the SSE stream until one appears (newly delegated OR
    reopened after review), then claims + prints it.

Loop: work → implement → `task review` → work. New/reopened tasks are
picked up automatically; run it in the background so the wait doesn't tie
up the turn.

- src/cli/commands/start.ts: extracted announceAgent / findAddressedOpenTask
  / claimAndPrintTask (shared by start + work); addressed-match now also
  covers assignedTo (reopened tasks coming back for rework).
- src/cli/commands/work.ts: wait-and-claim via /events, with a gap-close
  re-check after subscribing and an optional --timeout.
- index.ts: `agenthub work` command.
- templates: implementer guides lead with `work` (the autonomous loop),
  keep `start` as the one-shot.
- tests: immediate claim (local) + wait-then-claim (server SSE). 119/119.

Bump 0.3.1 -> 0.4.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 18:18:47 +02:00
chahinebrini
961675ac40 fix(server): auto-regenerate status snapshot on every change
The status snapshot (.agenthub/status/latest.md) was only refreshed on an
explicit `status --update`, so it drifted stale and misled agents that
follow golden rule #2 ("read status/latest.md") — e.g. an implementer
seeing an old task list and picking the wrong task.

- src/server/statusRefresh.ts: subscribe to the event bus and regenerate
  the snapshot on every task/handoff/decision/memory change (REST and
  filesystem-watch paths), debounced 300 ms. Presence ('agent') events
  are skipped; the snapshot lives outside the watched dirs so it can't
  feed back into the watcher.
- wired into startServer lifecycle (start + stop on close).
- test: status/latest.md reflects a new task shortly after POST /tasks.
  117/117 green.

Bump 0.3.0 -> 0.3.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:27:19 +02:00
chahinebrini
7723360054 feat: agenthub start — one-command onboarding (no copy-paste prompts)
An agent runs ONE command and is working: it announces presence, claims
the open task addressed to it, and prints the task + its handoff + the
next step. Removes the per-agent kickoff copy-paste.

- src/cli/commands/start.ts: `agenthub start --agent <name> --role <role>`.
  "Addressed to <agent>" = task title starts with "<agent>:" OR a handoff
  has toAgent=<agent>. Claims it, prints task body + handoff + the review
  gate reminder. No addressed task → lists open role tasks to pick.
  Works on local + --server paths.
- templates: implementer guides (AGENTS/CODEX/KIMI.md) now lead with
  "On your first turn, RUN `agenthub start …` — do not just summarize",
  so a fresh session self-onboards from one trigger word.
- tests: start auto-claims the addressed task, ignores others, no-ops on
  empty queue; templates test updated for the new commands. 116/116 green.

Bump 0.2.2 -> 0.3.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:15:25 +02:00
chahinebrini
353c139796 feat: review-gate (task review/reopen) + autonomous role guides
Implements the architect-controlled workflow: implementers submit work
for review, only the architect closes tasks.

- CLI: `agenthub task review <id>` (implementer submits → status review)
  and `agenthub task reopen <id>` (architect re-triggers → status open).
  Server already supported both statuses; now exposed on local + --server
  paths, with remoteClient.reviewTask/reopenTask.
- templates: AGENTS.md + role guides rewritten so agents self-drive the
  CLI on open (hello → claim → implement → task review → wait), with the
  hard rule that ONLY the architect runs `task done`. Implementer guides
  (codex/kimi) never call done; architect guide documents done/reopen.
- tests: review/reopen SSE events + formatEvent "Task review"/"Task
  reopened" lines. 113/113 green.

Bump 0.2.0 -> 0.2.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 16:48:42 +02:00
chahinebrini
45070222d0 feat: zero-config auto-connect + agent presence (join-announce)
Agents now connect to the hub with no manual env/flag, and announce
themselves on join — restoring the agreed onboarding flow.

Auto-connect (resolveContext):
- An initialized project WITHOUT a configured serverUrl now falls
  through to LAN auto-discovery (previously it went straight to local
  mode, so agents in an initialized repo never found the server). The
  discovered URL is persisted to the project config, so the next
  command is instant.
- IP-change self-heal: when a configured server is unreachable,
  runRemote re-discovers the live server and updates the config so the
  next command reconnects automatically.

Presence (join-announce):
- POST /announce broadcasts an ephemeral 'agent/joined' event (not
  written to disk). New `agenthub hello --agent <name> --role <role>`
  posts it; watchers print "AgentHub: <agent> joined (<role>)".
- AgentHubEvent extended with type 'agent' + actions 'joined'/'left';
  formatEvent renders presence lines; remoteClient.announce() added.

Tests: formatEvent agent lines + /announce SSE e2e. 109/109 green.
Bump 0.1.2 -> 0.2.0 (CLI --version too).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 16:33:03 +02:00
chahinebrini
ff79cbb639 feat(cli): brand all AgentHub console output with "AgentHub:" prefix
Every user-facing line — the watch stream and each command's success
line, on both the local and --server (remote) paths — now carries an
"AgentHub:" prefix so it's recognizable in any agent's console
(Claude / Codex / Kimi), independent of the board.

- watch: formatEvent rewritten to verb-based, branded lines
  ("AgentHub: Task received <id>  <title>  [status]",
   "AgentHub: Task done <id>  by <agent>", "AgentHub: Handoff …"),
  plus an "AgentHub: connected" line on stream start.
- task/handoff/decision/memory/delegate/init + server-listening lines
  branded on the local command path.
- cli/index.ts: same branding on the --server remote path (the path
  agents actually hit), so CLI line and SSE stream now match.
- tests: formatEvent assertions updated to the branded format
  (regex-tolerant of column padding). 106/106 green.

codex + kimi stay implementers by convention (role=implementer +
assignedTo) — no schema change. Bump 0.1.1 -> 0.1.2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 16:09:15 +02:00
chahinebrini
722388cb00 feat(server): emit SSE for CLI/file writes via filesystem watcher (TSK-0006)
Closes the documented /events limitation: mutations made through the
local CLI (direct file + SQLite writes, no --server) bypassed the
in-process event bus and were invisible to SSE subscribers. A watcher
(e.g. a Windows client) was therefore NOT triggered when another agent
created a task via plain `agenthub task create`.

- src/server/fsWatch.ts: watch the entity dirs (tasks/handoffs/
  decisions/memory); on any .md change, parse the entity and emit the
  matching AgentHubEvent. Debounced per-file; self-creates dirs so it
  attaches even before the first write.
- src/server/events.ts: shared dedup cache (signature = type🆔stamp)
  + emitChange() so the REST path and the watcher deliver each change
  exactly once (no echo when REST writes the file the watcher sees).
- src/server/routes.ts: route emits go through emitChange(); update the
  stale limitation comment.
- src/server/index.ts: start/stop the watcher with the server lifecycle.
- tests/sse.test.ts: CLI-write -> SSE, CLI-update -> SSE, and REST
  dedup (exactly-once). 102/102 green.

Effect: a watcher is auto-triggered the instant any agent creates a
task, with or without --server. Bump 0.1.0 -> 0.1.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 15:43:33 +02:00
chahinebrini
9f3dc28030 fix(cli): memory add no longer prompts when --category is supplied (non-interactive agents)
Local-mode branch of 'memory add' omitted category when calling memoryAdd, so it always fell through to an interactive select() prompt — which throws in non-TTY agent contexts and breaks the reporting loop. Forward category; add tests for the non-interactive flag path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:59:37 +02:00
chahinebrini
9c749beacb feat(activity): per-task timeline endpoint, board expand, --task/--tokens/--duration/--by flags
GET /tasks/:id/activity returns a time-sorted ActivityItem[] assembled from existing data (task created, handoffs by taskId, memory by relatedTasks, current status). memory add + task done gain optional tokens/duration/by metadata surfaced in the timeline. Board cards expand inline to show the timeline. Index gains taskId + relatedTasks columns with migrations. 74 -> 97 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 14:49:47 +02:00
chahinebrini
4e5e5ae6bb feat(realtime): SSE event channel + agenthub watch (TSK-0006 part 1)
- src/server/events.ts: in-process EventEmitter bus (AgentHubEventBus);
  singleton per server process, unlimited listeners for SSE fan-out.
- src/server/routes.ts: GET /events SSE endpoint — keepalive every 25 s,
  optional ?role= server-side filter, reply.hijack() for clean streaming;
  eventBus.publish() called on every successful mutating route (POST tasks/
  handoffs/decisions/memory, PATCH tasks/:id).
- src/cli/commands/watch.ts: SSE client using Node fetch + ReadableStream
  reader; exports parseSSEBuffer + formatEvent for testability; --once flag
  exits 0 after first event (turn-based agent use case); --role for client-
  side filtering (additive to server-side filter).
- src/cli/index.ts: register agenthub watch command via resolveContext.
- tests/sse.test.ts: 18 new tests (74 total, all green) — unit tests for
  parseSSEBuffer + formatEvent, integration tests for eventBus on each
  mutation type, E2E SSE stream + role-filter tests over real HTTP.

Limitation (documented): only REST mutations through the server emit events.
Local-CLI writes (direct file+SQLite) are invisible to subscribers — a
filesystem-watch increment is deferred to a later phase.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 00:16:16 +02:00
chahinebrini
b405b268a5 feat(board): fix gaps A+B — full task status transitions + handoff who→whom
GAP A: extend PATCH /tasks/:id to support all five TaskStatus values
(open, in_progress, review, done, cancelled). Add reviewTask, cancelTask,
reopenTask helpers in taskService. Claim semantics preserved: in_progress
requires assignedTo. Board columns for review and cancelled now reachable
via the API.

GAP B: index fromRole/toRole/fromAgent/toAgent on handoff upsert. SQLite
migration guard adds columns to pre-existing DBs without data loss. Board
renderHandoffs shows "fromRole[@agent] → toRole[@agent]" via &rarr; arrow.
GET /handoffs now carries the routing fields in every index entry.

Tests: +14 (56 total, 21 files, all green). Covers every new status
transition, index field presence, board markup assertions, and a guard for
the claim-without-assignedTo 400.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:41:54 +02:00
chahinebrini
d0e45230bc feat(server): add static Trello-like task board at GET /board
Serves a single self-contained HTML page (inline CSS+JS, no build step,
no framework, no npm deps) that polls /tasks, /handoffs and /decisions on
the same origin and renders a column board by task status
(open/in_progress/review/done/cancelled). Each card shows id, title, role
and assignedTo; small handoffs + decisions panels below; auto-refresh
every 4s with a connection indicator. Purely additive and read-only — the
CLI core path is untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:35:28 +02:00