Replace fragile patterns like: python3 -c "import json; print(json.load(...))" | grep echo "$json" | python3 -c "import sys,json; ...
354 lines
9.7 KiB
Bash
Executable File
354 lines
9.7 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
read_index() {
|
|
if [ -f "$INDEX_FILE" ]; then
|
|
cat "$INDEX_FILE"
|
|
else
|
|
echo '{"base": null, "pm_agent": null, "issues": {}}'
|
|
fi
|
|
}
|
|
|
|
write_index() {
|
|
local base="$1"
|
|
local pm_agent="$2"
|
|
local issues_json="$3"
|
|
local temp_file="$INDEX_FILE.tmp.$$"
|
|
printf '{"base": %s, "pm_agent": %s, "issues": %s}\n' "$base" "$pm_agent" "$issues_json" > "$temp_file"
|
|
|
|
if ! python3 -c "import json; json.load(open('$temp_file'))" 2>/dev/null; then
|
|
echo "Error: write_index would create malformed JSON, aborting. base=$base, pm_agent=$pm_agent, issues_json=$issues_json" >&2
|
|
rm -f "$temp_file"
|
|
return 1
|
|
fi
|
|
|
|
mv "$temp_file" "$INDEX_FILE"
|
|
}
|
|
|
|
get_base_session_id() {
|
|
local index=$(read_index)
|
|
echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('base') or '')"
|
|
}
|
|
|
|
get_pm_agent_session_id() {
|
|
local index=$(read_index)
|
|
echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('pm_agent') or '')"
|
|
}
|
|
|
|
get_session_for_issue() {
|
|
local issue_ref="$1"
|
|
local index=$(read_index)
|
|
echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('issues', {}).get('$issue_ref') or 'null')"
|
|
}
|
|
|
|
set_base_in_index() {
|
|
local session_id="$1"
|
|
local index=$(read_index)
|
|
local pm_agent=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('pm_agent') or 'null')")
|
|
local issues=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d.get('issues', {})))")
|
|
|
|
if [ "$session_id" = "null" ]; then
|
|
write_index "null" "$pm_agent" "$issues"
|
|
else
|
|
if [ "$pm_agent" = "null" ]; then
|
|
write_index "\"$session_id\"" "null" "$issues"
|
|
else
|
|
write_index "\"$session_id\"" "\"$pm_agent\"" "$issues"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
set_pm_agent_in_index() {
|
|
local session_id="$1"
|
|
local index=$(read_index)
|
|
local base=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('base') or 'null')")
|
|
local issues=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d.get('issues', {})))")
|
|
|
|
if [ "$session_id" = "null" ]; then
|
|
write_index "$base" "null" "$issues"
|
|
else
|
|
if [ "$base" = "null" ]; then
|
|
write_index "null" "\"$session_id\"" "$issues"
|
|
else
|
|
write_index "\"$base\"" "\"$session_id\"" "$issues"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
add_issue_to_index() {
|
|
local issue_ref="$1"
|
|
local session_file="$2"
|
|
|
|
local index=$(read_index)
|
|
local base=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('base') or 'null')")
|
|
local pm_agent=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('pm_agent') or 'null')")
|
|
|
|
local issues=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d.get('issues', {})))")
|
|
|
|
issues=$(python3 -c "import sys, json; d=json.load(sys.stdin); d['$issue_ref']='$session_file'; print(json.dumps(d))" <<< "$issues")
|
|
|
|
if [ "$base" = "null" ]; then
|
|
if [ "$pm_agent" = "null" ]; then
|
|
write_index "null" "null" "$issues"
|
|
else
|
|
write_index "null" "\"$pm_agent\"" "$issues"
|
|
fi
|
|
else
|
|
if [ "$pm_agent" = "null" ]; then
|
|
write_index "\"$base\"" "null" "$issues"
|
|
else
|
|
write_index "\"$base\"" "\"$pm_agent\"" "$issues"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
remove_issue_from_index() {
|
|
local issue_ref="$1"
|
|
|
|
local index=$(read_index)
|
|
local base=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('base') or 'null')")
|
|
local pm_agent=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('pm_agent') or 'null')")
|
|
|
|
local issues=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d.get('issues', {})))")
|
|
|
|
issues=$(python3 -c "import sys, json; d=json.load(sys.stdin); d.pop('$issue_ref', None); print(json.dumps(d))" <<< "$issues")
|
|
|
|
if [ "$base" = "null" ]; then
|
|
if [ "$pm_agent" = "null" ]; then
|
|
write_index "null" "null" "$issues"
|
|
else
|
|
write_index "null" "\"$pm_agent\"" "$issues"
|
|
fi
|
|
else
|
|
if [ "$pm_agent" = "null" ]; then
|
|
write_index "\"$base\"" "null" "$issues"
|
|
else
|
|
write_index "\"$base\"" "\"$pm_agent\"" "$issues"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
validate_issue_ref() {
|
|
local issue_ref="$1"
|
|
|
|
if [[ ! "$issue_ref" =~ ^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+#[0-9]+$ ]]; then
|
|
echo "Error: Invalid issue ref format: '$issue_ref'" >&2
|
|
echo "Expected format: instance/user/repo#number" >&2
|
|
echo "Example: github.com/shoko/kugetsu#14" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
read_json_file() {
|
|
local file_path="$1"
|
|
if [ -f "$file_path" ]; then
|
|
cat "$file_path"
|
|
else
|
|
echo "{}"
|
|
fi
|
|
}
|
|
|
|
write_json_file() {
|
|
local file_path="$1"
|
|
local json_content="$2"
|
|
local temp_file="$file_path.tmp.$$"
|
|
|
|
printf '%s' "$json_content" > "$temp_file"
|
|
|
|
if ! python3 -c "import json; json.load(open('$temp_file'))" 2>/dev/null; then
|
|
echo "Error: write_json_file would create malformed JSON: $file_path" >&2
|
|
rm -f "$temp_file"
|
|
return 1
|
|
fi
|
|
|
|
mv "$temp_file" "$file_path"
|
|
}
|
|
|
|
get_json_value() {
|
|
local file_path="$1"
|
|
local key="$2"
|
|
local default="${3:-}"
|
|
|
|
if [ ! -f "$file_path" ]; then
|
|
echo "$default"
|
|
return
|
|
fi
|
|
|
|
python3 -c "import json; print(json.load(open('$file_path')).get('$key', '$default'))" 2>/dev/null || echo "$default"
|
|
}
|
|
|
|
set_json_value() {
|
|
local file_path="$1"
|
|
local key="$2"
|
|
local value="$3"
|
|
|
|
if [ ! -f "$file_path" ]; then
|
|
printf '{"%s": "%s"}\n' "$key" "$value" > "$file_path"
|
|
return
|
|
fi
|
|
|
|
python3 << PYEOF
|
|
import json
|
|
import sys
|
|
|
|
file_path = "$file_path"
|
|
key = "$key"
|
|
value = "$value"
|
|
|
|
try:
|
|
with open(file_path, 'r') as f:
|
|
data = json.load(f)
|
|
except:
|
|
data = {}
|
|
|
|
data[key] = value
|
|
|
|
with open(file_path, 'w') as f:
|
|
json.dump(data, f, indent=2)
|
|
|
|
print(f"Set $key = $value in $file_path")
|
|
PYEOF
|
|
}
|
|
|
|
update_session_pr_url() {
|
|
local issue_ref="$1"
|
|
local pr_url="$2"
|
|
|
|
local session_file=$(get_session_for_issue "$issue_ref")
|
|
if [ -z "$session_file" ] || [ "$session_file" = "null" ]; then
|
|
echo "Error: No session found for '$issue_ref'" >&2
|
|
return 1
|
|
fi
|
|
|
|
local session_path="$SESSIONS_DIR/$session_file"
|
|
if [ ! -f "$session_path" ]; then
|
|
echo "Error: Session file not found: $session_path" >&2
|
|
return 1
|
|
fi
|
|
|
|
python3 << PYEOF
|
|
import json
|
|
|
|
session_path = "$session_path"
|
|
pr_url = "$pr_url"
|
|
|
|
with open(session_path, 'r') as f:
|
|
session = json.load(f)
|
|
|
|
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")
|
|
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'
|
|
}
|
|
|
|
# Add notification to notifications file
|
|
kugetsu_add_notification() {
|
|
local type="$1"
|
|
local message="$2"
|
|
local issue_ref="${3:-}"
|
|
local gitea_url="${4:-}"
|
|
|
|
mkdir -p "$(dirname "$NOTIFICATIONS_FILE")"
|
|
|
|
python3 << PYEOF
|
|
import json
|
|
import os
|
|
from datetime import datetime
|
|
|
|
notification = {
|
|
"type": "$type",
|
|
"message": "$message",
|
|
"issue_ref": "$issue_ref" if "$issue_ref" else None,
|
|
"gitea_url": "$gitea_url" if "$gitea_url" else None,
|
|
"timestamp": datetime.now().isoformat(),
|
|
"read": False
|
|
}
|
|
|
|
file_path = os.path.expanduser("$NOTIFICATIONS_FILE")
|
|
notifications = []
|
|
|
|
if os.path.exists(file_path):
|
|
try:
|
|
with open(file_path, 'r') as f:
|
|
notifications = json.load(f)
|
|
except:
|
|
notifications = []
|
|
|
|
notifications.append(notification)
|
|
|
|
with open(file_path, 'w') as f:
|
|
json.dump(notifications, f, indent=2)
|
|
|
|
print("Notification added")
|
|
PYEOF
|
|
}
|
|
|
|
# Update queue item state
|
|
update_queue_item_state() {
|
|
local queue_id="$1"
|
|
local new_state="$2"
|
|
local session_id="${3:-}"
|
|
local pid="${4:-}"
|
|
|
|
local item_file="$QUEUE_ITEMS_DIR/${queue_id}.json"
|
|
if [ ! -f "$item_file" ]; then
|
|
echo "Error: Queue item not found: $queue_id" >&2
|
|
return 1
|
|
fi
|
|
|
|
local issue_ref=$(python3 -c "import json; print(json.load(open('$item_file')).get('issue_ref', ''))" 2>/dev/null || echo "")
|
|
|
|
python3 << PYEOF
|
|
import json
|
|
from datetime import datetime
|
|
|
|
item_file = "$item_file"
|
|
new_state = "$new_state"
|
|
session_id = "$session_id"
|
|
pid = "$pid"
|
|
|
|
with open(item_file, 'r') as f:
|
|
item = json.load(f)
|
|
|
|
item['state'] = new_state
|
|
|
|
if new_state == "notified":
|
|
item['notified_at'] = datetime.now().isoformat() + "Z"
|
|
if session_id:
|
|
item['opencode_session_id'] = session_id
|
|
if pid:
|
|
item['pid'] = int(pid) if pid.isdigit() else None
|
|
elif new_state == "completed":
|
|
item['completed_at'] = datetime.now().isoformat() + "Z"
|
|
elif new_state == "error":
|
|
item['error'] = datetime.now().isoformat() + "Z"
|
|
|
|
with open(item_file, 'w') as f:
|
|
json.dump(item, f, indent=2)
|
|
|
|
print(f"Updated $queue_id to state: $new_state")
|
|
PYEOF
|
|
|
|
if [ "$new_state" = "completed" ]; then
|
|
kugetsu_add_notification "task_completed" "Task completed: $issue_ref" "$issue_ref"
|
|
elif [ "$new_state" = "error" ]; then
|
|
kugetsu_add_notification "task_error" "Task error: $issue_ref" "$issue_ref"
|
|
fi
|
|
}
|