forge-cpp-mcp 0.2.1__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 (83) hide show
  1. forge_cpp_mcp-0.2.1.dist-info/METADATA +436 -0
  2. forge_cpp_mcp-0.2.1.dist-info/RECORD +83 -0
  3. forge_cpp_mcp-0.2.1.dist-info/WHEEL +4 -0
  4. forge_cpp_mcp-0.2.1.dist-info/entry_points.txt +2 -0
  5. forge_cpp_mcp-0.2.1.dist-info/licenses/LICENSE +21 -0
  6. forgemcp/__init__.py +5 -0
  7. forgemcp/assets/clangd-result.html +119 -0
  8. forgemcp/assets/cmake-build.html +111 -0
  9. forgemcp/assets/cmake-configure.html +111 -0
  10. forgemcp/assets/cmake-profiles.html +111 -0
  11. forgemcp/assets/cmake-test.html +111 -0
  12. forgemcp/assets/process-details.html +113 -0
  13. forgemcp/assets/process-overview.html +111 -0
  14. forgemcp/assets/toolsets.html +111 -0
  15. forgemcp/assets/workspace-file.html +119 -0
  16. forgemcp/assets/workspace-result.html +119 -0
  17. forgemcp/assets/workspace-search.html +119 -0
  18. forgemcp/assets/workspace-tree.html +119 -0
  19. forgemcp/assets.py +62 -0
  20. forgemcp/clangd/__init__.py +1 -0
  21. forgemcp/clangd/errors.py +29 -0
  22. forgemcp/clangd/models.py +94 -0
  23. forgemcp/clangd/service.py +1279 -0
  24. forgemcp/clangd/session.py +520 -0
  25. forgemcp/cmake/__init__.py +1 -0
  26. forgemcp/cmake/errors.py +5 -0
  27. forgemcp/cmake/profiles.py +95 -0
  28. forgemcp/cmake/service.py +895 -0
  29. forgemcp/completion.py +49 -0
  30. forgemcp/icons/clangd.LICENSE +219 -0
  31. forgemcp/icons/clangd.svg +25 -0
  32. forgemcp/icons/cmake.svg +9 -0
  33. forgemcp/icons/process.svg +4 -0
  34. forgemcp/icons/toolchain.svg +1 -0
  35. forgemcp/icons/workspace-edit.svg +1 -0
  36. forgemcp/icons/workspace-file.svg +1 -0
  37. forgemcp/icons/workspace-search.svg +1 -0
  38. forgemcp/icons/workspace.svg +4 -0
  39. forgemcp/markdown.py +308 -0
  40. forgemcp/process/__init__.py +21 -0
  41. forgemcp/process/errors.py +21 -0
  42. forgemcp/process/models.py +171 -0
  43. forgemcp/process/service.py +830 -0
  44. forgemcp/process/transcript.py +116 -0
  45. forgemcp/progress.py +40 -0
  46. forgemcp/server.py +196 -0
  47. forgemcp/toolchain/__init__.py +1 -0
  48. forgemcp/toolchain/discovery.py +25 -0
  49. forgemcp/toolchain/errors.py +41 -0
  50. forgemcp/toolchain/loader.py +48 -0
  51. forgemcp/toolchain/providers/__init__.py +1 -0
  52. forgemcp/toolchain/providers/system.py +52 -0
  53. forgemcp/toolchain/providers/user.py +93 -0
  54. forgemcp/toolchain/providers/visual_studio.py +202 -0
  55. forgemcp/toolchain/service.py +226 -0
  56. forgemcp/toolchain/spec.py +73 -0
  57. forgemcp/toolchain/tools/__init__.py +1 -0
  58. forgemcp/toolchain/tools/clang.py +61 -0
  59. forgemcp/toolchain/tools/clang_cl.py +61 -0
  60. forgemcp/toolchain/tools/clangd.py +280 -0
  61. forgemcp/toolchain/tools/clangxx.py +61 -0
  62. forgemcp/toolchain/tools/cmake.py +280 -0
  63. forgemcp/toolchain/tools/cppvsdbg.py +27 -0
  64. forgemcp/toolchain/tools/ctest.py +202 -0
  65. forgemcp/toolchain/tools/gcc.py +61 -0
  66. forgemcp/toolchain/tools/gdb.py +61 -0
  67. forgemcp/toolchain/tools/git.py +61 -0
  68. forgemcp/toolchain/tools/gxx.py +61 -0
  69. forgemcp/toolchain/tools/link.py +27 -0
  70. forgemcp/toolchain/tools/lld.py +61 -0
  71. forgemcp/toolchain/tools/lld_link.py +61 -0
  72. forgemcp/toolchain/tools/lldb_dap.py +27 -0
  73. forgemcp/toolchain/tools/make.py +61 -0
  74. forgemcp/toolchain/tools/msbuild.py +61 -0
  75. forgemcp/toolchain/tools/msvc.py +27 -0
  76. forgemcp/toolchain/tools/ninja.py +61 -0
  77. forgemcp/workspace/__init__.py +5 -0
  78. forgemcp/workspace/diff.py +181 -0
  79. forgemcp/workspace/errors.py +5 -0
  80. forgemcp/workspace/metadata.py +87 -0
  81. forgemcp/workspace/path.py +71 -0
  82. forgemcp/workspace/providers.py +25 -0
  83. forgemcp/workspace/service.py +1766 -0
