feat(a4,c3b): complete A-4 Phase 2 agent knowledge migration & Option B isolation removal

- Option B / C-3b: Deprecate isolation.root and remove its 4 legacy consumers in lib.sh, workspace_uuid.py, verify_session.py, and stop_session.sh.
- M2~M7 Migration: Implement artifact_path, verify_artifact, purge_artifacts, spawn_spec, resume_spec, auth_ok, discover, ready_tokens, exit_key, and delegate_agent_key across BaseAgentAdapter and all 4 adapters (Claude, Agy, Hermes, Cline).
- Migrate shell duplications in lib.sh, create_session.sh, resume_session.sh, stop_session.sh, and reconcile.sh to python -m lib_py.agents facts.
- Hardening & Corrections: Fix Cline resume_spec flag to '-i --id', apply shlex.quote across all facts variables with MAM_ prefix, add safe fallback in wait_for_tui_ready.
- Add comprehensive contract tests in tests/test_a4_adapter_contract.py and sync IMPROVEMENTS.md / LOG.md.
- Verified: 100% PASS across unit, component, contract, and integration tests.
This commit is contained in:
2026-08-16 23:15:24 +09:00
parent 971f14ad3f
commit b4821fafa8
21 changed files with 904 additions and 531 deletions
+21 -55
View File
@@ -60,7 +60,7 @@ done
# Central TUI dialog and readiness validation tokens (OP-6)
_MAM_DIALOG_TOKENS='Do you trust the files|Yes, proceed|No, exit|Allow this|Press Enter to continue|browser to authenticate|Use arrow keys|Esc to cancel|Resuming the full session|Resume from summary'
_MAM_READY_TOKENS_CLAUDE='Anthropic|Assistant|Chat|Welcome|projects'
_MAM_READY_TOKENS_CLAUDE='Anthropic|Assistant|Chat|Welcome'
# Workspace-relative defaults with environment overrides (Phase Z)
HOME_DIR="${HOME_DIR:-$HOME}"
@@ -1097,25 +1097,6 @@ mam_workspace_key() {
printf '%s' "$(mam_abs_workspace "$1")" | tr '/_' '--'
}
# ---------------------------------------------------------------------------
# mam_session_iso_root <session_name>
# ---------------------------------------------------------------------------
mam_session_iso_root() {
MAM_STATE_JSON="$(load_state_json)" MAM_ISO_SESSION="$1" env_python "$AGENT_SESSIONS_YAML" <<'PYEOF'
import json, os
name = os.environ.get('MAM_ISO_SESSION', '')
try:
d = json.loads(os.environ.get('MAM_STATE_JSON', '{}'))
except Exception:
d = {}
for s in (d.get('herdr_sessions') or []):
if s.get('name') == name:
iso = s.get('isolation')
if isinstance(iso, dict) and iso.get('root'):
print(iso['root'])
break
PYEOF
}
# ---------------------------------------------------------------------------
# derive_session_name <workspace> <agent> [role]
@@ -1354,18 +1335,14 @@ capture_conversation_id() {
}
# ---------------------------------------------------------------------------
# Session isolation — Universal Global Config (Option A, Job 536a6625)
# Session isolation — Universal Global Config (Option B, P3-1)
#
# Config-home isolation (.mam/agent_homes/<uuid>/) was removed in favor of:
# Config-home isolation (.mam/agent_homes/<uuid>/) and legacy isolation.root
# row consumers were completely deprecated and removed in favor of:
# 1. Universal Global Config: all agents read/write standard ~/.claude, ~/.gemini,
# ~/.hermes, ~/.cline user configuration and credential stores.
# 2. Process Isolation: each agent-workspace pair runs in its own herdr pane.
# 3. Conversation Isolation: session UUIDs discriminate conversation history.
# The backward-compat stubs (provision_isolation / isolation_lever /
# isolation_env_prefix / isolation_cmd_args) were removed in P2-2 (C-3a);
# they had zero production callers. The `isolation.root` row field is still
# consumed (C-3b) — see verify_session_uuid / find_workspace_uuid /
# mam_session_iso_root / stop_session.sh purge guard.
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
@@ -1528,11 +1505,22 @@ start_watchdog() {
}
# wait_for_tui_ready <session_name> <agent>
# Waits up to 15 seconds for the agent's TUI to render its welcome screen.
# Waits up to 30 seconds for the agent's TUI to render its welcome screen.
wait_for_tui_ready() {
local sess="$1" agent="$2"
# Self-contained resolution: works whether or not caller evaluated facts (C1-(3)).
local tokens="${MAM_READY_TOKENS:-}"
if [ -z "$tokens" ]; then
local _facts=""
_facts="$("$(_delegate_py_bin)" -m lib_py.agents facts "$agent" 2>/dev/null)" || _facts=""
tokens="$(printf '%s\n' "$_facts" | sed -n 's/^MAM_READY_TOKENS=//p')"
[ -n "$tokens" ] && eval "tokens=$tokens"
fi
if [ -z "$tokens" ]; then
echo "wait_for_tui_ready: no ready tokens for agent '$agent'" >&2
return 1
fi
local i
for i in {1..30}; do
if _pane_dialog_open "$sess"; then
if printf '%s\n' "$(_pane_tail "$sess" 5)" | grep -q 'Press Enter to continue'; then
@@ -1545,32 +1533,10 @@ wait_for_tui_ready() {
local content
content=$(_sks_herdr capture-pane -p -t "$sess" 2>/dev/null || echo "")
if [ -n "$content" ]; then
case "$agent" in
claude)
if echo "$content" | grep -E -q "$_MAM_READY_TOKENS_CLAUDE" 2>/dev/null; then
echo "✅ Claude TUI detected ready."
return 0
fi
;;
agy)
if echo "$content" | grep -q "Antigravity" 2>/dev/null; then
echo "✅ Antigravity TUI detected ready."
return 0
fi
;;
hermes)
if echo "$content" | grep -q "Hermes" 2>/dev/null; then
echo "✅ Hermes TUI detected ready."
return 0
fi
;;
cline)
if echo "$content" | grep -E -q "Cline|history|Chat|What can I do|slash commands" 2>/dev/null; then
echo "✅ Cline TUI detected ready."
return 0
fi
;;
esac
if echo "$content" | grep -E -q "$tokens" 2>/dev/null; then
echo "$agent TUI detected ready."
return 0
fi
fi
sleep 1
done