When worktree exists but session is missing, ensure_session was
incorrectly removing the worktree before recreating. This caused
issues when cmd_continue called ensure_worktree first (creating the
worktree) then ensure_session (which wrongly removed it).
The fix removes the block that removes worktree when session is missing.
If worktree exists, just create the session without touching the worktree.
Fixes#229
- Add ensure_worktree() - creates worktree if missing, returns status
- Add ensure_session() - creates session if missing, handles inconsistent states
- Add fork_agent() - extracted agent forking logic
- Refactor cmd_continue() to use ensure_* functions (idempotent)
- Make cmd_start() a thin wrapper calling cmd_continue()
- Simplify daemon to always call cmd_continue (no existence check)
This makes cmd_continue truly idempotent - it will:
- Continue existing session if it exists
- Create session and worktree if they don't exist
- Clean and recreate if state is inconsistent
Closes#168
The for loop was overwriting message each iteration, causing only
the last word to survive. Changed to accumulate all words with
proper spacing.
Fixes#225
Add clear distinction between Task Mode (delegate) and Conversation Mode
(answer directly).
- Add kugetsu start tool with params and when to use
- Add kugetsu continue tool with params and when to use
- Add guidance on how to choose between start vs continue
- Add examples for conversation mode responses
- Improve few-shot examples with mode identification
Fixes#220
cmd_delegate deletes the message file immediately after spawning the
background nohup process, causing a race condition where opencode run
may not have read the file yet.
Error: File not found: msg-ses_xxx.txt
Fix by removing rm -f "$msg_file", consistent with cmd_start and
cmd_continue which write to $worktree_path/.kugetsu-msg.txt and never
delete it. Orphaned msg files in $LOGS_DIR/ are harmless.
Fixes#210
The queue daemon crashes with 'set_debug_mode: command not found'
because cmd_continue() calls set_debug_mode(), but that function
was only defined in the main kugetsu script.
Instead of duplicating the function, move it to kugetsu-config.sh
which is always sourced before kugetsu-session.sh in all contexts.
Fixes#207
The message passed to opencode run contains newlines and special
characters (parentheses, etc.) which break shell parsing when passed
directly in double quotes.
Fix by writing message to temp file and using '@msg_file' syntax
to pass to opencode run. This handles any characters in the message.
cmd_continue:
- If worktree is missing but session exists, remove stale session and call cmd_start automatically
- This allows automatic recovery without user intervention
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
cmd_init --force:
- Now destroys ALL sessions, worktrees, and logs for a clean slate
- Destroys base, pm-agent, all forked sessions, all worktrees, all logs
Daemon:
- Fixed wrong path in check_task_completion ($HOME/.kugetsu-worktrees -> $WORKTREES_DIR)
When base or pm_agent are not null, they need to be quoted with escaped quotes ("") in write_index calls.
This fixes 'write_index would create malformed JSON' error during init.
- Remove duplicate write_index, get_base_session_id, get_pm_agent_session_id,
get_session_for_issue, set_base_in_index, set_pm_agent_in_index,
add_issue_to_index, remove_issue_from_index from kugetsu
- These functions are already defined in kugetsu-index.sh which is sourced earlier
- The kugetsu versions were shadowing the kugetsu-index.sh ones unnecessarily
- This removes code duplication and ensures consistent behavior
Tests run sequentially to avoid memory exhaustion with too many opencode sessions:
- JSON session list parsing
- Session ID format validation
- create_session returns valid session ID
- create_session creates NEW session (different from base)
- create_session creates different sessions on multiple calls
- create_session accepts optional base session parameter
- Created session visible in opencode session list
- Add create_session() function that forks from base session using JSON session detection
- cmd_delegate: fork new session from base instead of using pm_agent
- cmd_start: use create_session() instead of broken before/after detection
- cmd_continue: use --session instead of --continue (no need to continue existing session)
- Remove pm_agent check from cmd_start (no longer needed)
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