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.
Files changed (121) hide show
  1. mycode/__init__.py +0 -0
  2. mycode/adapters/__init__.py +21 -0
  3. mycode/adapters/jsonl.py +692 -0
  4. mycode/agent/__init__.py +25 -0
  5. mycode/agent/events.py +111 -0
  6. mycode/agent/outcome.py +103 -0
  7. mycode/agent/progress.py +373 -0
  8. mycode/agent/runner.py +1481 -0
  9. mycode/application/__init__.py +38 -0
  10. mycode/application/agent_session.py +367 -0
  11. mycode/application/events.py +59 -0
  12. mycode/application/runtime.py +211 -0
  13. mycode/application/sessions.py +180 -0
  14. mycode/cli.py +840 -0
  15. mycode/config.py +355 -0
  16. mycode/context/__init__.py +1 -0
  17. mycode/context/artifacts.py +672 -0
  18. mycode/context/budget.py +752 -0
  19. mycode/context/builder.py +112 -0
  20. mycode/context/compact.py +795 -0
  21. mycode/context/tool_result_format.py +199 -0
  22. mycode/context/tool_result_retention.py +261 -0
  23. mycode/conversation.py +78 -0
  24. mycode/error_handling.py +481 -0
  25. mycode/event_format.py +147 -0
  26. mycode/instructions.py +285 -0
  27. mycode/llm.py +771 -0
  28. mycode/mcp/__init__.py +41 -0
  29. mycode/mcp/client.py +44 -0
  30. mycode/mcp/config.py +207 -0
  31. mycode/mcp/errors.py +302 -0
  32. mycode/mcp/manager.py +339 -0
  33. mycode/mcp/models.py +20 -0
  34. mycode/mcp/result_adapter.py +58 -0
  35. mycode/mcp/tool_adapter.py +145 -0
  36. mycode/mcp/trust.py +313 -0
  37. mycode/memory.py +570 -0
  38. mycode/memory_context.py +245 -0
  39. mycode/messages.py +63 -0
  40. mycode/observability.py +28 -0
  41. mycode/permissions.py +262 -0
  42. mycode/persistence/__init__.py +1 -0
  43. mycode/persistence/filesystem.py +291 -0
  44. mycode/persistence/project_storage.py +208 -0
  45. mycode/persistence/session_lock.py +138 -0
  46. mycode/persistence/session_store.py +503 -0
  47. mycode/presentation/__init__.py +1 -0
  48. mycode/presentation/cli/__init__.py +14 -0
  49. mycode/presentation/cli/confirmer.py +116 -0
  50. mycode/presentation/cli/mcp_trust.py +61 -0
  51. mycode/presentation/cli/presenter.py +320 -0
  52. mycode/presentation/cli/session_menu.py +146 -0
  53. mycode/presentation/cli/subagent_observer.py +124 -0
  54. mycode/presentation/command_format.py +90 -0
  55. mycode/presentation/commands.py +95 -0
  56. mycode/presentation/tui/__init__.py +6 -0
  57. mycode/presentation/tui/app.py +1351 -0
  58. mycode/presentation/tui/interactions.py +253 -0
  59. mycode/presentation/tui/presenter.py +266 -0
  60. mycode/presentation/tui/screens.py +305 -0
  61. mycode/presentation/tui/widgets.py +214 -0
  62. mycode/project.py +22 -0
  63. mycode/prompts.py +181 -0
  64. mycode/reasoning.py +40 -0
  65. mycode/session.py +86 -0
  66. mycode/skills/__init__.py +27 -0
  67. mycode/skills/builtin/database-recovery/SKILL.md +138 -0
  68. mycode/skills/builtin/database-recovery/references/sqlite.md +235 -0
  69. mycode/skills/registry.py +295 -0
  70. mycode/skills/state.py +68 -0
  71. mycode/subagents/__init__.py +1 -0
  72. mycode/subagents/audit.py +212 -0
  73. mycode/subagents/concurrency.py +124 -0
  74. mycode/subagents/contracts.py +421 -0
  75. mycode/subagents/delegate.py +80 -0
  76. mycode/subagents/delegation.py +128 -0
  77. mycode/subagents/lifecycle.py +86 -0
  78. mycode/subagents/limits.py +7 -0
  79. mycode/subagents/observability.py +150 -0
  80. mycode/subagents/persistence.py +152 -0
  81. mycode/subagents/profiles.py +184 -0
  82. mycode/subagents/prompts.py +67 -0
  83. mycode/subagents/results.py +178 -0
  84. mycode/subagents/runtime.py +528 -0
  85. mycode/subagents/snapshots.py +211 -0
  86. mycode/subagents/tool_batch.py +260 -0
  87. mycode/tools/__init__.py +81 -0
  88. mycode/tools/base.py +222 -0
  89. mycode/tools/bounds.py +14 -0
  90. mycode/tools/command_executor.py +167 -0
  91. mycode/tools/command_output.py +166 -0
  92. mycode/tools/command_risk.py +596 -0
  93. mycode/tools/defaults.py +59 -0
  94. mycode/tools/edit_file.py +524 -0
  95. mycode/tools/file_mutation.py +30 -0
  96. mycode/tools/glob.py +247 -0
  97. mycode/tools/grep.py +324 -0
  98. mycode/tools/ignore.py +122 -0
  99. mycode/tools/inspect_changes.py +269 -0
  100. mycode/tools/load_skill.py +92 -0
  101. mycode/tools/memory.py +264 -0
  102. mycode/tools/path_permissions.py +78 -0
  103. mycode/tools/patterns.py +48 -0
  104. mycode/tools/permission_metadata.py +27 -0
  105. mycode/tools/process_tree.py +166 -0
  106. mycode/tools/read_file.py +242 -0
  107. mycode/tools/read_skill_resource.py +93 -0
  108. mycode/tools/registry.py +279 -0
  109. mycode/tools/run_command.py +237 -0
  110. mycode/tools/run_skill_script.py +206 -0
  111. mycode/tools/run_validation.py +107 -0
  112. mycode/tools/submit_result.py +93 -0
  113. mycode/tools/text.py +15 -0
  114. mycode/tools/validation_command.py +377 -0
  115. mycode/tools/workspace.py +33 -0
  116. mycode/tools/write_file.py +169 -0
  117. mycode_coding_agent-0.1.0.dist-info/METADATA +244 -0
  118. mycode_coding_agent-0.1.0.dist-info/RECORD +121 -0
  119. mycode_coding_agent-0.1.0.dist-info/WHEEL +4 -0
  120. mycode_coding_agent-0.1.0.dist-info/entry_points.txt +2 -0
  121. 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
+ ]
@@ -0,0 +1,6 @@
1
+ """Textual presentation for the MyCode interactive UI."""
2
+
3
+ from mycode.presentation.tui.app import MyCodeTuiApp, run_tui
4
+ from mycode.presentation.tui.presenter import TuiPresenter
5
+
6
+ __all__ = ["MyCodeTuiApp", "TuiPresenter", "run_tui"]