diff --git a/.agents/scripts/pulse-wrapper.sh b/.agents/scripts/pulse-wrapper.sh index 73260776e..e7f19562c 100755 --- a/.agents/scripts/pulse-wrapper.sh +++ b/.agents/scripts/pulse-wrapper.sh @@ -211,7 +211,13 @@ WRAPPER_LOGFILE="${HOME}/.aidevops/logs/pulse-wrapper.log" SESSION_FLAG="${HOME}/.aidevops/logs/pulse-session.flag" STOP_FLAG="${HOME}/.aidevops/logs/pulse-session.stop" OPENCODE_BIN="${OPENCODE_BIN:-$(command -v opencode 2>/dev/null || echo "opencode")}" -PULSE_DIR="${PULSE_DIR:-${HOME}/Git/aidevops}" +# PULSE_DIR: working directory for the supervisor pulse session. +# Defaults to a neutral workspace path so pulse sessions are not associated +# with any specific managed repo in the host app's session database. +# Previously defaulted to ~/Git/aidevops, which caused 155+ orphaned sessions +# to accumulate under that project even when it had pulse:false (GH#5136). +# Override via env var if a specific directory is needed. +PULSE_DIR="${PULSE_DIR:-${HOME}/.aidevops/.agent-workspace}" PULSE_MODEL="${PULSE_MODEL:-}" HEADLESS_RUNTIME_HELPER="${HEADLESS_RUNTIME_HELPER:-${SCRIPT_DIR}/headless-runtime-helper.sh}" REPOS_JSON="${REPOS_JSON:-${HOME}/.config/aidevops/repos.json}" @@ -226,9 +232,10 @@ if [[ ! -x "$HEADLESS_RUNTIME_HELPER" ]]; then fi ####################################### -# Ensure log directory exists +# Ensure log and workspace directories exist ####################################### mkdir -p "$(dirname "$PIDFILE")" +mkdir -p "$PULSE_DIR" ####################################### # Acquire an exclusive instance lock using mkdir atomicity (GH#4513) @@ -1842,8 +1849,14 @@ gathered by pulse-wrapper.sh BEFORE this session started." fi # Run the provider-aware headless wrapper in background. - # It alternates direct Anthropic/OpenAI models, persists pulse sessions per - # provider, and avoids opencode/* gateway models for headless runs. + # It alternates direct Anthropic/OpenAI models and avoids opencode/* + # gateway models for headless runs. + # Session reuse is intentionally DISABLED for pulse role (GH#5136, + # headless-runtime-helper.sh line 804-809): each cycle clears the + # persisted session ID to avoid stale conversational context contaminating + # dispatch decisions. This means each cycle creates a fresh session. + # PULSE_DIR uses a neutral workspace path (not a managed repo) so these + # sessions don't pollute any project's session list. local -a pulse_cmd=("$HEADLESS_RUNTIME_HELPER" run --role pulse --session-key supervisor-pulse --dir "$PULSE_DIR" --title "Supervisor Pulse" --agent Automate --prompt "$prompt") if [[ -n "$PULSE_MODEL" ]]; then pulse_cmd+=(--model "$PULSE_MODEL") diff --git a/setup.sh b/setup.sh index 6eced9737..9792f1e24 100755 --- a/setup.sh +++ b/setup.sh @@ -892,10 +892,6 @@ main() { # - Non-interactive: only installs if config explicitly says true local wrapper_script="$HOME/.aidevops/agents/scripts/pulse-wrapper.sh" local pulse_label="com.aidevops.aidevops-supervisor-pulse" - local _aidevops_dir _pulse_repo_dir - _aidevops_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - _pulse_repo_dir=$(_resolve_main_worktree_dir "$_aidevops_dir") - # Read explicit user consent from config.jsonc (not merged defaults). # Empty = user never configured this; "true"/"false" = explicit choice. local _pulse_user_config="" @@ -1009,12 +1005,14 @@ main() { # XML-escape paths for safe plist embedding (prevents injection # if $HOME or paths contain &, <, > characters) - local _xml_wrapper_script _xml_home _xml_opencode_bin _xml_aidevops_dir _xml_path + local _xml_wrapper_script _xml_home _xml_opencode_bin _xml_pulse_dir _xml_path local _headless_xml_env="" _xml_wrapper_script=$(_xml_escape "$wrapper_script") _xml_home=$(_xml_escape "$HOME") _xml_opencode_bin=$(_xml_escape "$opencode_bin") - _xml_aidevops_dir=$(_xml_escape "$_pulse_repo_dir") + # Use neutral workspace path for PULSE_DIR so supervisor sessions + # are not associated with any specific managed repo (GH#5136). + _xml_pulse_dir=$(_xml_escape "${HOME}/.aidevops/.agent-workspace") _xml_path=$(_xml_escape "$PATH") if [[ -n "${AIDEVOPS_HEADLESS_MODELS:-}" ]]; then local _xml_headless_models @@ -1061,7 +1059,7 @@ main() { OPENCODE_BIN ${_xml_opencode_bin} PULSE_DIR - ${_xml_aidevops_dir} + ${_xml_pulse_dir} PULSE_STALE_THRESHOLD 1800 ${_headless_xml_env} @@ -1092,8 +1090,9 @@ PLIST # PATH= here, it overrides the global line and breaks nvm/bun/cargo. # OPENCODE_BIN removed — resolved from PATH at runtime via command -v. # See #4099 and #4240 for history. - local _cron_aidevops_dir _cron_wrapper_script _cron_headless_env="" - _cron_aidevops_dir=$(_cron_escape "$_pulse_repo_dir") + local _cron_pulse_dir _cron_wrapper_script _cron_headless_env="" + # Use neutral workspace path for PULSE_DIR (GH#5136) + _cron_pulse_dir=$(_cron_escape "${HOME}/.aidevops/.agent-workspace") _cron_wrapper_script=$(_cron_escape "$wrapper_script") if [[ -n "${AIDEVOPS_HEADLESS_MODELS:-}" ]]; then local _cron_headless_models @@ -1107,7 +1106,7 @@ PLIST fi ( crontab -l 2>/dev/null | grep -v 'aidevops: supervisor-pulse' - echo "*/2 * * * * PULSE_DIR=${_cron_aidevops_dir}${_cron_headless_env} /bin/bash ${_cron_wrapper_script} >> \"\$HOME/.aidevops/logs/pulse-wrapper.log\" 2>&1 # aidevops: supervisor-pulse" + echo "*/2 * * * * PULSE_DIR=${_cron_pulse_dir}${_cron_headless_env} /bin/bash ${_cron_wrapper_script} >> \"\$HOME/.aidevops/logs/pulse-wrapper.log\" 2>&1 # aidevops: supervisor-pulse" ) | crontab - || true if crontab -l 2>/dev/null | grep -qF "aidevops: supervisor-pulse"; then print_info "Supervisor pulse enabled (cron, every 2 min). Disable: crontab -e and remove the supervisor-pulse line"