soothe-cli 0.6.7__tar.gz → 0.6.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/PKG-INFO +1 -1
  2. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/commands/loop_cmd.py +4 -4
  3. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/execution/daemon.py +1 -1
  4. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/execution/headless.py +8 -9
  5. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/main.py +1 -1
  6. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/headless/processor.py +1 -1
  7. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/headless/processor_state.py +1 -1
  8. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/policy/essential_events.py +4 -4
  9. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/policy/tui_trace_log.py +1 -1
  10. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/state/step_router.py +1 -1
  11. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/transport/session.py +6 -6
  12. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/turn/prepare.py +12 -12
  13. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/_app.py +2 -2
  14. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/_module_init.py +1 -1
  15. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/_startup.py +4 -1
  16. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/command_registry.py +1 -1
  17. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/commands/command_router.py +2 -2
  18. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/config.py +1 -1
  19. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/sessions.py +2 -2
  20. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/textual_adapter.py +18 -18
  21. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/tips.py +1 -1
  22. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/welcome.py +1 -1
  23. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/.gitignore +0 -0
  24. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/README.md +0 -0
  25. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/pyproject.toml +0 -0
  26. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/__init__.py +0 -0
  27. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/__init__.py +0 -0
  28. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/commands/__init__.py +0 -0
  29. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/commands/autopilot_cmd.py +0 -0
  30. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/commands/run_cmd.py +0 -0
  31. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/commands/status_cmd.py +0 -0
  32. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/execution/__init__.py +0 -0
  33. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/execution/daemon_errors.py +0 -0
  34. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/execution/headless_renderer.py +0 -0
  35. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/cli/execution/launcher.py +0 -0
  36. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/config/__init__.py +0 -0
  37. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/config/cli_config.py +0 -0
  38. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/config/loader.py +0 -0
  39. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/config/logging_setup.py +0 -0
  40. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/__init__.py +0 -0
  41. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/parse/_utils.py +0 -0
  42. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/parse/message_processing.py +0 -0
  43. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/parse/tool_call_resolution.py +0 -0
  44. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/parse/tool_message_format.py +0 -0
  45. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/parse/tool_result.py +0 -0
  46. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/policy/display_policy.py +0 -0
  47. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/presentation/async_renderer_protocol.py +0 -0
  48. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/presentation/duration_format.py +0 -0
  49. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/presentation/engine.py +0 -0
  50. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/presentation/explore_task_display.py +0 -0
  51. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/presentation/renderer_base.py +0 -0
  52. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/presentation/renderer_protocol.py +0 -0
  53. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/state/file_tracker.py +0 -0
  54. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/state/session_stats.py +0 -0
  55. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/state/stream_accumulator.py +0 -0
  56. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/state/transcript.py +0 -0
  57. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/task_scope.py +0 -0
  58. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/turn/pipeline.py +0 -0
  59. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/wire/chunk_filter.py +0 -0
  60. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/wire/display_text.py +0 -0
  61. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/wire/message_text.py +0 -0
  62. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/runtime/wire/messages.py +0 -0
  63. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/__init__.py +0 -0
  64. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/_cli_context.py +0 -0
  65. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/_env_vars.py +0 -0
  66. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/_version.py +0 -0
  67. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/__init__.py +0 -0
  68. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/_commands.py +0 -0
  69. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/_execution.py +0 -0
  70. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/_history.py +0 -0
  71. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/_messages_mixin.py +0 -0
  72. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/_model.py +0 -0
  73. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/_ui.py +0 -0
  74. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/app/app.tcss +0 -0
  75. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/binding.py +0 -0
  76. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/commands/__init__.py +0 -0
  77. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/commands/slash_commands.py +0 -0
  78. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/commands/subagent_routing.py +0 -0
  79. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/file_change_notify.py +0 -0
  80. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/file_change_renderers.py +0 -0
  81. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/hooks.py +0 -0
  82. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/input.py +0 -0
  83. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/media_utils.py +0 -0
  84. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/model_config.py +0 -0
  85. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/path_utils.py +0 -0
  86. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/preview_limits.py +0 -0
  87. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/project_utils.py +0 -0
  88. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/skills/__init__.py +0 -0
  89. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/skills/invocation.py +0 -0
  90. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/skills/load.py +0 -0
  91. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/theme.py +0 -0
  92. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/tool_display.py +0 -0
  93. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/unicode_security.py +0 -0
  94. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/update_check.py +0 -0
  95. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/__init__.py +0 -0
  96. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/_links.py +0 -0
  97. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/autocomplete.py +0 -0
  98. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/autopilot_dashboard.py +0 -0
  99. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/autopilot_screen.py +0 -0
  100. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/chat_input.py +0 -0
  101. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/clipboard.py +0 -0
  102. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/diff.py +0 -0
  103. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/editor.py +0 -0
  104. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/file_change_preview.py +0 -0
  105. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/history.py +0 -0
  106. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/loading.py +0 -0
  107. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/loop_selector.py +0 -0
  108. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/mcp_viewer.py +0 -0
  109. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/message_store.py +0 -0
  110. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/messages.py +0 -0
  111. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/model_selector.py +0 -0
  112. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/notification_settings.py +0 -0
  113. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/status.py +0 -0
  114. {soothe_cli-0.6.7 → soothe_cli-0.6.8}/src/soothe_cli/tui/widgets/theme_selector.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soothe-cli
