cade-cli 0.3.3__py3-none-any.whl

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 (44) hide show
  1. cade_cli-0.3.3.dist-info/METADATA +151 -0
  2. cade_cli-0.3.3.dist-info/RECORD +44 -0
  3. cade_cli-0.3.3.dist-info/WHEEL +4 -0
  4. cade_cli-0.3.3.dist-info/entry_points.txt +2 -0
  5. cadecoder/__init__.py +1 -0
  6. cadecoder/ai/__init__.py +6 -0
  7. cadecoder/ai/prompts.py +572 -0
  8. cadecoder/cli/__init__.py +0 -0
  9. cadecoder/cli/app.py +147 -0
  10. cadecoder/cli/auth.py +483 -0
  11. cadecoder/cli/commands/__init__.py +5 -0
  12. cadecoder/cli/commands/auth.py +143 -0
  13. cadecoder/cli/commands/chat.py +264 -0
  14. cadecoder/cli/commands/mcp.py +477 -0
  15. cadecoder/cli/commands/tools.py +226 -0
  16. cadecoder/core/__init__.py +12 -0
  17. cadecoder/core/config.py +380 -0
  18. cadecoder/core/constants.py +281 -0
  19. cadecoder/core/errors.py +145 -0
  20. cadecoder/core/logging.py +148 -0
  21. cadecoder/core/types.py +235 -0
  22. cadecoder/core/utils.py +279 -0
  23. cadecoder/execution/__init__.py +46 -0
  24. cadecoder/execution/context_window.py +521 -0
  25. cadecoder/execution/orchestrator.py +562 -0
  26. cadecoder/execution/parallel.py +287 -0
  27. cadecoder/providers/__init__.py +60 -0
  28. cadecoder/providers/base.py +294 -0
  29. cadecoder/providers/openai.py +251 -0
  30. cadecoder/storage/__init__.py +0 -0
  31. cadecoder/storage/threads.py +489 -0
  32. cadecoder/templates/login_failed.html +21 -0
  33. cadecoder/templates/login_success.html +21 -0
  34. cadecoder/templates/styles.css +87 -0
  35. cadecoder/tools/__init__.py +19 -0
  36. cadecoder/tools/builtin.py +644 -0
  37. cadecoder/tools/filesystem.py +315 -0
  38. cadecoder/tools/git.py +221 -0
  39. cadecoder/tools/manager.py +1635 -0
  40. cadecoder/ui/__init__.py +7 -0
  41. cadecoder/ui/display.py +338 -0
  42. cadecoder/ui/input.py +145 -0
  43. cadecoder/ui/session.py +455 -0
  44. cadecoder/ui/state.py +20 -0
