feat: agent completion events + plugin hooks
spawnAgent() now writes completion events to events.jsonl.
Plugin hooks check for completions on:
- SessionStart: report agents that finished since last session
- Notification(idle_prompt): check when Claude is idle
Event format: {"type":"agent_completed","agent":"...","workspace":"...","timestamp":"..."}
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
662217c6f5
commit
58749c87f8
5 changed files with 122 additions and 0 deletions
|
|
@ -91,6 +91,28 @@
|
|||
}
|
||||
],
|
||||
"description": "Restore recent session context on startup"
|
||||
},
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/check-completions.sh"
|
||||
}
|
||||
],
|
||||
"description": "Report agent completions from previous session"
|
||||
}
|
||||
],
|
||||
"Notification": [
|
||||
{
|
||||
"matcher": "idle_prompt",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/check-completions.sh"
|
||||
}
|
||||
],
|
||||
"description": "Check for agent completions when idle"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
47
claude/core/scripts/check-completions.sh
Executable file
47
claude/core/scripts/check-completions.sh
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
#!/bin/bash
|
||||
# Check for agent completion events since last check.
|
||||
# Called by plugin hooks to notify the orchestrating agent.
|
||||
|
||||
EVENTS_FILE="$HOME/Code/host-uk/core/.core/workspace/events.jsonl"
|
||||
MARKER_FILE="$HOME/Code/host-uk/core/.core/workspace/.events-read"
|
||||
|
||||
if [ ! -f "$EVENTS_FILE" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get events newer than last read
|
||||
if [ -f "$MARKER_FILE" ]; then
|
||||
LAST_READ=$(cat "$MARKER_FILE")
|
||||
NEW_EVENTS=$(awk -v ts="$LAST_READ" '$0 ~ "timestamp" && $0 > ts' "$EVENTS_FILE" 2>/dev/null)
|
||||
else
|
||||
NEW_EVENTS=$(cat "$EVENTS_FILE")
|
||||
fi
|
||||
|
||||
if [ -z "$NEW_EVENTS" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Update marker
|
||||
date -u +%Y-%m-%dT%H:%M:%SZ > "$MARKER_FILE"
|
||||
|
||||
# Count completions
|
||||
COUNT=$(echo "$NEW_EVENTS" | grep -c "agent_completed")
|
||||
|
||||
if [ "$COUNT" -gt 0 ]; then
|
||||
# Format for hook output
|
||||
AGENTS=$(echo "$NEW_EVENTS" | grep "agent_completed" | python3 -c "
|
||||
import sys, json
|
||||
events = [json.loads(l) for l in sys.stdin if l.strip()]
|
||||
for e in events:
|
||||
print(f\" {e.get('agent','?')} — {e.get('workspace','?')}\")
|
||||
" 2>/dev/null)
|
||||
|
||||
cat << EOF
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "Notification",
|
||||
"additionalContext": "$COUNT agent(s) completed:\n$AGENTS\n\nRun /core:status to review."
|
||||
}
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
BIN
core-agent
BIN
core-agent
Binary file not shown.
|
|
@ -121,6 +121,9 @@ func (s *PrepSubsystem) spawnAgent(agent, prompt, wsDir, srcDir string) (int, st
|
|||
writeStatus(wsDir, st)
|
||||
}
|
||||
|
||||
// Emit completion event
|
||||
emitCompletionEvent(agent, filepath.Base(wsDir))
|
||||
|
||||
// Ingest scan findings as issues
|
||||
s.ingestFindings(wsDir)
|
||||
|
||||
|
|
|
|||
50
pkg/agentic/events.go
Normal file
50
pkg/agentic/events.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package agentic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
coreio "forge.lthn.ai/core/go-io"
|
||||
)
|
||||
|
||||
// CompletionEvent is emitted when a dispatched agent finishes.
|
||||
// Written to ~/.core/workspace/events.jsonl as append-only log.
|
||||
type CompletionEvent struct {
|
||||
Type string `json:"type"`
|
||||
Agent string `json:"agent"`
|
||||
Workspace string `json:"workspace"`
|
||||
Status string `json:"status"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
|
||||
// emitCompletionEvent appends a completion event to the events log.
|
||||
// The plugin's hook watches this file to notify the orchestrating agent.
|
||||
func emitCompletionEvent(agent, workspace string) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
eventsFile := filepath.Join(home, "Code", "host-uk", "core", ".core", "workspace", "events.jsonl")
|
||||
|
||||
event := CompletionEvent{
|
||||
Type: "agent_completed",
|
||||
Agent: agent,
|
||||
Workspace: workspace,
|
||||
Status: "completed",
|
||||
Timestamp: time.Now().UTC().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
data, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Append to events log
|
||||
existing, _ := coreio.Local.Read(eventsFile)
|
||||
coreio.Local.Write(eventsFile, existing+string(data)+"\n")
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue