Compare commits
11 Commits
1886c4a9c5
...
fix/issue-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f6a30f01c | ||
|
|
f39e39156a | ||
| deb18f1e32 | |||
|
|
cbfc8a0646 | ||
|
|
7fa669b4c3 | ||
| acb503471d | |||
|
|
1d4f190d97 | ||
|
|
ab0c4e1448 | ||
|
|
9bb8afe8c5 | ||
|
|
fd7a98b263 | ||
| 3942a915ff |
@@ -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")
|
||||
@@ -321,12 +310,31 @@ get_pending_tasks() {
|
||||
return
|
||||
fi
|
||||
|
||||
find "$QUEUE_ITEMS_DIR" -name "*.json" -type f 2>/dev/null | while read -r file; do
|
||||
local state=$(python3 -c "import json; print(json.load(open('$file')).get('state', ''))" 2>/dev/null || echo "")
|
||||
if [ "$state" = "pending" ]; then
|
||||
cat "$file"
|
||||
fi
|
||||
done | head -"$limit"
|
||||
python3 -c "
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
queue_dir = os.environ.get('QUEUE_ITEMS_DIR', '')
|
||||
limit = int(sys.argv[1]) if len(sys.argv) > 1 else 10
|
||||
|
||||
items = []
|
||||
if os.path.isdir(queue_dir):
|
||||
for filename in os.listdir(queue_dir):
|
||||
if filename.endswith('.json'):
|
||||
filepath = os.path.join(queue_dir, filename)
|
||||
try:
|
||||
with open(filepath) as f:
|
||||
data = json.load(f)
|
||||
if data.get('state') == 'pending':
|
||||
items.append(data)
|
||||
if len(items) >= limit:
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
print(json.dumps(items))
|
||||
" "$limit"
|
||||
}
|
||||
|
||||
get_queue_stats() {
|
||||
@@ -820,6 +828,18 @@ cmd_status() {
|
||||
return
|
||||
fi
|
||||
|
||||
local opencode_sessions=$(opencode session list 2>/dev/null | grep -oP '^ses_\w+' || true)
|
||||
|
||||
if ! echo "$opencode_sessions" | grep -q "^${base}$"; then
|
||||
echo "error: base session '$base' not found in opencode"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! echo "$opencode_sessions" | grep -q "^${pm_agent}$"; then
|
||||
echo "error: pm_agent session '$pm_agent' not found in opencode"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "ok"
|
||||
}
|
||||
|
||||
|
||||
@@ -133,3 +133,16 @@ with open(session_path, 'w') as f:
|
||||
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'
|
||||
}
|
||||
|
||||
66
skills/kugetsu/scripts/kugetsu-queue-daemon.sh
Executable file → Normal file
66
skills/kugetsu/scripts/kugetsu-queue-daemon.sh
Executable file → Normal file
@@ -8,8 +8,55 @@ source "$SCRIPT_DIR/kugetsu-index.sh"
|
||||
source "$SCRIPT_DIR/kugetsu-worktree.sh"
|
||||
source "$SCRIPT_DIR/kugetsu-log.sh"
|
||||
|
||||
load_agent_env "pm-agent"
|
||||
|
||||
# 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)
|
||||
local state=$(python3 -c "import json; print(json.load(open('$item')).get('state', ''))" 2>/dev/null)
|
||||
|
||||
[ "$state" = "notified" ] || return 0
|
||||
|
||||
# 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 forked session still exists in opencode
|
||||
if ! opencode session list 2>/dev/null | grep -q "$session_id"; then
|
||||
# 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
|
||||
|
||||
if [ -d "$worktree_path" ] && [ -d "$worktree_path/.git" ]; then
|
||||
# Check if worktree has new commits beyond origin/main
|
||||
if [ -n "$(git -C "$worktree_path" log --oneline origin/main..HEAD 2>/dev/null)" ]; then
|
||||
has_commits=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$has_commits" = true ]; then
|
||||
update_queue_item_state "$queue_id" "completed"
|
||||
echo "Task $queue_id ($issue_ref) completed — new commits found"
|
||||
else
|
||||
update_queue_item_state "$queue_id" "error"
|
||||
echo "Task $queue_id ($issue_ref) marked error — no commits found after session ended"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
while true; do
|
||||
# Check completion of notified tasks
|
||||
if [ -d "$QUEUE_ITEMS_DIR" ]; then
|
||||
for item in "$QUEUE_ITEMS_DIR"/*.json; do
|
||||
[ -f "$item" ] || continue
|
||||
check_task_completion "$item"
|
||||
done
|
||||
|
||||
# Process pending tasks
|
||||
for item in "$QUEUE_ITEMS_DIR"/*.json; do
|
||||
[ -f "$item" ] || continue
|
||||
state=$(python3 -c "import json; print(json.load(open('$item')).get('state', ''))" 2>/dev/null)
|
||||
@@ -18,12 +65,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
|
||||
# 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"
|
||||
GITEA_TOKEN="${GITEA_TOKEN:-}" nohup sh -c "opencode run '$message' --continue --session '$pm_session' >> '$log_file' 2>&1" > /dev/null 2>&1 &
|
||||
cmd_continue "$issue_ref" "$message" >> "$log_file" 2>&1 &
|
||||
pid=$!
|
||||
update_queue_item_state "$queue_id" "notified" "$pm_session" "$pid"
|
||||
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
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
set -euo pipefail
|
||||
|
||||
KUGETSU="./skills/kugetsu/scripts/kugetsu"
|
||||
TEST_KUGETSU_DIR="/tmp/test-kugetsu-$$"
|
||||
export KUGETSU_DIR="$TEST_KUGETSU_DIR"
|
||||
TEST_ISSUE_REF="github.com/shoko/kugetsu#14"
|
||||
TEST_DISCUSS_REF="github.com/shoko/kugetsu#-discuss"
|
||||
TEST_BASE_SESSION_ID="ses_test_base_123"
|
||||
@@ -18,28 +20,28 @@ PASS=0
|
||||
FAIL=0
|
||||
|
||||
cleanup() {
|
||||
rm -rf ~/.kugetsu/sessions/* ~/.kugetsu/worktrees/* ~/.kugetsu/index.json 2>/dev/null || true
|
||||
rm -rf "$TEST_KUGETSU_DIR" 2>/dev/null || true
|
||||
}
|
||||
|
||||
setup_mock_base() {
|
||||
mkdir -p ~/.kugetsu/sessions ~/.kugetsu/worktrees
|
||||
cat > ~/.kugetsu/index.json << EOF
|
||||
mkdir -p "$TEST_KUGETSU_DIR/sessions" "$TEST_KUGETSU_DIR/worktrees"
|
||||
cat > "$TEST_KUGETSU_DIR/index.json" << EOF
|
||||
{
|
||||
"base": "$TEST_BASE_SESSION_ID",
|
||||
"pm_agent": "$TEST_PM_AGENT_SESSION_ID",
|
||||
"issues": {}
|
||||
}
|
||||
EOF
|
||||
cat > ~/.kugetsu/sessions/$TEST_BASE_SESSION_FILE << EOF
|
||||
cat > "$TEST_KUGETSU_DIR/sessions/$TEST_BASE_SESSION_FILE" << EOF
|
||||
{"type": "base", "opencode_session_id": "$TEST_BASE_SESSION_ID", "created_at": "2026-03-29T18:00:00+02:00", "state": "idle"}
|
||||
EOF
|
||||
cat > ~/.kugetsu/sessions/$TEST_PM_AGENT_SESSION_FILE << EOF
|
||||
cat > "$TEST_KUGETSU_DIR/sessions/$TEST_PM_AGENT_SESSION_FILE" << EOF
|
||||
{"type": "pm_agent", "opencode_session_id": "$TEST_PM_AGENT_SESSION_ID", "created_at": "2026-03-29T18:00:00+02:00", "state": "idle"}
|
||||
EOF
|
||||
}
|
||||
|
||||
setup_mock_forked() {
|
||||
cat > ~/.kugetsu/index.json << EOF
|
||||
cat > "$TEST_KUGETSU_DIR/index.json" << EOF
|
||||
{
|
||||
"base": "$TEST_BASE_SESSION_ID",
|
||||
"pm_agent": "$TEST_PM_AGENT_SESSION_ID",
|
||||
@@ -48,7 +50,7 @@ setup_mock_forked() {
|
||||
}
|
||||
}
|
||||
EOF
|
||||
cat > ~/.kugetsu/sessions/$TEST_FORKED_SESSION_FILE << EOF
|
||||
cat > "$TEST_KUGETSU_DIR/sessions/$TEST_FORKED_SESSION_FILE" << EOF
|
||||
{"type": "forked", "issue_ref": "$TEST_ISSUE_REF", "opencode_session_id": "ses_forked_789", "worktree_path": "/tmp/test-worktree", "created_at": "2026-03-29T18:00:00+02:00", "state": "idle"}
|
||||
EOF
|
||||
}
|
||||
@@ -112,16 +114,16 @@ echo ""
|
||||
|
||||
# Test 3b: start fails without pm-agent
|
||||
echo "--- Test: start without pm-agent session ---"
|
||||
rm -f ~/.kugetsu/index.json ~/.kugetsu/sessions/*
|
||||
mkdir -p ~/.kugetsu/sessions
|
||||
cat > ~/.kugetsu/index.json << EOF
|
||||
rm -f $TEST_KUGETSU_DIR/index.json $TEST_KUGETSU_DIR/sessions/*
|
||||
mkdir -p $TEST_KUGETSU_DIR/sessions
|
||||
cat > $TEST_KUGETSU_DIR/index.json << EOF
|
||||
{
|
||||
"base": "$TEST_BASE_SESSION_ID",
|
||||
"pm_agent": null,
|
||||
"issues": {}
|
||||
}
|
||||
EOF
|
||||
cat > ~/.kugetsu/sessions/$TEST_BASE_SESSION_FILE << EOF
|
||||
cat > $TEST_KUGETSU_DIR/sessions/$TEST_BASE_SESSION_FILE << EOF
|
||||
{"type": "base", "opencode_session_id": "$TEST_BASE_SESSION_ID", "created_at": "2026-03-29T18:00:00+02:00", "state": "idle"}
|
||||
EOF
|
||||
OUTPUT=$($KUGETSU start github.com/shoko/kugetsu#14 "test" 2>&1 || true)
|
||||
@@ -176,7 +178,7 @@ echo ""
|
||||
|
||||
# Test 6c: index.json has pm_agent field
|
||||
echo "--- Test: index.json has pm_agent field ---"
|
||||
if grep -q '"pm_agent"' ~/.kugetsu/index.json; then
|
||||
if grep -q '"pm_agent"' $TEST_KUGETSU_DIR/index.json; then
|
||||
pass "index.json has pm_agent field"
|
||||
else
|
||||
fail "index.json missing pm_agent field"
|
||||
@@ -227,12 +229,12 @@ echo ""
|
||||
echo "--- Test: destroy --pm-agent -y ---"
|
||||
setup_mock_base
|
||||
OUTPUT=$($KUGETSU destroy --pm-agent -y 2>&1 || true)
|
||||
if [ -f ~/.kugetsu/sessions/$TEST_PM_AGENT_SESSION_FILE ]; then
|
||||
if [ -f $TEST_KUGETSU_DIR/sessions/$TEST_PM_AGENT_SESSION_FILE ]; then
|
||||
fail "destroy --pm-agent -y removes pm-agent file"
|
||||
else
|
||||
pass "destroy --pm-agent -y removes pm-agent file"
|
||||
fi
|
||||
if grep -q '"pm_agent": null' ~/.kugetsu/index.json; then
|
||||
if grep -q '"pm_agent": null' $TEST_KUGETSU_DIR/index.json; then
|
||||
pass "destroy --pm-agent -y sets pm_agent to null in index"
|
||||
else
|
||||
fail "destroy --pm-agent -y should set pm_agent to null"
|
||||
@@ -243,7 +245,7 @@ echo ""
|
||||
echo "--- Test: destroy --base -y ---"
|
||||
setup_mock_base
|
||||
OUTPUT=$($KUGETSU destroy --base -y 2>&1 || true)
|
||||
if [ -f ~/.kugetsu/sessions/$TEST_BASE_SESSION_FILE ]; then
|
||||
if [ -f $TEST_KUGETSU_DIR/sessions/$TEST_BASE_SESSION_FILE ]; then
|
||||
fail "destroy --base -y removes base file"
|
||||
else
|
||||
pass "destroy --base -y removes base file"
|
||||
@@ -292,7 +294,7 @@ echo ""
|
||||
|
||||
# Test 15: worktree path in session file
|
||||
echo "--- Test: worktree_path in session file ---"
|
||||
if grep -q "worktree_path" ~/.kugetsu/sessions/$TEST_FORKED_SESSION_FILE; then
|
||||
if grep -q "worktree_path" $TEST_KUGETSU_DIR/sessions/$TEST_FORKED_SESSION_FILE; then
|
||||
pass "session file contains worktree_path"
|
||||
else
|
||||
fail "session file missing worktree_path"
|
||||
@@ -303,7 +305,7 @@ echo ""
|
||||
echo "--- Test: prune with orphaned worktree ---"
|
||||
cleanup
|
||||
setup_mock_base
|
||||
mkdir -p ~/.kugetsu/worktrees/orphaned-worktree
|
||||
mkdir -p $TEST_KUGETSU_DIR/worktrees/orphaned-worktree
|
||||
OUTPUT=$($KUGETSU prune 2>&1 || true)
|
||||
if echo "$OUTPUT" | grep -q "orphaned worktree"; then
|
||||
pass "prune detects orphaned worktree"
|
||||
@@ -315,7 +317,7 @@ echo ""
|
||||
# Test 17: prune --force removes orphaned worktrees
|
||||
echo "--- Test: prune --force removes orphaned worktrees ---"
|
||||
OUTPUT=$($KUGETSU prune --force 2>&1 || true)
|
||||
if [ -d ~/.kugetsu/worktrees/orphaned-worktree ]; then
|
||||
if [ -d $TEST_KUGETSU_DIR/worktrees/orphaned-worktree ]; then
|
||||
fail "prune --force should remove orphaned worktree"
|
||||
else
|
||||
pass "prune --force removes orphaned worktree"
|
||||
@@ -332,10 +334,10 @@ echo ""
|
||||
echo "--- Test: destroy removes worktree ---"
|
||||
cleanup
|
||||
setup_mock_forked
|
||||
# remove_worktree_for_issue derives path from issue ref: ~/.kugetsu/worktrees/github.com-shoko-kugetsu-14
|
||||
mkdir -p ~/.kugetsu/worktrees/github.com-shoko-kugetsu-14
|
||||
# remove_worktree_for_issue derives path from issue ref: $TEST_KUGETSU_DIR/worktrees/github.com-shoko-kugetsu-14
|
||||
mkdir -p $TEST_KUGETSU_DIR/worktrees/github.com-shoko-kugetsu-14
|
||||
OUTPUT=$($KUGETSU destroy github.com/shoko/kugetsu#14 -y 2>&1 || true)
|
||||
if [ -d ~/.kugetsu/worktrees/github.com-shoko-kugetsu-14 ]; then
|
||||
if [ -d $TEST_KUGETSU_DIR/worktrees/github.com-shoko-kugetsu-14 ]; then
|
||||
fail "destroy should remove worktree"
|
||||
else
|
||||
pass "destroy removes worktree"
|
||||
@@ -345,7 +347,7 @@ echo ""
|
||||
# Test 20: session file properly formatted for v2.2
|
||||
echo "--- Test: session file format v2.2 ---"
|
||||
setup_mock_forked
|
||||
SESSION_CONTENT=$(cat ~/.kugetsu/sessions/$TEST_FORKED_SESSION_FILE)
|
||||
SESSION_CONTENT=$(cat $TEST_KUGETSU_DIR/sessions/$TEST_FORKED_SESSION_FILE)
|
||||
if echo "$SESSION_CONTENT" | grep -q '"type": "forked"' && \
|
||||
echo "$SESSION_CONTENT" | grep -q '"worktree_path"'; then
|
||||
pass "session file has v2.2 format"
|
||||
@@ -367,8 +369,8 @@ echo ""
|
||||
|
||||
# Test 22: status when base missing
|
||||
echo "--- Test: status (base missing) ---"
|
||||
mkdir -p ~/.kugetsu/sessions
|
||||
cat > ~/.kugetsu/index.json << EOF
|
||||
mkdir -p $TEST_KUGETSU_DIR/sessions
|
||||
cat > $TEST_KUGETSU_DIR/index.json << EOF
|
||||
{
|
||||
"base": null,
|
||||
"pm_agent": "$TEST_PM_AGENT_SESSION_ID",
|
||||
@@ -385,7 +387,7 @@ echo ""
|
||||
|
||||
# Test 23: status when pm-agent missing
|
||||
echo "--- Test: status (pm-agent missing) ---"
|
||||
cat > ~/.kugetsu/index.json << EOF
|
||||
cat > $TEST_KUGETSU_DIR/index.json << EOF
|
||||
{
|
||||
"base": "$TEST_BASE_SESSION_ID",
|
||||
"pm_agent": null,
|
||||
@@ -402,7 +404,7 @@ echo ""
|
||||
|
||||
# Test 24: status when pm-agent is "None" (Python None output)
|
||||
echo "--- Test: status (pm-agent is Python None) ---"
|
||||
cat > ~/.kugetsu/index.json << EOF
|
||||
cat > $TEST_KUGETSU_DIR/index.json << EOF
|
||||
{
|
||||
"base": "$TEST_BASE_SESSION_ID",
|
||||
"pm_agent": "None",
|
||||
@@ -445,8 +447,8 @@ echo ""
|
||||
# Test 27: delegate when pm-agent missing
|
||||
echo "--- Test: delegate (pm-agent missing) ---"
|
||||
cleanup
|
||||
mkdir -p ~/.kugetsu/sessions ~/.kugetsu/worktrees
|
||||
cat > ~/.kugetsu/index.json << EOF
|
||||
mkdir -p $TEST_KUGETSU_DIR/sessions $TEST_KUGETSU_DIR/worktrees
|
||||
cat > $TEST_KUGETSU_DIR/index.json << EOF
|
||||
{
|
||||
"base": "$TEST_BASE_SESSION_ID",
|
||||
"pm_agent": null,
|
||||
@@ -508,7 +510,7 @@ echo ""
|
||||
# Test 32: delegate is fire-and-forget (returns immediately)
|
||||
echo "--- Test: delegate is fire-and-forget ---"
|
||||
setup_mock_base
|
||||
mkdir -p ~/.kugetsu/logs
|
||||
mkdir -p $TEST_KUGETSU_DIR/logs
|
||||
START=$(date +%s)
|
||||
OUTPUT=$($KUGETSU delegate "test fire-and-forget" 2>&1 || true)
|
||||
END=$(date +%s)
|
||||
@@ -527,10 +529,10 @@ echo ""
|
||||
# Test 33: delegate creates log file
|
||||
echo "--- Test: delegate creates log file ---"
|
||||
setup_mock_base
|
||||
LOG_COUNT_BEFORE=$(ls ~/.kugetsu/logs/*.log 2>/dev/null | wc -l)
|
||||
LOG_COUNT_BEFORE=$(ls $TEST_KUGETSU_DIR/logs/*.log 2>/dev/null | wc -l)
|
||||
$KUGETSU delegate "test log file" 2>&1 || true
|
||||
sleep 1
|
||||
LOG_COUNT_AFTER=$(ls ~/.kugetsu/logs/*.log 2>/dev/null | wc -l)
|
||||
LOG_COUNT_AFTER=$(ls $TEST_KUGETSU_DIR/logs/*.log 2>/dev/null | wc -l)
|
||||
if [ $LOG_COUNT_AFTER -gt $LOG_COUNT_BEFORE ]; then
|
||||
pass "delegate creates log file"
|
||||
else
|
||||
@@ -558,10 +560,10 @@ echo ""
|
||||
|
||||
# Test E2: env set creates file
|
||||
echo "--- Test: env set creates env file ---"
|
||||
mkdir -p ~/.kugetsu/env
|
||||
rm -f ~/.kugetsu/env/pm-agent.env
|
||||
mkdir -p $TEST_KUGETSU_DIR/env
|
||||
rm -f $TEST_KUGETSU_DIR/env/pm-agent.env
|
||||
$KUGETSU env set TEST_VAR "test_value" pm-agent 2>&1 || true
|
||||
if [ -f ~/.kugetsu/env/pm-agent.env ]; then
|
||||
if [ -f $TEST_KUGETSU_DIR/env/pm-agent.env ]; then
|
||||
pass "env set creates pm-agent.env file"
|
||||
else
|
||||
fail "env set did not create pm-agent.env"
|
||||
@@ -570,7 +572,7 @@ echo ""
|
||||
|
||||
# Test E3: env show masks sensitive values
|
||||
echo "--- Test: env show masks sensitive values ---"
|
||||
cat > ~/.kugetsu/env/pm-agent.env << 'ENVEOF'
|
||||
cat > $TEST_KUGETSU_DIR/env/pm-agent.env << 'ENVEOF'
|
||||
export GITEA_TOKEN="secret_token_123"
|
||||
export MY_VAR="visible_value"
|
||||
ENVEOF
|
||||
@@ -584,14 +586,14 @@ echo ""
|
||||
|
||||
# Test E4: Variables exported to child processes via set -a
|
||||
echo "--- Test: set -a exports variables to children ---"
|
||||
mkdir -p ~/.kugetsu/env
|
||||
cat > ~/.kugetsu/env/test.env << 'ENVEOF'
|
||||
mkdir -p $TEST_KUGETSU_DIR/env
|
||||
cat > $TEST_KUGETSU_DIR/env/test.env << 'ENVEOF'
|
||||
export EXPORT_TEST="exported_value"
|
||||
SIMPLE_TEST="not_exported"
|
||||
ENVEOF
|
||||
|
||||
# Simulate what cmd_delegate does
|
||||
ENV_FILE="~/.kugetsu/env/test.env"
|
||||
ENV_FILE="$TEST_KUGETSU_DIR/env/test.env"
|
||||
env_sh="set -a; source '$ENV_FILE'; set +a; "
|
||||
result=$(bash -c "${env_sh}bash -c 'echo \$EXPORT_TEST'")
|
||||
|
||||
@@ -604,11 +606,11 @@ echo ""
|
||||
|
||||
# Test E5: pm-agent.env takes precedence
|
||||
echo "--- Test: pm-agent.env takes precedence over default ---"
|
||||
mkdir -p ~/.kugetsu/env
|
||||
cat > ~/.kugetsu/env/default.env << 'ENVEOF'
|
||||
mkdir -p $TEST_KUGETSU_DIR/env
|
||||
cat > $TEST_KUGETSU_DIR/env/default.env << 'ENVEOF'
|
||||
export GITEA_TOKEN="default_token"
|
||||
ENVEOF
|
||||
cat > ~/.kugetsu/env/pm-agent.env << 'ENVEOF'
|
||||
cat > $TEST_KUGETSU_DIR/env/pm-agent.env << 'ENVEOF'
|
||||
export GITEA_TOKEN="pm_agent_token"
|
||||
ENVEOF
|
||||
|
||||
@@ -644,7 +646,7 @@ fi
|
||||
echo ""
|
||||
|
||||
# Cleanup env files
|
||||
rm -rf ~/.kugetsu/env 2>/dev/null || true
|
||||
rm -rf $TEST_KUGETSU_DIR/env 2>/dev/null || true
|
||||
|
||||
# Test E7: fix_session_permissions function exists
|
||||
echo "--- Test: fix_session_permissions function exists ---"
|
||||
@@ -736,7 +738,7 @@ PASS=0
|
||||
FAIL=0
|
||||
|
||||
test_cleanup() {
|
||||
rm -rf ~/.kugetsu/sessions/* ~/.kugetsu/worktrees/* ~/.kugetsu/index.json ~/.kugetsu/logs/* ~/.kugetsu/.agent_count ~/.kugetsu/.agent_lock 2>/dev/null || true
|
||||
rm -rf $TEST_KUGETSU_DIR/sessions/* $TEST_KUGETSU_DIR/worktrees/* $TEST_KUGETSU_DIR/index.json $TEST_KUGETSU_DIR/logs/* $TEST_KUGETSU_DIR/.agent_count $TEST_KUGETSU_DIR/.agent_lock 2>/dev/null || true
|
||||
}
|
||||
|
||||
pass() {
|
||||
@@ -750,25 +752,25 @@ fail() {
|
||||
}
|
||||
|
||||
setup_mock_sessions() {
|
||||
mkdir -p ~/.kugetsu/sessions ~/.kugetsu/worktrees ~/.kugetsu/logs
|
||||
cat > ~/.kugetsu/index.json << INDEX
|
||||
mkdir -p $TEST_KUGETSU_DIR/sessions $TEST_KUGETSU_DIR/worktrees $TEST_KUGETSU_DIR/logs
|
||||
cat > $TEST_KUGETSU_DIR/index.json << INDEX
|
||||
{
|
||||
"base": "ses_test_base_123",
|
||||
"pm_agent": "ses_test_pm_456",
|
||||
"issues": {}
|
||||
}
|
||||
INDEX
|
||||
echo '{"type": "base", "opencode_session_id": "ses_test_base_123", "created_at": "2026-03-29T18:00:00+02:00", "state": "idle"}' > ~/.kugetsu/sessions/base.json
|
||||
echo '{"type": "pm_agent", "opencode_session_id": "ses_test_pm_456", "created_at": "2026-03-29T18:00:00+02:00", "state": "idle"}' > ~/.kugetsu/sessions/pm-agent.json
|
||||
echo '{"type": "base", "opencode_session_id": "ses_test_base_123", "created_at": "2026-03-29T18:00:00+02:00", "state": "idle"}' > $TEST_KUGETSU_DIR/sessions/base.json
|
||||
echo '{"type": "pm_agent", "opencode_session_id": "ses_test_pm_456", "created_at": "2026-03-29T18:00:00+02:00", "state": "idle"}' > $TEST_KUGETSU_DIR/sessions/pm-agent.json
|
||||
}
|
||||
|
||||
# Test C1: Agent count file is initialized to 0
|
||||
echo "--- Test: agent count file initialized ---"
|
||||
test_cleanup
|
||||
mkdir -p ~/.kugetsu/sessions ~/.kugetsu/worktrees
|
||||
mkdir -p $TEST_KUGETSU_DIR/sessions $TEST_KUGETSU_DIR/worktrees
|
||||
$KUGETSU list > /dev/null 2>&1 || true
|
||||
if [ -f ~/.kugetsu/.agent_count ]; then
|
||||
COUNT=$(cat ~/.kugetsu/.agent_count)
|
||||
if [ -f $TEST_KUGETSU_DIR/.agent_count ]; then
|
||||
COUNT=$(cat $TEST_KUGETSU_DIR/.agent_count)
|
||||
if [ "$COUNT" = "0" ]; then
|
||||
pass "agent count file initialized to 0"
|
||||
else
|
||||
@@ -795,10 +797,10 @@ test_cleanup
|
||||
setup_mock_sessions
|
||||
|
||||
# Initialize count to 0
|
||||
echo 0 > ~/.kugetsu/.agent_count
|
||||
echo 0 > $TEST_KUGETSU_DIR/.agent_count
|
||||
|
||||
# Verify initial state
|
||||
INITIAL=$(cat ~/.kugetsu/.agent_count)
|
||||
INITIAL=$(cat $TEST_KUGETSU_DIR/.agent_count)
|
||||
if [ "$INITIAL" = "0" ]; then
|
||||
pass "agent count starts at 0"
|
||||
else
|
||||
@@ -809,7 +811,7 @@ fi
|
||||
$KUGETSU list > /dev/null 2>&1
|
||||
|
||||
# Verify count is still 0 (no slot leak)
|
||||
AFTER=$(cat ~/.kugetsu/.agent_count)
|
||||
AFTER=$(cat $TEST_KUGETSU_DIR/.agent_count)
|
||||
if [ "$AFTER" = "0" ]; then
|
||||
pass "agent count stays 0 after list (no leak)"
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user