@@ -0,0 +1,279 @@
1
+ """Utility functions for URL computation, date context, and console output.
2
+
3
+ This module provides pure utility functions for common operations:
4
+ - URL computation for Arcade Engine and login endpoints
5
+ - Date/time context generation
6
+ - Console output helpers
7
+
8
+ All functions are pure except console printing functions which have
9
+ side effects (output to console).
10
+ """
11
+
12
+ import datetime
13
+ import ipaddress
14
+ from urllib.parse import ParseResult, urlencode, urlparse
15
+
16
+ import idna
17
+ from rich.console import Console
18
+ from rich.text import Text
19
+
20
+ from cadecoder.core.constants import (
21
+ DEFAULT_CALLBACK_PORT,
22
+ DEFAULT_DEV_PORT,
23
+ DEFAULT_LOGIN_PORT,
24
+ LOCALHOST,
25
+ )
26
+
27
+ # --- URL Computation ---
28
+
29
+
30
+ def _normalize_host(host: str) -> str:
31
+ """Normalize host to localhost if it's a localhost alias.
32
+
33
+ Args:
34
+ host: Hostname or IP address
35
+
36
+ Returns:
37
+ Normalized hostname (localhost for 127.0.0.1 or 0.0.0.0)
38
+ """
39
+ return LOCALHOST if host in ["127.0.0.1", "0.0.0.0"] else host # noqa: S104
40
+
41
+
42
+ def _determine_tls_setting(force_tls: bool, force_no_tls: bool, host: str) -> bool:
43
+ """Determine TLS setting based on flags and host.
44
+
45
+ Args:
46
+ force_tls: Force TLS enabled
47
+ force_no_tls: Force TLS disabled (takes precedence)
48
+ host: Hostname
49
+
50
+ Returns:
51
+ True if TLS should be used, False otherwise
52
+ """
53
+ if force_no_tls:
54
+ return False
55
+ elif force_tls:
56
+ return True
57
+ else:
58
+ return host != LOCALHOST
59
+
60
+
61
+ def _encode_idn(host: str) -> str:
62
+ """Encode Internationalized Domain Name to ASCII.
63
+
64
+ Args:
65
+ host: Hostname potentially containing IDN characters
66
+
67
+ Returns:
68
+ ASCII-encoded hostname
69
+ """
70
+ try:
71
+ return idna.encode(host).decode("ascii")
72
+ except idna.IDNAError:
73
+ return host
74
+
75
+
76
+ def _is_ip_address(host: str) -> bool:
77
+ """Check if host is a valid IP address (IPv4 or IPv6).
78
+
79
+ Args:
80
+ host: Hostname or IP address
81
+
82
+ Returns:
83
+ True if host is an IP address, False otherwise
84
+ """
85
+ try:
86
+ ipaddress.ip_address(host)
87
+ return True
88
+ except ValueError:
89
+ return False
90
+
91
+
92
+ def _is_fqdn(parsed_host: ParseResult, is_ip: bool) -> bool:
93
+ """Check if host is a fully qualified domain name.
94
+
95
+ Args:
96
+ parsed_host: Parsed URL host
97
+ is_ip: Whether host is an IP address
98
+
99
+ Returns:
100
+ True if host is an FQDN, False otherwise
101
+ """
102
+ return "." in parsed_host.netloc and not is_ip and "_" not in parsed_host.netloc
103
+
104
+
105
+ def _extract_existing_port(parsed_host: ParseResult, is_ip: bool) -> str | None:
106
+ """Extract port from host if it already includes one.
107
+
108
+ Args:
109
+ parsed_host: Parsed URL host
110
+ is_ip: Whether host is an IP address
111
+
112
+ Returns:
113
+ Full host:port string if port exists, None otherwise
114
+ """
115
+ if ":" in parsed_host.netloc and not is_ip:
116
+ host, existing_port = parsed_host.netloc.rsplit(":", 1)
117
+ if existing_port.isdigit():
118
+ return parsed_host.netloc
119
+ return None
120
+
121
+
122
+ def compute_base_url(
123
+ force_tls: bool,
124
+ force_no_tls: bool,
125
+ host: str,
126
+ port: int | None,
127
+ ) -> str:
128
+ """Compute the base URL for the Arcade Engine from the provided overrides.
129
+
130
+ Pure function: no side effects, returns computed URL string.
131
+
132
+ Treats 127.0.0.1 and 0.0.0.0 as aliases for localhost.
133
+
134
+ force_no_tls takes precedence over force_tls. For example, if both are
135
+ set to True, the resulting URL will use http.
136
+
137
+ The port is included in the URL unless the host is a fully qualified
138
+ domain name (excluding IP addresses) and no port is specified. Handles
139
+ IPv4, IPv6, IDNs, and hostnames with underscores.
140
+
141
+ Args:
142
+ force_tls: Force TLS enabled
143
+ force_no_tls: Force TLS disabled (takes precedence)
144
+ host: Hostname or IP address
145
+ port: Optional port number
146
+
147
+ Returns:
148
+ Fully constructed URL for the Arcade Engine
149
+ """
150
+ host = _normalize_host(host)
151
+ is_tls = _determine_tls_setting(force_tls, force_no_tls, host)
152
+ protocol = "https" if is_tls else "http"
153
+
154
+ # Default to dev port for localhost
155
+ if host == LOCALHOST and port is None:
156
+ port = DEFAULT_DEV_PORT
157
+
158
+ encoded_host = _encode_idn(host)
159
+ is_ip = _is_ip_address(encoded_host)
160
+
161
+ # Parse host, handling IPv6 addresses
162
+ host_for_parsing = f"[{encoded_host}]" if is_ip and ":" in encoded_host else encoded_host
163
+ parsed_host = urlparse(f"//{host_for_parsing}")
164
+
165
+ # Check for existing port in host
166
+ existing_port_url = _extract_existing_port(parsed_host, is_ip)
167
+ if existing_port_url:
168
+ return f"{protocol}://{existing_port_url}"
169
+
170
+ # Build URL based on FQDN and port
171
+ is_fqdn = _is_fqdn(parsed_host, is_ip)
172
+ if is_fqdn and port is None:
173
+ return f"{protocol}://{encoded_host}"
174
+ elif port is not None:
175
+ return f"{protocol}://{encoded_host}:{port}"
176
+ else:
177
+ return f"{protocol}://{encoded_host}"
178
+
179
+
180
+ def compute_login_url(host: str, state: str, port: int | None) -> str:
181
+ """Compute the full URL for the CLI login endpoint.
182
+
183
+ Pure function: no side effects, returns computed URL string.
184
+
185
+ Args:
186
+ host: Hostname or IP address
187
+ state: OAuth state parameter
188
+ port: Optional port number (defaults to DEFAULT_LOGIN_PORT for localhost)
189
+
190
+ Returns:
191
+ Complete login URL with query parameters
192
+ """
193
+ callback_uri = f"http://{LOCALHOST}:{DEFAULT_CALLBACK_PORT}/callback"
194
+ params = urlencode({"callback_uri": callback_uri, "state": state})
195
+
196
+ port = port if port else DEFAULT_LOGIN_PORT
197
+
198
+ login_base_url = (
199
+ f"http://{LOCALHOST}:{port}"
200
+ if host in [LOCALHOST, "127.0.0.1", "0.0.0.0"] # noqa: S104
201
+ else f"https://{host}"
202
+ )
203
+ endpoint = "/api/v1/auth/cli_login"
204
+
205
+ return f"{login_base_url}{endpoint}?{params}"
206
+
207
+
208
+ # --- Date/Time Context ---
209
+
210
+
211
+ def get_today_context() -> str:
212
+ """Generate system prompt with today's date and day of the week.
213
+
214
+ Pure function: no side effects, returns formatted date string.
215
+
216
+ This helps the AI with time-sensitive requests and reasoning about dates.
217
+
218
+ Returns:
219
+ Formatted string with today's date and day of week
220
+ """
221
+ today = datetime.datetime.now()
222
+ day_of_week = today.strftime("%A")
223
+ date_str = today.strftime("%B %d, %Y")
224
+
225
+ return (
226
+ f"You are a helpful AI assistant. "
227
+ f"Today is {day_of_week}, {date_str}. "
228
+ "Please keep this in mind when helping with time-sensitive tasks."
229
+ )
230
+
231
+
232
+ # --- Console Output ---
233
+
234
+
235
+ _console = Console(stderr=True)
236
+
237
+
238
+ def print_info(message: str) -> None:
239
+ """Print an informational message in blue.
240
+
241
+ Side effect: writes to console.
242
+
243
+ Args:
244
+ message: Message to print
245
+ """
246
+ _console.print(Text(message, style="bold blue"))
247
+
248
+
249
+ def print_success(message: str) -> None:
250
+ """Print a success message in green.
251
+
252
+ Side effect: writes to console.
253
+
254
+ Args:
255
+ message: Message to print
256
+ """
257
+ _console.print(Text(message, style="bold green"))
258
+
259
+
260
+ def print_warning(message: str) -> None:
261
+ """Print a warning message in yellow.
262
+
263
+ Side effect: writes to console.
264
+
265
+ Args:
266
+ message: Message to print
267
+ """
268
+ _console.print(Text(message, style="bold yellow"))
269
+
270
+
271
+ def print_error(message: str) -> None:
272
+ """Print an error message in red.
273
+
274
+ Side effect: writes to console.
275
+
276
+ Args:
277
+ message: Message to print
278
+ """
279
+ _console.print(Text(message, style="bold red"))
@@ -0,0 +1,46 @@
1
+ """Execution package for task processing.
2
+
3
+ This package contains:
4
+ - Orchestrator: Central control flow for agent execution
5
+ - Context window management: Token tracking and compaction
6
+ - Parallel execution: Concurrent tool execution with dependency analysis
7
+ """
8
+
9
+ from cadecoder.execution.context_window import (
10
+ CompactionStrategy,
11
+ ContextBackup,
12
+ ContextWindowManager,
13
+ TokenEstimate,
14
+ ToolOutputCollection,
15
+ create_context_manager,
16
+ )
17
+ from cadecoder.execution.orchestrator import (
18
+ ContinuationDecision,
19
+ ExecutionContext,
20
+ ExecutionEvent,
21
+ ExecutionMode,
22
+ ExecutionResult,
23
+ Orchestrator,
24
+ create_orchestrator,
25
+ )
26
+ from cadecoder.execution.parallel import ParallelToolExecutor
27
+
28
+ __all__ = [
29
+ # Context window
30
+ "CompactionStrategy",
31
+ "ContextBackup",
32
+ "ContextWindowManager",
33
+ "TokenEstimate",
34
+ "ToolOutputCollection",
35
+ "create_context_manager",
36
+ # Orchestrator
37
+ "ContinuationDecision",
38
+ "ExecutionContext",
39
+ "ExecutionEvent",
40
+ "ExecutionMode",
41
+ "ExecutionResult",
42
+ "Orchestrator",
43
+ "create_orchestrator",
44
+ # Parallel execution
45
+ "ParallelToolExecutor",
46
+ ]