refactor(honcho): shorten the peers-map helpers
_api_workspace_peers returns peer IDs instead of dicts. The created date it carried was never printed. Callers index the list directly. _preview_peer_resolution uses _sanitize_peer_id instead of a local copy. _sibling_resolutions strips the display suffix itself; its one caller did. _seen_gateway_accounts opens the database under contextlib.closing and parses origin_json once into a dict. _save_alias_map picks the target block first and writes it once. cmd_peers_map renders through one local show() and computes the previous resolution on one path for both account numbers and typed runtime IDs.
This commit is contained in:
+97
-179
@@ -1058,23 +1058,18 @@ def _state_db_path() -> Path:
|
||||
|
||||
|
||||
def _seen_gateway_accounts(db_path: Path) -> list[dict]:
|
||||
"""Return gateway accounts recorded in state.db, most recent first.
|
||||
"""Gateway accounts recorded in state.db, most recent first; bot authors are skipped.
|
||||
|
||||
The gateway stamps each session row with its routing peer (source,
|
||||
user_id, display_name, origin_json), so grouping rows by
|
||||
(source, user_id) enumerates every account the gateway has handled.
|
||||
Bot authors are skipped.
|
||||
The gateway stamps each session row with its routing peer, so grouping rows by
|
||||
(source, user_id) enumerates every account it has handled.
|
||||
"""
|
||||
if not db_path.exists():
|
||||
return []
|
||||
import sqlite3
|
||||
try:
|
||||
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
|
||||
except sqlite3.Error:
|
||||
return []
|
||||
from contextlib import closing
|
||||
# profile_name marks which profile a multiplexing gateway routed the
|
||||
# session to; older state.db files predate the column.
|
||||
base_query = """SELECT source, user_id,
|
||||
query = """SELECT source, user_id,
|
||||
MAX(COALESCE(display_name, '')),
|
||||
MAX(COALESCE(origin_json, '')),
|
||||
COUNT(*){profiles_col}
|
||||
@@ -1083,66 +1078,60 @@ def _seen_gateway_accounts(db_path: Path) -> list[dict]:
|
||||
GROUP BY source, user_id
|
||||
ORDER BY MAX(COALESCE(started_at, 0)) DESC"""
|
||||
try:
|
||||
try:
|
||||
rows = conn.execute(base_query.format(
|
||||
profiles_col=",\n GROUP_CONCAT(DISTINCT COALESCE(profile_name, 'default'))",
|
||||
)).fetchall()
|
||||
except sqlite3.OperationalError:
|
||||
rows = [r + (None,) for r in conn.execute(
|
||||
base_query.format(profiles_col=""),
|
||||
).fetchall()]
|
||||
with closing(sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)) as conn:
|
||||
try:
|
||||
rows = conn.execute(query.format(
|
||||
profiles_col=", GROUP_CONCAT(DISTINCT COALESCE(profile_name, 'default'))",
|
||||
)).fetchall()
|
||||
except sqlite3.OperationalError:
|
||||
rows = [r + (None,) for r in conn.execute(query.format(profiles_col="")).fetchall()]
|
||||
except sqlite3.Error:
|
||||
return []
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
accounts = []
|
||||
for source, user_id, display_name, origin_json, count, profiles in rows:
|
||||
user_name = ""
|
||||
user_id_alt = ""
|
||||
is_bot = False
|
||||
if origin_json:
|
||||
try:
|
||||
origin = json.loads(origin_json)
|
||||
user_name = origin.get("user_name") or ""
|
||||
user_id_alt = origin.get("user_id_alt") or ""
|
||||
is_bot = bool(origin.get("is_bot"))
|
||||
except Exception:
|
||||
pass
|
||||
if is_bot:
|
||||
try:
|
||||
origin = dict(json.loads(origin_json)) if origin_json else {}
|
||||
except Exception:
|
||||
origin = {}
|
||||
if origin.get("is_bot"):
|
||||
continue
|
||||
accounts.append({
|
||||
"platform": source or "?",
|
||||
"user_id": str(user_id),
|
||||
"user_id_alt": str(user_id_alt),
|
||||
"label": user_name or display_name or "",
|
||||
"user_id_alt": str(origin.get("user_id_alt") or ""),
|
||||
"label": origin.get("user_name") or display_name or "",
|
||||
"sessions": count,
|
||||
"profiles": sorted(profiles.split(",")) if profiles else [],
|
||||
})
|
||||
return accounts
|
||||
|
||||
|
||||
def _sanitize_peer_id(s: str) -> str:
|
||||
import re
|
||||
return re.sub(r'[^a-zA-Z0-9_-]', '-', s)
|
||||
|
||||
|
||||
def _preview_peer_resolution(
|
||||
user_id: str, *, pin: bool, aliases: dict, prefix: str, peer_name: str,
|
||||
user_id_alt: str = "",
|
||||
) -> str:
|
||||
"""Mirror the runtime resolver ladder for display: pin → alias → prefix → raw."""
|
||||
import re
|
||||
|
||||
def sanitize(s: str) -> str:
|
||||
return re.sub(r'[^a-zA-Z0-9_-]', '-', s)
|
||||
|
||||
if pin and peer_name:
|
||||
return f"{sanitize(peer_name)} (pinned)"
|
||||
# The runtime resolver checks the primary ID first, then the alt ID
|
||||
# (Signal UUID, Feishu union_id) against the same alias map.
|
||||
return f"{_sanitize_peer_id(peer_name)} (pinned)"
|
||||
# The runtime resolver tries the alt ID (Signal UUID, Feishu union_id) after the primary.
|
||||
for rid in (user_id, user_id_alt):
|
||||
alias = aliases.get(rid) if rid else None
|
||||
if isinstance(alias, str) and alias.strip():
|
||||
return sanitize(alias.strip())
|
||||
return _sanitize_peer_id(alias.strip())
|
||||
if prefix:
|
||||
return f"{sanitize(prefix + user_id)} (prefixed)"
|
||||
return sanitize(user_id)
|
||||
return f"{_sanitize_peer_id(prefix + user_id)} (prefixed)"
|
||||
return _sanitize_peer_id(user_id)
|
||||
|
||||
|
||||
def _resolution_base(resolved: str) -> str:
|
||||
"""Strip display suffixes so the name can be checked against peer IDs."""
|
||||
return resolved.removesuffix(" (pinned)").removesuffix(" (prefixed)")
|
||||
|
||||
|
||||
# Workspaces holding thousands of peers (public bots) must not stall the CLI.
|
||||
@@ -1150,10 +1139,7 @@ _PEERS_MAP_FETCH_CAP = 200
|
||||
|
||||
|
||||
def _peers_map_client(workspace: str | None = None):
|
||||
"""Return (client, config) for the active host, or (None, None) offline.
|
||||
|
||||
``workspace`` overrides the configured workspace for browse mode.
|
||||
"""
|
||||
"""(client, config) for the active host, or (None, None) offline. ``workspace`` overrides the configured one."""
|
||||
try:
|
||||
from dataclasses import replace
|
||||
from plugins.memory.honcho.client import HonchoClientConfig, get_honcho_client
|
||||
@@ -1167,22 +1153,16 @@ def _peers_map_client(workspace: str | None = None):
|
||||
return None, None
|
||||
|
||||
|
||||
def _api_workspace_peers(client) -> list[dict] | None:
|
||||
"""Fetch workspace peers (id + created date). None = API unavailable."""
|
||||
def _api_workspace_peers(client) -> list[str] | None:
|
||||
"""Workspace peer IDs, at most _PEERS_MAP_FETCH_CAP. None = API unavailable."""
|
||||
if client is None:
|
||||
return None
|
||||
try:
|
||||
peers: list[dict] = []
|
||||
peers: list[str] = []
|
||||
page = 1
|
||||
while len(peers) < _PEERS_MAP_FETCH_CAP:
|
||||
batch = list(client.peers(page=page, size=50))
|
||||
if not batch:
|
||||
break
|
||||
for p in batch:
|
||||
peers.append({
|
||||
"id": str(p.id),
|
||||
"created": str(getattr(p, "created_at", "") or "")[:10],
|
||||
})
|
||||
peers += [str(p.id) for p in batch]
|
||||
if len(batch) < 50:
|
||||
break
|
||||
page += 1
|
||||
@@ -1213,11 +1193,6 @@ def _api_peer_detail(client, peer_id: str) -> str:
|
||||
return f"(peer detail unavailable: {e})"
|
||||
|
||||
|
||||
def _sanitize_peer_id(s: str) -> str:
|
||||
import re
|
||||
return re.sub(r'[^a-zA-Z0-9_-]', '-', s)
|
||||
|
||||
|
||||
def _classify_workspace_peers(
|
||||
peer_ids: list[str], cfg: dict, accounts: list[dict],
|
||||
aliases: dict, prefix: str,
|
||||
@@ -1248,8 +1223,7 @@ def _classify_workspace_peers(
|
||||
for key, kind in (("peerName", "peer"), ("aiPeer", "AI peer")):
|
||||
val = block.get(key)
|
||||
if isinstance(val, str) and val.strip():
|
||||
labels.setdefault(
|
||||
_sanitize_peer_id(val.strip()), f"{kind} of app '{hostk}'")
|
||||
labels.setdefault(_sanitize_peer_id(val.strip()), f"{kind} of app '{hostk}'")
|
||||
|
||||
for target in aliases.values():
|
||||
if isinstance(target, str) and target.strip():
|
||||
@@ -1257,20 +1231,13 @@ def _classify_workspace_peers(
|
||||
|
||||
for acct in accounts:
|
||||
rid = acct["user_id"]
|
||||
candidates = [_sanitize_peer_id(rid)]
|
||||
if prefix:
|
||||
candidates.append(_sanitize_peer_id(prefix + rid))
|
||||
for candidate in candidates:
|
||||
labels.setdefault(
|
||||
candidate, f"runtime peer · {acct['platform']} {rid}")
|
||||
for candidate in ([rid, prefix + rid] if prefix else [rid]):
|
||||
labels.setdefault(_sanitize_peer_id(candidate), f"runtime peer · {acct['platform']} {rid}")
|
||||
|
||||
out = {}
|
||||
for pid in peer_ids:
|
||||
label = labels.get(pid)
|
||||
if label is None and pid.startswith("user-"):
|
||||
label = "fallback peer (pre-identity traffic)"
|
||||
out[pid] = label or "unrecognized"
|
||||
return out
|
||||
return {
|
||||
pid: labels.get(pid) or ("fallback peer (pre-identity traffic)" if pid.startswith("user-") else "unrecognized")
|
||||
for pid in peer_ids
|
||||
}
|
||||
|
||||
|
||||
def _sibling_resolutions(cfg: dict, acct: dict) -> dict[str, str]:
|
||||
@@ -1278,25 +1245,19 @@ def _sibling_resolutions(cfg: dict, acct: dict) -> dict[str, str]:
|
||||
out = {}
|
||||
for name, _hostk, block in _all_profile_host_configs():
|
||||
pin, aliases, prefix, _, _ = _resolve_effective_identity_mapping(cfg, block)
|
||||
pn = block.get("peerName") or cfg.get("peerName") or ""
|
||||
out[name] = _preview_peer_resolution(
|
||||
out[name] = _resolution_base(_preview_peer_resolution(
|
||||
acct["user_id"], pin=pin, aliases=aliases, prefix=prefix,
|
||||
peer_name=pn, user_id_alt=acct["user_id_alt"],
|
||||
)
|
||||
peer_name=block.get("peerName") or cfg.get("peerName") or "",
|
||||
user_id_alt=acct["user_id_alt"],
|
||||
))
|
||||
return out
|
||||
|
||||
|
||||
def _resolution_base(resolved: str) -> str:
|
||||
"""Strip display suffixes so the name can be checked against peer IDs."""
|
||||
return resolved.removesuffix(" (pinned)").removesuffix(" (prefixed)")
|
||||
|
||||
|
||||
def _render_peers_map_view(
|
||||
workspace: str, ws_peers: list[dict] | None, labels: dict,
|
||||
workspace: str, ws_peers: list[str] | None, labels: dict,
|
||||
accounts: list[dict], cfg: dict, *,
|
||||
pin: bool, working: dict, prefix: str, peer_name: str,
|
||||
) -> None:
|
||||
peer_id_set = {p["id"] for p in (ws_peers or [])}
|
||||
if ws_peers is None:
|
||||
print(f"\nWorkspace '{workspace}' — peers unavailable (offline or not configured)")
|
||||
print(" Mapping still works; target peers are typed instead of picked.")
|
||||
@@ -1305,14 +1266,11 @@ def _render_peers_map_view(
|
||||
if not ws_peers:
|
||||
print(" No peers here yet — peers appear after the first conversation.")
|
||||
print(" Wrong workspace? 'w' lists the workspaces this key can see.")
|
||||
for i, p in enumerate(ws_peers, 1):
|
||||
print(f" p{i:<4} {p['id']:<30} {labels.get(p['id'], '')}")
|
||||
for i, pid in enumerate(ws_peers, 1):
|
||||
print(f" p{i:<4} {pid:<30} {labels.get(pid, '')}")
|
||||
if len(ws_peers) >= _PEERS_MAP_FETCH_CAP:
|
||||
print(f" … listing capped at {_PEERS_MAP_FETCH_CAP} peers.")
|
||||
recognized = any(
|
||||
v.startswith(("your peer", "AI peer")) for v in labels.values()
|
||||
)
|
||||
if ws_peers and not recognized:
|
||||
if ws_peers and not any(v.startswith(("your peer", "AI peer")) for v in labels.values()):
|
||||
print(f"\n None of these match your configured identity ('{peer_name or workspace}').")
|
||||
print(" Wrong workspace? 'w' lists the workspaces this key can see.")
|
||||
|
||||
@@ -1324,32 +1282,24 @@ def _render_peers_map_view(
|
||||
print(" by typing it at the prompt below.")
|
||||
return
|
||||
print(f" {'#':<4} {'Platform':<10} {'Runtime ID':<22} {'Name':<14} {'Resolves to'}")
|
||||
known = set(ws_peers or [])
|
||||
for idx, acct in enumerate(accounts, 1):
|
||||
resolved = _preview_peer_resolution(
|
||||
acct["user_id"], pin=pin, aliases=working,
|
||||
prefix=prefix, peer_name=peer_name,
|
||||
user_id_alt=acct["user_id_alt"],
|
||||
acct["user_id"], pin=pin, aliases=working, prefix=prefix,
|
||||
peer_name=peer_name, user_id_alt=acct["user_id_alt"],
|
||||
)
|
||||
marker = ""
|
||||
if ws_peers is not None:
|
||||
marker = " ✓" if _resolution_base(resolved) in peer_id_set else " ○ new"
|
||||
siblings = _sibling_resolutions(cfg, acct)
|
||||
mine = _resolution_base(resolved)
|
||||
marker = "" if ws_peers is None else (" ✓" if mine in known else " ○ new")
|
||||
diverging = {
|
||||
n: _resolution_base(v) for n, v in siblings.items()
|
||||
if n != active_profile and _resolution_base(v) != mine
|
||||
n: v for n, v in _sibling_resolutions(cfg, acct).items()
|
||||
if n != active_profile and v != mine
|
||||
}
|
||||
div = ""
|
||||
if diverging:
|
||||
div = " ≠ " + ", ".join(f"{n}→{v}" for n, v in sorted(diverging.items()))
|
||||
via = ""
|
||||
div = " ≠ " + ", ".join(f"{n}→{v}" for n, v in sorted(diverging.items())) if diverging else ""
|
||||
profiles = acct.get("profiles") or []
|
||||
if profiles and active_profile not in profiles:
|
||||
via = f" (traffic → {', '.join(profiles)})"
|
||||
label = acct["label"][:13]
|
||||
via = f" (traffic → {', '.join(profiles)})" if profiles and active_profile not in profiles else ""
|
||||
print(
|
||||
f" {idx:<4} {acct['platform']:<10} {acct['user_id']:<22} "
|
||||
f"{label:<14} {resolved}{marker}{div}{via}"
|
||||
f"{acct['label'][:13]:<14} {resolved}{marker}{div}{via}"
|
||||
)
|
||||
|
||||
|
||||
@@ -1364,8 +1314,7 @@ def _workspaces_flow(client, current_ws: str, cfg: dict, host: str):
|
||||
return None
|
||||
print(f"\n Workspaces this key can see ({len(ws_list)}):")
|
||||
for i, w in enumerate(ws_list, 1):
|
||||
marker = " ← current" if w == current_ws else ""
|
||||
print(f" {i:<4} {w}{marker}")
|
||||
print(f" {i:<4} {w}{' ← current' if w == current_ws else ''}")
|
||||
print("\n Tip: for a full workspace browser, install honcho-cli")
|
||||
print(" (uv tool install honcho-cli).")
|
||||
sel = _prompt("Browse a workspace (number, blank to go back)", default="").strip()
|
||||
@@ -1378,17 +1327,16 @@ def _workspaces_flow(client, current_ws: str, cfg: dict, host: str):
|
||||
print(f" Could not list peers of '{target_ws}'.")
|
||||
return None
|
||||
print(f"\n Workspace '{target_ws}' — {len(b_peers)} peers")
|
||||
for p in b_peers[:30]:
|
||||
print(f" {p['id']}")
|
||||
for pid in b_peers[:30]:
|
||||
print(f" {pid}")
|
||||
if len(b_peers) > 30:
|
||||
print(f" … and {len(b_peers) - 30} more")
|
||||
if target_ws == current_ws:
|
||||
return None
|
||||
switch = _prompt(
|
||||
if not _yes(_prompt(
|
||||
f"Point this profile at '{target_ws}'? Existing memory stays in '{current_ws}'. (y/N)",
|
||||
default="n",
|
||||
).strip().lower()
|
||||
if switch not in {"y", "yes"}:
|
||||
)):
|
||||
return None
|
||||
cfg.setdefault("hosts", {}).setdefault(host, {})["workspace"] = target_ws
|
||||
_write_config(cfg)
|
||||
@@ -1401,23 +1349,21 @@ def _save_alias_map(cfg: dict, host: str, working: dict, aliases_from_root: bool
|
||||
profiles = _all_profile_host_configs()
|
||||
write_root = aliases_from_root
|
||||
if aliases_from_root and len(profiles) > 1:
|
||||
scope = _prompt(
|
||||
"Apply to all profiles (root) or only this profile? (all/this)",
|
||||
default="all",
|
||||
).strip().lower()
|
||||
if scope in {"this", "t", "host", "only"}:
|
||||
scope = _prompt("Apply to all profiles (root) or only this profile? (all/this)", default="all")
|
||||
if scope.strip().lower() in {"this", "t", "host", "only"}:
|
||||
write_root = False
|
||||
print(f" This forks [{host}] from the shared root map — future root")
|
||||
print(" edits no longer reach this profile.")
|
||||
|
||||
target = cfg if write_root else cfg.setdefault("hosts", {}).setdefault(host, {})
|
||||
if working:
|
||||
target["userPeerAliases"] = working
|
||||
else:
|
||||
target.pop("userPeerAliases", None)
|
||||
target_desc = f"host block [{host}]"
|
||||
if write_root:
|
||||
if working:
|
||||
cfg["userPeerAliases"] = working
|
||||
else:
|
||||
cfg.pop("userPeerAliases", None)
|
||||
target_desc = "root config (shared by all profiles)"
|
||||
hermes_host = _host_block(cfg, host)
|
||||
active_ws = hermes_host.get("workspace") or cfg.get("workspace") or host
|
||||
active_ws = _host_block(cfg, host).get("workspace") or cfg.get("workspace") or host
|
||||
other_ws: dict[str, list[str]] = {}
|
||||
for name, hostk, block in profiles:
|
||||
ws = block.get("workspace") or cfg.get("workspace") or hostk
|
||||
@@ -1426,13 +1372,6 @@ def _save_alias_map(cfg: dict, host: str, working: dict, aliases_from_root: bool
|
||||
for ws, names in sorted(other_ws.items()):
|
||||
print(f" ⚠ root aliases also apply in workspace '{ws}' (profile")
|
||||
print(f" {', '.join(names)}) — picked peers may not exist there.")
|
||||
else:
|
||||
block = cfg.setdefault("hosts", {}).setdefault(host, {})
|
||||
if working:
|
||||
block["userPeerAliases"] = working
|
||||
else:
|
||||
block.pop("userPeerAliases", None)
|
||||
target_desc = f"host block [{host}]"
|
||||
|
||||
_write_config(cfg)
|
||||
print(f"\n userPeerAliases = {working if working else '{}'}")
|
||||
@@ -1444,38 +1383,33 @@ def cmd_peers_map(args) -> None:
|
||||
cfg = _read_config()
|
||||
host = _host_key()
|
||||
hermes_host = _host_block(cfg, host)
|
||||
(
|
||||
pin, aliases, prefix, aliases_from_root, _prefix_from_root,
|
||||
) = _resolve_effective_identity_mapping(cfg, hermes_host)
|
||||
pin, aliases, prefix, aliases_from_root, _ = _resolve_effective_identity_mapping(cfg, hermes_host)
|
||||
peer_name = hermes_host.get("peerName") or cfg.get("peerName") or ""
|
||||
|
||||
if pin:
|
||||
print("\n pinUserPeer is on: every gateway account resolves to peer")
|
||||
print(f" '{peer_name or '(peerName not set)'}' and aliases have no effect.")
|
||||
print(" Turn the pin off with 'hermes honcho setup' to use per-account peers.")
|
||||
cont = _prompt("Edit aliases anyway? (y/N)", default="n").strip().lower()
|
||||
if cont not in {"y", "yes"}:
|
||||
if not _yes(_prompt("Edit aliases anyway? (y/N)", default="n")):
|
||||
print(" Nothing changed.\n")
|
||||
return
|
||||
|
||||
accounts = _seen_gateway_accounts(_state_db_path())
|
||||
working = dict(aliases) if isinstance(aliases, dict) else {}
|
||||
|
||||
client, client_cfg = _peers_map_client()
|
||||
workspace = (
|
||||
getattr(client_cfg, "workspace_id", None)
|
||||
or hermes_host.get("workspace") or cfg.get("workspace") or host
|
||||
)
|
||||
ws_peers = _api_workspace_peers(client)
|
||||
labels = _classify_workspace_peers(
|
||||
[p["id"] for p in (ws_peers or [])], cfg, accounts, working, prefix,
|
||||
)
|
||||
|
||||
_render_peers_map_view(
|
||||
workspace, ws_peers, labels, accounts, cfg,
|
||||
pin=pin, working=working, prefix=prefix, peer_name=peer_name,
|
||||
)
|
||||
def show() -> dict[str, str]:
|
||||
labels = _classify_workspace_peers(ws_peers or [], cfg, accounts, working, prefix)
|
||||
_render_peers_map_view(workspace, ws_peers, labels, accounts, cfg,
|
||||
pin=pin, working=working, prefix=prefix, peer_name=peer_name)
|
||||
return labels
|
||||
|
||||
labels = show()
|
||||
print("\n Map: account number or a runtime ID · pN inspects a peer ·")
|
||||
print(" w lists workspaces · blank finishes.")
|
||||
changed = False
|
||||
@@ -1489,39 +1423,26 @@ def cmd_peers_map(args) -> None:
|
||||
switched = _workspaces_flow(client, workspace, cfg, host)
|
||||
if switched:
|
||||
workspace, client, ws_peers = switched
|
||||
labels = _classify_workspace_peers(
|
||||
[p["id"] for p in ws_peers], cfg, accounts, working, prefix,
|
||||
)
|
||||
_render_peers_map_view(
|
||||
workspace, ws_peers, labels, accounts, cfg,
|
||||
pin=pin, working=working, prefix=prefix, peer_name=peer_name,
|
||||
)
|
||||
labels = show()
|
||||
continue
|
||||
|
||||
if low.startswith("p") and low[1:].isdigit() and ws_peers:
|
||||
n = int(low[1:])
|
||||
if 1 <= n <= len(ws_peers):
|
||||
pid = ws_peers[n - 1]["id"]
|
||||
pid = ws_peers[n - 1]
|
||||
print(f"\n {pid} — {labels.get(pid, '')}")
|
||||
print(f" {_api_peer_detail(client, pid)}\n")
|
||||
continue
|
||||
|
||||
if sel.isdigit() and 1 <= int(sel) <= len(accounts):
|
||||
acct = accounts[int(sel) - 1]
|
||||
rid = acct["user_id"]
|
||||
label = f"{acct['platform']} {rid}" + (
|
||||
f" ({acct['label']})" if acct["label"] else ""
|
||||
)
|
||||
prev_resolved = _resolution_base(_preview_peer_resolution(
|
||||
rid, pin=pin, aliases=working, prefix=prefix,
|
||||
peer_name=peer_name, user_id_alt=acct["user_id_alt"],
|
||||
))
|
||||
rid, alt = acct["user_id"], acct["user_id_alt"]
|
||||
label = f"{acct['platform']} {rid}" + (f" ({acct['label']})" if acct["label"] else "")
|
||||
else:
|
||||
rid = sel
|
||||
label = sel
|
||||
prev_resolved = _resolution_base(_preview_peer_resolution(
|
||||
rid, pin=pin, aliases=working, prefix=prefix, peer_name=peer_name,
|
||||
))
|
||||
rid, alt, label = sel, "", sel
|
||||
prev_resolved = _resolution_base(_preview_peer_resolution(
|
||||
rid, pin=pin, aliases=working, prefix=prefix, peer_name=peer_name, user_id_alt=alt,
|
||||
))
|
||||
|
||||
current = working.get(rid, "")
|
||||
hint = " (pN from the peers table, a name, '-' clears)" if ws_peers else ""
|
||||
@@ -1532,18 +1453,15 @@ def cmd_peers_map(args) -> None:
|
||||
changed = True
|
||||
print(f" cleared: {rid}")
|
||||
continue
|
||||
if entered.lower().startswith("p") and entered[1:].isdigit() and ws_peers:
|
||||
n = int(entered[1:])
|
||||
if 1 <= n <= len(ws_peers):
|
||||
entered = ws_peers[n - 1]["id"]
|
||||
if ws_peers and entered[:1].lower() == "p" and entered[1:].isdigit() and 0 < int(entered[1:]) <= len(ws_peers):
|
||||
entered = ws_peers[int(entered[1:]) - 1]
|
||||
if entered and entered != current:
|
||||
working[rid] = entered
|
||||
changed = True
|
||||
peer_id_set = {p["id"] for p in (ws_peers or [])}
|
||||
print(f" {rid} → {entered} — future messages resolve to '{entered}'")
|
||||
if ws_peers is not None and _sanitize_peer_id(entered) not in peer_id_set:
|
||||
if ws_peers is not None and _sanitize_peer_id(entered) not in ws_peers:
|
||||
print(f" '{entered}' is a new peer — created on first message.")
|
||||
if prev_resolved in peer_id_set and prev_resolved != _sanitize_peer_id(entered):
|
||||
if prev_resolved in (ws_peers or ()) and prev_resolved != _sanitize_peer_id(entered):
|
||||
print(f" peer '{prev_resolved}' keeps its existing history.")
|
||||
|
||||
if not changed:
|
||||
|
||||
@@ -186,10 +186,7 @@ class TestCmdPeersMap:
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
honcho_cli, "_api_workspace_peers",
|
||||
lambda client: (
|
||||
[{"id": p, "created": "2026-01-01"} for p in ws_peers]
|
||||
if client is not None and ws_peers is not None else None
|
||||
),
|
||||
lambda client: list(ws_peers) if client is not None and ws_peers is not None else None,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
honcho_cli, "_api_workspaces",
|
||||
|
||||
Reference in New Issue
Block a user