docs: update DRAFT_PLAN.md with problem definitions & gRPC justification, move agent rules to .agents/

This commit is contained in:
2026-07-06 09:53:36 +09:00
parent 403793cbb9
commit ee9ae41195
29 changed files with 1294 additions and 2139 deletions
+45 -3
View File
@@ -19,7 +19,7 @@ WORKSPACE_ROOT="$(cd "$SKILL_DIR/../.." && pwd)"
AGENT_SESSIONS_YAML="${AGENT_SESSIONS_YAML:-$WORKSPACE_ROOT/.mam/agent-sessions.yaml}"
# Workspace-relative defaults with environment overrides (Phase Z)
HOME_DIR="${HOME_DIR:-$WORKSPACE_ROOT}"
HOME_DIR="${HOME_DIR:-$HOME}"
CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$HOME/.claude/projects}"
LOCAL_BIN="${LOCAL_BIN:-$HOME/.local/bin}"
@@ -305,6 +305,8 @@ def _validate(d):
raise SystemExit(f"VALIDATE: tmux_sessions[{i}] not a mapping")
if not s.get('name') or not s.get('status'):
raise SystemExit(f"VALIDATE: tmux_sessions[{i}] missing name/status")
if s.get('role') is not None and (not isinstance(s['role'], str) or not s['role'].strip()):
raise SystemExit(f"VALIDATE: tmux_sessions[{i}] {s.get('name')!r} role must be a non-empty string")
if s['status'] not in valid:
raise SystemExit(f"VALIDATE: tmux_sessions[{i}] {s.get('name')!r} bad status {s['status']!r}")
if not isinstance(s.get('pane'), dict):
@@ -366,10 +368,17 @@ try:
d['tmux_sessions'] = []
old_terminals = get_terminal_set(d)
old_roles = {s.get('name'): s.get('role') for s in db_sessions if s.get('role')}
# --- caller mutation (module scope: sees d, yaml, os, glob, subprocess) ---
exec(compile(os.environ['AGENT_SESSIONS_MUTATION'], '<mutation>', 'exec'), globals())
# Role immutability check
for s in d.get('tmux_sessions', []):
name = s.get('name')
if name in old_roles and s.get('role') != old_roles[name]:
raise SystemExit(f"VALIDATE: role of session {name!r} cannot be modified from {old_roles[name]!r} to {s.get('role')!r}")
_validate(d)
# Separate globals and sessions for normalization
@@ -475,7 +484,7 @@ def db_exists(uuid):
def hermes_exists(uuid):
hdb = f"{home}/.mam/state.db"
hdb = f"{home}/.hermes/state.db"
if not os.path.exists(hdb):
return False
try:
@@ -487,6 +496,10 @@ def hermes_exists(uuid):
return False
def cline_exists(uuid):
return os.path.exists(f"{home}/.cline/data/sessions/{uuid}/{uuid}.json")
def emit(u):
print(u)
raise SystemExit(0)
@@ -536,6 +549,10 @@ for s in sessions:
cand = s.get('hermes_conversation_id_own')
if cand and hermes_exists(cand):
emit(cand)
if agent == 'cline' and name.endswith('-creator-cline'):
cand = s.get('cline_conversation_id_own')
if cand and cline_exists(cand):
emit(cand)
# 2) disk scan scoped to THIS workspace
if agent == 'claude':
@@ -565,7 +582,7 @@ elif agent == 'agy':
if cand and db_exists(cand):
emit(cand)
elif agent == 'hermes':
hdb = f"{home}/.mam/state.db"
hdb = f"{home}/.hermes/state.db"
if os.path.exists(hdb):
cand = None
try:
@@ -578,6 +595,27 @@ elif agent == 'hermes':
cand = None
if cand:
emit(cand)
elif agent == 'cline':
sessions_dir = f"{home}/.cline/data/sessions"
if os.path.isdir(sessions_dir):
candidates = []
for session_folder in glob.glob(f"{sessions_dir}/*"):
if os.path.isdir(session_folder):
folder_name = os.path.basename(session_folder)
json_file = f"{session_folder}/{folder_name}.json"
if os.path.exists(json_file):
candidates.append(json_file)
candidates.sort(key=os.path.getmtime, reverse=True)
for j in candidates:
try:
with open(j) as f:
sdata = json.load(f)
if sdata.get('cwd') == ws or sdata.get('workspace_root') == ws:
sid = sdata.get('session_id')
if sid:
emit(sid)
except Exception:
pass
# 3) agent_identities cache, ONLY when its project_cwd == this workspace
ai = {}
@@ -609,6 +647,10 @@ if ai_agent.get('project_cwd') == ws:
cand = ai_agent.get('session_id') or ai.get('conversation_id')
if cand and hermes_exists(cand):
emit(cand)
elif agent == 'cline':
cand = ai_agent.get('session_id') or ai.get('conversation_id')
if cand and cline_exists(cand):
emit(cand)
print('')
PYEOF