mycode-coding-agent 0.1.0__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.
- mycode/__init__.py +0 -0
- mycode/adapters/__init__.py +21 -0
- mycode/adapters/jsonl.py +692 -0
- mycode/agent/__init__.py +25 -0
- mycode/agent/events.py +111 -0
- mycode/agent/outcome.py +103 -0
- mycode/agent/progress.py +373 -0
- mycode/agent/runner.py +1481 -0
- mycode/application/__init__.py +38 -0
- mycode/application/agent_session.py +367 -0
- mycode/application/events.py +59 -0
- mycode/application/runtime.py +211 -0
- mycode/application/sessions.py +180 -0
- mycode/cli.py +840 -0
- mycode/config.py +355 -0
- mycode/context/__init__.py +1 -0
- mycode/context/artifacts.py +672 -0
- mycode/context/budget.py +752 -0
- mycode/context/builder.py +112 -0
- mycode/context/compact.py +795 -0
- mycode/context/tool_result_format.py +199 -0
- mycode/context/tool_result_retention.py +261 -0
- mycode/conversation.py +78 -0
- mycode/error_handling.py +481 -0
- mycode/event_format.py +147 -0
- mycode/instructions.py +285 -0
- mycode/llm.py +771 -0
- mycode/mcp/__init__.py +41 -0
- mycode/mcp/client.py +44 -0
- mycode/mcp/config.py +207 -0
- mycode/mcp/errors.py +302 -0
- mycode/mcp/manager.py +339 -0
- mycode/mcp/models.py +20 -0
- mycode/mcp/result_adapter.py +58 -0
- mycode/mcp/tool_adapter.py +145 -0
- mycode/mcp/trust.py +313 -0
- mycode/memory.py +570 -0
- mycode/memory_context.py +245 -0
- mycode/messages.py +63 -0
- mycode/observability.py +28 -0
- mycode/permissions.py +262 -0
- mycode/persistence/__init__.py +1 -0
- mycode/persistence/filesystem.py +291 -0
- mycode/persistence/project_storage.py +208 -0
- mycode/persistence/session_lock.py +138 -0
- mycode/persistence/session_store.py +503 -0
- mycode/presentation/__init__.py +1 -0
- mycode/presentation/cli/__init__.py +14 -0
- mycode/presentation/cli/confirmer.py +116 -0
- mycode/presentation/cli/mcp_trust.py +61 -0
- mycode/presentation/cli/presenter.py +320 -0
- mycode/presentation/cli/session_menu.py +146 -0
- mycode/presentation/cli/subagent_observer.py +124 -0
- mycode/presentation/command_format.py +90 -0
- mycode/presentation/commands.py +95 -0
- mycode/presentation/tui/__init__.py +6 -0
- mycode/presentation/tui/app.py +1351 -0
- mycode/presentation/tui/interactions.py +253 -0
- mycode/presentation/tui/presenter.py +266 -0
- mycode/presentation/tui/screens.py +305 -0
- mycode/presentation/tui/widgets.py +214 -0
- mycode/project.py +22 -0
- mycode/prompts.py +181 -0
- mycode/reasoning.py +40 -0
- mycode/session.py +86 -0
- mycode/skills/__init__.py +27 -0
- mycode/skills/builtin/database-recovery/SKILL.md +138 -0
- mycode/skills/builtin/database-recovery/references/sqlite.md +235 -0
- mycode/skills/registry.py +295 -0
- mycode/skills/state.py +68 -0
- mycode/subagents/__init__.py +1 -0
- mycode/subagents/audit.py +212 -0
- mycode/subagents/concurrency.py +124 -0
- mycode/subagents/contracts.py +421 -0
- mycode/subagents/delegate.py +80 -0
- mycode/subagents/delegation.py +128 -0
- mycode/subagents/lifecycle.py +86 -0
- mycode/subagents/limits.py +7 -0
- mycode/subagents/observability.py +150 -0
- mycode/subagents/persistence.py +152 -0
- mycode/subagents/profiles.py +184 -0
- mycode/subagents/prompts.py +67 -0
- mycode/subagents/results.py +178 -0
- mycode/subagents/runtime.py +528 -0
- mycode/subagents/snapshots.py +211 -0
- mycode/subagents/tool_batch.py +260 -0
- mycode/tools/__init__.py +81 -0
- mycode/tools/base.py +222 -0
- mycode/tools/bounds.py +14 -0
- mycode/tools/command_executor.py +167 -0
- mycode/tools/command_output.py +166 -0
- mycode/tools/command_risk.py +596 -0
- mycode/tools/defaults.py +59 -0
- mycode/tools/edit_file.py +524 -0
- mycode/tools/file_mutation.py +30 -0
- mycode/tools/glob.py +247 -0
- mycode/tools/grep.py +324 -0
- mycode/tools/ignore.py +122 -0
- mycode/tools/inspect_changes.py +269 -0
- mycode/tools/load_skill.py +92 -0
- mycode/tools/memory.py +264 -0
- mycode/tools/path_permissions.py +78 -0
- mycode/tools/patterns.py +48 -0
- mycode/tools/permission_metadata.py +27 -0
- mycode/tools/process_tree.py +166 -0
- mycode/tools/read_file.py +242 -0
- mycode/tools/read_skill_resource.py +93 -0
- mycode/tools/registry.py +279 -0
- mycode/tools/run_command.py +237 -0
- mycode/tools/run_skill_script.py +206 -0
- mycode/tools/run_validation.py +107 -0
- mycode/tools/submit_result.py +93 -0
- mycode/tools/text.py +15 -0
- mycode/tools/validation_command.py +377 -0
- mycode/tools/workspace.py +33 -0
- mycode/tools/write_file.py +169 -0
- mycode_coding_agent-0.1.0.dist-info/METADATA +244 -0
- mycode_coding_agent-0.1.0.dist-info/RECORD +121 -0
- mycode_coding_agent-0.1.0.dist-info/WHEEL +4 -0
- mycode_coding_agent-0.1.0.dist-info/entry_points.txt +2 -0
- mycode_coding_agent-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Shared text formatting for interactive command output."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
|
|
5
|
+
from mycode.application.agent_session import CompactResult, ContextStatus
|
|
6
|
+
from mycode.persistence.session_store import SessionRecord
|
|
7
|
+
from mycode.presentation.commands import COMMAND_SPECS
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def format_command_help() -> tuple[str, ...]:
|
|
11
|
+
lines = ["available commands:"]
|
|
12
|
+
for spec in COMMAND_SPECS:
|
|
13
|
+
aliases = ""
|
|
14
|
+
if spec.aliases:
|
|
15
|
+
aliases = " (alias: " + ", ".join(
|
|
16
|
+
f"/{alias}" for alias in spec.aliases
|
|
17
|
+
) + ")"
|
|
18
|
+
lines.append(f"{spec.usage}{aliases} - {spec.description}")
|
|
19
|
+
return tuple(lines)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def format_session_list(
|
|
23
|
+
sessions: Iterable[SessionRecord],
|
|
24
|
+
*,
|
|
25
|
+
current_session_id: str,
|
|
26
|
+
) -> tuple[str, ...]:
|
|
27
|
+
records = tuple(sessions)
|
|
28
|
+
if not records:
|
|
29
|
+
return ("sessions in current project:", "(no sessions)")
|
|
30
|
+
return (
|
|
31
|
+
"sessions in current project:",
|
|
32
|
+
*(
|
|
33
|
+
f"{'*' if session.id == current_session_id else ' '} "
|
|
34
|
+
f"{session.id} {session.title}"
|
|
35
|
+
for session in records
|
|
36
|
+
),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def format_context_status(status: ContextStatus) -> tuple[str, ...]:
|
|
41
|
+
percent = (
|
|
42
|
+
0.0
|
|
43
|
+
if status.max_input_tokens < 1
|
|
44
|
+
else status.estimated_input_tokens / status.max_input_tokens * 100
|
|
45
|
+
)
|
|
46
|
+
provider = (
|
|
47
|
+
"unavailable"
|
|
48
|
+
if status.last_provider_prompt_tokens is None
|
|
49
|
+
else f"{status.last_provider_prompt_tokens:,} tokens"
|
|
50
|
+
)
|
|
51
|
+
memory = (
|
|
52
|
+
"memory: none"
|
|
53
|
+
if status.memory_entry_count == 0
|
|
54
|
+
else (
|
|
55
|
+
"memory: "
|
|
56
|
+
f"{status.memory_entry_count} entries / "
|
|
57
|
+
f"~{status.memory_estimated_tokens:,} tokens"
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
return (
|
|
61
|
+
"Context",
|
|
62
|
+
"estimated input: "
|
|
63
|
+
f"{status.estimated_input_tokens:,} / "
|
|
64
|
+
f"{status.max_input_tokens:,} tokens ({percent:.1f}%)",
|
|
65
|
+
f"context window: {status.context_window_tokens:,}",
|
|
66
|
+
f"reserved output: {status.reserved_output_tokens:,}",
|
|
67
|
+
f"safety margin: {status.safety_margin_tokens:,}",
|
|
68
|
+
f"estimate source: {status.estimate_source}",
|
|
69
|
+
f"last provider prompt: {provider}",
|
|
70
|
+
"messages: "
|
|
71
|
+
f"{status.source_message_count} source / "
|
|
72
|
+
f"{status.model_visible_message_count} model-visible",
|
|
73
|
+
memory,
|
|
74
|
+
"compact: "
|
|
75
|
+
f"{status.compact_status} / "
|
|
76
|
+
f"{status.compact_covered_message_count} messages covered",
|
|
77
|
+
"tool results: "
|
|
78
|
+
f"{status.compressed_tool_result_count} compressed",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def format_compact_result(result: CompactResult) -> str:
|
|
83
|
+
if result.status == "compacted" and result.before and result.after:
|
|
84
|
+
return (
|
|
85
|
+
"compacted: ~"
|
|
86
|
+
f"{result.before.estimated_input_tokens:,} → ~"
|
|
87
|
+
f"{result.after.estimated_input_tokens:,} tokens"
|
|
88
|
+
)
|
|
89
|
+
reason = "unknown" if result.reason is None else result.reason
|
|
90
|
+
return f"compact {result.status}: {reason}"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Definitions and parsing for MyCode's shared slash commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class CommandSpec:
|
|
10
|
+
"""Metadata describing one canonical slash command."""
|
|
11
|
+
|
|
12
|
+
name: str
|
|
13
|
+
aliases: tuple[str, ...]
|
|
14
|
+
usage: str
|
|
15
|
+
description: str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class ParsedCommand:
|
|
20
|
+
"""A recognized command with its whitespace-separated arguments."""
|
|
21
|
+
|
|
22
|
+
name: str
|
|
23
|
+
args: tuple[str, ...] = ()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CommandParseError(ValueError):
|
|
27
|
+
"""Raised when a registered command receives invalid arguments."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, command: str, usage: str) -> None:
|
|
30
|
+
self.command = command
|
|
31
|
+
self.usage = usage
|
|
32
|
+
super().__init__(f"Invalid arguments for /{command}; usage: {usage}")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
COMMAND_SPECS: tuple[CommandSpec, ...] = (
|
|
36
|
+
CommandSpec("help", (), "/help", "Show available slash commands."),
|
|
37
|
+
CommandSpec("new", (), "/new", "Start a new session."),
|
|
38
|
+
CommandSpec(
|
|
39
|
+
"sessions",
|
|
40
|
+
(),
|
|
41
|
+
"/sessions",
|
|
42
|
+
"List sessions in the current project.",
|
|
43
|
+
),
|
|
44
|
+
CommandSpec("resume", (), "/resume <session_id>", "Resume a session."),
|
|
45
|
+
CommandSpec("context", (), "/context", "Show current context information."),
|
|
46
|
+
CommandSpec("compact", (), "/compact", "Compact the current conversation."),
|
|
47
|
+
CommandSpec(
|
|
48
|
+
"exit",
|
|
49
|
+
("quit",),
|
|
50
|
+
"/exit",
|
|
51
|
+
"Exit the current interactive runtime.",
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
_COMMANDS_BY_NAME: dict[str, CommandSpec] = {}
|
|
56
|
+
for _spec in COMMAND_SPECS:
|
|
57
|
+
_COMMANDS_BY_NAME[_spec.name] = _spec
|
|
58
|
+
for _alias in _spec.aliases:
|
|
59
|
+
_COMMANDS_BY_NAME[_alias] = _spec
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def parse_slash_command(text: str) -> ParsedCommand | None:
|
|
63
|
+
"""Parse a registered slash command, or return ``None`` for normal input.
|
|
64
|
+
|
|
65
|
+
Command names and aliases are case-insensitive. Arguments are split on
|
|
66
|
+
whitespace only; command-specific validation is intentionally limited to
|
|
67
|
+
the current contract.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
parts = text.strip().split()
|
|
71
|
+
if not parts or not parts[0].startswith("/"):
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
command_token = parts[0][1:].lower()
|
|
75
|
+
spec = _COMMANDS_BY_NAME.get(command_token)
|
|
76
|
+
if spec is None:
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
args = tuple(parts[1:])
|
|
80
|
+
if spec.name == "resume":
|
|
81
|
+
if len(args) != 1:
|
|
82
|
+
raise CommandParseError(spec.name, spec.usage)
|
|
83
|
+
elif args:
|
|
84
|
+
raise CommandParseError(spec.name, spec.usage)
|
|
85
|
+
|
|
86
|
+
return ParsedCommand(name=spec.name, args=args)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
__all__ = [
|
|
90
|
+
"COMMAND_SPECS",
|
|
91
|
+
"CommandParseError",
|
|
92
|
+
"CommandSpec",
|
|
93
|
+
"ParsedCommand",
|
|
94
|
+
"parse_slash_command",
|
|
95
|
+
]
|