feat(kugetsu): auto-create pm-agent session during init
- kugetsu init now creates both base and pm-agent sessions - kugetsu start checks for pm-agent existence, errors if missing - Add kugetsu destroy --pm-agent command - Update list to show pm-agent session - Update prune to preserve pm-agent.json - Update SKILL.md documentation to v2.1 Part of issue #19 Phase 3 implementation
This commit is contained in:
@@ -5,7 +5,7 @@ license: MIT
|
|||||||
compatibility: Requires opencode CLI, bash, python3, and filesystem access.
|
compatibility: Requires opencode CLI, bash, python3, and filesystem access.
|
||||||
metadata:
|
metadata:
|
||||||
author: shoko
|
author: shoko
|
||||||
version: "2.0"
|
version: "2.1"
|
||||||
---
|
---
|
||||||
|
|
||||||
# kugetsu - OpenCode Session Manager (Issue-Driven)
|
# kugetsu - OpenCode Session Manager (Issue-Driven)
|
||||||
@@ -30,7 +30,8 @@ chmod +x ~/.local/bin/kugetsu
|
|||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
### Session Pattern
|
### Session Pattern
|
||||||
- **Base Session**: Created once via TUI, used for forking
|
- **Base Session**: Created once via TUI, used for forking dev agents
|
||||||
|
- **PM Agent Session**: Created during init, persistent coordinator for task management
|
||||||
- **Forked Sessions**: One per issue, branched from base via `opencode run --fork --session <base>`
|
- **Forked Sessions**: One per issue, branched from base via `opencode run --fork --session <base>`
|
||||||
|
|
||||||
### Directory Structure
|
### Directory Structure
|
||||||
@@ -38,14 +39,16 @@ chmod +x ~/.local/bin/kugetsu
|
|||||||
~/.kugetsu/
|
~/.kugetsu/
|
||||||
├── sessions/
|
├── sessions/
|
||||||
│ ├── base.json # Base session metadata
|
│ ├── base.json # Base session metadata
|
||||||
|
│ ├── pm-agent.json # PM agent session metadata
|
||||||
│ └── github.com-shoko-kugetsu-14.json # Forked session per issue
|
│ └── github.com-shoko-kugetsu-14.json # Forked session per issue
|
||||||
└── index.json # Maps issue refs to session files
|
└── index.json # Maps session IDs and issue refs to session files
|
||||||
```
|
```
|
||||||
|
|
||||||
### Index File
|
### Index File
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"base": "ses_abc123",
|
"base": "ses_abc123",
|
||||||
|
"pm_agent": "ses_pm_xyz789",
|
||||||
"issues": {
|
"issues": {
|
||||||
"github.com/shoko/kugetsu#14": "github.com-shoko-kugetsu-14.json"
|
"github.com/shoko/kugetsu#14": "github.com-shoko-kugetsu-14.json"
|
||||||
}
|
}
|
||||||
@@ -55,8 +58,7 @@ chmod +x ~/.local/bin/kugetsu
|
|||||||
### Session File
|
### Session File
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "base|forked",
|
"type": "base|forked|pm_agent",
|
||||||
"issue_ref": "github.com/shoko/kugetsu#14",
|
|
||||||
"opencode_session_id": "ses_xyz789",
|
"opencode_session_id": "ses_xyz789",
|
||||||
"created_at": "2026-03-29T18:16:10+02:00",
|
"created_at": "2026-03-29T18:16:10+02:00",
|
||||||
"state": "idle"
|
"state": "idle"
|
||||||
@@ -76,11 +78,90 @@ Examples:
|
|||||||
|
|
||||||
### kugetsu init [--force]
|
### kugetsu init [--force]
|
||||||
|
|
||||||
Initialize base session via TUI:
|
Initialize base + PM agent sessions via TUI:
|
||||||
```bash
|
```bash
|
||||||
kugetsu init
|
kugetsu init
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- Requires a terminal (TTY) to spawn the opencode TUI
|
||||||
|
- Creates base session and PM agent session
|
||||||
|
- Stores both session IDs in `index.json`
|
||||||
|
- Subsequent runs error unless `--force` is used
|
||||||
|
|
||||||
|
### kugetsu start `<issue-ref>` `<message>` [--debug]
|
||||||
|
|
||||||
|
Start task for an issue by forking from base session:
|
||||||
|
```bash
|
||||||
|
kugetsu start github.com/shoko/kugetsu#14 "fix authentication bug"
|
||||||
|
```
|
||||||
|
|
||||||
|
- Forks new session from base
|
||||||
|
- Requires PM agent to exist (created by init)
|
||||||
|
- Stores mapping in `index.json`
|
||||||
|
- Uses `opencode run --fork --session <base-session-id> "<message>"`
|
||||||
|
|
||||||
|
### kugetsu continue `<issue-ref>` `<message>` [--debug]
|
||||||
|
|
||||||
|
Continue work on an existing issue session:
|
||||||
|
```bash
|
||||||
|
kugetsu continue github.com/shoko/kugetsu#14 "add unit tests"
|
||||||
|
```
|
||||||
|
|
||||||
|
- Looks up session file from index
|
||||||
|
- Uses `opencode run --continue --session <opencode-session-id> "<message>"`
|
||||||
|
|
||||||
|
### kugetsu list
|
||||||
|
|
||||||
|
List all tracked sessions:
|
||||||
|
```bash
|
||||||
|
kugetsu list
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
```
|
||||||
|
ISSUE_REF TYPE SESSION_ID CREATED
|
||||||
|
─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
(base) base ses_abc123 N/A
|
||||||
|
(pm-agent) pm_agent ses_pm_xyz789 2026-03-29T18:16:10+02:00
|
||||||
|
github.com/shoko/kugetsu#14 forked ses_xyz789 2026-03-29T18:16:10+02:00
|
||||||
|
```
|
||||||
|
|
||||||
|
### kugetsu prune [--force]
|
||||||
|
|
||||||
|
Remove orphaned sessions (files not in index):
|
||||||
|
```bash
|
||||||
|
kugetsu prune # Shows what would be deleted
|
||||||
|
kugetsu prune --force # Deletes orphaned sessions
|
||||||
|
```
|
||||||
|
|
||||||
|
- Orphaned = session files in `sessions/` but not in `index.json`
|
||||||
|
- Always keeps `base.json` and `pm-agent.json`
|
||||||
|
- Useful after opencode session cleanup
|
||||||
|
|
||||||
|
### kugetsu destroy `<issue-ref>` [-y]
|
||||||
|
|
||||||
|
Delete session for specific issue:
|
||||||
|
```bash
|
||||||
|
kugetsu destroy github.com/shoko/kugetsu#14 # Prompts for confirmation
|
||||||
|
kugetsu destroy github.com/shoko/kugetsu#14 -y # Skips confirmation
|
||||||
|
```
|
||||||
|
|
||||||
|
### kugetsu destroy --pm-agent [-y]
|
||||||
|
|
||||||
|
Delete PM agent session (requires explicit `--pm-agent`):
|
||||||
|
```bash
|
||||||
|
kugetsu destroy --pm-agent -y
|
||||||
|
```
|
||||||
|
|
||||||
|
### kugetsu destroy --base [-y]
|
||||||
|
|
||||||
|
Delete base session (requires explicit `--base`):
|
||||||
|
```bash
|
||||||
|
kugetsu destroy --base -y
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: Destroying base also destroys PM agent since PM depends on base.
|
||||||
|
|
||||||
- Requires a terminal (TTY) to spawn the opencode TUI
|
- Requires a terminal (TTY) to spawn the opencode TUI
|
||||||
- Creates base session once; subsequent runs error unless `--force` is used
|
- Creates base session once; subsequent runs error unless `--force` is used
|
||||||
- Stores base session ID in `index.json`
|
- Stores base session ID in `index.json`
|
||||||
@@ -153,6 +234,7 @@ kugetsu destroy --base -y
|
|||||||
```bash
|
```bash
|
||||||
# First-time setup (requires TTY)
|
# First-time setup (requires TTY)
|
||||||
kugetsu init
|
kugetsu init
|
||||||
|
# Creates: base session + pm-agent session
|
||||||
|
|
||||||
# Start work on issue
|
# Start work on issue
|
||||||
kugetsu start github.com/shoko/kugetsu#14 "implement feature X"
|
kugetsu start github.com/shoko/kugetsu#14 "implement feature X"
|
||||||
@@ -182,6 +264,7 @@ This design solves the headless CLI limitation discovered in Issue #14:
|
|||||||
|
|
||||||
The pattern:
|
The pattern:
|
||||||
- Base session created once via TUI (interactive)
|
- Base session created once via TUI (interactive)
|
||||||
|
- PM agent session created during init (persistent coordinator)
|
||||||
- All subsequent work uses `--fork --session <base>` or `--continue --session <forked>`
|
- All subsequent work uses `--fork --session <base>` or `--continue --session <forked>`
|
||||||
|
|
||||||
## Recovery
|
## Recovery
|
||||||
|
|||||||
@@ -10,12 +10,13 @@ usage() {
|
|||||||
kugetsu - OpenCode Session Manager (Issue-Driven)
|
kugetsu - OpenCode Session Manager (Issue-Driven)
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
kugetsu init [--force] Initialize base session (requires TTY)
|
kugetsu init [--force] Initialize base + pm-agent sessions (requires TTY)
|
||||||
kugetsu start <issue-ref> <message> [--debug] Start task for issue (forks base session)
|
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 continue <issue-ref> [message] [--debug] Continue existing task for issue
|
||||||
kugetsu list List all tracked sessions
|
kugetsu list List all tracked sessions
|
||||||
kugetsu prune [--force] Remove orphaned sessions (keeps base)
|
kugetsu prune [--force] Remove orphaned sessions (keeps base + pm-agent)
|
||||||
kugetsu destroy <issue-ref> [-y] Delete session for issue
|
kugetsu destroy <issue-ref> [-y] Delete session for issue
|
||||||
|
kugetsu destroy --pm-agent [-y] Delete pm-agent session
|
||||||
kugetsu destroy --base [-y] Delete base session
|
kugetsu destroy --base [-y] Delete base session
|
||||||
kugetsu help Show this help
|
kugetsu help Show this help
|
||||||
|
|
||||||
@@ -24,14 +25,15 @@ Issue Ref Format:
|
|||||||
Example: github.com/shoko/kugetsu#14
|
Example: github.com/shoko/kugetsu#14
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
init Create base session via TUI. Requires terminal access.
|
init Create base + pm-agent sessions via TUI. Requires terminal access.
|
||||||
Use --force to reinitialize if base session exists.
|
Use --force to reinitialize if sessions exist.
|
||||||
start Fork new session from base for specific issue.
|
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.
|
continue Continue work on existing issue session.
|
||||||
list Show all sessions (base + forked issues).
|
list Show all sessions (base + pm-agent + forked issues).
|
||||||
prune Remove sessions not in index (orphaned from opencode).
|
prune Remove sessions not in index (orphaned from opencode).
|
||||||
Use --force to skip confirmation.
|
Use --force to skip confirmation.
|
||||||
destroy Delete specific issue session or base session.
|
destroy Delete specific issue, pm-agent, or base session.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--debug Show real-time debug output and capture to debug.log
|
--debug Show real-time debug output and capture to debug.log
|
||||||
@@ -66,15 +68,16 @@ read_index() {
|
|||||||
if [ -f "$INDEX_FILE" ]; then
|
if [ -f "$INDEX_FILE" ]; then
|
||||||
cat "$INDEX_FILE"
|
cat "$INDEX_FILE"
|
||||||
else
|
else
|
||||||
echo '{"base": null, "issues": {}}'
|
echo '{"base": null, "pm_agent": null, "issues": {}}'
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
write_index() {
|
write_index() {
|
||||||
local base="$1"
|
local base="$1"
|
||||||
local issues_json="$2"
|
local pm_agent="$2"
|
||||||
|
local issues_json="$3"
|
||||||
local temp_file="$INDEX_FILE.tmp.$$"
|
local temp_file="$INDEX_FILE.tmp.$$"
|
||||||
printf '{"base": %s, "issues": %s}\n' "$base" "$issues_json" > "$temp_file"
|
printf '{"base": %s, "pm_agent": %s, "issues": %s}\n' "$base" "$pm_agent" "$issues_json" > "$temp_file"
|
||||||
mv "$temp_file" "$INDEX_FILE"
|
mv "$temp_file" "$INDEX_FILE"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +86,11 @@ get_base_session_id() {
|
|||||||
echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('base') or '')"
|
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() {
|
get_session_for_issue() {
|
||||||
local issue_ref="$1"
|
local issue_ref="$1"
|
||||||
local index=$(read_index)
|
local index=$(read_index)
|
||||||
@@ -91,8 +99,24 @@ get_session_for_issue() {
|
|||||||
|
|
||||||
set_base_in_index() {
|
set_base_in_index() {
|
||||||
local base_session_id="$1"
|
local base_session_id="$1"
|
||||||
|
local pm_agent=$(get_pm_agent_session_id)
|
||||||
local issues_json=$(read_index | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d['issues']))")
|
local issues_json=$(read_index | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d['issues']))")
|
||||||
write_index "\"$base_session_id\"" "$issues_json"
|
if [ -z "$pm_agent" ] || [ "$pm_agent" = "null" ]; then
|
||||||
|
write_index "\"$base_session_id\"" "null" "$issues_json"
|
||||||
|
else
|
||||||
|
write_index "\"$base_session_id\"" "\"$pm_agent\"" "$issues_json"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
set_pm_agent_in_index() {
|
||||||
|
local pm_agent_session_id="$1"
|
||||||
|
local base=$(get_base_session_id)
|
||||||
|
local issues_json=$(read_index | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d['issues']))")
|
||||||
|
if [ -z "$base" ] || [ "$base" = "null" ]; then
|
||||||
|
write_index "null" "\"$pm_agent_session_id\"" "$issues_json"
|
||||||
|
else
|
||||||
|
write_index "\"$base\"" "\"$pm_agent_session_id\"" "$issues_json"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
add_issue_to_index() {
|
add_issue_to_index() {
|
||||||
@@ -100,12 +124,21 @@ add_issue_to_index() {
|
|||||||
local session_file="$2"
|
local session_file="$2"
|
||||||
local index=$(read_index)
|
local index=$(read_index)
|
||||||
local base=$(get_base_session_id)
|
local base=$(get_base_session_id)
|
||||||
|
local pm_agent=$(get_pm_agent_session_id)
|
||||||
local issues=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d['issues']))")
|
local issues=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print(json.dumps(d['issues']))")
|
||||||
local new_issues=$(echo "$issues" | python3 -c "import sys, json; d=json.load(sys.stdin); d['$issue_ref']='$session_file'; print(json.dumps(d))")
|
local new_issues=$(echo "$issues" | python3 -c "import sys, json; d=json.load(sys.stdin); d['$issue_ref']='$session_file'; print(json.dumps(d))")
|
||||||
if [ "$base" = "null" ] || [ -z "$base" ]; then
|
if [ -z "$base" ] || [ "$base" = "null" ]; then
|
||||||
write_index "null" "$new_issues"
|
if [ -z "$pm_agent" ] || [ "$pm_agent" = "null" ]; then
|
||||||
|
write_index "null" "null" "$new_issues"
|
||||||
else
|
else
|
||||||
write_index "\"$base\"" "$new_issues"
|
write_index "null" "\"$pm_agent\"" "$new_issues"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ -z "$pm_agent" ] || [ "$pm_agent" = "null" ]; then
|
||||||
|
write_index "\"$base\"" "null" "$new_issues"
|
||||||
|
else
|
||||||
|
write_index "\"$base\"" "\"$pm_agent\"" "$new_issues"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,11 +146,20 @@ remove_issue_from_index() {
|
|||||||
local issue_ref="$1"
|
local issue_ref="$1"
|
||||||
local index=$(read_index)
|
local index=$(read_index)
|
||||||
local base=$(get_base_session_id)
|
local base=$(get_base_session_id)
|
||||||
|
local pm_agent=$(get_pm_agent_session_id)
|
||||||
local new_issues=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); d['issues'].pop('$issue_ref', None); print(json.dumps(d['issues']))")
|
local new_issues=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); d['issues'].pop('$issue_ref', None); print(json.dumps(d['issues']))")
|
||||||
if [ "$base" = "null" ] || [ -z "$base" ]; then
|
if [ -z "$base" ] || [ "$base" = "null" ]; then
|
||||||
write_index "null" "$new_issues"
|
if [ -z "$pm_agent" ] || [ "$pm_agent" = "null" ]; then
|
||||||
|
write_index "null" "null" "$new_issues"
|
||||||
else
|
else
|
||||||
write_index "\"$base\"" "$new_issues"
|
write_index "null" "\"$pm_agent\"" "$new_issues"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ -z "$pm_agent" ] || [ "$pm_agent" = "null" ]; then
|
||||||
|
write_index "\"$base\"" "null" "$new_issues"
|
||||||
|
else
|
||||||
|
write_index "\"$base\"" "\"$pm_agent\"" "$new_issues"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +214,11 @@ cmd_init() {
|
|||||||
ensure_dirs
|
ensure_dirs
|
||||||
|
|
||||||
local existing_base=$(get_base_session_id)
|
local existing_base=$(get_base_session_id)
|
||||||
|
local existing_pm=$(get_pm_agent_session_id)
|
||||||
|
|
||||||
if [ -n "$existing_base" ] && [ "$existing_base" != "null" ]; then
|
if [ -n "$existing_base" ] && [ "$existing_base" != "null" ]; then
|
||||||
if [ "$force" = true ]; then
|
if [ "$force" = true ]; then
|
||||||
echo "Warning: Reinitializing base session (force mode)" >&2
|
echo "Warning: Reinitializing sessions (force mode)" >&2
|
||||||
else
|
else
|
||||||
echo "Error: Base session already exists: $existing_base" >&2
|
echo "Error: Base session already exists: $existing_base" >&2
|
||||||
echo "Use --force to reinitialize" >&2
|
echo "Use --force to reinitialize" >&2
|
||||||
@@ -207,8 +251,40 @@ cmd_init() {
|
|||||||
"$new_session_id" "$(date -Iseconds)" > "$SESSIONS_DIR/$session_file"
|
"$new_session_id" "$(date -Iseconds)" > "$SESSIONS_DIR/$session_file"
|
||||||
|
|
||||||
set_base_in_index "$new_session_id"
|
set_base_in_index "$new_session_id"
|
||||||
|
|
||||||
echo "Base session initialized: $new_session_id"
|
echo "Base session initialized: $new_session_id"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Creating PM agent session..."
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
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 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" != "$new_session_id" ]]; then
|
||||||
|
new_pm_session_id="$sess"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done <<< "$after_sessions"
|
||||||
|
|
||||||
|
if [ -z "$new_pm_session_id" ]; then
|
||||||
|
echo "Warning: Could not detect PM agent session ID. It may still have been created." >&2
|
||||||
|
else
|
||||||
|
local pm_session_file="pm-agent.json"
|
||||||
|
printf '{"type": "pm_agent", "opencode_session_id": "%s", "created_at": "%s", "state": "idle"}\n' \
|
||||||
|
"$new_pm_session_id" "$(date -Iseconds)" > "$SESSIONS_DIR/$pm_session_file"
|
||||||
|
set_pm_agent_in_index "$new_pm_session_id"
|
||||||
|
echo "PM agent session initialized: $new_pm_session_id"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Initialization complete!"
|
||||||
|
echo "- Base session: $new_session_id"
|
||||||
|
echo "- PM agent: ${new_pm_session_id:-created by hermes}"
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_start() {
|
cmd_start() {
|
||||||
@@ -240,6 +316,12 @@ cmd_start() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local pm_agent_session_id=$(get_pm_agent_session_id)
|
||||||
|
if [ -z "$pm_agent_session_id" ] || [ "$pm_agent_session_id" = "null" ]; then
|
||||||
|
echo "Error: No PM agent session. Run 'kugetsu init' first to create it." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
local existing_session=$(get_session_for_issue "$issue_ref")
|
local existing_session=$(get_session_for_issue "$issue_ref")
|
||||||
if [ -n "$existing_session" ] && [ "$existing_session" != "null" ]; then
|
if [ -n "$existing_session" ] && [ "$existing_session" != "null" ]; then
|
||||||
echo "Error: Session for '$issue_ref' already exists" >&2
|
echo "Error: Session for '$issue_ref' already exists" >&2
|
||||||
@@ -348,13 +430,22 @@ cmd_list() {
|
|||||||
printf "%-50s %-10s %-25s %s\n" "(base)" "base" "$base_session_id" "N/A"
|
printf "%-50s %-10s %-25s %s\n" "(base)" "base" "$base_session_id" "N/A"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local pm_agent_session_id=$(get_pm_agent_session_id)
|
||||||
|
if [ -n "$pm_agent_session_id" ] && [ "$pm_agent_session_id" != "null" ]; then
|
||||||
|
local pm_created="N/A"
|
||||||
|
if [ -f "$SESSIONS_DIR/pm-agent.json" ]; then
|
||||||
|
pm_created=$(python3 -c "import json; print(json.load(open('$SESSIONS_DIR/pm-agent.json'))['created_at'])" 2>/dev/null || echo "N/A")
|
||||||
|
fi
|
||||||
|
printf "%-50s %-10s %-25s %s\n" "(pm-agent)" "pm_agent" "$pm_agent_session_id" "$pm_created"
|
||||||
|
fi
|
||||||
|
|
||||||
local index=$(read_index)
|
local index=$(read_index)
|
||||||
local issue_refs=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print('\n'.join(d['issues'].keys()))" 2>/dev/null || true)
|
local issue_refs=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); print('\n'.join(d['issues'].keys()))" 2>/dev/null || true)
|
||||||
|
|
||||||
for session_file in "$SESSIONS_DIR"/*.json; do
|
for session_file in "$SESSIONS_DIR"/*.json; do
|
||||||
if [ -f "$session_file" ]; then
|
if [ -f "$session_file" ]; then
|
||||||
local filename=$(basename "$session_file" .json)
|
local filename=$(basename "$session_file" .json)
|
||||||
if [ "$filename" = "base" ]; then
|
if [ "$filename" = "base" ] || [ "$filename" = "pm-agent" ]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -382,7 +473,7 @@ cmd_prune() {
|
|||||||
ensure_dirs
|
ensure_dirs
|
||||||
|
|
||||||
local index=$(read_index)
|
local index=$(read_index)
|
||||||
local index_session_files=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); sessions=set(d['issues'].values()); sessions.add('base.json'); print('\n'.join(sessions))" 2>/dev/null || echo "base.json")
|
local index_session_files=$(echo "$index" | python3 -c "import sys, json; d=json.load(sys.stdin); sessions=set(d['issues'].values()); sessions.add('base.json'); sessions.add('pm-agent.json'); print('\n'.join(sessions))" 2>/dev/null || echo -e "base.json\npm-agent.json")
|
||||||
|
|
||||||
local orphaned=()
|
local orphaned=()
|
||||||
for session_file in "$SESSIONS_DIR"/*.json; do
|
for session_file in "$SESSIONS_DIR"/*.json; do
|
||||||
@@ -424,6 +515,9 @@ cmd_destroy() {
|
|||||||
--base)
|
--base)
|
||||||
target="base"
|
target="base"
|
||||||
;;
|
;;
|
||||||
|
--pm-agent)
|
||||||
|
target="pm-agent"
|
||||||
|
;;
|
||||||
-y|--yes)
|
-y|--yes)
|
||||||
force=true
|
force=true
|
||||||
;;
|
;;
|
||||||
@@ -437,14 +531,20 @@ cmd_destroy() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ -z "$target" ]; then
|
if [ -z "$target" ]; then
|
||||||
echo "Error: destroy requires <issue-ref> or --base" >&2
|
echo "Error: destroy requires <issue-ref>, --base, or --pm-agent" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$target" = "base" ]; then
|
if [ "$target" = "base" ]; then
|
||||||
if [ "$force" = true ]; then
|
if [ "$force" = true ]; then
|
||||||
rm -f "$SESSIONS_DIR/base.json"
|
rm -f "$SESSIONS_DIR/base.json"
|
||||||
echo '{"base": null, "issues": {}}' > "$INDEX_FILE"
|
local pm_agent=$(get_pm_agent_session_id)
|
||||||
|
if [ -n "$pm_agent" ] && [ "$pm_agent" != "null" ]; then
|
||||||
|
rm -f "$SESSIONS_DIR/pm-agent.json"
|
||||||
|
echo '{"base": null, "pm_agent": null, "issues": {}}' > "$INDEX_FILE"
|
||||||
|
else
|
||||||
|
echo '{"base": null, "pm_agent": null, "issues": {}}' > "$INDEX_FILE"
|
||||||
|
fi
|
||||||
echo "Base session destroyed"
|
echo "Base session destroyed"
|
||||||
else
|
else
|
||||||
echo "Error: destroying base session requires --base -y" >&2
|
echo "Error: destroying base session requires --base -y" >&2
|
||||||
@@ -453,6 +553,23 @@ cmd_destroy() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$target" = "pm-agent" ]; then
|
||||||
|
if [ "$force" = true ]; then
|
||||||
|
rm -f "$SESSIONS_DIR/pm-agent.json"
|
||||||
|
local base=$(get_base_session_id)
|
||||||
|
if [ -n "$base" ] && [ "$base" != "null" ]; then
|
||||||
|
write_index "\"$base\"" "null" "{}"
|
||||||
|
else
|
||||||
|
write_index "null" "null" "{}"
|
||||||
|
fi
|
||||||
|
echo "PM agent session destroyed"
|
||||||
|
else
|
||||||
|
echo "Error: destroying pm-agent session requires --pm-agent -y" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
validate_issue_ref "$target"
|
validate_issue_ref "$target"
|
||||||
|
|
||||||
local session_file=$(get_session_for_issue "$target")
|
local session_file=$(get_session_for_issue "$target")
|
||||||
|
|||||||
Reference in New Issue
Block a user