3
- Version: 0.6.7
3
+ Version: 0.6.8
4
4
  Summary: Soothe CLI client - communicates with daemon via WebSocket
5
5
  Project-URL: Homepage, https://github.com/mirasoth/soothe
6
6
  Project-URL: Documentation, https://soothe.readthedocs.io
@@ -1,4 +1,4 @@
1
- """Loop management CLI commands for AgentLoop instances.
1
+ """Loop management CLI commands for StrangeLoop instances.
2
2
 
3
3
  RFC-503: Loop-First User Experience
4
4
  RFC-504: Loop Management CLI Commands
@@ -24,7 +24,7 @@ from soothe_cli.runtime import load_config
24
24
  console = Console()
25
25
 
26
26
  # Create loop command group
27
- loop_app = typer.Typer(help="Manage AgentLoop instances")
27
+ loop_app = typer.Typer(help="Manage StrangeLoop instances")
28
28
 
29
29
 
30
30
  def _require_daemon(ws_url: str) -> None:
@@ -139,7 +139,7 @@ def list_loops(
139
139
  typer.Option("--limit", "-l", help="Limit number of results."),
140
140
  ] = 20,
141
141
  ) -> None:
142
- """List all AgentLoop instances.
142
+ """List all StrangeLoop instances.
143
143
 
144
144
  Examples:
145
145
  soothe loop list