@@ -0,0 +1,21 @@
1
+ """Expected process execution failures."""
2
+
3
+
4
+ class ProcessError(Exception):
5
+ """Base class for expected process failures."""
6
+
7
+
8
+ class ProcessStartError(ProcessError):
9
+ """Raised when an external process cannot be started."""
10
+
11
+
12
+ class ProcessNotFoundError(ProcessError):
13
+ """Raised when an unknown tracked process is requested."""
14
+
15
+
16
+ class ProcessExitedError(ProcessError):
17
+ """Raised when process I/O is attempted after exit."""
18
+
19
+
20
+ class ProcessStreamError(ProcessError):
21
+ """Raised when a process stream is consumed through an incompatible API."""
@@ -0,0 +1,171 @@
1
+ """Process state shared by service consumers and MCP inspection."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime, timezone
6
+ from typing import Literal
7
+
8
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
9
+ from pydantic.dataclasses import dataclass
10
+
11
+ ProcessStream = Literal["stdin", "stdout", "stderr"]
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class ProcessTimeout:
16
+ total: float | None = Field(
17
+ description="All allowed time (configured in seconds) for process.",
18
+ default=None,
19
+ ge=0,
20
+ )
21
+ idle: float | None = Field(
22
+ description="Max time (configured in seconds) without any chunks in stdout/stdin queues.",
23
+ default=None,
24
+ ge=0,
25
+ )
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class ProcessEncoding:
30
+ """Encoding options of process"""
31
+
32
+ driver: str | Literal["default"]
33
+ errors: Literal["strict", "replace"] = "replace"
34
+
35
+
36
+ @dataclass(frozen=True)
37
+ class ProcessOutput:
38
+ """One decoded chunk from a combined stdout/stderr stream."""
39
+
40
+ stream: Literal["stdout", "stderr"]
41
+ text: str
42
+
43
+
44
+ @dataclass(frozen=True, kw_only=True)
45
+ class ProcessLogEntry:
46
+ """One text entry retained in the in-memory process transcript."""
47
+
48
+ timestamp: datetime = Field(
49
+ description="When this log entry appeared.",
50
+ default_factory=lambda: datetime.now(timezone.utc),
51
+ )
52
+ time: float = Field(repr=False)
53
+ stream: Literal["stdout", "stderr", "stdin"]
54
+ text: str
55
+ start_line: int
56
+ end_line: int
57
+
58
+
59
+ @dataclass(frozen=True)
60
+ class ProcessSummary:
61
+ """Model-visible summary of one tracked process."""
62
+
63
+ process_id: int = Field(description="Stable identifier assigned by ForgeMCP.")
64
+ executable: str = Field(description="Executable requested by the owning service.")
65
+ arguments: list[str] = Field(description="Arguments passed to the executable.")
66
+ cwd: str = Field(description="Process working directory.")
67
+ encoding: str = Field(description="Encoding used for the retained text transcript.")
68
+ timeout: ProcessTimeout = Field(description="Configured timeout mode and duration.")
69
+
70
+
71
+ class ProcessStatus(BaseModel):
72
+ """Current state of the process."""
73
+
74
+ pid: int = Field(description="Operating-system process identifier.")
75
+ started: datetime = Field(
76
+ description="UTC start timestamp.",
77
+ default_factory=lambda: datetime.now(timezone.utc),
78
+ )
79
+ work_time: float = Field(
80
+ description="Process work time in seconds.",
81
+ ge=0,
82
+ default=0,
83
+ )
84
+ current_status: Literal[
85
+ "interrupted", "running", "stopped", "stream_failure"
86
+ ] | int = Field(
87
+ description="Exit status or process status."
88
+ )
89
+
90
+
91
+ class ProcessInfo(BaseModel):
92
+ """Command and lifecycle snapshot without the potentially large transcript."""
93
+
94
+ summary: ProcessSummary
95
+ status: ProcessStatus
96
+
97
+
98
+ class ProcessOverview(BaseModel):
99
+ """Model-visible snapshot of tracked processes."""
100
+
101
+ running: int = Field(
102
+ description="Number of processes currently running or starting."
103
+ )
104
+ completed: int = Field(description="Number of processes in a terminal state.")
105
+ processes: list[ProcessInfo] = Field(
106
+ description="Processes matching the requested filter."
107
+ )
108
+
109
+
110
+ class ProcessDetails(BaseModel):
111
+ """One immutable point-in-time view of a process and its ordered transcript."""
112
+
113
+ process: ProcessInfo
114
+ transcript: list[ProcessLogEntry]
115
+ lines: tuple[int, int] | None = None
116
+
117
+
118
+ class FirstLines(BaseModel):
119
+ """Select the first N lines."""
120
+
121
+ model_config = ConfigDict(extra="forbid")
122
+ first: int = Field(ge=1)
123
+
124
+
125
+ class LastLines(BaseModel):
126
+ """Select the last N lines."""
127
+
128
+ model_config = ConfigDict(extra="forbid")
129
+ last: int = Field(ge=1)
130
+
131
+
132
+ class LineRange(BaseModel):
133
+ """Select an inclusive absolute line range."""
134
+
135
+ model_config = ConfigDict(extra="forbid")
136
+ start: int = Field(ge=1)
137
+ end: int = Field(ge=1)
138
+
139
+ @model_validator(mode="after")
140
+ def validate_range(self) -> LineRange:
141
+ if self.end < self.start:
142
+ raise ValueError("Line range requires start <= end.")
143
+ return self
144
+
145
+
146
+ class FirstSeconds(BaseModel):
147
+ """Select the first N seconds from process start."""
148
+
149
+ model_config = ConfigDict(extra="forbid")
150
+ first: float = Field(gt=0, allow_inf_nan=False)
151
+
152
+
153
+ class LastSeconds(BaseModel):
154
+ """Select the last N seconds of the process snapshot."""
155
+
156
+ model_config = ConfigDict(extra="forbid")
157
+ last: float = Field(gt=0, allow_inf_nan=False)
158
+
159
+
160
+ class TimeRange(BaseModel):
161
+ """Seconds from process start; include start and exclude end."""
162
+
163
+ model_config = ConfigDict(extra="forbid")
164
+ start: float = Field(ge=0, allow_inf_nan=False)
165
+ end: float = Field(ge=0, allow_inf_nan=False)
166
+
167
+ @model_validator(mode="after")
168
+ def validate_range(self) -> TimeRange:
169
+ if self.end <= self.start:
170
+ raise ValueError("Time range requires start < end.")
171
+ return self