fix(hub): SessionStart-Hook und agenthub start liefern denselben Text + Verzeichnis-Guard

1) hookContext druckte einen eigenen, aelteren Text. Fuer Codex/Kimi ist der
   Hook aber oft der EINZIGE Einstieg (sie starten automatisch) — dadurch
   kannten auto-gestartete Agenten weder den Check-in-Kanal noch DEC-0035.
   Aufgefallen, als codex ohne `agenthub start` losgelaufen ist. Beide Wege
   nutzen jetzt agentBriefing().

2) `server start` prueft jetzt VOR dem Binden, ob hier ueberhaupt ein Projekt
   liegt. Vorher band der Server erst den Port und starb dann beim Laden der
   Config — der alte Hub war da schon gekillt, die Agenten liefen ins Leere.
   Klassiker: aus dem Quellrepo statt aus dem Projekt gestartet (an einem Tag
   dreimal passiert). Jetzt sofortiger, verstaendlicher Fehler.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
chahinebrini 2026-07-29 19:21:08 +02:00
parent 1250359e6d
commit 5fb2b6d6c6
3 changed files with 31 additions and 13 deletions

View File

@ -2,6 +2,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { homedir } from 'node:os';
import { findProjectRoot } from '../../core/paths.js';
import { agentBriefing } from './startAgent.js';
/**
* Auto-start: make an agent enter the agenthub work-loop the moment its CLI
@ -37,16 +38,12 @@ export function inferCli(agent: string, explicit?: string): AgentCli {
/** Printed by the SessionStart hook → injected as session context. */
export function hookContext(opts: { agent: string; role: string }): void {
const { agent, role } = opts;
process.stdout.write(
`AgentHub auto-start — you are "${agent}" (${role}). Before anything else, enter the work loop:\n` +
` agenthub work --agent ${agent} --role ${role}\n` +
`(or call the agenthub_work tool with { agent: "${agent}", role: "${role}" }). It BLOCKS until a ` +
`task or message addressed to you arrives, then returns it. Handle it, then IMMEDIATELY call ` +
`agenthub_work AGAIN — run it in the BACKGROUND so you're woken on the next event without ` +
`tying up your turn. The loop is: work -> handle -> agenthub_task_review -> work, forever. ` +
`agenthub_work claims your tasks AND delivers your messages. Never run agenthub_task_done. ` +
`Staying in this loop is what keeps you reachable — do not end a turn without relaunching agenthub_work.\n`,
);
// Denselben Text wie `agenthub start` ausgeben. Der Hook ist fuer viele
// Sessions der EINZIGE Einstieg (Codex/Kimi starten automatisch) — ein
// eigener, aelterer Text hier fuehrt dazu, dass auto-gestartete Agenten den
// Check-in-Kanal und DEC-0035 gar nicht kennen. Genau das war der Fall, bis
// der CEO bemerkte, dass codex ohne `agenthub start` losgelaufen ist.
process.stdout.write(`${agentBriefing(agent, role)}\n`);
}
// ─── Marker-delimited upsert (for line-based TOML configs) ───────────────────

View File

@ -1,4 +1,5 @@
import { startServer } from '../../server/index.js';
import { findProjectRoot } from '../../core/paths.js';
/**
* Probe a URL to check whether an AgentHub server is already answering there.
@ -30,5 +31,22 @@ export async function serverStart(cwd: string, options: { port: number; host: st
return;
}
await startServer(cwd, options);
// Verzeichnis-Guard: NICHT den Port binden, wenn hier gar kein Projekt liegt.
// Ohne diese Prüfung bindet der Server erst den Port, stolpert dann beim
// Laden der Config und stirbt — der Port ist kurz belegt, der alte Hub ist
// schon gekillt, und die Agenten laufen ins Leere. Klassischer Fall: aus dem
// agenthub-Quellrepo statt aus dem Projekt gestartet (mir an einem Tag
// dreimal passiert). Lieber sofort und verständlich scheitern.
const projectRoot = findProjectRoot(cwd);
if (!projectRoot) {
console.error(
`Kein AgentHub-Projekt in ${cwd} (und keinem übergeordneten Verzeichnis).\n` +
`Starte den Server aus dem Projekt-Root — dort liegt .agenthub/ mit den Daten.\n` +
`Falls das hier ein neues Projekt werden soll: agenthub init`,
);
process.exitCode = 1;
return;
}
await startServer(projectRoot, options);
}

View File

@ -24,7 +24,10 @@ export interface StartAgentOptions {
role?: string;
}
function briefing(agent: string, role: string): string {
/** Das verbindliche Briefing. Wird von `agenthub start` UND vom SessionStart-Hook
* benutzt beide MÜSSEN denselben Text liefern, sonst arbeitet ein
* auto-gestarteter Agent nach veralteten Regeln. */
export function agentBriefing(agent: string, role: string): string {
return [
`Du bist "${agent}" im AgentHub (Rolle: ${role}).`,
'',
@ -174,7 +177,7 @@ export async function startAgentSession(options: StartAgentOptions): Promise<str
return 'architect';
}
console.log(briefing(agent, role ?? 'implementer'));
console.log(agentBriefing(agent, role ?? "implementer"));
// Was liegt gerade an? Damit die Session nicht blind in den Loop geht.
try {