sudosu 0.1.5__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.
sudosu/ui/__init__.py ADDED
@@ -0,0 +1,451 @@
1
+ """Console UI helpers for Sudosu."""
2
+
3
+ from pathlib import Path
4
+
5
+ from prompt_toolkit import PromptSession
6
+ from prompt_toolkit.formatted_text import HTML
7
+ from prompt_toolkit.history import FileHistory
8
+ from rich.console import Console
9
+ from rich.live import Live
10
+ from rich.markdown import Markdown
11
+ from rich.markup import escape
12
+ from rich.panel import Panel
13
+ from rich.progress import Progress, SpinnerColumn, TextColumn
14
+ from rich.syntax import Syntax
15
+ from rich.table import Table
16
+ from rich.text import Text
17
+
18
+
19
+ console = Console()
20
+
21
+ # ══════════════════════════════════════════════════════════════════════════════
22
+ # COMMAND HISTORY - Enables up/down arrow navigation for previous commands
23
+ # ══════════════════════════════════════════════════════════════════════════════
24
+
25
+ def _get_history_file() -> Path:
26
+ """Get the path to the command history file.
27
+
28
+ Uses XDG-compliant location: ~/.local/share/sudosu/command_history
29
+ This keeps app data separate from project-level .sudosu/ configs.
30
+ """
31
+ # Use XDG-compliant location for app data
32
+ history_dir = Path.home() / ".local" / "share" / "sudosu"
33
+ history_dir.mkdir(parents=True, exist_ok=True)
34
+ return history_dir / "command_history"
35
+
36
+
37
+ # Global prompt session with persistent file history
38
+ _prompt_session: PromptSession | None = None
39
+
40
+
41
+ def _get_prompt_session() -> PromptSession:
42
+ """Get or create the global prompt session with history."""
43
+ global _prompt_session
44
+ if _prompt_session is None:
45
+ history_file = _get_history_file()
46
+ _prompt_session = PromptSession(history=FileHistory(str(history_file)))
47
+ return _prompt_session
48
+
49
+ # ══════════════════════════════════════════════════════════════════════════════
50
+ # SUDOSU BRAND COLORS
51
+ # ══════════════════════════════════════════════════════════════════════════════
52
+ COLOR_PRIMARY = "#FEEAC9" # Warm cream/peach - Logo, main headings
53
+ COLOR_SECONDARY = "#FFCDC9" # Light coral/pink - Section headings
54
+ COLOR_ACCENT = "#FD7979" # Coral red - Warnings, important highlights
55
+ COLOR_INTERACTIVE = "#BDE3C3" # Light blue - Commands, agent names, interactive elements
56
+
57
+ # Sudosu ASCII Art Logo
58
+ SUDOSU_LOGO = """
59
+ ⣀⣀⣀⣀⣀⣀⣀⣀⣀
60
+ ⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦
61
+ ⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷
62
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
63
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
64
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
65
+ ⣿⣿⣿⣿⡿⠋⠁⠈⠙⢿⡿⠋⠁⠈⠻⣿⣿⣿⣿
66
+ ⣿⣿⣿⣿⡇⠀⣿⣿⠀⢸⡇⠀⣿⣿⠀⢸⣿⣿⣿
67
+ ⣿⣿⣿⣿⣷⣄⣀⣀⣠⣾⣷⣄⣀⣀⣠⣾⣿⣿⣿
68
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
69
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
70
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
71
+ ⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟
72
+ ⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋
73
+ ⠉⠉⠉⠉⠉⠉⠉⠉⠉
74
+ """
75
+
76
+ # Simpler fallback ASCII logo using basic characters
77
+ # Matches the Sudosu logo: filled body with hollow circular eyes and connected ears
78
+ SUDOSU_LOGO_SIMPLE = """
79
+ ▄▄ ▄▄
80
+ ██▀▀▀▀▀▀▀▀██
81
+ ████ ██ ████
82
+ ██████████████
83
+ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀
84
+ """
85
+
86
+
87
+ def get_version() -> str:
88
+ """Get Sudosu version."""
89
+ try:
90
+ from importlib.metadata import version
91
+ return version("sudosu")
92
+ except Exception:
93
+ return "0.1.0"
94
+
95
+
96
+ def print_welcome(username: str = "User"):
97
+ """Print welcome message with ASCII art logo - Claude Code style."""
98
+ console.print()
99
+
100
+ # Create the welcome box similar to Claude Code
101
+ version = get_version()
102
+
103
+ # Create a table for the layout (left: welcome + logo, right: tips)
104
+ layout_table = Table.grid(padding=(0, 4))
105
+ layout_table.add_column(justify="center", width=35) # Left column for welcome + logo
106
+ layout_table.add_column(justify="left") # Right column for tips
107
+
108
+ # Build left side content
109
+ left_content = Text()
110
+ left_content.append(f"Welcome back {username}!\n\n", style="bold white")
111
+ left_content.append(SUDOSU_LOGO_SIMPLE, style=f"bold {COLOR_PRIMARY}") # Primary color for logo
112
+ left_content.append(f"\nv{version}", style="dim")
113
+
114
+ # Build right side content (tips and recent activity)
115
+ right_content = Text()
116
+ right_content.append("Tips for getting started\n", style=f"bold {COLOR_SECONDARY}") # Secondary for headings
117
+ right_content.append("Type a message to chat with your AI agent\n", style="white")
118
+ right_content.append("Use ", style="white")
119
+ right_content.append("@agent_name", style=f"{COLOR_INTERACTIVE}") # Interactive color for commands
120
+ right_content.append(" to switch agents\n", style="white")
121
+ right_content.append("Type ", style="white")
122
+ right_content.append("/help", style=f"{COLOR_INTERACTIVE}")
123
+ right_content.append(" for all commands\n\n", style="white")
124
+ right_content.append("Recent activity\n", style=f"bold {COLOR_SECONDARY}")
125
+ right_content.append("No recent activity", style="dim")
126
+
127
+ layout_table.add_row(left_content, right_content)
128
+
129
+ # Wrap in a panel with the title
130
+ panel = Panel(
131
+ layout_table,
132
+ title=f"[bold {COLOR_PRIMARY}]Sudosu v{version}[/bold {COLOR_PRIMARY}]",
133
+ title_align="left",
134
+ border_style=COLOR_PRIMARY,
135
+ padding=(1, 2),
136
+ )
137
+
138
+ console.print(panel)
139
+ console.print()
140
+
141
+
142
+ def print_help():
143
+ """Print help message."""
144
+ table = Table(title="Sudosu Commands", border_style=COLOR_PRIMARY, title_style=f"bold {COLOR_PRIMARY}")
145
+ table.add_column("Command", style=COLOR_INTERACTIVE)
146
+ table.add_column("Description")
147
+
148
+ commands = [
149
+ ("/help", "Show this help message"),
150
+ ("/agent", "List available agents"),
151
+ ("/agent create <name>", "Create a new agent"),
152
+ ("/agent delete <name>", "Delete an agent"),
153
+ ("/memory", "Show conversation memory info"),
154
+ ("/memory clear", "Clear conversation (fresh start)"),
155
+ ("/back", "Return to sudosu from an agent"),
156
+ ("/profile", "View your profile"),
157
+ ("/profile edit", "Update your profile"),
158
+ ("/config", "Show current configuration"),
159
+ ("/config set <key> <value>", "Set a configuration value"),
160
+ ("/clear", "Clear the screen"),
161
+ ("/quit", "Exit Sudosu"),
162
+ ("", ""),
163
+ ("-- Background Tasks --", ""),
164
+ ("/tasks", "List your background tasks"),
165
+ ("/tasks status <id>", "Get task status"),
166
+ ("/tasks logs <id>", "View task execution logs"),
167
+ ("/tasks cancel <id>", "Cancel a running task"),
168
+ ("/tasks watch <id>", "Watch task progress live"),
169
+ ("", ""),
170
+ ("-- Integrations --", ""),
171
+ ("/connect gmail", "Connect your Gmail account"),
172
+ ("/disconnect gmail", "Disconnect Gmail"),
173
+ ("/integrations", "Show connected integrations"),
174
+ ("", ""),
175
+ ("@<agent> <message>", "Switch to and message an agent"),
176
+ ("<message>", "Continue with current agent"),
177
+ ]
178
+
179
+ for cmd, desc in commands:
180
+ table.add_row(cmd, desc)
181
+
182
+ console.print(table)
183
+ console.print(f"\n[dim]Tip: After sudosu routes you to an agent,\n your follow-ups go to that agent automatically.[/dim]")
184
+
185
+
186
+ def print_agents(agents: list[dict]):
187
+ """Print list of available agents in the current project."""
188
+ if not agents:
189
+ console.print(f"[{COLOR_ACCENT}]No agents found in this project.[/{COLOR_ACCENT}]")
190
+ console.print(f"[dim]Create one with [{COLOR_INTERACTIVE}]/agent create <name>[/{COLOR_INTERACTIVE}][/dim]")
191
+ console.print("[dim]Or type a message to chat with the default Sudosu assistant.[/dim]")
192
+ return
193
+
194
+ table = Table(title="Available Agents", border_style=COLOR_PRIMARY, title_style=f"bold {COLOR_PRIMARY}")
195
+ table.add_column("Name", style=COLOR_INTERACTIVE)
196
+ table.add_column("Description")
197
+ table.add_column("Model", style="dim")
198
+
199
+ for agent in agents:
200
+ table.add_row(
201
+ f"@{agent['name']}",
202
+ agent.get("description", "No description"),
203
+ agent.get("model", "gemini-2.5-pro"),
204
+ )
205
+
206
+ console.print(table)
207
+ console.print("\n[dim]Agents are stored in .sudosu/agents/ | Default prompt in .sudosu/AGENT.md[/dim]")
208
+
209
+
210
+ def print_error(message: str):
211
+ """Print error message."""
212
+ console.print(f"[bold {COLOR_ACCENT}]Error:[/bold {COLOR_ACCENT}] {escape(message)}", highlight=False)
213
+
214
+
215
+ def print_success(message: str):
216
+ """Print success message."""
217
+ console.print(f"[bold {COLOR_INTERACTIVE}]✓[/bold {COLOR_INTERACTIVE}] {escape(message)}", highlight=False)
218
+
219
+
220
+ def print_warning(message: str):
221
+ """Print warning message."""
222
+ console.print(f"[bold {COLOR_ACCENT}]⚠[/bold {COLOR_ACCENT}] {escape(message)}", highlight=False)
223
+
224
+
225
+ def print_info(message: str):
226
+ """Print info message."""
227
+ console.print(f"[bold {COLOR_INTERACTIVE}]ℹ[/bold {COLOR_INTERACTIVE}] {escape(message)}", highlight=False)
228
+
229
+
230
+ def print_agent_thinking(agent_name: str):
231
+ """Print agent thinking indicator.
232
+
233
+ For the default 'sudosu' agent, just shows 'thinking...'
234
+ For other agents, shows '@agent_name thinking...'
235
+ """
236
+ if agent_name.lower() == "sudosu":
237
+ console.print(f"\n[bold {COLOR_PRIMARY}]thinking...[/bold {COLOR_PRIMARY}]\n")
238
+ else:
239
+ console.print(f"\n[bold {COLOR_PRIMARY}]@{agent_name}[/bold {COLOR_PRIMARY}] is thinking...\n")
240
+
241
+
242
+ def print_routing_to_agent(agent_name: str):
243
+ """Print routing transition message."""
244
+ console.print(f"\n[bold {COLOR_INTERACTIVE}]→ Routing to @{agent_name}...[/bold {COLOR_INTERACTIVE}]\n")
245
+
246
+
247
+ def print_consultation_route(from_agent: str, to_agent: str, reason: str):
248
+ """Print consultation routing message."""
249
+ console.print(f"\n[dim]💭 @{from_agent} consulted the orchestrator...[/dim]")
250
+ console.print(f"[bold {COLOR_INTERACTIVE}]→ Handing off to @{to_agent}[/bold {COLOR_INTERACTIVE}]")
251
+ console.print(f"[dim] Reason: {reason}[/dim]\n")
252
+
253
+
254
+ def print_tool_execution(tool_name: str, args: dict):
255
+ """Print tool execution info."""
256
+ if tool_name == "write_file":
257
+ path = args.get("path", "file")
258
+ console.print(f"[dim]📝 Writing to {path}...[/dim]")
259
+ elif tool_name == "read_file":
260
+ path = args.get("path", "file")
261
+ console.print(f"[dim]📖 Reading {path}...[/dim]")
262
+ elif tool_name == "list_directory":
263
+ path = args.get("path", ".")
264
+ console.print(f"[dim]📁 Listing {path}...[/dim]")
265
+ elif tool_name == "run_command":
266
+ cmd = args.get("command", "command")
267
+ console.print(f"[dim]⚡ Running: {cmd}[/dim]")
268
+ else:
269
+ console.print(f"[dim]🔧 Executing {tool_name}...[/dim]")
270
+
271
+
272
+ def print_tool_result(tool_name: str, result: dict):
273
+ """Print tool execution result."""
274
+ if result.get("success"):
275
+ if tool_name == "write_file":
276
+ console.print(f"[{COLOR_INTERACTIVE}]✓ File saved: {result.get('path', 'unknown')}[/{COLOR_INTERACTIVE}]")
277
+ elif tool_name == "read_file":
278
+ # Don't print content, it goes to the agent
279
+ pass
280
+ elif tool_name == "list_directory":
281
+ # Don't print listing, it goes to the agent
282
+ pass
283
+ elif "error" in result:
284
+ console.print(f"[{COLOR_ACCENT}]✗ {result['error']}[/{COLOR_ACCENT}]")
285
+
286
+
287
+ def print_markdown(content: str):
288
+ """Print markdown content."""
289
+ md = Markdown(content)
290
+ console.print(md)
291
+
292
+
293
+ def print_code(code: str, language: str = "python"):
294
+ """Print syntax-highlighted code."""
295
+ syntax = Syntax(code, language, theme="monokai", line_numbers=True)
296
+ console.print(syntax)
297
+
298
+
299
+ def create_spinner(message: str = "Processing..."):
300
+ """Create a spinner progress indicator."""
301
+ return Progress(
302
+ SpinnerColumn(),
303
+ TextColumn("[progress.description]{task.description}"),
304
+ console=console,
305
+ transient=True,
306
+ )
307
+
308
+
309
+ class StreamPrinter:
310
+ """Handles streaming text output with markdown rendering support.
311
+
312
+ Modes:
313
+ - render_markdown=True, show_streaming=False: Buffer all, render markdown at end (cleanest)
314
+ - render_markdown=True, show_streaming=True: Show raw stream then render markdown (redundant but shows activity)
315
+ - render_markdown=False: Print raw text as it streams (no formatting)
316
+ """
317
+
318
+ def __init__(self, render_markdown: bool = True, show_streaming: bool = False):
319
+ self.buffer = ""
320
+ self.render_markdown = render_markdown
321
+ self.show_streaming = show_streaming
322
+ self._chunk_count = 0
323
+
324
+ def print_chunk(self, chunk: str):
325
+ """Print a chunk of streaming text."""
326
+ self._chunk_count += 1
327
+
328
+ if self.render_markdown:
329
+ # Buffer for final markdown rendering
330
+ self.buffer += chunk
331
+
332
+ if self.show_streaming:
333
+ # Also show raw text as it streams (dimmed)
334
+ console.print(chunk, end="", style="dim")
335
+ else:
336
+ # Raw mode: print directly without markdown processing
337
+ console.print(chunk, end="")
338
+
339
+ def flush(self):
340
+ """Flush buffer and render as markdown."""
341
+ if self.buffer:
342
+ if self.render_markdown:
343
+ if self.show_streaming:
344
+ # Add visual separator before formatted version
345
+ console.print("\n")
346
+ console.rule(style="dim blue")
347
+ console.print()
348
+
349
+ # Render the complete response as formatted markdown
350
+ md = Markdown(self.buffer.strip())
351
+ console.print(md)
352
+ else:
353
+ # Just ensure newline at end for raw mode
354
+ pass
355
+ self.buffer = ""
356
+ console.print() # Final newline
357
+
358
+
359
+ class LiveStreamPrinter:
360
+ """Streams text with live-updating markdown rendering.
361
+
362
+ Uses Rich's Live display to progressively render markdown as chunks arrive.
363
+ Provides the best experience: see formatted output as it streams.
364
+ """
365
+
366
+ def __init__(self):
367
+ self.buffer = ""
368
+ self._live: Live | None = None
369
+
370
+ def start(self):
371
+ """Start live display."""
372
+ self._live = Live(
373
+ Markdown(""),
374
+ console=console,
375
+ refresh_per_second=10,
376
+ vertical_overflow="visible",
377
+ )
378
+ self._live.start()
379
+
380
+ def print_chunk(self, chunk: str):
381
+ """Add chunk and update live markdown display."""
382
+ self.buffer += chunk
383
+ if self._live:
384
+ # Re-render markdown with updated content
385
+ self._live.update(Markdown(self.buffer))
386
+
387
+ def flush(self):
388
+ """Stop live display and print final output."""
389
+ if self._live:
390
+ self._live.stop()
391
+ self._live = None
392
+ console.print() # Final newline
393
+
394
+ def __enter__(self):
395
+ self.start()
396
+ return self
397
+
398
+ def __exit__(self, *args):
399
+ self.flush()
400
+
401
+
402
+ def get_user_input(prompt: str = "> ") -> str:
403
+ """Get user input with styled prompt and command history.
404
+
405
+ Supports:
406
+ - Up/Down arrows to navigate command history
407
+ - History persisted to ~/.sudosu/command_history
408
+ - Standard readline-style editing (Ctrl+A, Ctrl+E, etc.)
409
+
410
+ Note: This is a sync wrapper. For async contexts, use get_user_input_async().
411
+ """
412
+ session = _get_prompt_session()
413
+ # Use prompt_toolkit's HTML formatting for proper color support
414
+ # COLOR_PRIMARY is #FEEAC9 (warm cream)
415
+ styled_prompt = HTML(f'<style fg="#FEEAC9" bold="true">{prompt}</style>')
416
+
417
+ # Check if we're in an async context
418
+ import asyncio
419
+ try:
420
+ asyncio.get_running_loop()
421
+ # We're in an async context - use a thread to avoid event loop conflicts
422
+ import concurrent.futures
423
+ with concurrent.futures.ThreadPoolExecutor() as executor:
424
+ future = executor.submit(session.prompt, styled_prompt)
425
+ return future.result()
426
+ except RuntimeError:
427
+ # No running loop - safe to use sync version
428
+ return session.prompt(styled_prompt)
429
+
430
+
431
+ async def get_user_input_async(prompt: str = "> ") -> str:
432
+ """Async version of get_user_input with command history.
433
+
434
+ Use this in async contexts (like the main interactive loop).
435
+ """
436
+ session = _get_prompt_session()
437
+ # Use prompt_toolkit's HTML formatting for proper color support
438
+ # COLOR_PRIMARY is #FEEAC9 (warm cream)
439
+ styled_prompt = HTML(f'<style fg="#FEEAC9" bold="true">{prompt}</style>')
440
+ return await session.prompt_async(styled_prompt)
441
+
442
+
443
+ def get_user_confirmation(message: str) -> bool:
444
+ """Get yes/no confirmation from user."""
445
+ response = console.input(f"{message} [y/N]: ").strip().lower()
446
+ return response in ("y", "yes")
447
+
448
+
449
+ def clear_screen():
450
+ """Clear the terminal screen."""
451
+ console.clear()
@@ -0,0 +1,172 @@
1
+ Metadata-Version: 2.4
2
+ Name: sudosu
3
+ Version: 0.1.5
4
+ Summary: Your AI Coworker - that can actually get work done. Unlike chatbots that just talk, these teammates can read your files, write code, create documents, connect to all your tools (Gmail, Calendar, GitHub, Linear, Slack), and run commands - all while you stay in control
5
+ Author: Akash Munshi
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/csakash/sudosu-cli
8
+ Project-URL: Repository, https://github.com/csakash/sudosu-cli
9
+ Project-URL: Issues, https://github.com/csakash/sudosu-cli/issues
10
+ Keywords: ai,assistant,cli,automation,agent,coworker,productivity,llm
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: Office/Business
20
+ Classifier: Topic :: Communications
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: typer>=0.9.0
25
+ Requires-Dist: rich>=13.0.0
26
+ Requires-Dist: websockets>=12.0
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: python-frontmatter>=1.0.0
29
+ Requires-Dist: httpx>=0.25.0
30
+ Requires-Dist: prompt-toolkit>=3.0.0
31
+ Requires-Dist: python-dotenv>=1.0.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
35
+ Requires-Dist: black>=23.0.0; extra == "dev"
36
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # Sudosu 🚀
40
+
41
+ [![PyPI version](https://badge.fury.io/py/sudosu.svg)](https://badge.fury.io/py/sudosu)
42
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
43
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
44
+ [![Downloads](https://pepy.tech/badge/sudosu)](https://pepy.tech/project/sudosu)
45
+
46
+ **Your AI Coworker - Right in Your Terminal**
47
+
48
+ Sudosu gives you AI coworkers that can actually get work done. Unlike chatbots that just talk, these teammates can read your files, write code, create documents, connect to all your tools (Gmail, Calendar, GitHub, Linear, Slack), and run commands - all while you stay in control.
49
+
50
+ **No more hopping between tools.** Your AI coworker does it all.
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install sudosu
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ **Zero configuration required.** Just install and run:
61
+
62
+ ```bash
63
+ # Install
64
+ pip install sudosu
65
+
66
+ # Start using immediately - no setup needed!
67
+ sudosu
68
+ ```
69
+
70
+ That's it! Sudosu works out of the box with our hosted backend.
71
+
72
+ ### Example Tasks
73
+
74
+ ```bash
75
+ # Start interactive session
76
+ sudosu
77
+
78
+ # Then just ask:
79
+ > Summarize the unread emails in my inbox
80
+ > Create a Linear ticket for the bug we discussed
81
+ > Check my calendar for tomorrow and draft a prep email
82
+ > Go through #product-team slack and summarize yesterday's messages
83
+ ```
84
+
85
+ ### Connect Your Tools
86
+
87
+ ```bash
88
+ # Inside sudosu, connect integrations:
89
+ /connect gmail # Connect Gmail
90
+ /connect slack # Connect Slack
91
+ /connect linear # Connect Linear
92
+ /connect github # Connect GitHub
93
+ /connect notion # Connect Notion
94
+ ```
95
+
96
+ ## Features
97
+
98
+ - 🚀 **Zero Config**: Install and run - works immediately with hosted backend
99
+ - 🤖 **AI Coworkers**: Create specialized coworkers with specific personalities and capabilities
100
+ - 🔌 **Tool Integrations**: Connect to Gmail, Calendar, GitHub, Linear, Slack, Notion, and more
101
+ - 📝 **File Operations**: Coworkers can read and write files in your repository
102
+ - 🔄 **Real-time Streaming**: See responses as they're generated
103
+ - 🔒 **Local Execution**: File operations happen on your machine, keeping data secure
104
+ - ⚡ **Action-Oriented**: Your coworkers don't just answer questions — they take action
105
+
106
+ ## Commands
107
+
108
+ | Command | Description |
109
+ |---------|-------------|
110
+ | `/help` | Show all available commands |
111
+ | `/connect <service>` | Connect an integration (gmail, slack, etc.) |
112
+ | `/disconnect <service>` | Disconnect an integration |
113
+ | `/integrations` | Show connected integrations |
114
+ | `/agent create <name>` | Create a new agent |
115
+ | `/agent list` | List available agents |
116
+ | `/clear` | Clear the screen |
117
+ | `/quit` | Exit sudosu |
118
+
119
+ ## Configuration (Optional)
120
+
121
+ Sudosu works out of the box, but you can customize it:
122
+
123
+ ### Environment Modes
124
+
125
+ ```bash
126
+ # Development mode (local backend)
127
+ export SUDOSU_MODE=dev
128
+ sudosu
129
+
130
+ # Production mode (default - uses hosted backend)
131
+ export SUDOSU_MODE=prod
132
+ sudosu
133
+
134
+ # Or switch within CLI
135
+ /config mode dev # Switch to development
136
+ /config mode prod # Switch to production
137
+ ```
138
+
139
+ ### Configuration Files
140
+
141
+ Sudosu stores minimal global config in `~/.sudosu/`:
142
+
143
+ ```
144
+ ~/.sudosu/
145
+ └── config.yaml # API keys, mode settings, user ID
146
+ ```
147
+
148
+ **Project-level configuration** is created automatically when you run `sudosu` in any folder:
149
+
150
+ ```
151
+ your-project/
152
+ └── .sudosu/
153
+ ├── AGENT.md # Your customizable AI assistant prompt
154
+ ├── agents/ # Custom agents created with /agent create
155
+ └── context.md # (optional) Project context for all agents
156
+ ```
157
+
158
+ Edit `.sudosu/AGENT.md` to customize how your AI assistant behaves in that project.
159
+
160
+ ## Requirements
161
+
162
+ - Python 3.10+
163
+ - Internet connection (for hosted backend)
164
+
165
+ ## Links
166
+
167
+ - **Website**: [trysudosu.com](https://trysudosu.com)
168
+ - **Issues**: [GitHub Issues](https://github.com/csakash/sudosu-cli/issues)
169
+
170
+ ## License
171
+
172
+ MIT
@@ -0,0 +1,25 @@
1
+ sudosu/__init__.py,sha256=jg4Ppqo_x4UYQ14sFr_H-vc8xSIdjA1UOBKV0fY_RWY,64
2
+ sudosu/cli.py,sha256=uF8LVHIaaQipRN-WZBnuGNZiG4F55oThBBNaQCm4iSY,19989
3
+ sudosu/commands/__init__.py,sha256=GNCZ4yx2q3NqosnBdtz4-3JvfH_sDaBhRe3rsZoz7UI,326
4
+ sudosu/commands/agent.py,sha256=ujD9iox56xX4VIlkKVDjNIIQk7Ph4oG3y4oFNQIHATQ,10603
5
+ sudosu/commands/config.py,sha256=cxmVG5X5Lh8eetKpjK0vK5kTmpMzR8t7AE-WZuGJSUc,3061
6
+ sudosu/commands/init.py,sha256=31s5VeM1ZbDKB6mKf_Lmgw-MdaDYYZWXtLHTiKtn0a4,2370
7
+ sudosu/commands/integrations.py,sha256=0BUItdpOSPfacfmyN_cNXkvCDORZIu45pRhOMOMulUw,18953
8
+ sudosu/commands/memory.py,sha256=pxX23l495myCR_6YuNXKvIJ-lTfe0XrSPtiJ30YjgFo,7240
9
+ sudosu/commands/onboarding.py,sha256=U8jLNNkgP-ZaMPkCk1yQgiEhk4gLVSzHoeiUpEQQndU,11040
10
+ sudosu/commands/tasks.py,sha256=UN3cpTtgwOiO-KZvYsBgn4G3RerO-soWZCSLcwraXq8,22620
11
+ sudosu/core/__init__.py,sha256=i9Il2BOL496bw1AHCpFBBKPWxnNhptbgYABcSltaXl8,7270
12
+ sudosu/core/agent_loader.py,sha256=mDesHWKspt_0r_zAZ8cAV5fGF6KF4xIQfwc5PLSmXLk,7769
13
+ sudosu/core/connection.py,sha256=KYCJJIgPEbCvEK9-4gxCtGR9764NL-Rx_5xhMu5r_BY,7172
14
+ sudosu/core/default_agent.py,sha256=FeYkxLiGfML_Sw-Mb2gEqepglXajzwnyyhz3gjwefYM,20684
15
+ sudosu/core/prompt_refiner.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ sudosu/core/safety.py,sha256=grJ4_3kPjmin0FVJlBsKIJ6ABEiKDeXQGDLsBgC9ZmI,2357
17
+ sudosu/core/session.py,sha256=HoxZDuoKDcLSt7O-hTtGhHibDxojlcsTeFDQ5OyUTEI,6870
18
+ sudosu/tools/__init__.py,sha256=1cpnkbOyjE8VWkUvFDUwGwLM-maubPcuipQisIORzdI,11536
19
+ sudosu/ui/__init__.py,sha256=HhX62SG_oZeLp9wNFN9MWE30UeRujAiGCyPuN9N7Q5E,17628
20
+ sudosu-0.1.5.dist-info/licenses/LICENSE,sha256=HI2QFjJE024vQ134p2J-LSneIOVfC6V_QHj4sBIuWE4,1069
21
+ sudosu-0.1.5.dist-info/METADATA,sha256=yFtD6JseNICJutBB7dMYMUubIb6x_kabXo96ewPiP5o,5560
22
+ sudosu-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ sudosu-0.1.5.dist-info/entry_points.txt,sha256=VPkFcpsv3fqmP2RXvQFleD0I2tnMgUVFu2P8iUR-JDw,42
24
+ sudosu-0.1.5.dist-info/top_level.txt,sha256=7MGNQzAxurlmEFHv0OHniQxH7xvYz-nKErWnCNPFmhs,7
25
+ sudosu-0.1.5.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sudosu = sudosu.cli:app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Akash Munshi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ sudosu