feat(kugetsu): add status, delegate, doctor commands; inject PM context at init

This commit implements Phase 3b/3c architectural improvements:

### New kugetsu CLI commands:
- `kugetsu status` - Check initialization status (replaces kugetsu-helper check-status)
- `kugetsu delegate <msg>` - Send message to PM agent (new command)
- `kugetsu doctor [--fix]` - Diagnose and fix kugetsu issues

### PM Context Injection:
- kugetsu init now reads ~/.kugetsu/pm-agent.md (if exists) and injects
  it into the PM agent session at creation time
- PM context is loaded ONCE at init, not on every delegation
- This improves efficiency - kugetsu-pm content read once, not 10 times

### kugetsu-chat updated:
- Now uses `kugetsu delegate` instead of kugetsu-helper
- Now uses `kugetsu status` instead of kugetsu-helper check-status
- Simplified - no longer depends on kugetsu-helpers

### kugetsu continue:
- Removed strict issue-ref format validation
- Now accepts any session name that is tracked in index.json["issues"]
- Issue-ref format is a guideline, not a hard requirement

### Documentation updated:
- phase3a-setup.md - Updated to reflect new kugetsu commands
- kugetsu-install.sh - Simplified Phase 3a setup instructions

### Breaking changes:
- kugetsu-helpers is no longer required for Phase 3a Chat Agent
- kugetsu-chat skill v3.0 now requires kugetsu CLI with new commands
This commit is contained in:
shokollm
2026-03-31 01:09:12 +00:00
parent bc3cc8dd1e
commit b3171ed632
5 changed files with 290 additions and 108 deletions

View File

