Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions .agents/scripts/pulse-wrapper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand All @@ -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)
Expand Down Expand Up @@ -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")
Expand Down
19 changes: 9 additions & 10 deletions setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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=""
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1061,7 +1059,7 @@ main() {
<key>OPENCODE_BIN</key>
<string>${_xml_opencode_bin}</string>
<key>PULSE_DIR</key>
<string>${_xml_aidevops_dir}</string>
<string>${_xml_pulse_dir}</string>
<key>PULSE_STALE_THRESHOLD</key>
<string>1800</string>
${_headless_xml_env}
Expand Down Expand Up @@ -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
Expand All @@ -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"
Expand Down
Loading