With set -u, expanding $GITEA_TOKEN fails if not set.
Changed to ${GITEA_TOKEN:-} to provide empty default.
Also initializes $ENV_DIR/default.env during kugetsu init
so users are aware of the env file structure.
1. daemon: use $WORKTREES_DIR instead of $HOME/.kugetsu-worktrees
- Worktrees are created in ~/.kugetsu/worktrees but daemon was checking ~/.kugetsu-worktrees
- This caused cmd_start to be called when cmd_continue should have been
2. load_agent_env: add fallback to pm-agent.env
- When dev.env and default.env don't exist, fallback to pm-agent.env
- Ensures GITEA_TOKEN is available
3. Remove '&& disown' pattern that causes 'no such job' errors
- nohup already makes process immune to SIGHUP
- disown was causing errors because job context was lost
- Added build_dev_agent_message() function to generate default workflow prompt
- cmd_start now forks the agent after creating session (fire-and-forget)
- cmd_continue now uses default message when empty and forks agent (fire-and-forget)
- Both commands log output to $LOGS_DIR/dev-$session_id.log
cmd_start was calling create_worktree without passing $WORKTREES_DIR,
causing worktrees to be created in $PWD (daemon's working directory)
instead of ~/.kugetsu-worktrees/
Removed erroneous code that set target="" when target="--base".
This caused the early exit at 'if [ -z "$target" ]' to trigger
before reaching the actual --base handling at line 517.
The sed pattern 's/.*\///' on line 44 was removing everything up to the
LAST slash, but for issue refs like 'git.fbrns.co/shoko/kugetsu#158' it
should remove the instance prefix only (up to the FIRST slash).
Before: git.fbrns.co/shoko/kugetsu#158 -> kugetsu (WRONG)
After: git.fbrns.co/shoko/kugetsu#158 -> shoko/kugetsu (CORRECT)
Also adds comprehensive test suite for git URL parsing functions:
- get_repo_url(), issue_ref_to_worktree_name(), issue_ref_to_branch_name()
- extract_issue_ref_from_message(), validate_issue_ref()
- issue_ref_to_filename(), filename_to_issue_ref()
Fixes#179 - cmd_start fails due to incorrect worktree path being created
with .kugetsu-worktrees/.kugetsu-worktrees/ instead of just the worktree name.
Fix issue where full URLs like #158
were incorrectly parsed to 'shoko/kugetsu/issues#158' instead of
'git.fbrns.co/shoko/kugetsu#158'.
The regex now correctly extracts instance, owner, repo, and number
using bash regex capture groups instead of fragile sed/cut pipeline.
Fix 3 bugs from issue #174 that caused silent failure loop:
1. kugetsu-log.sh: Fix json.loads with newlines
- Previously, notifications JSON was embedded in a single-quoted Python
string literal, but newlines in the JSON broke the Python parser.
- Fix: Pass JSON via stdin to Python instead of embedding in string.
2. kugetsu-queue-daemon.sh: Create logs directory during init
- The logs/ directory ($LOGS_DIR) was never created during kugetsu init.
- Fix: Add mkdir -p for LOGS_DIR, WORKTREES_DIR, QUEUE_DIR, and
QUEUE_ITEMS_DIR to ensure_dirs() and ensure_queue_dirs().
3. kugetsu: Fix parse_issue_ref_from_message URL parsing
- The function used buggy grep/sed to parse URLs like
#158
- Fix: Use bash regex (=~) for reliable URL parsing with proper
capture groups.
Additional improvements:
- ensure_dirs() now creates all necessary directories instead of just
SESSIONS_DIR
- ensure_queue_dirs() now also creates QUEUE_DIR and LOGS_DIR
- parse_issue_ref_from_message uses consistent bash regex approach
for all URL patterns
The init script used 'tail -1' to find newly created sessions, which
fails when old sessions exist because it picks an existing session
instead of the newly created one.
The fix captures session IDs before and after creating new sessions,
then diffs to identify newly created sessions.
Fixes#172
The main kugetsu script had its own update_queue_item_state() definition
with broken os.system() calls that overwrote the fixed version in kugetsu-index.sh.
Now kugetsu will use the fixed version from kugetsu-index.sh (which sources
kugetsu-log.sh) since that module is sourced first.
Fixes#170
os.system() spawns a new subprocess that cannot access bash functions.
Now calling kugetsu_add_notification directly from bash after Python updates JSON.
Fixes#167
- Add acquire_lock/release_lock to prevent daemon vs manual conflicts
- Check cmd_start/cmd_continue success before updating state to 'notified'
- Set state to 'error' if command fails
- Track actual session_id from session file after cmd_start completes
- Release lock when task completes (success or error)
- Use load_agent_env 'pm-agent' for GITEA_TOKEN
Fixes critical race conditions and failure handling in queue processing
When daemon sources kugetsu-session.sh to call cmd_start/cmd_continue,
it needs access to functions from kugetsu-config.sh, kugetsu-index.sh,
kugetsu-worktree.sh, and kugetsu-log.sh. Add sourcing at top of
kugetsu-session.sh.
The daemon (kugetsu-queue-daemon.sh) sources kugetsu-index.sh but not the main kugetsu script.
Move update_queue_item_state and kugetsu_add_notification to kugetsu-index.sh
so the daemon can use these functions when processing tasks.
When cmd_delegate detects an issue ref with number (e.g. git.fbrns.co/shoko/kugetsu#158),
it was calling cmd_start directly which tries to create worktree and clone.
This breaks the queue-based workflow where daemon should handle task execution.
Now cmd_delegate calls enqueue_task to add to queue, and daemon processes
tasks by calling cmd_start/cmd_continue as appropriate.
- 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.
- 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
1. cmd_status now validates session IDs against opencode session list
- Reports 'error: base session X not found in opencode' if missing
- Reports 'error: pm_agent session X not found in opencode' if missing
2. Test suite now uses isolated KUGETSU_DIR=/tmp/test-kugetsu-$$
- All tests use separate test directory instead of ~/.kugetsu
- Prevents test suite from corrupting real user data
- Cleanup removes test directory entirely
Fixes#148
Add third pattern to parse_issue_ref_from_message() to support the mixed
format 'gitserver/owner/repo#number' (e.g., git.fbrns.co/shoko/kugetsu#116).
Previously only two formats were supported:
1. Full URL: #116
2. Short format: shoko/kugetsu#116
Now supports:
3. Mixed format: git.fbrns.co/shoko/kugetsu#116
Fixes#144
Split the monolithic kugetsu script into modular components:
Modules created:
- kugetsu-config.sh - Config/env loading and global variables
- kugetsu-index.sh - Index.json read/write via JSON
- kugetsu-worktree.sh - Git worktree operations
- kugetsu-log.sh - Structured logging and notifications
- kugetsu-session.sh - Session create/fork/destroy logic
- kugetsu-queue-daemon.sh - Queue daemon subprocess
Main script (kugetsu) is now a thin dispatcher that sources all modules.
Acceptance Criteria:
- All existing commands work exactly as before
- Main script sources modules
- Each module is independently testable
Fixes#116
Fixes#142 - process_queue silently skips all queue items because
issue_ref and message Python extraction commands were missing a closing
parenthesis. The error was silently swallowed by 2>/dev/null causing
both variables to be empty, so every queue item was skipped.
Implements #137 - Agent timeout handling.
Changes:
- Add TASK_TIMEOUT_HOURS config (default: 1 hour)
- Update queue item to track opencode_session_id and pid
- Add check_task_timeouts() function that:
- Checks notified tasks against timeout threshold
- Kills process if exceeded
- Marks session as 'timeout' state
- Integrate timeout check into queue daemon loop
Timeout behavior:
- Task is marked 'notified' when PM receives it
- If not completed within TASK_TIMEOUT_HOURS, task is killed
- Queue item marked 'error', session marked 'timeout'
- Extract hostname from pr_url instead of hardcoding domains
- Look up server base URL from GIT_SERVERS config
- Append /api/v1 to derive API URL (configurable per server)
- Works with any server configured in GIT_SERVERS
- Rename update-pr to set-pr for clarity (it's setting the PR URL, not updating PR)
- Add optional pr-url argument to kugetsu start command
Usage: kugetsu start <issue-ref> <message> [pr-url]
- If pr-url is provided at start, it's stored directly in session file
- Add WORKTREE_CHECK_PR_STATUS config (default: true)
- Add pr_url and branch_name fields to session files
- Add check_pr_status() to query PR status via API (Gitea/GitHub)
- Add update_session_pr_url() to update PR URL in session
- Add kugetsu update-pr command to set PR URL
- Modify cmd_destroy to check PR status before destroying worktree
Closes#135
- Parse issue refs from message (gitserver.com/owner/repo/issues/123 or owner/repo#123)
- Find existing worktrees/sessions by issue number
- Ask user to confirm which worktree to use, or delegate anyway
- Inject missing info context to PM agent
- Inject selected worktree context to PM agent
Fixes#128
The --dir flag only sets directory for the subprocess, not the session's
stored directory in opencode's SQLite DB. This was already fixed for
cmd_start in v0.1.10, but cmd_continue still had the bug.
Fixes#127
1. Init: cd to ~/.kugetsu-worktrees before creating base session
This keeps all worktrees inside a predictable directory structure
and avoids external_directory permission issues
2. Init: Clear old logs but keep repos.json, config, and env files
3. Fork context: Add kugetsu_get_fork_context() that provides:
- Important working rules (stop on error, don't pivot)
- Repository configuration from repos.json
- Environment file location info
4. Fork message: Prepend context to user message when forking session
Previously destroy only removed local session files but didn't delete
the sessions from opencode's database. This caused init to reuse the
same session with old context.
Now destroy calls 'opencode session delete <id>' to properly remove
the session from opencode.
Warn users if running kugetsu init from a directory with files or
git repository. This prevents project context from contaminating the
base session, which causes forked sessions to have unwanted context.
opencode session list doesn't show sessions in ~/.kugetsu-worktrees/ directories.
This caused detection to fail even though sessions were being created.
Now we query the database directly for sessions matching the worktree path.
Also fixed database path in fix_session_permissions (was ~/.opencode/, should be ~/.local/share/opencode/).
Previously we only fixed base session permissions before forking.
But permissions are NOT inherited from parent to child.
Now we update the newly created session's permissions immediately
after detection, ensuring the forked session can access external
directories like ~/.kugetsu/worktrees/.
- Call fix_session_permissions in cmd_start before forking to ensure
base session has correct permissions for external_directory access
- Add debug logging to show forked session's directory and permissions
after creation to help diagnose permission inheritance issues
1. Move session detection BEFORE checking if fork process is still running.
Previous code broke out of loop if forked process exited, skipping detection.
2. Add database query debugging when detection fails to help diagnose
why opencode session list might miss newly created sessions.