@@ -15,10 +15,13 @@ Usage:
kugetsu init [--force] Initialize base + pm-agent sessions (requires TTY)
kugetsu start <issue-ref> <message> [--debug] Start task for issue (forks base session)
kugetsu continue <issue-ref> [message] [--debug] Continue existing task for issue
kugetsu delegate <message> Send message to PM agent
kugetsu status Check kugetsu initialization status
kugetsu doctor [--fix] Diagnose and fix kugetsu issues
kugetsu list List all tracked sessions
kugetsu prune [--force] Remove orphaned sessions (keeps base + pm-agent)
kugetsu destroy <issue-ref> [-y] Delete session for issue
kugetsu destroy --pm-agent [-y] Delete pm-agent session
kugetsu destroy --pm-agent [-y] Delete pm-agent session (not recommended)
kugetsu destroy --base [-y] Delete base session
kugetsu help Show this help
@@ -32,6 +35,10 @@ Commands:
start Fork new session from base for specific issue.
Requires pm-agent to be running (created by init).
continue Continue work on existing issue session.
delegate Send message to PM agent for task coordination.
PM context is loaded once at init time.
status Check if kugetsu is initialized and PM agent is active.
doctor Diagnose kugetsu issues. Use --fix to attempt repairs.
list Show all sessions (base + pm-agent + forked issues).
prune Remove sessions not in index (orphaned from opencode).
Use --force to skip confirmation.
@@ -40,14 +47,20 @@ Commands:
Options:
--debug Show real-time debug output and capture to debug.log
PM Context:
kugetsu reads ~/.kugetsu/pm-agent.md (if exists) and injects it
into the PM agent session at init time. This allows customizing PM
behavior without recreating the session.
Examples:
kugetsu init
kugetsu status
kugetsu delegate "work on issue #5"
kugetsu doctor
kugetsu doctor --fix
kugetsu start github.com/shoko/kugetsu#14 "fix bug"
kugetsu continue github.com/shoko/kugetsu#14 "add tests"
kugetsu list
kugetsu prune
kugetsu prune --force
kugetsu destroy github.com/shoko/kugetsu#14
EOF
}
@@ -283,6 +296,188 @@ check_opencode_session_exists() {
opencode session list 2>/dev/null | grep -q "^$session_id"
}
kugetsu_get_pm_context() {
local pm_context_file="${KUGETSU_DIR}/pm-agent.md"
if [ -f "$pm_context_file" ]; then
cat "$pm_context_file"
else
echo ""
fi
}
cmd_status() {
if [ ! -f "$INDEX_FILE" ]; then
echo "kugetsu_not_initialized"
return
fi
local base=$(get_base_session_id)
local pm_agent=$(get_pm_agent_session_id)
if [ -z "$base" ] || [ "$base" = "null" ]; then
echo "base_session_missing"
return
fi
if [ -z "$pm_agent" ] || [ "$pm_agent" = "null" ] || [ "$pm_agent" = "None" ]; then
echo "pm_agent_missing"
return
fi
if ! check_opencode_session_exists "$pm_agent"; then
echo "pm_agent_expired"
return
fi
echo "ok"
}
cmd_delegate() {
local message="${1:-}"
if [ -z "$message" ]; then
echo "Error: message is required" >&2
echo "Usage: kugetsu delegate <message>" >&2
exit 1
fi
local pm_session=$(get_pm_agent_session_id)
if [ -z "$pm_session" ] || [ "$pm_session" = "null" ] || [ "$pm_session" = "None" ]; then
echo "Error: PM agent session not found. Run 'kugetsu init' first." >&2
exit 1
fi
if ! check_opencode_session_exists "$pm_session"; then
echo "Error: PM agent session has expired. Run 'kugetsu init' again." >&2
exit 1
fi
opencode run --continue --session "$pm_session" "$message" 2>&1
}
cmd_doctor() {
local fix=false
while [ $# -gt 0 ]; do
case "$1" in
--fix)
fix=true
;;
*)
;;
esac
shift
done
echo "=== kugetsu doctor ==="
echo ""
local issues=0
if [ ! -f "$INDEX_FILE" ]; then
echo "[ISSUE] kugetsu not initialized (index.json missing)"
issues=$((issues + 1))
else
echo "[OK] kugetsu initialized"
local base=$(get_base_session_id)
if [ -z "$base" ] || [ "$base" = "null" ]; then
echo "[ISSUE] Base session missing"
issues=$((issues + 1))
else
echo "[OK] Base session: $base"
if check_opencode_session_exists "$base"; then
echo "[OK] Base session active"
else
echo "[ISSUE] Base session expired"
issues=$((issues + 1))
fi
fi
local pm_agent=$(get_pm_agent_session_id)
if [ -z "$pm_agent" ] || [ "$pm_agent" = "null" ] || [ "$pm_agent" = "None" ]; then
echo "[ISSUE] PM agent session missing"
issues=$((issues + 1))
else
echo "[OK] PM agent: $pm_agent"
if check_opencode_session_exists "$pm_agent"; then
echo "[OK] PM agent session active"
else
echo "[ISSUE] PM agent session expired"
issues=$((issues + 1))
fi
fi
local pm_context_file="${KUGETSU_DIR}/pm-agent.md"
if [ -f "$pm_context_file" ]; then
echo "[OK] PM context file exists"
else
echo "[INFO] PM context file not found (optional): $pm_context_file"
fi
fi
echo ""
if [ $issues -eq 0 ]; then
echo "No issues found."
else
echo "Found $issues issue(s)."
fi
if [ "$fix" = true ] && [ $issues -gt 0 ]; then
echo ""
echo "Running fixes..."
if [ ! -f "$INDEX_FILE" ]; then
echo "Cannot fix: not initialized. Run 'kugetsu init' first."
else
local pm_agent=$(get_pm_agent_session_id)
if [ -n "$pm_agent" ] && [ "$pm_agent" != "null" ] && [ "$pm_agent" != "None" ]; then
if ! check_opencode_session_exists "$pm_agent"; then
echo "[FIX] Recreating expired PM agent session..."
local base=$(get_base_session_id)
if [ -n "$base" ] && [ "$base" != "null" ]; then
rm -f "$SESSIONS_DIR/pm-agent.json"
local before_sessions=$(opencode session list 2>/dev/null | grep -oP '^ses_\w+' | sort)
local before_set="${before_sessions//$'\n'/|}"
local pm_context=$(kugetsu_get_pm_context)
if [ -n "$pm_context" ]; then
opencode run --fork --session "$base" "You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. $pm_context" 2>&1 || true
else
opencode run --fork --session "$base" "You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. Wait for instructions." 2>&1 || true
fi
local after_sessions=$(opencode session list 2>/dev/null | grep -oP '^ses_\w+' | sort)
local new_pm_session_id=""
while IFS= read -r sess; do
if [[ ! "$before_set" =~ \|${sess}\| ]] && [[ "$sess" != "$base" ]]; then
new_pm_session_id="$sess"
break
fi
done <<< "$after_sessions"
if [ -n "$new_pm_session_id" ]; then
printf '{"type": "pm_agent", "opencode_session_id": "%s", "created_at": "%s", "state": "idle"}\n' \
"$new_pm_session_id" "$(date -Iseconds)" > "$SESSIONS_DIR/pm-agent.json"
set_pm_agent_in_index "$new_pm_session_id"
echo "[FIX] PM agent recreated: $new_pm_session_id"
else
echo "[FIX] Warning: Could not detect new PM session ID"
fi
else
echo "[FIX] Cannot recreate PM agent: base session missing"
fi
else
echo "[FIX] PM agent is active, no fix needed"
fi
else
echo "[FIX] Cannot fix: PM agent not initialized. Run 'kugetsu init' first."
fi
fi
fi
}
DEBUG_MODE=false
set_debug_mode() {
@@ -365,7 +560,13 @@ cmd_init() {
local before_sessions=$(opencode session list 2>/dev/null | grep -oP '^ses_\w+' | sort)
local before_set="${before_sessions//$'\n'/|}"
opencode run --fork --session "$new_session_id" "You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. Wait for instructions." 2>&1 || true
local pm_context=$(kugetsu_get_pm_context)
local pm_prompt="You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. Wait for instructions."
if [ -n "$pm_context" ]; then
pm_prompt="You are a PM (Project Manager) agent. Your role is to coordinate task delegation and review PRs. $pm_context"
fi
opencode run --fork --session "$new_session_id" "$pm_prompt" 2>&1 || true
local after_sessions=$(opencode session list 2>/dev/null | grep -oP '^ses_\w+' | sort)
local new_pm_session_id=""
@@ -474,22 +675,22 @@ cmd_start() {
}
cmd_continue() {
local issue_ref=""
local session_name=""
local message=""
local args=("$@")
args=$(set_debug_mode "${args[@]}")
for arg in $args; do
if [ -z "$issue_ref" ]; then
issue_ref="$arg"
if [ -z "$session_name" ]; then
session_name="$arg"
elif [ -z "$message" ]; then
message="$arg"
fi
done
if [ -z "$issue_ref" ]; then
echo "Error: continue requires <issue-ref>" >&2
if [ -z "$session_name" ]; then
echo "Error: continue requires <session-name>" >&2
exit 1
fi
@@ -498,19 +699,17 @@ cmd_continue() {
exit 1
fi
validate_issue_ref "$issue_ref"
local session_file=$(get_session_for_issue "$issue_ref")
local session_file=$(get_session_for_issue "$session_name")
if [ -z "$session_file" ] || [ "$session_file" = "null" ]; then
echo "Error: No session found for '$issue_ref'" >&2
echo "Use 'kugetsu start $issue_ref <message>' to create one" >&2
echo "Error: No session found for '$session_name'" >&2
echo "Use 'kugetsu start <issue-ref> <message>' to create one" >&2
exit 1
fi
local session_path="$SESSIONS_DIR/$session_file"
if [ ! -f "$session_path" ]; then
echo "Error: Session file missing: $session_path" >&2
echo "Run 'kugetsu start $issue_ref <message>' to recreate" >&2
echo "Run 'kugetsu start <issue-ref> <message>' to recreate" >&2
exit 1
fi
@@ -522,7 +721,7 @@ cmd_continue() {
echo "Attempting to continue anyway..." >&2
fi
echo "Continuing session for '$issue_ref'..."
echo "Continuing session for '$session_name'..."
if [ -n "$worktree_path" ] && [ -d "$worktree_path" ]; then
echo "Using worktree: $worktree_path"
if [ "$DEBUG_MODE" = true ]; then
@@ -770,6 +969,15 @@ main() {
continue)
cmd_continue "$@"
;;
delegate)
cmd_delegate "$@"
;;
status)
cmd_status
;;
doctor)
cmd_doctor "$@"
;;
list)
cmd_list "$@"
;;

View File

@@ -48,10 +48,8 @@ echo "=== Phase 3a Chat Agent Setup (Optional) ==="
echo "To also install the Chat Agent skills for Phase 3a:"
echo ""
echo " 1. Link skills to Hermes:"
echo " mkdir -p ~/.hermes/skills/kugetsu-chat ~/.hermes/skills/kugetsu-pm ~/.hermes/skills/kugetsu-helpers"
echo " mkdir -p ~/.hermes/skills/kugetsu-chat"
echo " ln -sf /path/to/kugetsu/skills/kugetsu-chat ~/.hermes/skills/"
echo " ln -sf /path/to/kugetsu/skills/kugetsu-pm ~/.hermes/skills/"
echo " ln -sf /path/to/kugetsu/skills/kugetsu-helpers ~/.hermes/skills/"
echo ""
echo " 2. Install Chat Agent SOUL:"
echo " cp /path/to/kugetsu/skills/kugetsu-chat/SOUL.md ~/.hermes/SOUL-chat.md"
@@ -59,4 +57,7 @@ echo ""
echo " 3. Initialize kugetsu (requires TTY):"
echo " kugetsu init"
echo ""
echo " 4. Verify setup:"
echo " kugetsu status"
echo ""
echo "See docs/phase3a-setup.md for full installation guide."