fix(herdr): prevent pane misattribution and prioritize idle-pane reuse in new-session
- Restrict generic agent_kind fallback in _resolve_herdr_pane_id to bare-kind searches - Exclude 'agent' key from exact-match loop to enforce R-1 fail-closed contract - Prioritize reusing existing idle pane on new-session to prevent unbounded pane proliferation - Wrap final_cmd with env prefix to preserve env_flags when reusing idle pane
This commit is contained in:
+36
-3
@@ -29,7 +29,7 @@ export WORKSPACE_ROOT
|
|||||||
# Framework semantic version. Single runtime source of truth; kept in lockstep
|
# Framework semantic version. Single runtime source of truth; kept in lockstep
|
||||||
# with VERSIONS.md and the 8 SKILL.md frontmatters by tests/test_version_consistency.py.
|
# with VERSIONS.md and the 8 SKILL.md frontmatters by tests/test_version_consistency.py.
|
||||||
# NOTE: unlike other MAM_* variables this one is intentionally NOT env-overridable.
|
# NOTE: unlike other MAM_* variables this one is intentionally NOT env-overridable.
|
||||||
MAM_VERSION="4.1.1"
|
MAM_VERSION="4.1.2"
|
||||||
export MAM_VERSION
|
export MAM_VERSION
|
||||||
AGENT_SESSIONS_YAML="${AGENT_SESSIONS_YAML:-$WORKSPACE_ROOT/.mam/agent-sessions.yaml}"
|
AGENT_SESSIONS_YAML="${AGENT_SESSIONS_YAML:-$WORKSPACE_ROOT/.mam/agent-sessions.yaml}"
|
||||||
|
|
||||||
@@ -412,7 +412,7 @@ try:
|
|||||||
if tws:
|
if tws:
|
||||||
panes = [p for p in panes if p.get('workspace_id') == tws]
|
panes = [p for p in panes if p.get('workspace_id') == tws]
|
||||||
# ISSUE-2: exact match first, then agent-sessions.yaml lookup fallback
|
# ISSUE-2: exact match first, then agent-sessions.yaml lookup fallback
|
||||||
for key in ('label', 'name', 'agent'):
|
for key in ('label', 'name'):
|
||||||
for p in panes:
|
for p in panes:
|
||||||
v = p.get(key)
|
v = p.get(key)
|
||||||
if v and (v == tn or v == tsa):
|
if v and (v == tn or v == tsa):
|
||||||
@@ -433,7 +433,13 @@ try:
|
|||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
sys.stderr.write(f'warning: yaml load failed: {e}\n')
|
sys.stderr.write(f'warning: yaml load failed: {e}\n')
|
||||||
if agent_kind:
|
# BUG-1: only trust the generic agent_kind fallback when the caller's
|
||||||
|
# own target string IS the bare kind (e.g. target == 'agy'). Using a
|
||||||
|
# *derived* kind (looked up via the yaml entry matched by tn/tsa) to
|
||||||
|
# then broadly match any pane of this kind is unsound whenever another,
|
||||||
|
# unrelated same-kind session is alive in the workspace - it misattributes
|
||||||
|
# that unrelated pane as this target even though their names differ.
|
||||||
|
if agent_kind and (tn == agent_kind or tsa == agent_kind):
|
||||||
matching = [p.get('pane_id') for p in panes if p.get('agent') == agent_kind and p.get('pane_id')]
|
matching = [p.get('pane_id') for p in panes if p.get('agent') == agent_kind and p.get('pane_id')]
|
||||||
if len(matching) == 1:
|
if len(matching) == 1:
|
||||||
print(matching[0])
|
print(matching[0])
|
||||||
@@ -702,6 +708,32 @@ except Exception:
|
|||||||
ws_id=""
|
ws_id=""
|
||||||
target_pane=""
|
target_pane=""
|
||||||
if [ -n "$existing_ws" ]; then
|
if [ -n "$existing_ws" ]; then
|
||||||
|
# BUG-4: prefer an already-idle (agent-less) pane in the existing
|
||||||
|
# workspace over splitting a new one — avoids unbounded pane
|
||||||
|
# proliferation and 2x2 grid-layout churn when a prior agent's pane
|
||||||
|
# was left behind idle.
|
||||||
|
idle_pane=$(_real_herdr pane list 2>/dev/null | TARGET_WS="$existing_ws" python3 -c "
|
||||||
|
import sys, json, os
|
||||||
|
target_ws = os.environ.get('TARGET_WS', '')
|
||||||
|
try:
|
||||||
|
d = json.loads(sys.stdin.read())
|
||||||
|
panes = d.get('result', {}).get('panes', [])
|
||||||
|
for p in panes:
|
||||||
|
if p.get('workspace_id') == target_ws and not p.get('agent') and p.get('pane_id'):
|
||||||
|
print(p.get('pane_id'))
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
" 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [ -n "$idle_pane" ]; then
|
||||||
|
target_pane="$idle_pane"
|
||||||
|
if [ -n "$final_cmd" ]; then
|
||||||
|
idle_env="${env_flags//--env /}"
|
||||||
|
idle_env="${idle_env:+$idle_env }HERDR_WORKSPACE_ID=$existing_ws"
|
||||||
|
final_cmd="env $idle_env $final_cmd"
|
||||||
|
fi
|
||||||
|
else
|
||||||
# W2a: Determine split direction policy via pane layout
|
# W2a: Determine split direction policy via pane layout
|
||||||
sample_pane=$(_real_herdr pane list 2>/dev/null | TARGET_WS="$existing_ws" python3 -c "
|
sample_pane=$(_real_herdr pane list 2>/dev/null | TARGET_WS="$existing_ws" python3 -c "
|
||||||
import sys, json, os
|
import sys, json, os
|
||||||
@@ -752,6 +784,7 @@ except Exception:
|
|||||||
" 2>/dev/null || echo "")
|
" 2>/dev/null || echo "")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "$existing_ws" ] || [ -z "$target_pane" ]; then
|
if [ -z "$existing_ws" ] || [ -z "$target_pane" ]; then
|
||||||
ws_json=$(_real_herdr workspace create --cwd "${ws:-.}" ${MAM_WS_LABEL:+--label "$MAM_WS_LABEL"} $env_flags --no-focus 2>/dev/null || echo "")
|
ws_json=$(_real_herdr workspace create --cwd "${ws:-.}" ${MAM_WS_LABEL:+--label "$MAM_WS_LABEL"} $env_flags --no-focus 2>/dev/null || echo "")
|
||||||
|
|||||||
Reference in New Issue
Block a user