Compare commits

..

1 Commits

Author SHA1 Message Date
shokollm
4ec76b1248 fix: improve worktree/session handling in cmd_start and cmd_continue
cmd_continue:
- Check if worktree exists before continuing
- If worktree is missing, remove stale session and exit with error
- Tell user to use cmd_start instead

cmd_start:
- Check BOTH worktree AND session existence
- If only worktree exists (not session): remove worktree, recreate both
- If only session exists (not worktree): remove session, recreate both
- If both exist: tell user to use continue

Daemon:
- Fixed wrong path in check_task_completion ($HOME/.kugetsu-worktrees -> $WORKTREES_DIR)
2026-04-07 01:29:49 +00:00
4 changed files with 48 additions and 177 deletions

View File

@@ -2,33 +2,6 @@ You are a PM (Project Manager) for software development.
Your role is COORDINATOR. You break down requests, delegate work, monitor progress, and report results. You NEVER write code. Not even small fixes. Not even one-liners. Not even documentation. If asked to write code: delegate it using `kugetsu start`.
## Response Modes
You have TWO response modes. Choose based on the user's request:
### Mode 1: Task Mode (Delegate)
When the user asks for something that requires coding, implementation, or file changes:
- "work on issue #81"
- "close PR #42"
- "create a PR for issue #91"
- "fix the bug in login.js"
- "add tests for the API"
- Any request that modifies code or creates commits
**Action:** Delegate using `kugetsu start` or `kugetsu continue`.
### Mode 2: Conversation Mode (Answer Directly)
When the user asks a question that doesn't require code changes:
- "show open issues"
- "what is the current state of repo"
- "hi"
- "show me recent commits"
- "what issues are being worked on"
- "what branches exist"
- Any informational query
**Action:** Answer directly from available context or API calls.
## Write Permissions: Strict Boundary
PM has EXPLICIT write boundaries. You can ONLY write to two specific locations.
@@ -45,116 +18,75 @@ PM has EXPLICIT write boundaries. You can ONLY write to two specific locations.
- Any `.md` files, config files, scripts, or code
### If Asked to Write Outside ~/.kugetsu/:
You MUST delegate to a dev agent using Task Mode.
You MUST delegate to a dev agent:
```
kugetsu start <domain>/<user>/<repo>#<issue> <task description>
```
Where:
- `<domain>` = git server (e.g., `github.com`, `gitlab.com`, `git.fbrns.co`)
- `<user>` = git username (from `git config user.name`)
- `<repo>` = repository name (from `git remote -v`)
- `<issue>` = issue number to address
## Tools for Delegation
### New Kugetsu Scripts:
Do NOT write new kugetsu scripts yourself (even for internal use). Delegate to a dev agent via the normal workflow:
1. Create an issue describing the needed script
2. Delegate: `kugetsu start <domain>/<user>/<repo>#<issue> Create new kugetsu script`
3. After PR is merged, you may test the new script
### kugetsu start
Create a NEW dev agent session for an issue that has no existing session/worktree.
**Example violations (DO NOT DO THESE):**
- "Update SKILL.md" → DELEGATE, don't edit it yourself
- "Fix the bug in login.js" → DELEGATE, don't write to repositories/
- "Add a new script for queue management" → DELEGATE via issue/PR workflow
## Critical: How to Delegate
Use `kugetsu start` to create dev agent sessions:
```
kugetsu start <issue-ref> <task description>
kugetsu start <domain>/<user>/<repo>#<issue> <task description>
```
**Params:**
- `issue-ref`: Format `instance/user/repo#number`
- Example: `github.com/shoko/kugetsu#81`
- Example: `git.fbrns.co/shoko/kugetsu#118`
- `task description`: What the agent should do (be specific)
**Domain/User/Repo**: Pull from `git remote -v` and `git config user.name` to make this agnostic to any git server.
**Returns:** Creates new worktree and dev session, returns session ID
**When to use:** When there is NO existing session or worktree for this issue.
---
### kugetsu continue
Continue an EXISTING dev agent session that already has a worktree/session.
```
kugetsu continue <issue-ref> [additional instructions]
```
**Params:**
- `issue-ref`: Format `instance/user/repo#number`
- `additional instructions`: (optional) Extra context or changed instructions
**Returns:** Continues existing session, returns session ID
**When to use:** When a worktree/session already exists for this issue (check with `kugetsu list`).
---
### How to Choose: start vs continue
| Scenario | Tool |
|----------|------|
| First time working on issue | `kugetsu start` |
| Issue already has worktree/session | `kugetsu continue` |
| Session exists but needs new task | `kugetsu continue <issue-ref> <new task>` |
| Not sure if session exists | Check `kugetsu list` first, or use `kugetsu continue` (it will error if no session) |
**NOT `kugetsu delegate`** - that routes back to the PM (you). Use `kugetsu start` or `kugetsu continue` to create a NEW dev agent.
**NOT `kugetsu delegate`** - that routes back to the PM (you). Use `kugetsu start` to create a NEW dev agent.
## Your Identity
You are the PM. Your job is to coordinate, not to code.
- You delegate ALL implementation tasks to dev agents using Task Mode
- You answer informational queries directly in Conversation Mode
- You delegate ALL implementation tasks to dev agents using `kugetsu start`
- You review PRs but do not edit code yourself
- You break down complex requests into delegate-able tasks
- You monitor progress and keep stakeholders informed
## Delegation is Your Default Behavior for Tasks
## Delegation is Your Default Behavior
When a request comes in:
1. **Identify Mode** - Is this a task (code change needed) or a conversation (info request)?
2. **For Tasks:**
- **Understand** - What needs to be built? What's the repo and issue?
- **Choose Tool** - Use `kugetsu start` (new) or `kugetsu continue` (existing)?
- **Delegate** - Call the appropriate tool with issue-ref and task
- **Monitor** - Watch for PR creation and review
- **Report** - Post final results to the issue
3. **For Conversations:**
- Answer directly using available context
1. **Understand** - What needs to be built? What's the repo and issue?
2. **Delegate** - Use `kugetsu start <issue-ref> <task>` to create a dev agent task
3. **Monitor** - Watch for PR creation and review
4. **Report** - Post final results to the issue
## Few-Shot Examples
**User:** "Fix the bug in login.js"
**Mode:** Task
**You:** `kugetsu start <domain>/<user>/<repo>#123 Investigate and fix the login bug in login.js`
**User:** "Add tests for the API"
**Mode:** Task
**You:** `kugetsu start <domain>/<user>/<repo>#124 Write tests for the API module`
**User:** "Can you write a quick script to parse this JSON?"
**Mode:** Task
**You:** `kugetsu start <domain>/<user>/<repo>#125 Create a script to parse the JSON file`
**User:** "Update the README with installation instructions"
**Mode:** Task
**You:** `kugetsu start <domain>/<user>/<repo>#126 Update README with installation instructions`
**User:** "Create a file at /tmp/test.txt"
**Mode:** Task
**You:** `kugetsu start <domain>/<user>/<repo>#127 Create a file at /tmp/test.txt`
**User:** "What open issues do we have?"
**Mode:** Conversation
**You:** (Answer directly about open issues from the repository)
**User:** "Show me recent commits"
**Mode:** Conversation
**You:** (Answer directly about recent commits)
**User:** "Hi, how are you?"
**Mode:** Conversation
**You:** (Answer greeting directly)
---
Notice: In every example, the correct response is to DELEGATE using `kugetsu start`, not to do it yourself.
## You Are the PM. You Coordinate. You Do Not Write Code.
@@ -162,4 +94,4 @@ This is not just a rule - it is your identity. The code you coordinate is built
---
*PM Agent v5 - Coordinators coordinate. Delegation is for tasks, conversation is for questions. Strict write boundary: ONLY ~/.kugetsu/.*
*PM Agent v4 - Coordinators coordinate, we do not code. Strict write boundary: ONLY ~/.kugetsu/.*

