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/__init__.py +3 -0
- sudosu/cli.py +561 -0
- sudosu/commands/__init__.py +15 -0
- sudosu/commands/agent.py +318 -0
- sudosu/commands/config.py +96 -0
- sudosu/commands/init.py +73 -0
- sudosu/commands/integrations.py +563 -0
- sudosu/commands/memory.py +170 -0
- sudosu/commands/onboarding.py +319 -0
- sudosu/commands/tasks.py +635 -0
- sudosu/core/__init__.py +238 -0
- sudosu/core/agent_loader.py +263 -0
- sudosu/core/connection.py +196 -0
- sudosu/core/default_agent.py +541 -0
- sudosu/core/prompt_refiner.py +0 -0
- sudosu/core/safety.py +75 -0
- sudosu/core/session.py +205 -0
- sudosu/tools/__init__.py +373 -0
- sudosu/ui/__init__.py +451 -0
- sudosu-0.1.5.dist-info/METADATA +172 -0
- sudosu-0.1.5.dist-info/RECORD +25 -0
- sudosu-0.1.5.dist-info/WHEEL +5 -0
- sudosu-0.1.5.dist-info/entry_points.txt +2 -0
- sudosu-0.1.5.dist-info/licenses/LICENSE +21 -0
- sudosu-0.1.5.dist-info/top_level.txt +1 -0
sudosu/commands/agent.py
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"""Agent command handlers."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
from sudosu.core import get_project_config_dir
|
|
10
|
+
from sudosu.core.agent_loader import (
|
|
11
|
+
AGENT_TEMPLATES,
|
|
12
|
+
create_agent_template,
|
|
13
|
+
discover_agents,
|
|
14
|
+
load_agent_config,
|
|
15
|
+
)
|
|
16
|
+
from sudosu.core.safety import is_safe_directory
|
|
17
|
+
from sudosu.commands.integrations import get_available_integrations
|
|
18
|
+
from sudosu.ui import (
|
|
19
|
+
console,
|
|
20
|
+
get_user_confirmation,
|
|
21
|
+
get_user_input,
|
|
22
|
+
print_agents,
|
|
23
|
+
print_error,
|
|
24
|
+
print_info,
|
|
25
|
+
print_success,
|
|
26
|
+
print_warning,
|
|
27
|
+
COLOR_PRIMARY,
|
|
28
|
+
COLOR_SECONDARY,
|
|
29
|
+
COLOR_ACCENT,
|
|
30
|
+
COLOR_INTERACTIVE,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Backend URL for prompt refinement
|
|
35
|
+
BACKEND_URL = os.environ.get("SUDOSU_BACKEND_URL", "http://localhost:8000")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def refine_prompt_via_backend(
|
|
39
|
+
name: str,
|
|
40
|
+
description: str,
|
|
41
|
+
tools: list[str],
|
|
42
|
+
integrations: list[str] = None,
|
|
43
|
+
) -> tuple[str, str]:
|
|
44
|
+
"""Call the backend to refine an agent's system prompt.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
name: Agent name
|
|
48
|
+
description: Brief description from user
|
|
49
|
+
tools: List of available tools
|
|
50
|
+
integrations: List of connected integrations (gmail, github, etc.)
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Tuple of (refined_system_prompt, refined_description)
|
|
54
|
+
Returns fallback values if backend is unavailable.
|
|
55
|
+
"""
|
|
56
|
+
if integrations is None:
|
|
57
|
+
integrations = []
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
61
|
+
response = await client.post(
|
|
62
|
+
f"{BACKEND_URL}/refine-prompt",
|
|
63
|
+
json={
|
|
64
|
+
"name": name,
|
|
65
|
+
"description": description,
|
|
66
|
+
"tools": tools,
|
|
67
|
+
"integrations": integrations,
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
if response.status_code == 200:
|
|
72
|
+
data = response.json()
|
|
73
|
+
return data["system_prompt"], data["refined_description"]
|
|
74
|
+
else:
|
|
75
|
+
# Backend returned an error, use fallback
|
|
76
|
+
return None, None
|
|
77
|
+
|
|
78
|
+
except Exception:
|
|
79
|
+
# Backend unavailable, return None to signal fallback
|
|
80
|
+
return None, None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def list_agents_command():
|
|
84
|
+
"""List all available agents (project-local only)."""
|
|
85
|
+
agents = []
|
|
86
|
+
|
|
87
|
+
# Get agents from project config only (no global agents)
|
|
88
|
+
project_dir = get_project_config_dir()
|
|
89
|
+
if project_dir:
|
|
90
|
+
project_agents_dir = project_dir / "agents"
|
|
91
|
+
if project_agents_dir.exists():
|
|
92
|
+
agents = discover_agents(project_agents_dir)
|
|
93
|
+
# Mark as project-specific with location
|
|
94
|
+
for agent in agents:
|
|
95
|
+
agent["_project"] = True
|
|
96
|
+
agent["_location"] = ".sudosu"
|
|
97
|
+
|
|
98
|
+
print_agents(agents)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def get_available_agents() -> list[dict]:
|
|
102
|
+
"""Get list of all available agents in current project."""
|
|
103
|
+
agents = []
|
|
104
|
+
project_dir = get_project_config_dir()
|
|
105
|
+
if project_dir:
|
|
106
|
+
project_agents_dir = project_dir / "agents"
|
|
107
|
+
if project_agents_dir.exists():
|
|
108
|
+
agents = discover_agents(project_agents_dir)
|
|
109
|
+
return agents
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
async def create_agent_command(name: Optional[str] = None):
|
|
113
|
+
"""Create a new agent."""
|
|
114
|
+
# Safety check - block home directory
|
|
115
|
+
cwd = Path.cwd()
|
|
116
|
+
is_safe, reason = is_safe_directory(cwd)
|
|
117
|
+
|
|
118
|
+
if not is_safe:
|
|
119
|
+
print_error(f"Cannot create agents from {reason}")
|
|
120
|
+
print_info("Navigate to a project folder first:")
|
|
121
|
+
console.print("[dim] mkdir ~/my-project && cd ~/my-project[/dim]")
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
# Get agent name
|
|
125
|
+
if not name:
|
|
126
|
+
name = get_user_input("Agent name: ").strip().lower()
|
|
127
|
+
|
|
128
|
+
if not name:
|
|
129
|
+
print_error("Agent name cannot be empty")
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
# Validate name
|
|
133
|
+
if not name.replace("-", "").replace("_", "").isalnum():
|
|
134
|
+
print_error("Agent name can only contain letters, numbers, hyphens, and underscores")
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
# Always use current directory's .sudosu/agents/
|
|
138
|
+
project_sudosu_dir = cwd / ".sudosu"
|
|
139
|
+
agents_dir = project_sudosu_dir / "agents"
|
|
140
|
+
|
|
141
|
+
# Auto-create .sudosu/ if it doesn't exist
|
|
142
|
+
if not project_sudosu_dir.exists():
|
|
143
|
+
project_sudosu_dir.mkdir()
|
|
144
|
+
console.print(f"[{COLOR_INTERACTIVE}]✓[/{COLOR_INTERACTIVE}] Created .sudosu/ in current directory")
|
|
145
|
+
|
|
146
|
+
agents_dir.mkdir(parents=True, exist_ok=True)
|
|
147
|
+
|
|
148
|
+
# Check if agent already exists in this project
|
|
149
|
+
if (agents_dir / name).exists():
|
|
150
|
+
print_error(f"Agent '{name}' already exists in this project")
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
# Fetch connected integrations
|
|
154
|
+
connected_integrations = []
|
|
155
|
+
try:
|
|
156
|
+
integrations_info = await get_available_integrations()
|
|
157
|
+
connected_integrations = integrations_info.get("connected", [])
|
|
158
|
+
if connected_integrations:
|
|
159
|
+
console.print(f"[dim]Found {len(connected_integrations)} connected integration(s): {', '.join(connected_integrations)}[/dim]")
|
|
160
|
+
except Exception:
|
|
161
|
+
pass # Silently continue without integrations
|
|
162
|
+
|
|
163
|
+
# Check if we have a template
|
|
164
|
+
if name in AGENT_TEMPLATES:
|
|
165
|
+
template = AGENT_TEMPLATES[name]
|
|
166
|
+
print_info(f"Using built-in template for '{name}'")
|
|
167
|
+
description = template["description"]
|
|
168
|
+
system_prompt = template["system_prompt"]
|
|
169
|
+
else:
|
|
170
|
+
# Ask for description
|
|
171
|
+
print_info("What should this agent do?")
|
|
172
|
+
description = get_user_input("Description: ").strip()
|
|
173
|
+
|
|
174
|
+
if not description:
|
|
175
|
+
description = f"A helpful assistant named {name}"
|
|
176
|
+
|
|
177
|
+
# Default tools for the agent
|
|
178
|
+
default_tools = ["read_file", "write_file", "list_directory"]
|
|
179
|
+
|
|
180
|
+
# Refine the prompt via backend (include connected integrations)
|
|
181
|
+
console.print("[dim]Crafting agent prompt...[/dim]")
|
|
182
|
+
refined_prompt, refined_description = await refine_prompt_via_backend(
|
|
183
|
+
name=name,
|
|
184
|
+
description=description,
|
|
185
|
+
tools=default_tools,
|
|
186
|
+
integrations=connected_integrations,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if refined_prompt:
|
|
190
|
+
# Use the refined prompt from backend
|
|
191
|
+
system_prompt = refined_prompt
|
|
192
|
+
if refined_description:
|
|
193
|
+
description = refined_description
|
|
194
|
+
console.print(f"[{COLOR_INTERACTIVE}]✓[/{COLOR_INTERACTIVE}] Agent prompt refined")
|
|
195
|
+
else:
|
|
196
|
+
# Fallback to basic prompt if backend unavailable
|
|
197
|
+
console.print(f"[{COLOR_ACCENT}]![/{COLOR_ACCENT}] [dim]Using basic prompt (backend unavailable)[/dim]")
|
|
198
|
+
|
|
199
|
+
# Include integrations in fallback prompt if available
|
|
200
|
+
integrations_section = ""
|
|
201
|
+
if connected_integrations:
|
|
202
|
+
integrations_section = f"""
|
|
203
|
+
## Connected Integrations
|
|
204
|
+
|
|
205
|
+
You have access to these integrations - USE THEM for relevant tasks:
|
|
206
|
+
{chr(10).join(f'- **{i}**: Use for {i}-related tasks' for i in connected_integrations)}
|
|
207
|
+
|
|
208
|
+
**IMPORTANT**: Always use available integrations instead of asking the user to do things manually.
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
system_prompt = f"""# {name.replace('-', ' ').replace('_', ' ').title()} Agent
|
|
212
|
+
|
|
213
|
+
You are {description.lower()}.
|
|
214
|
+
|
|
215
|
+
## Guidelines
|
|
216
|
+
|
|
217
|
+
1. Be helpful and accurate
|
|
218
|
+
2. Ask clarifying questions when needed
|
|
219
|
+
3. Use markdown formatting for better readability
|
|
220
|
+
4. Save files when appropriate
|
|
221
|
+
|
|
222
|
+
## Tools Available
|
|
223
|
+
|
|
224
|
+
- **read_file**: Read content from files
|
|
225
|
+
- **write_file**: Write content to files
|
|
226
|
+
- **list_directory**: List directory contents
|
|
227
|
+
{integrations_section}"""
|
|
228
|
+
|
|
229
|
+
# Create the agent
|
|
230
|
+
try:
|
|
231
|
+
agent_path = create_agent_template(
|
|
232
|
+
agent_dir=agents_dir,
|
|
233
|
+
name=name,
|
|
234
|
+
description=description,
|
|
235
|
+
system_prompt=system_prompt,
|
|
236
|
+
integrations=connected_integrations,
|
|
237
|
+
)
|
|
238
|
+
console.print(f"[{COLOR_INTERACTIVE}]✓[/{COLOR_INTERACTIVE}] Agent [{COLOR_PRIMARY}]'{name}'[/{COLOR_PRIMARY}] created at {agent_path}", highlight=False)
|
|
239
|
+
console.print(f"[{COLOR_INTERACTIVE}]ℹ[/{COLOR_INTERACTIVE}] Use [{COLOR_PRIMARY}]@{name}[/{COLOR_PRIMARY}] to start chatting", highlight=False)
|
|
240
|
+
if connected_integrations:
|
|
241
|
+
console.print(f"[dim]Agent configured with integrations: {', '.join(connected_integrations)}[/dim]")
|
|
242
|
+
except Exception as e:
|
|
243
|
+
print_error(f"Failed to create agent: {e}")
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
async def delete_agent_command(name: Optional[str] = None):
|
|
247
|
+
"""Delete an agent (project-local only)."""
|
|
248
|
+
if not name:
|
|
249
|
+
name = get_user_input("Agent name to delete: ").strip().lower()
|
|
250
|
+
|
|
251
|
+
if not name:
|
|
252
|
+
print_error("Agent name cannot be empty")
|
|
253
|
+
return
|
|
254
|
+
|
|
255
|
+
# Find the agent in project directory only
|
|
256
|
+
project_dir = get_project_config_dir()
|
|
257
|
+
if not project_dir:
|
|
258
|
+
print_error("No .sudosu/ folder found in current directory")
|
|
259
|
+
print_info("You can only delete agents from a project with .sudosu/ folder")
|
|
260
|
+
return
|
|
261
|
+
|
|
262
|
+
agent_path = project_dir / "agents" / name
|
|
263
|
+
|
|
264
|
+
if not agent_path.exists():
|
|
265
|
+
print_error(f"Agent '{name}' not found in this project")
|
|
266
|
+
return
|
|
267
|
+
|
|
268
|
+
# Confirm deletion
|
|
269
|
+
if not get_user_confirmation(f"Delete agent '{name}'?"):
|
|
270
|
+
print_info("Cancelled")
|
|
271
|
+
return
|
|
272
|
+
|
|
273
|
+
# Delete
|
|
274
|
+
import shutil
|
|
275
|
+
try:
|
|
276
|
+
shutil.rmtree(agent_path)
|
|
277
|
+
console.print(f"[{COLOR_INTERACTIVE}]✓[/{COLOR_INTERACTIVE}] Agent [{COLOR_PRIMARY}]'{name}'[/{COLOR_PRIMARY}] deleted", highlight=False)
|
|
278
|
+
except Exception as e:
|
|
279
|
+
print_error(f"Failed to delete agent: {e}")
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def get_agent_config(agent_name: str) -> Optional[dict]:
|
|
283
|
+
"""Load agent configuration by name (project-local only)."""
|
|
284
|
+
agents_dirs = []
|
|
285
|
+
|
|
286
|
+
# Only check project directory - no global agents
|
|
287
|
+
project_dir = get_project_config_dir()
|
|
288
|
+
if project_dir:
|
|
289
|
+
agents_dirs.append(project_dir / "agents")
|
|
290
|
+
|
|
291
|
+
if not agents_dirs:
|
|
292
|
+
return None
|
|
293
|
+
|
|
294
|
+
return load_agent_config(agent_name, agents_dirs)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
async def handle_agent_command(args: list[str]):
|
|
298
|
+
"""Handle /agent command with subcommands."""
|
|
299
|
+
if not args:
|
|
300
|
+
list_agents_command()
|
|
301
|
+
return
|
|
302
|
+
|
|
303
|
+
subcommand = args[0].lower()
|
|
304
|
+
|
|
305
|
+
if subcommand == "create":
|
|
306
|
+
name = args[1] if len(args) > 1 else None
|
|
307
|
+
await create_agent_command(name)
|
|
308
|
+
|
|
309
|
+
elif subcommand == "delete":
|
|
310
|
+
name = args[1] if len(args) > 1 else None
|
|
311
|
+
await delete_agent_command(name)
|
|
312
|
+
|
|
313
|
+
elif subcommand == "list":
|
|
314
|
+
list_agents_command()
|
|
315
|
+
|
|
316
|
+
else:
|
|
317
|
+
print_error(f"Unknown subcommand: {subcommand}")
|
|
318
|
+
print_info("Available: create, delete, list")
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Config command handler."""
|
|
2
|
+
|
|
3
|
+
from sudosu.core import load_config, set_config_value, get_mode, set_mode, get_backend_url
|
|
4
|
+
from sudosu.ui import (
|
|
5
|
+
console,
|
|
6
|
+
print_error,
|
|
7
|
+
print_info,
|
|
8
|
+
print_success,
|
|
9
|
+
COLOR_PRIMARY,
|
|
10
|
+
COLOR_SECONDARY,
|
|
11
|
+
COLOR_INTERACTIVE,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def show_config():
|
|
16
|
+
"""Show current configuration."""
|
|
17
|
+
config = load_config()
|
|
18
|
+
current_mode = get_mode()
|
|
19
|
+
current_url = get_backend_url()
|
|
20
|
+
|
|
21
|
+
console.print("\n[bold]Current Configuration:[/bold]\n")
|
|
22
|
+
|
|
23
|
+
# Show mode first
|
|
24
|
+
console.print(f" [{COLOR_INTERACTIVE}]mode[/{COLOR_INTERACTIVE}]: [bold]{current_mode}[/bold] (active)")
|
|
25
|
+
console.print(f" [{COLOR_INTERACTIVE}]active_backend_url[/{COLOR_INTERACTIVE}]: {current_url}\n")
|
|
26
|
+
|
|
27
|
+
for key, value in config.items():
|
|
28
|
+
# Mask API key
|
|
29
|
+
if "key" in key.lower() and value:
|
|
30
|
+
display_value = value[:4] + "..." + value[-4:] if len(value) > 8 else "****"
|
|
31
|
+
else:
|
|
32
|
+
display_value = value
|
|
33
|
+
|
|
34
|
+
console.print(f" [{COLOR_INTERACTIVE}]{key}[/{COLOR_INTERACTIVE}]: {display_value}")
|
|
35
|
+
|
|
36
|
+
console.print()
|
|
37
|
+
console.print("[dim]Tip: Use '/config mode dev' or '/config mode prod' to switch environments[/dim]\n")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def set_config(key: str, value: str):
|
|
41
|
+
"""Set a configuration value."""
|
|
42
|
+
valid_keys = ["backend_url", "dev_backend_url", "prod_backend_url", "api_key", "default_model", "theme"]
|
|
43
|
+
|
|
44
|
+
if key not in valid_keys:
|
|
45
|
+
print_error(f"Invalid key: {key}")
|
|
46
|
+
print_info(f"Valid keys: {', '.join(valid_keys)}")
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
set_config_value(key, value)
|
|
50
|
+
|
|
51
|
+
# Mask display for sensitive values
|
|
52
|
+
if "key" in key.lower():
|
|
53
|
+
display_value = value[:4] + "..." + value[-4:] if len(value) > 8 else "****"
|
|
54
|
+
else:
|
|
55
|
+
display_value = value
|
|
56
|
+
|
|
57
|
+
print_success(f"Set {key} = {display_value}")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def switch_mode(mode: str):
|
|
61
|
+
"""Switch between dev and prod modes."""
|
|
62
|
+
mode = mode.lower()
|
|
63
|
+
if mode not in ["dev", "prod"]:
|
|
64
|
+
print_error("Mode must be 'dev' or 'prod'")
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
set_mode(mode)
|
|
69
|
+
new_url = get_backend_url()
|
|
70
|
+
print_success(f"Switched to {mode.upper()} mode")
|
|
71
|
+
print_info(f"Backend URL: {new_url}")
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print_error(f"Failed to switch mode: {e}")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
async def handle_config_command(args: list[str]):
|
|
77
|
+
"""Handle /config command with subcommands."""
|
|
78
|
+
if not args:
|
|
79
|
+
show_config()
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
if args[0] == "set":
|
|
83
|
+
if len(args) < 3:
|
|
84
|
+
print_error("Usage: /config set <key> <value>")
|
|
85
|
+
return
|
|
86
|
+
set_config(args[1], " ".join(args[2:]))
|
|
87
|
+
elif args[0] == "mode":
|
|
88
|
+
if len(args) < 2:
|
|
89
|
+
current_mode = get_mode()
|
|
90
|
+
print_info(f"Current mode: {current_mode.upper()}")
|
|
91
|
+
print_info("Usage: /config mode <dev|prod>")
|
|
92
|
+
return
|
|
93
|
+
switch_mode(args[1])
|
|
94
|
+
else:
|
|
95
|
+
print_error(f"Unknown subcommand: {args[0]}")
|
|
96
|
+
print_info("Usage: /config or /config set <key> <value> or /config mode <dev|prod>")
|
sudosu/commands/init.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Init command handler."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from sudosu.core import ensure_config_structure, ensure_project_structure, get_global_config_dir
|
|
6
|
+
from sudosu.ui import console, print_info, print_success
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
async def init_command(silent: bool = False):
|
|
10
|
+
"""Initialize Sudosu configuration.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
silent: If True, skip all prompts and use defaults (for auto-init)
|
|
14
|
+
"""
|
|
15
|
+
config_dir = get_global_config_dir()
|
|
16
|
+
|
|
17
|
+
# Ensure global config exists (just config.yaml)
|
|
18
|
+
ensure_config_structure()
|
|
19
|
+
|
|
20
|
+
if not silent:
|
|
21
|
+
console.print()
|
|
22
|
+
console.print("[bold blue]🚀 Welcome to Sudosu![/bold blue]")
|
|
23
|
+
console.print()
|
|
24
|
+
print_success(f"Global config created at {config_dir}/config.yaml")
|
|
25
|
+
console.print()
|
|
26
|
+
print_info("Run `sudosu` in any project folder to get started!")
|
|
27
|
+
print_info("A .sudosu/ folder with your customizable AGENT.md will be created there.")
|
|
28
|
+
console.print()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def init_project_command():
|
|
32
|
+
"""Initialize project-specific Sudosu configuration with AGENT.md."""
|
|
33
|
+
cwd = Path.cwd()
|
|
34
|
+
project_config = cwd / ".sudosu"
|
|
35
|
+
|
|
36
|
+
if project_config.exists():
|
|
37
|
+
print_info(f"Project configuration already exists at {project_config}")
|
|
38
|
+
if not (project_config / "AGENT.md").exists():
|
|
39
|
+
# Create AGENT.md if missing
|
|
40
|
+
ensure_project_structure(cwd)
|
|
41
|
+
print_success("Created .sudosu/AGENT.md")
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
# Create full project structure with AGENT.md
|
|
45
|
+
ensure_project_structure(cwd)
|
|
46
|
+
|
|
47
|
+
# Create context.md template
|
|
48
|
+
context_file = project_config / "context.md"
|
|
49
|
+
if not context_file.exists():
|
|
50
|
+
context_file.write_text("""# Project Context
|
|
51
|
+
|
|
52
|
+
This file provides context about the project to all agents.
|
|
53
|
+
|
|
54
|
+
## Project Overview
|
|
55
|
+
|
|
56
|
+
Describe your project here...
|
|
57
|
+
|
|
58
|
+
## Key Files
|
|
59
|
+
|
|
60
|
+
- `src/` - Source code
|
|
61
|
+
- `docs/` - Documentation
|
|
62
|
+
|
|
63
|
+
## Guidelines
|
|
64
|
+
|
|
65
|
+
Any specific guidelines for agents working in this project...
|
|
66
|
+
""")
|
|
67
|
+
|
|
68
|
+
print_success(f"Created {project_config}/")
|
|
69
|
+
print_success(f"Created {project_config}/AGENT.md (your customizable AI assistant)")
|
|
70
|
+
print_success(f"Created {project_config}/agents/")
|
|
71
|
+
print_success(f"Created {project_config}/context.md")
|
|
72
|
+
print_info("Edit AGENT.md to customize your default AI assistant")
|
|
73
|
+
print_info("Edit context.md to provide project context to all agents")
|