From 7fa669b4c38efdba34183ccc21395cc17c717527 Mon Sep 17 00:00:00 2001 From: shokollm <270575765+shokollm@users.noreply.github.com> Date: Sun, 5 Apr 2026 20:57:51 +0000 Subject: [PATCH 1/2] fix(kugetsu): queue daemon runs PM agent in correct worktree with proper token - Load GITEA_TOKEN from ~/.kugetsu/env/default.env at daemon startup - Use --fork --session --dir instead of --continue to run in correct directory - Create worktree if it doesn't exist for the issue - Track forked session ID (not parent pm_session) for completion detection - Forked session ends when task completes, parent pm_session continues Fixes #156 --- .../kugetsu/scripts/kugetsu-queue-daemon.sh | 55 +++++++++++++++++-- 1 file changed, 49 insertions(+), 6 deletions(-) mode change 100755 => 100644 skills/kugetsu/scripts/kugetsu-queue-daemon.sh diff --git a/skills/kugetsu/scripts/kugetsu-queue-daemon.sh b/skills/kugetsu/scripts/kugetsu-queue-daemon.sh old mode 100755 new mode 100644 index d1d1e9f..77fd413 --- a/skills/kugetsu/scripts/kugetsu-queue-daemon.sh +++ b/skills/kugetsu/scripts/kugetsu-queue-daemon.sh @@ -8,7 +8,12 @@ source "$SCRIPT_DIR/kugetsu-index.sh" source "$SCRIPT_DIR/kugetsu-worktree.sh" source "$SCRIPT_DIR/kugetsu-log.sh" -# Check if a notified task has completed (session ended or has new commits) +# Load GITEA_TOKEN from default.env +if [ -f "$HOME/.kugetsu/env/default.env" ]; then + source "$HOME/.kugetsu/env/default.env" +fi + +# Check if a notified task has completed (forked session ended or has new commits) check_task_completion() { local item="$1" local queue_id=$(basename "$item" .json) @@ -16,15 +21,16 @@ check_task_completion() { [ "$state" = "notified" ] || return 0 - local session_id=$(python3 -c "import json; print(json.load(open('$item')).get('session_id', ''))" 2>/dev/null) + # Use opencode_session_id (the forked session, not the parent pm_session) + local session_id=$(python3 -c "import json; print(json.load(open('$item')).get('opencode_session_id', ''))" 2>/dev/null) local issue_ref=$(python3 -c "import json; print(json.load(open('$item')).get('issue_ref', ''))" 2>/dev/null) # If no session tracked, skip [ -n "$session_id" ] || return 0 - # Check if session still exists in opencode + # Check if forked session still exists in opencode if ! opencode session list 2>/dev/null | grep -q "$session_id"; then - # Session ended — check if work was done + # Forked session ended — check if work was done local worktree_path=$(issue_ref_to_worktree_path "$issue_ref" "$HOME/.kugetsu-worktrees") local has_commits=false @@ -64,10 +70,47 @@ while true; do pm_session=$(get_pm_agent_session_id) if [ -n "$pm_session" ] && [ "$pm_session" != "null" ]; then + # Compute worktree path for this issue + worktree_path=$(issue_ref_to_worktree_path "$issue_ref" "$HOME/.kugetsu-worktrees") + + # Ensure worktree exists, create if needed + if [ ! -d "$worktree_path" ]; then + echo "Creating worktree for $issue_ref at $worktree_path..." + create_worktree "$issue_ref" "$HOME/.kugetsu-worktrees" + fi + + # Capture sessions before fork to identify the new forked session + sessions_before=$(opencode session list 2>/dev/null || echo "") + log_file="$LOGS_DIR/delegate-$(date +%s).log" - nohup env GITEA_TOKEN="$GITEA_TOKEN" sh -c "opencode run '$message' --continue --session '$pm_session' >> '$log_file' 2>&1" > /dev/null 2>&1 & + # Use --fork --dir to run in the correct worktree directory + # The forked session will end when the task completes, while parent pm_session continues + (cd "$worktree_path" && nohup bash -c "export GITEA_TOKEN=$GITEA_TOKEN; opencode run '$message' --fork --session '$pm_session' --dir '$worktree_path'" >> "$log_file" 2>&1) & pid=$! - update_queue_item_state "$queue_id" "notified" "$pm_session" "$pid" + + # Wait for fork to initialize and capture new session + sleep 3 + + # Find the forked session ID by comparing session lists + sessions_after=$(opencode session list 2>/dev/null || echo "") + forked_session="" + while IFS= read -r line; do + session=$(echo "$line" | awk '{print $1}' | tr -d '[:space:]') + if [ -n "$session" ] && ! echo "$sessions_before" | grep -q "$session"; then + forked_session="$session" + break + fi + done <<< "$sessions_after" + + # Store the forked session ID (not the parent pm_session) for completion detection + if [ -n "$forked_session" ]; then + update_queue_item_state "$queue_id" "notified" "$forked_session" "$pid" + echo "Task $queue_id notified with forked session $forked_session for $issue_ref" + else + # Fallback: still update with empty session so task isn't stuck + update_queue_item_state "$queue_id" "notified" "" "$pid" + echo "Task $queue_id notified but could not capture forked session for $issue_ref" + fi fi fi done -- 2.49.1 From cbfc8a064614375598770820a0def4c678c65f78 Mon Sep 17 00:00:00 2001 From: shokollm <270575765+shokollm@users.noreply.github.com> Date: Sun, 5 Apr 2026 21:29:34 +0000 Subject: [PATCH 2/2] refactor(kugetsu): daemon uses cmd_start/cmd_continue instead of direct opencode calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move issue_ref_to_filename and filename_to_issue_ref to kugetsu-index.sh (where they logically belong, instead of in main kugetsu script) - Refactor queue daemon to use cmd_start/cmd_continue for session management - Daemon now checks if worktree/session exists → cmd_continue, else → cmd_start - Removes ~40 lines of direct opencode session forking logic from daemon - cmd_start/cmd_continue handle worktree creation, session forking, and tracking This simplifies the daemon significantly and centralizes session management in kugetsu-session.sh where it belongs. --- skills/kugetsu/scripts/kugetsu | 11 ---- skills/kugetsu/scripts/kugetsu-index.sh | 15 ++++- .../kugetsu/scripts/kugetsu-queue-daemon.sh | 56 +++++-------------- 3 files changed, 29 insertions(+), 53 deletions(-) diff --git a/skills/kugetsu/scripts/kugetsu b/skills/kugetsu/scripts/kugetsu index 43524c2..ab2e6bd 100755 --- a/skills/kugetsu/scripts/kugetsu +++ b/skills/kugetsu/scripts/kugetsu @@ -99,17 +99,6 @@ ensure_worktree_dir() { mkdir -p "$WORKTREES_DIR" } -issue_ref_to_filename() { - local issue_ref="$1" - echo "$issue_ref" | sed 's/[\/:]/-/g' | sed 's/#/-/' -} - -filename_to_issue_ref() { - local filename="$1" - local name="${filename%.json}" - echo "$name" | sed 's/-\([0-9]*\)$/#\1/' | sed 's/-/\//g' -} - issue_ref_to_context_file() { local issue_ref="$1" local context_filename=$(issue_ref_to_filename "$issue_ref") diff --git a/skills/kugetsu/scripts/kugetsu-index.sh b/skills/kugetsu/scripts/kugetsu-index.sh index 0be7814..eb85d26 100755 --- a/skills/kugetsu/scripts/kugetsu-index.sh +++ b/skills/kugetsu/scripts/kugetsu-index.sh @@ -130,6 +130,19 @@ session['pr_url'] = pr_url with open(session_path, 'w') as f: json.dump(session, f, indent=2) -print(f"Updated PR URL for $issue_ref: $pr_url") + print(f"Updated PR URL for $issue_ref: $pr_url") PYEOF } + +# Convert issue ref to session filename +issue_ref_to_filename() { + local issue_ref="$1" + echo "$issue_ref" | sed 's/[\/:]/-/g' | sed 's/#/-/' +} + +# Convert session filename back to issue ref +filename_to_issue_ref() { + local filename="$1" + local name="${filename%.json}" + echo "$name" | sed 's-\([0-9]*\)$-#\1-' | sed 's/-/\//g' +} diff --git a/skills/kugetsu/scripts/kugetsu-queue-daemon.sh b/skills/kugetsu/scripts/kugetsu-queue-daemon.sh index 77fd413..d1471f3 100644 --- a/skills/kugetsu/scripts/kugetsu-queue-daemon.sh +++ b/skills/kugetsu/scripts/kugetsu-queue-daemon.sh @@ -68,49 +68,23 @@ while true; do issue_ref=$(python3 -c "import json; print(json.load(open('$item')).get('issue_ref', ''))" 2>/dev/null) message=$(python3 -c "import json; print(json.load(open('$item')).get('message', ''))" 2>/dev/null) - pm_session=$(get_pm_agent_session_id) - if [ -n "$pm_session" ] && [ "$pm_session" != "null" ]; then - # Compute worktree path for this issue - worktree_path=$(issue_ref_to_worktree_path "$issue_ref" "$HOME/.kugetsu-worktrees") - - # Ensure worktree exists, create if needed - if [ ! -d "$worktree_path" ]; then - echo "Creating worktree for $issue_ref at $worktree_path..." - create_worktree "$issue_ref" "$HOME/.kugetsu-worktrees" - fi - - # Capture sessions before fork to identify the new forked session - sessions_before=$(opencode session list 2>/dev/null || echo "") - + # Source session management and use cmd_start/cmd_continue + source "$SCRIPT_DIR/kugetsu-session.sh" + + if worktree_exists "$issue_ref" "$HOME/.kugetsu-worktrees" || [ -f "$SESSIONS_DIR/$(issue_ref_to_filename "$issue_ref").json" ]; then + # Continue existing session log_file="$LOGS_DIR/delegate-$(date +%s).log" - # Use --fork --dir to run in the correct worktree directory - # The forked session will end when the task completes, while parent pm_session continues - (cd "$worktree_path" && nohup bash -c "export GITEA_TOKEN=$GITEA_TOKEN; opencode run '$message' --fork --session '$pm_session' --dir '$worktree_path'" >> "$log_file" 2>&1) & + cmd_continue "$issue_ref" "$message" >> "$log_file" 2>&1 & pid=$! - - # Wait for fork to initialize and capture new session - sleep 3 - - # Find the forked session ID by comparing session lists - sessions_after=$(opencode session list 2>/dev/null || echo "") - forked_session="" - while IFS= read -r line; do - session=$(echo "$line" | awk '{print $1}' | tr -d '[:space:]') - if [ -n "$session" ] && ! echo "$sessions_before" | grep -q "$session"; then - forked_session="$session" - break - fi - done <<< "$sessions_after" - - # Store the forked session ID (not the parent pm_session) for completion detection - if [ -n "$forked_session" ]; then - update_queue_item_state "$queue_id" "notified" "$forked_session" "$pid" - echo "Task $queue_id notified with forked session $forked_session for $issue_ref" - else - # Fallback: still update with empty session so task isn't stuck - update_queue_item_state "$queue_id" "notified" "" "$pid" - echo "Task $queue_id notified but could not capture forked session for $issue_ref" - fi + update_queue_item_state "$queue_id" "notified" "" "$pid" + echo "Task $queue_id continued for $issue_ref" + else + # Start new session + log_file="$LOGS_DIR/delegate-$(date +%s).log" + cmd_start "$issue_ref" "$message" >> "$log_file" 2>&1 & + pid=$! + update_queue_item_state "$queue_id" "notified" "" "$pid" + echo "Task $queue_id started for $issue_ref" fi fi done -- 2.49.1