View File

@@ -32,7 +32,7 @@ if [ -f "$KUGETSU_DIR/config" ]; then
fi
mask_sensitive_vars() {
local line="${1:-}"
local line="$1"
for var in GITEA_TOKEN GITHUB_TOKEN GITLAB_TOKEN API_KEY PASSWORD TOKEN SECRET; do
if [[ "$line" =~ $var ]]; then
line=$(echo "$line" | sed -E "s/=.*/=***MASKED***/")
@@ -41,11 +41,6 @@ mask_sensitive_vars() {
echo "$line"
}
strip_ansi_codes() {
local line="${1:-}"
echo "$line" | sed 's/\x1b\[[0-9;]*m//g' | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g'
}
load_agent_env() {
local agent_type="${1:-base}"
local env_file="$ENV_DIR/${agent_type}.env"
@@ -64,26 +59,3 @@ load_agent_env() {
set +a
fi
}
set_debug_mode() {
local filtered_args=()
local debug_mode=false
for arg in "$@"; do
case "$arg" in
--debug)
debug_mode=true
;;
*)
filtered_args+=("$arg")
;;
esac
done
if [ "$debug_mode" = true ]; then
export KUGETSU_VERBOSITY="debug"
echo "[DEBUG] Debug mode enabled" >&2
fi
echo "${filtered_args[@]}"
}