@@ -169,7 +169,7 @@ def list_loops(
169
169
  return
170
170
 
171
171
  # Render table
172
- table = Table(title="AgentLoops")
172
+ table = Table(title="StrangeLoops")
173
173
  table.add_column("Loop ID", style="cyan")
174
174
  table.add_column("Status", style="green")
175
175
  table.add_column("Contexts", justify="right")
@@ -39,7 +39,7 @@ _CANCEL_SEND_TIMEOUT_S = 3.0
39
39
 
40
40
 
41
41
  def _is_loop_scoped_event(event: dict[str, Any], *, active_loop_id: str) -> bool:
42
- """Return whether a daemon frame belongs to the active AgentLoop session."""
42
+ """Return whether a daemon frame belongs to the active StrangeLoop session."""
43
43
  event_type = event.get("type", "")
44
44
  if event_type not in {"status", "event"}:
45
45
  return True
@@ -2,7 +2,6 @@
2
2
 
3
3
  import asyncio
4
4
  import sys
5
- import time
6
5
 
7
6
  import typer
8
7
  from soothe_sdk.client import (
@@ -42,7 +41,10 @@ def run_headless(
42
41
  # Auto-start daemon if not running (RFC-0013) - WebSocket RPC checks (IG-174 Phase 1)
43
42
  async def _run_headless_pipeline() -> int:
44
43
  """Ensure daemon is reachable, then run the headless daemon session."""
45
- daemon_live = await is_daemon_live(ws_url, timeout=5.0)
44
+ # Check if daemon is live and ready (IG-489: wait for readiness, not just port-live)
45
+ daemon_live = await is_daemon_live(
46
+ ws_url, timeout=5.0, wait_for_ready=True, ready_timeout=30.0
47
+ )
46
48
 
47
49
  if not daemon_live:
48
50
  # Attempt cleanup if stale daemon (connection exists but daemon not responsive)
@@ -64,13 +66,10 @@ def run_headless(
64
66
  stderr=subprocess.DEVNULL,
65
67
  )
66
68
 
67
- # Wait for daemon to become fully ready with timeout
68
- start_time = time.time()
69
- while time.time() - start_time < _DAEMON_START_WAIT_TIMEOUT:
70
- daemon_live = await is_daemon_live(ws_url, timeout=2.0)
71
- if daemon_live:
72
- break
73
- await asyncio.sleep(0.5)
69
+ # Wait for daemon to become fully ready with timeout (IG-489)
70
+ daemon_live = await is_daemon_live(
71
+ ws_url, timeout=2.0, wait_for_ready=True, ready_timeout=_DAEMON_START_WAIT_TIMEOUT
72
+ )
74
73
  # Note: We don't fail here - let the connection attempt handle errors
75
74
  # This allows tests and edge cases to proceed with mocked daemons
76
75
 
@@ -152,7 +152,7 @@ def main(
152
152
  soothe -p "Research AI advances" # One-shot headless (non-TUI) query
153
153
  soothe -p "Hello" --tui # TUI with an auto-submitted prompt
154
154
  soothe --daemon-port 9000 loop list # Subcommands inherit global flags
155
- soothe loop list # List AgentLoop instances
155
+ soothe loop list # List StrangeLoop instances
156
156
  """
157
157
  # Handle -h/--help flag
158
158
  if show_help:
@@ -110,7 +110,7 @@ class EventProcessor:
110
110
 
111
111
  @property
112
112
  def loop_id(self) -> str:
113
- """Active AgentLoop id from daemon status frames."""
113
+ """Active StrangeLoop id from daemon status frames."""
114
114
  return self._state.loop_id
115
115
 
116
116
  @property
@@ -38,7 +38,7 @@ class ProcessorState:
38
38
  # Current plan state (updated on plan events)
39
39
  current_plan: Plan | None = None
40
40
 
41
- # Active AgentLoop id from daemon status frames (``loop_id``)
41
+ # Active StrangeLoop id from daemon status frames (``loop_id``)
42
42
  loop_id: str = ""
43
43
 
44
44
  # Internal context tracking (suppress internal LLM responses)
@@ -6,24 +6,24 @@ from typing import Final
6
6
 
7
7
  GOAL_START_EVENT_TYPES: Final[frozenset[str]] = frozenset(
8
8
  {
9
- "soothe.cognition.agent_loop.started",
9
+ "soothe.cognition.strange_loop.started",
10
10
  "soothe.cognition.plan.creating",
11
11
  }
12
12
  )
13
13
 
14
14
  STEP_START_EVENT_TYPES: Final[frozenset[str]] = frozenset(
15
15
  {
16
- "soothe.cognition.agent_loop.step.started",
16
+ "soothe.cognition.strange_loop.step.started",
17
17
  }
18
18
  )
19
19
 
20
20
  STEP_COMPLETE_EVENT_TYPES: Final[frozenset[str]] = frozenset(
21
21
  {
22
- "soothe.cognition.agent_loop.step.completed",
22
+ "soothe.cognition.strange_loop.step.completed",
23
23
  }
24
24
  )
25
25
 
26
- LOOP_REASON_EVENT_TYPE: Final[str] = "soothe.cognition.agent_loop.reasoned"
26
+ LOOP_REASON_EVENT_TYPE: Final[str] = "soothe.cognition.strange_loop.reasoned"
27
27
 
28
28
  ESSENTIAL_PROGRESS_EVENT_TYPES: Final[frozenset[str]] = frozenset(
29
29
  set(GOAL_START_EVENT_TYPES)
@@ -30,7 +30,7 @@ def log_tui_trace(*, tui_debug: bool, event: str, **fields: Any) -> None:
30
30
  tui_debug: Whether tracing is enabled (from config).
31
31
  event: Short event name (e.g. ``renderer.assistant_text``).
32
32
  fields: Key/value pairs appended as ``key='value'`` (strings truncated).
33
- Common fields include ``loop_id`` for the active AgentLoop id.
33
+ Common fields include ``loop_id`` for the active StrangeLoop id.
34
34
  """
35
35
  if not tui_debug:
36
36
  return
@@ -1,4 +1,4 @@
1
- """Per-turn routing for AgentLoop steps, root tools, and subagent task namespaces.
1
+ """Per-turn routing for StrangeLoop steps, root tools, and subagent task namespaces.
2
2
 
3
3
  Owns associations between execute ``step_id``, root ``tool_call_id``, LangGraph
4
4
  subgraph ``namespace``, and ``task`` delegations. Designed for parallel execute waves
@@ -54,7 +54,7 @@ class TuiDaemonSession:
54
54
 
55
55
  @property
56
56
  def loop_id(self) -> str | None:
57
- """Active AgentLoop id for this WebSocket session."""
57
+ """Active StrangeLoop id for this WebSocket session."""
58
58
  return self._loop_id
59
59
 
60
60
  async def connect(self, *, resume_loop_id: str | None = None) -> dict[str, Any]:
@@ -100,7 +100,7 @@ class TuiDaemonSession:
100
100
  return "adaptive"
101
101
 
102
102
  async def new_loop(self) -> dict[str, Any]:
103
- """Start a new AgentLoop conversation."""
103
+ """Start a new StrangeLoop conversation."""
104
104
  return await self._bootstrap_loop(resume_loop_id=None)
105
105
 
106
106
  async def switch_loop(self, loop_id: str) -> dict[str, Any]:
@@ -398,7 +398,7 @@ class TuiDaemonSession:
398
398
  binder that produced the original cards.
399
399
 
400
400
  Args:
401
- loop_id: AgentLoop id.
401
+ loop_id: StrangeLoop id.
402
402
 
403
403
  Returns:
404
404
  ``SimpleNamespace`` with ``cards: list[dict]``, ``seq: int``,
@@ -442,14 +442,14 @@ class TuiDaemonSession:
442
442
  )
443
443
 
444
444
  async def aget_loop_state(self, loop_id: str) -> Any:
445
- """Load agent-loop state channels from the daemon (``loop_state_get`` RPC).
445
+ """Load StrangeLoop state channels from the daemon (``loop_state_get`` RPC).
446
446
 
447
447
  Returns a namespace with a ``values`` mapping so history code can share the
448
448
  same consumption pattern as the in-process agent snapshot, without passing
449
449
  graph config objects over the wire.
450
450
 
451
451
  Args:
452
- loop_id: AgentLoop id.
452
+ loop_id: StrangeLoop id.
453
453
 
454
454
  Returns:
455
455
  ``types.SimpleNamespace`` with ``values: dict[str, Any]``.
@@ -489,7 +489,7 @@ class TuiDaemonSession:
489
489
  """Merge partial state into the loop on the daemon host (``loop_state_update`` RPC).
490
490
 
491
491
  Args:
492
- loop_id: AgentLoop id.
492
+ loop_id: StrangeLoop id.
493
493
  values: Channel updates (e.g. ``messages``) in JSON-serializable form.
494
494
  timeout: RPC wait budget in seconds.
495
495
  as_node: Optional LangGraph node to attribute the write to. When
@@ -11,12 +11,12 @@ from typing import Any
11
11
 
12
12
  from langchain_core.messages import ToolMessage
13
13
  from soothe_sdk.core.events import (
14
- AGENT_LOOP_COMPLETED,
15
- AGENT_LOOP_PLAN_DECISION,
16
- AGENT_LOOP_STARTED,
17
- AGENT_LOOP_STEP_COMPLETED,
18
- AGENT_LOOP_STEP_QUEUED,
19
- AGENT_LOOP_STEP_STARTED,
14
+ STRANGE_LOOP_COMPLETED,
15
+ STRANGE_LOOP_PLAN_DECISION,
16
+ STRANGE_LOOP_STARTED,
17
+ STRANGE_LOOP_STEP_COMPLETED,
18
+ STRANGE_LOOP_STEP_QUEUED,
19
+ STRANGE_LOOP_STEP_STARTED,
20
20
  )
21
21
  from soothe_sdk.ux.classification import classify_event_to_tier
22
22
  from soothe_sdk.ux.loop_stream import assistant_output_phase
@@ -38,12 +38,12 @@ _MAIN_LOOP_CUSTOM_TYPES = frozenset(
38
38
  {
39
39
  STREAM_TOOL_CALL_UPDATE,
40
40
  TOOL_CALL_UPDATES_BATCH,
41
- AGENT_LOOP_STARTED,
42
- AGENT_LOOP_COMPLETED,
43
- AGENT_LOOP_PLAN_DECISION,
44
- AGENT_LOOP_STEP_STARTED,
45
- AGENT_LOOP_STEP_QUEUED,
46
- AGENT_LOOP_STEP_COMPLETED,
41
+ STRANGE_LOOP_STARTED,
42
+ STRANGE_LOOP_COMPLETED,
43
+ STRANGE_LOOP_PLAN_DECISION,
44
+ STRANGE_LOOP_STEP_STARTED,
45
+ STRANGE_LOOP_STEP_QUEUED,
46
+ STRANGE_LOOP_STEP_COMPLETED,
47
47
  }
48
48
  )
49
49
 
@@ -156,7 +156,7 @@ class SootheApp(
156
156
  daemon_config: Loaded Soothe configuration (WebSocket URL, etc.).
157
157
  assistant_id: Agent identifier for memory storage.
158
158
  cwd: Current working directory to display.
159
- resume_loop_id: Initial AgentLoop id when attaching to an existing loop.
159
+ resume_loop_id: Initial StrangeLoop id when attaching to an existing loop.
160
160
  initial_prompt: Optional prompt to auto-submit when session starts.
161
161
  initial_skill: Optional skill name to invoke when session starts.
162
162
  mcp_server_info: MCP server metadata for the `/mcp` viewer.
@@ -174,7 +174,7 @@ class SootheApp(
174
174
 
175
175
  self._cwd = str(cwd) if cwd else str(Path.cwd())
176
176
 
177
- # Active AgentLoop id; LangGraph stores it as configurable.thread_id.
177
+ # Active StrangeLoop id; LangGraph stores it as configurable.thread_id.
178
178
  # Named `_lc_loop_id` to avoid colliding with Textual's App._thread_id.
179
179
  self._lc_loop_id = resume_loop_id
180
180
 
@@ -355,7 +355,7 @@ class AppResult:
355
355
  """Exit code (0 for success, non-zero for error)."""
356
356
 
357
357
  loop_id: str | None
358
- """The final AgentLoop id at shutdown (may change if the user switched loops)."""
358
+ """The final StrangeLoop id at shutdown (may change if the user switched loops)."""
359
359
 
360
360
  session_stats: SessionStats = field(default_factory=SessionStats)
361
361
  """Cumulative usage stats across all turns in the session."""
@@ -442,7 +442,10 @@ class _StartupMixin:
442
442
  ws_url = websocket_url_from_config(self._daemon_config)
443
443
 
444
444
  # Check daemon status via WebSocket RPC (IG-174 Phase 1)
445
- daemon_live = await is_daemon_live(ws_url, timeout=5.0)
445
+ # Wait for daemon to be fully ready, not just port-live (IG-489)
446
+ daemon_live = await is_daemon_live(
447
+ ws_url, timeout=5.0, wait_for_ready=True, ready_timeout=30.0
448
+ )
446
449
 
447
450
  if not daemon_live:
448
451
  # CLI does NOT control daemon start/stop per architectural separation (IG-174/IG-175)
@@ -97,7 +97,7 @@ COMMANDS: tuple[SlashCommand, ...] = (
97
97
  ),
98
98
  SlashCommand(
99
99
  name="/resume",
100
- description="Browse and resume AgentLoop instances",
100
+ description="Browse and resume StrangeLoop instances",
101
101
  bypass_tier=BypassTier.IMMEDIATE_UI,
102
102
  hidden_keywords="continue history sessions loops",
103
103
  ),
@@ -50,7 +50,7 @@ def validate_command(
50
50
  entry: Command registry entry
51
51
  command: Command name
52
52
  query: Query parameter (if present)
53
- loop_id: Active AgentLoop id for this session
53
+ loop_id: Active StrangeLoop id for this session
54
54
 
55
55
  Returns:
56
56
  Tuple of (is_valid, error_message)
@@ -245,7 +245,7 @@ async def handle_routing_command(
245
245
 
246
246
  For routing commands that map to a configured subagent id (e.g. ``/research``, ``/explore``),
247
247
  sets the WebSocket ``preferred_subagent`` field so the daemon merges a subagent hint into
248
- AgentLoop (IG-349). Other routing commands (e.g. ``/plan``) are sent as plain text unchanged.
248
+ StrangeLoop (IG-349). Other routing commands (e.g. ``/plan``) are sent as plain text unchanged.
249
249
 
250
250
  Args:
251
251
  cmd_input: Full command input (e.g., "/research topic summary")
@@ -578,7 +578,7 @@ def build_stream_config(
578
578
  * Including the SDK version here ensures it survives the merge.
579
579
 
580
580
  Args:
581
- loop_id: Active AgentLoop id (stored under LangGraph ``configurable.thread_id``).
581
+ loop_id: Active StrangeLoop id (stored under LangGraph ``configurable.thread_id``).
582
582
  assistant_id: The agent/assistant identifier, if any.
583
583
  sandbox_type: Sandbox provider name for trace metadata, or `None` if no
584
584
  sandbox is active.
@@ -73,7 +73,7 @@ class LoopInfo(TypedDict, total=False):
73
73
  """Loop metadata returned by `list_loops_via_daemon_rpc`."""
74
74
 
75
75
  loop_id: str
76
- """Unique identifier for the AgentLoop."""
76
+ """Unique identifier for the StrangeLoop."""
77
77
 
78
78
  status: str
79
79
  """Loop status (running, paused, completed, etc.)."""
@@ -230,7 +230,7 @@ async def list_loops_via_daemon_rpc(
230
230
  limit: int = 20,
231
231
  sort_by: str = "updated",
232
232
  ) -> list[LoopInfo]:
233
- """List AgentLoop instances via daemon WebSocket RPC (RFC-504).
233
+ """List StrangeLoop instances via daemon WebSocket RPC (RFC-504).
234
234
 
235
235
  Queries daemon's loop persistence (per-loop metadata.json files)
236
236
  instead of only local SQLite checkpoint walks.
@@ -31,15 +31,15 @@ if TYPE_CHECKING:
31
31
 
32
32
  from langchain_core.messages import AIMessage, HumanMessage
33
33
  from soothe_sdk.core.events import (
34
- AGENT_LOOP_COMPLETED,
35
- AGENT_LOOP_PLAN_DECISION,
36
- AGENT_LOOP_STARTED,
37
- AGENT_LOOP_STEP_COMPLETED,
38
- AGENT_LOOP_STEP_QUEUED,
39
- AGENT_LOOP_STEP_STARTED,
40
34
  LOOP_CLARIFICATION_ANSWERED,
41
35
  LOOP_CLARIFICATION_DEFERRED,
42
36
  LOOP_CLARIFICATION_REQUESTED,
37
+ STRANGE_LOOP_COMPLETED,
38
+ STRANGE_LOOP_PLAN_DECISION,
39
+ STRANGE_LOOP_STARTED,
40
+ STRANGE_LOOP_STEP_COMPLETED,
41
+ STRANGE_LOOP_STEP_QUEUED,
42
+ STRANGE_LOOP_STEP_STARTED,
43
43
  )
44
44
  from soothe_sdk.core.subagent_wire import is_allowlisted_subagent_event_type
45
45
  from soothe_sdk.langchain_wire import (
@@ -158,7 +158,7 @@ class TextualUIAdapter:
158
158
  """Stable tool_call_id → step card for subagent activity and pending-tool routing."""
159
159
 
160
160
  self._current_step_messages: dict[str, CognitionStepMessage] = {}
161
- """Map of agent-loop act step IDs to step card widgets."""
161
+ """Map of StrangeLoop act step IDs to step card widgets."""
162
162
 
163
163
  self._step_by_namespace: dict[tuple[Any, ...], CognitionStepMessage] = {}
164
164
  """Active step card per stream namespace (main-agent tool aggregation, IG-402)."""
@@ -2475,7 +2475,7 @@ async def execute_task_textual(
2475
2475
  await adapter._set_spinner(None)
2476
2476
  continue
2477
2477
 
2478
- if event_type == AGENT_LOOP_STARTED:
2478
+ if event_type == STRANGE_LOOP_STARTED:
2479
2479
  if not ns_key:
2480
2480
  goal_loop_start_monotonic = time.monotonic()
2481
2481
  ui_coalesce.execute_wave_active = True
@@ -2494,7 +2494,7 @@ async def execute_task_textual(
2494
2494
  assistant_message_by_namespace.pop(ns_key, None)
2495
2495
  continue
2496
2496
 
2497
- if event_type == AGENT_LOOP_COMPLETED:
2497
+ if event_type == STRANGE_LOOP_COMPLETED:
2498
2498
  continue
2499
2499
 
2500
2500
  if event_type in (
@@ -2553,7 +2553,7 @@ async def execute_task_textual(
2553
2553
  adapter._clarification_pending = False
2554
2554
  continue
2555
2555
 
2556
- if event_type == AGENT_LOOP_PLAN_DECISION and not ns_key:
2556
+ if event_type == STRANGE_LOOP_PLAN_DECISION and not ns_key:
2557
2557
  raw_steps = data.get("steps")
2558
2558
  if isinstance(raw_steps, list):
2559
2559
  execution_mode = str(data.get("execution_mode", "")).strip()
@@ -2566,7 +2566,7 @@ async def execute_task_textual(
2566
2566
  ui_coalesce.execute_wave_active = True
2567
2567
  continue
2568
2568
 
2569
- if event_type == AGENT_LOOP_STEP_QUEUED:
2569
+ if event_type == STRANGE_LOOP_STEP_QUEUED:
2570
2570
  step_id = str(data.get("step_id", "")).strip()
2571
2571
  description = str(data.get("description", "")).strip()
2572
2572
  if step_id:
@@ -2584,7 +2584,7 @@ async def execute_task_textual(
2584
2584
  step_widget.set_queued()
2585
2585
  continue
2586
2586
 
2587
- if event_type == AGENT_LOOP_STEP_STARTED:
2587
+ if event_type == STRANGE_LOOP_STEP_STARTED:
2588
2588
  ui_coalesce.execute_wave_active = True
2589
2589
  step_id = str(data.get("step_id", "")).strip()
2590
2590
  description = str(data.get("description", "")).strip()
@@ -2637,7 +2637,7 @@ async def execute_task_textual(
2637
2637
 
2638
2638
  continue
2639
2639
 
2640
- if event_type == AGENT_LOOP_STEP_COMPLETED:
2640
+ if event_type == STRANGE_LOOP_STEP_COMPLETED:
2641
2641
  step_id = str(data.get("step_id", "")).strip()
2642
2642
  if step_id:
2643
2643
  # Drain buffered tools that still reference this
@@ -2924,11 +2924,11 @@ __all__ = [
2924
2924
  "SessionStats",
2925
2925
  "SpinnerStatus",
2926
2926
  "format_token_count",
2927
- "AGENT_LOOP_COMPLETED",
2928
- "AGENT_LOOP_STARTED",
2929
- "AGENT_LOOP_STEP_COMPLETED",
2930
- "AGENT_LOOP_STEP_QUEUED",
2931
- "AGENT_LOOP_STEP_STARTED",
2927
+ "STRANGE_LOOP_COMPLETED",
2928
+ "STRANGE_LOOP_STARTED",
2929
+ "STRANGE_LOOP_STEP_COMPLETED",
2930
+ "STRANGE_LOOP_STEP_QUEUED",
2931
+ "STRANGE_LOOP_STEP_STARTED",
2932
2932
  "TurnToolUiCoalescer",
2933
2933
  ]
2934
2934
 
@@ -6,7 +6,7 @@ import random
6
6
 
7
7
  SESSION_TIPS: list[str] = [
8
8
  "Use @ to reference files and / for commands",
9
- "Try /resume to pick up a previous AgentLoop instance",
9
+ "Try /resume to pick up a previous StrangeLoop instance",
10
10
  "After Ctrl+C exit, use 'soothe loop continue' to resume",
11
11
  "Use /tokens to check context usage",
12
12
  "Use /mcp to see your loaded tools and servers",
@@ -55,7 +55,7 @@ class WelcomeBanner(Static):
55
55
  """Initialize the welcome banner.
56
56
 
57
57
  Args:
58
- loop_id: Optional AgentLoop id to display in the banner.
58
+ loop_id: Optional StrangeLoop id to display in the banner.
59
59
  mcp_tool_count: Number of MCP tools loaded at startup.
60
60
  workspace_path: Session workspace path shown in the source row.
61
61
  connecting: When `True`, show a connecting footer instead of
File without changes
File without changes
File without changes