feat(skills): implement state loader DRY (OP-5) and Job-centric directory structure
- Extract load_state_json centralized helper inside lib.sh to unify state querying - Refactor status, resume, stop, and monitor scripts to fetch state via MAM_STATE_JSON env var to avoid stdin pipeline collisions - Restructure delegate-job to provision .mam/jobs/<job_id>/brief.md and direct agents to it, minimizing token size and preventing TUI paste freezes - Harden send_keys_safe submission loop with was_popup state capture and edge case guards, preventing timing spin false-positives - Passed cross-verification approved PASS from Planner Claude session
This commit is contained in:
+62
-97
@@ -119,52 +119,50 @@ tmux() {
|
||||
# Fallback to TMUX_SERVER_NAME or 'default' if not registered or field is missing.
|
||||
# Prints the resolved server name on stdout.
|
||||
# ---------------------------------------------------------------------------
|
||||
resolve_tmux_server() {
|
||||
local session_name="$1"
|
||||
SESSION_NAME="$session_name" env_python "$AGENT_SESSIONS_YAML" <<'PYEOF'
|
||||
load_state_json() {
|
||||
env_python "$AGENT_SESSIONS_YAML" <<'PYEOF'
|
||||
import os, sys, sqlite3, json, yaml
|
||||
name = os.environ['SESSION_NAME']
|
||||
yaml_path = os.environ['YAML_PATH']
|
||||
db_path = os.path.splitext(yaml_path)[0] + '.db'
|
||||
d = {}
|
||||
db_sessions = []
|
||||
try:
|
||||
if os.path.exists(db_path):
|
||||
conn = sqlite3.connect(db_path, timeout=60.0)
|
||||
try:
|
||||
row = conn.execute('SELECT data FROM sessions WHERE name=?', (name,)).fetchone()
|
||||
if row:
|
||||
s = json.loads(row[0])
|
||||
server = s.get('tmux_server')
|
||||
if server:
|
||||
print(server)
|
||||
sys.exit(0)
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
row = conn.execute('SELECT data FROM state WHERE id=1').fetchone()
|
||||
if row:
|
||||
d = json.loads(row[0])
|
||||
for s in d.get('tmux_sessions', []):
|
||||
if s.get('name') == name:
|
||||
server = s.get('tmux_server')
|
||||
if server:
|
||||
print(server)
|
||||
sys.exit(0)
|
||||
try:
|
||||
cursor = conn.execute('SELECT data FROM sessions')
|
||||
for r in cursor.fetchall():
|
||||
db_sessions.append(json.loads(r[0]))
|
||||
d['tmux_sessions'] = db_sessions
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
conn.close()
|
||||
elif os.path.exists(yaml_path):
|
||||
with open(yaml_path) as f:
|
||||
d = yaml.safe_load(f) or {}
|
||||
for s in d.get('tmux_sessions', []):
|
||||
if s.get('name') == name:
|
||||
server = s.get('tmux_server')
|
||||
if server:
|
||||
print(server)
|
||||
sys.exit(0)
|
||||
except Exception:
|
||||
pass
|
||||
# Fallback
|
||||
print(os.environ.get('TMUX_SERVER_NAME', 'default'))
|
||||
print(json.dumps(d, ensure_ascii=False))
|
||||
PYEOF
|
||||
}
|
||||
|
||||
resolve_tmux_server() {
|
||||
local session_name="$1"
|
||||
MAM_STATE_JSON="$(load_state_json)" SESSION_NAME="$session_name" python3 -c "
|
||||
import sys, os, json
|
||||
name = os.environ['SESSION_NAME']
|
||||
d = json.loads(os.environ.get('MAM_STATE_JSON', '{}'))
|
||||
for s in d.get('tmux_sessions', []):
|
||||
if s.get('name') == name:
|
||||
print(s.get('tmux_server', 'default'))
|
||||
sys.exit(0)
|
||||
print(os.environ.get('TMUX_SERVER_NAME', 'default'))
|
||||
"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# derive_session_name <workspace> <agent>
|
||||
#
|
||||
@@ -495,15 +493,12 @@ PYEOF
|
||||
find_workspace_uuid() {
|
||||
local workspace="$1" agent="$2" session_name="${3:-}"
|
||||
local abs; abs="$(cd "$workspace" 2>/dev/null && pwd)" || abs="$workspace"
|
||||
WS_ABS="$abs" AGENT="$agent" TARGET_SESSION="$session_name" env_python "$AGENT_SESSIONS_YAML" <<'PYEOF'
|
||||
import os, json, glob, sqlite3
|
||||
import yaml
|
||||
MAM_STATE_JSON="$(load_state_json)" WS_ABS="$abs" AGENT="$agent" TARGET_SESSION="$session_name" env_python "$AGENT_SESSIONS_YAML" <<'PYEOF'
|
||||
import os, sys, json, glob, sqlite3
|
||||
|
||||
ws = os.environ['WS_ABS']
|
||||
agent = os.environ['AGENT']
|
||||
home = os.environ['HOME_DIR']
|
||||
yaml_path = os.environ['YAML_PATH']
|
||||
db_path = os.path.splitext(yaml_path)[0] + '.db'
|
||||
claude_project_dir = os.environ.get('CLAUDE_PROJECT_DIR', f"{home}/.claude/projects")
|
||||
target = os.environ.get('TARGET_SESSION', '')
|
||||
|
||||
@@ -512,13 +507,10 @@ OWN_KEY = {'claude': 'claude_session_id_own', 'agy': 'agy_conversation_id_own',
|
||||
|
||||
|
||||
def iso_root_of(s):
|
||||
# T5: per-row isolation root (all-L2). None => legacy global state dirs.
|
||||
iso = s.get('isolation')
|
||||
return iso.get('root') if isinstance(iso, dict) else None
|
||||
|
||||
|
||||
# exists checks take an optional isolation root; path templates per lever
|
||||
# (Phase 0 measured — note cline's isolated layout is <root>/sessions/, NOT data/sessions/).
|
||||
def jsonl_exists(uuid, iso=None):
|
||||
base = f"{iso}/projects" if iso else claude_project_dir
|
||||
key = ws.replace('/', '-').replace('_', '-')
|
||||
@@ -553,37 +545,21 @@ def own_exists(a, uuid, iso=None):
|
||||
'hermes': hermes_exists, 'cline': cline_exists}[a](uuid, iso)
|
||||
|
||||
|
||||
running_ids = set()
|
||||
# Ingest the merged state dictionary from stdin pipeline
|
||||
try:
|
||||
if os.path.exists(db_path):
|
||||
conn = sqlite3.connect(db_path, timeout=60.0)
|
||||
try:
|
||||
cursor = conn.execute("SELECT data FROM sessions WHERE status='running'")
|
||||
for r_row in cursor.fetchall():
|
||||
s_data = json.loads(r_row[0])
|
||||
# the target row's own ids are legitimately "claimed by itself" — don't filter them
|
||||
if target and s_data.get('name') == target:
|
||||
continue
|
||||
for k in ['claude_session_id_own', 'agy_conversation_id_own', 'hermes_conversation_id_own', 'cline_conversation_id_own']:
|
||||
val = s_data.get(k)
|
||||
if val:
|
||||
running_ids.add(val)
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
conn.close()
|
||||
if not running_ids and os.path.exists(yaml_path):
|
||||
with open(yaml_path) as f:
|
||||
d_state = yaml.safe_load(f) or {}
|
||||
for s_item in d_state.get('tmux_sessions', []):
|
||||
if s_item.get('status') == 'running':
|
||||
if target and s_item.get('name') == target:
|
||||
continue
|
||||
for k in ['claude_session_id_own', 'agy_conversation_id_own', 'hermes_conversation_id_own', 'cline_conversation_id_own']:
|
||||
val = s_item.get(k)
|
||||
if val:
|
||||
running_ids.add(val)
|
||||
d = json.loads(os.environ.get('MAM_STATE_JSON', '{}'))
|
||||
except Exception:
|
||||
pass
|
||||
d = {}
|
||||
|
||||
running_ids = set()
|
||||
for s_item in d.get('tmux_sessions', []):
|
||||
if s_item.get('status') == 'running':
|
||||
if target and s_item.get('name') == target:
|
||||
continue
|
||||
for k in ['claude_session_id_own', 'agy_conversation_id_own', 'hermes_conversation_id_own', 'cline_conversation_id_own']:
|
||||
val = s_item.get(k)
|
||||
if val:
|
||||
running_ids.add(val)
|
||||
|
||||
|
||||
def emit(u):
|
||||
@@ -593,35 +569,12 @@ def emit(u):
|
||||
raise SystemExit(0)
|
||||
|
||||
|
||||
# 1) per-row own id for THIS workspace (optimized with direct sqlite query if db exists)
|
||||
# Fetch all sessions matching this workspace
|
||||
sessions = []
|
||||
try:
|
||||
if os.path.exists(db_path):
|
||||
conn = sqlite3.connect(db_path, timeout=60.0)
|
||||
has_sessions_table = False
|
||||
try:
|
||||
cursor = conn.execute('SELECT data FROM sessions WHERE pane_cwd=?', (ws,))
|
||||
for row in cursor.fetchall():
|
||||
sessions.append(json.loads(row[0]))
|
||||
has_sessions_table = True
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
if not has_sessions_table or not sessions:
|
||||
row = conn.execute('SELECT data FROM state WHERE id=1').fetchone()
|
||||
if row:
|
||||
d = json.loads(row[0])
|
||||
for s in d.get('tmux_sessions', []):
|
||||
if isinstance(s, dict) and (s.get('pane') or {}).get('cwd') == ws:
|
||||
sessions.append(s)
|
||||
conn.close()
|
||||
elif os.path.exists(yaml_path):
|
||||
with open(yaml_path) as f:
|
||||
d = yaml.safe_load(f) or {}
|
||||
for s in d.get('tmux_sessions', []):
|
||||
if isinstance(s, dict) and (s.get('pane') or {}).get('cwd') == ws:
|
||||
sessions.append(s)
|
||||
except Exception:
|
||||
pass
|
||||
for s in d.get('tmux_sessions', []):
|
||||
if isinstance(s, dict) and (s.get('pane') or {}).get('cwd') == ws:
|
||||
sessions.append(s)
|
||||
|
||||
|
||||
# T5: target-session mode — resolve strictly within the named row's scope.
|
||||
# An isolated row's conversation lives ONLY in its isolation root (which holds
|
||||
@@ -1191,15 +1144,27 @@ send_keys_safe() {
|
||||
_sks_tmux paste-buffer -b "sks_$job_id" -t "$sess"
|
||||
_sks_tmux delete-buffer -b "sks_$job_id" 2>/dev/null || true
|
||||
sleep 0.5
|
||||
_pane_capture "$sess" | grep -Fq "$marker" || { echo "send_keys_safe: paste not visible ($sess)" >&2; return 3; }
|
||||
local pane_content was_popup=0
|
||||
pane_content=$(_pane_capture "$sess")
|
||||
if printf '%s\n' "$pane_content" | grep -Eq "Pasted text|paste again to expand"; then
|
||||
was_popup=1
|
||||
elif ! printf '%s\n' "$pane_content" | grep -Fq "$marker"; then
|
||||
echo "send_keys_safe: paste not visible ($sess)" >&2
|
||||
return 3
|
||||
fi
|
||||
|
||||
for try in 1 2 3; do
|
||||
pre_submit=$(_pane_capture "$sess")
|
||||
_sks_tmux send-keys -t "$sess" C-m
|
||||
sleep "$try"
|
||||
# Submitted = input area released the text AND rendering changed after Enter.
|
||||
if ! _pane_tail "$sess" 3 | grep -Fq "$marker" \
|
||||
&& [ "$(_pane_capture "$sess")" != "$pre_submit" ]; then
|
||||
local cur_content
|
||||
cur_content=$(_pane_capture "$sess")
|
||||
# Hardened Submission Checks
|
||||
if [ "$was_popup" = "0" ] && ! _pane_tail "$sess" 3 | grep -Fq "$marker" && [ "$cur_content" != "$pre_submit" ]; then
|
||||
return 0
|
||||
elif [ "$was_popup" = "1" ] && \
|
||||
! printf '%s\n' "$cur_content" | grep -Eq "Pasted text|paste again to expand" && \
|
||||
[ "$cur_content" != "$pre_submit" ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user