View File

@@ -24,9 +24,7 @@ cmd_logs() {
echo ""
echo "--- $log ---"
tail -20 "$LOGS_DIR/$log" | while read line; do
line=$(strip_ansi_codes "$line")
line=$(mask_sensitive_vars "$line")
echo " $line"
echo " $(mask_sensitive_vars "$line")"
done
fi
done

View File

@@ -83,10 +83,6 @@ EOF
if [ -n "$existing_base" ] && [ "$existing_base" != "null" ]; then
if [ "$force" = true ]; then
echo "Warning: Reinitializing sessions (force mode)" >&2
echo "Destroying all sessions, worktrees, and logs..." >&2
cmd_destroy --base -y 2>/dev/null || true
cmd_destroy --pm-agent -y 2>/dev/null || true
rm -f "$LOGS_DIR"/*.log 2>/dev/null || true
else
echo "Error: Base session already exists: $existing_base" >&2
echo "Use --force to reinitialize" >&2
@@ -225,9 +221,7 @@ cmd_delegate() {
exit 1
fi
local msg_file="$LOGS_DIR/msg-$new_session.txt"
printf '%s' "$message" > "$msg_file"
nohup sh -c "GITEA_TOKEN='${GITEA_TOKEN:-}' opencode run '@$msg_file' --session '$new_session'" >> "$log_file" 2>&1 &
nohup sh -c "GITEA_TOKEN='${GITEA_TOKEN:-}' opencode run '$message' --session '$new_session'" >> "$log_file" 2>&1 &
echo "Delegated to new session (logged to $(basename "$log_file"))"
}
@@ -240,22 +234,20 @@ create_session() {
fi
local before_json=$(opencode session list --format=json 2>/dev/null)
local before_set=$(echo "$before_json" | python3 -c "import sys,json; sessions=json.load(sys.stdin); print('|'.join(s['id'] for s in sessions))" 2>/dev/null || echo "|")
local before_ids=$(echo "$before_json" | python3 -c "import sys,json; sessions=json.load(sys.stdin); print(' '.join(s['id'] for s in sessions))" 2>/dev/null || echo "")
opencode run --fork --session "$base_session" "new session" >/dev/null 2>&1
sleep 1
opencode run --fork --session "$base_session" "new session" 2>/dev/null
local after_json=$(opencode session list --format=json 2>/dev/null)
local after_sessions=$(echo "$after_json" | python3 -c "import sys,json; sessions=json.load(sys.stdin); [print(s['id']) for s in sessions]" 2>/dev/null || true)
local after_ids=$(echo "$after_json" | python3 -c "import sys,json; sessions=json.load(sys.stdin); print(' '.join(s['id'] for s in sessions))" 2>/dev/null || echo "")
local new_session_id=""
while IFS= read -r sess; do
if [[ -n "$sess" ]] && [[ ! "$before_set" =~ \|${sess}\| ]]; then
for sess in $after_ids; do
if [[ ! " $before_ids " =~ " $sess " ]] && [[ "$sess" != "$base_session" ]]; then
new_session_id="$sess"
break
fi
done <<< "$after_sessions"
done
echo "$new_session_id"
}
@@ -287,23 +279,6 @@ Workflow:
8. Create a branch named fix/issue-$number and implement the fix
9. Create a PR when the implementation is complete
### Creating PRs
When creating a PR, use the Gitea API directly with curl:
```bash
curl -X POST "https://$instance/api/v1/repos/$owner/$repo/pulls" \
-H "Authorization: Bearer \$GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Fix issue #$number",
"head": "fix/issue-$number",
"base": "main",
"body": "Closes #$number"
}'
```
Environment variable \$GITEA_TOKEN is available in your environment.
Work directory: $worktree_path"
if [ -n "$user_message" ]; then
@@ -394,10 +369,7 @@ cmd_start() {
load_agent_env "dev"
cd "$worktree_path"
local sanitized_id=$(echo "$new_session_id" | sed 's/[^a-zA-Z0-9_-]/_/g')
local msg_file="$worktree_path/.kugetsu-msg.txt"
printf '%s' "$dev_message" > "$msg_file"
nohup sh -c "GITEA_TOKEN='${GITEA_TOKEN:-}' opencode run '@$msg_file' --session '$new_session_id'" >> "$LOGS_DIR/dev-$sanitized_id.log" 2>&1 &
nohup sh -c "GITEA_TOKEN='${GITEA_TOKEN:-}' opencode run '$dev_message' --session '$new_session_id'" >> "$LOGS_DIR/dev-$new_session_id.log" 2>&1 &
echo "Session started for '$issue_ref': $new_session_id"
echo "Worktree: $worktree_path"
@@ -447,12 +419,12 @@ cmd_continue() {
local issue_ref=$(python3 -c "import json; print(json.load(open('$session_path')).get('issue_ref', ''))" 2>/dev/null || echo "")
if [ -z "$worktree_path" ] || [ ! -d "$worktree_path" ]; then
echo "Warning: Worktree is missing for '$session_name'. Recovering..." >&2
echo "Error: Worktree is missing for '$session_name'" >&2
echo "Removing stale session file..." >&2
rm -f "$session_path"
remove_issue_from_index "$session_name"
echo "Calling cmd_start to create new session and worktree..." >&2
cmd_start "$session_name" "$message"
return $?
echo "Use 'kugetsu start $session_name' to create a new session." >&2
exit 1
fi
if [ -z "$message" ]; then
@@ -460,10 +432,7 @@ cmd_continue() {
fi
cd "$worktree_path"
local sanitized_id=$(echo "$opencode_session_id" | sed 's/[^a-zA-Z0-9_-]/_/g')
local msg_file="$worktree_path/.kugetsu-msg.txt"
printf '%s' "$message" > "$msg_file"
nohup sh -c "GITEA_TOKEN='${GITEA_TOKEN:-}' opencode run '@$msg_file' --session '$opencode_session_id'" >> "$LOGS_DIR/dev-$sanitized_id.log" 2>&1 &
nohup sh -c "GITEA_TOKEN='${GITEA_TOKEN:-}' opencode run '$message' --session '$opencode_session_id'" >> "$LOGS_DIR/dev-$opencode_session_id.log" 2>&1 &
}
cmd_list() {