fix(commands): keep session transcript commands local-only
This commit is contained in:
@@ -2325,7 +2325,15 @@ def create_default_command_registry(
|
||||
registry.register(SlashCommand("version", "Show the installed OpenHarness version", _version_handler))
|
||||
registry.register(SlashCommand("status", "Show session status", _status_handler))
|
||||
registry.register(SlashCommand("context", "Show the active runtime system prompt", _context_handler))
|
||||
registry.register(SlashCommand("summary", "Summarize conversation history", _summary_handler))
|
||||
registry.register(
|
||||
SlashCommand(
|
||||
"summary",
|
||||
"Summarize conversation history",
|
||||
_summary_handler,
|
||||
remote_invocable=False,
|
||||
remote_admin_opt_in=True,
|
||||
)
|
||||
)
|
||||
registry.register(SlashCommand("compact", "Compact older conversation history", _compact_handler))
|
||||
registry.register(SlashCommand("cost", "Show token usage and estimated cost", _cost_handler))
|
||||
registry.register(SlashCommand("usage", "Show usage and token estimates", _usage_handler))
|
||||
@@ -2333,7 +2341,15 @@ def create_default_command_registry(
|
||||
registry.register(SlashCommand("dream", "Consolidate memory", _dream_handler))
|
||||
registry.register(SlashCommand("memory", "Inspect and manage project memory", _memory_handler))
|
||||
registry.register(SlashCommand("hooks", "Show configured hooks", _hooks_handler))
|
||||
registry.register(SlashCommand("resume", "Restore the latest saved session", _resume_handler))
|
||||
registry.register(
|
||||
SlashCommand(
|
||||
"resume",
|
||||
"Restore the latest saved session",
|
||||
_resume_handler,
|
||||
remote_invocable=False,
|
||||
remote_admin_opt_in=True,
|
||||
)
|
||||
)
|
||||
registry.register(SlashCommand("session", "Inspect the current session storage", _session_handler))
|
||||
registry.register(SlashCommand("export", "Export the current transcript", _export_handler))
|
||||
registry.register(SlashCommand("share", "Create a shareable transcript snapshot", _share_handler))
|
||||
|
||||
@@ -235,6 +235,9 @@ async def test_sensitive_control_plane_commands_are_local_only(tmp_path: Path, m
|
||||
"/model show",
|
||||
"/commit remote requested commit",
|
||||
"/ship",
|
||||
"/resume",
|
||||
"/resume session-from-another-sender",
|
||||
"/summary 10",
|
||||
):
|
||||
command, _ = registry.lookup(payload)
|
||||
assert command is not None
|
||||
|
||||
@@ -293,10 +293,88 @@ async def test_runtime_pool_summary_does_not_restore_other_slack_thread_sender(t
|
||||
updates = [u async for u in pool.stream_message(bob_message, bob_key)]
|
||||
|
||||
assert updates[-1].kind == "final"
|
||||
assert updates[-1].text == "No conversation content to summarize."
|
||||
assert updates[-1].text == "/summary is only available in the local OpenHarness UI."
|
||||
assert "ALICE_PRIVATE_SUMMARY_SECRET" not in updates[-1].text
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_runtime_pool_blocks_registered_resume_without_listing_or_loading_other_sessions(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
workspace = tmp_path / ".ohmo-home"
|
||||
initialize_workspace(workspace)
|
||||
registry = create_default_command_registry()
|
||||
command, _ = registry.lookup("/resume alice-session")
|
||||
|
||||
assert command is not None
|
||||
assert command.name == "resume"
|
||||
assert command.remote_invocable is False
|
||||
|
||||
alice_secret = "ALICE_PRIVATE_RESUME_SECRET"
|
||||
alice_key = "slack:C_SHARED:thread1:U_ALICE"
|
||||
bob_key = "slack:C_SHARED:thread1:U_BOB"
|
||||
save_session_snapshot(
|
||||
cwd=tmp_path,
|
||||
workspace=workspace,
|
||||
model="gpt-5.4",
|
||||
system_prompt="test",
|
||||
session_id="alice-session",
|
||||
session_key=alice_key,
|
||||
usage=UsageSnapshot(),
|
||||
messages=[ConversationMessage.from_user_text(f"Alice private note: {alice_secret}")],
|
||||
)
|
||||
|
||||
async def fake_build_runtime(**kwargs):
|
||||
class FakeEngine:
|
||||
messages = []
|
||||
total_usage = UsageSnapshot()
|
||||
|
||||
def set_system_prompt(self, prompt):
|
||||
return None
|
||||
|
||||
def load_messages(self, messages):
|
||||
raise AssertionError("remote /resume must not load saved messages")
|
||||
|
||||
return SimpleNamespace(
|
||||
engine=FakeEngine(),
|
||||
cwd=str(tmp_path),
|
||||
session_id="bob-session",
|
||||
current_settings=lambda: SimpleNamespace(model="gpt-5.4"),
|
||||
commands=registry,
|
||||
tool_registry=None,
|
||||
app_state=None,
|
||||
session_backend=None,
|
||||
extra_skill_dirs=(),
|
||||
extra_plugin_roots=(),
|
||||
hook_summary=lambda: "",
|
||||
mcp_summary=lambda: "",
|
||||
plugin_summary=lambda: "",
|
||||
)
|
||||
|
||||
async def fake_start_runtime(bundle):
|
||||
return None
|
||||
|
||||
monkeypatch.setattr("ohmo.gateway.runtime.build_runtime", fake_build_runtime)
|
||||
monkeypatch.setattr("ohmo.gateway.runtime.start_runtime", fake_start_runtime)
|
||||
|
||||
pool = OhmoSessionRuntimePool(cwd=tmp_path, workspace=workspace, provider_profile="codex")
|
||||
for payload in ("/resume", "/resume alice-session"):
|
||||
message = InboundMessage(
|
||||
channel="slack",
|
||||
sender_id="U_BOB",
|
||||
chat_id="C_SHARED",
|
||||
content=payload,
|
||||
timestamp=datetime.utcnow(),
|
||||
metadata={"thread_ts": "thread1", "chat_type": "group"},
|
||||
)
|
||||
updates = [u async for u in pool.stream_message(message, bob_key)]
|
||||
|
||||
assert updates[-1].kind == "final"
|
||||
assert updates[-1].text == "/resume is only available in the local OpenHarness UI."
|
||||
assert "alice-session" not in updates[-1].text
|
||||
assert alice_secret not in updates[-1].text
|
||||
|
||||
|
||||
def test_gateway_error_formats_claude_refresh_failure():
|
||||
exc = ValueError("Claude OAuth refresh failed: HTTP Error 400: Bad Request")
|
||||
assert "claude-login" in _format_gateway_error(exc)
|
||||
|
||||
Reference in New Issue
Block a user