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
forgemcp/assets.py ADDED
@@ -0,0 +1,62 @@
1
+ """Small helpers for files shipped inside the ForgeMCP package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import base64
6
+ import mimetypes
7
+ from dataclasses import dataclass
8
+ from importlib.resources import files
9
+ from importlib.resources.abc import Traversable
10
+ from pathlib import PurePosixPath
11
+
12
+ from mcp.types import Icon
13
+
14
+ PACKAGE = "forgemcp"
15
+
16
+
17
+ def package_file(relative_path: str) -> Traversable:
18
+ """Resolve a safe path relative to the ForgeMCP package."""
19
+ path = PurePosixPath(relative_path.replace("\\", "/"))
20
+ if path.is_absolute() or ".." in path.parts:
21
+ raise ValueError(
22
+ f"Package path must be relative and cannot contain '..': {relative_path}"
23
+ )
24
+
25
+ resource = files(PACKAGE)
26
+ for part in path.parts:
27
+ resource = resource.joinpath(part)
28
+ return resource
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class Widget:
33
+ """A generated single-file MCP App stored relative to the package root."""
34
+
35
+ path: str
36
+
37
+ @property
38
+ def uri(self) -> str:
39
+ return f"ui://forgemcp/{PurePosixPath(self.path).name}"
40
+
41
+ @property
42
+ def content(self) -> str:
43
+ return package_file(self.path).read_text(encoding="utf-8")
44
+
45
+
46
+ @dataclass(frozen=True)
47
+ class IconFile:
48
+ """An icon source file converted to portable MCP icon metadata."""
49
+
50
+ path: str
51
+ sizes: tuple[str, ...] = ("any",)
52
+
53
+ @property
54
+ def icon(self) -> Icon:
55
+ resource = package_file(self.path)
56
+ mime_type = mimetypes.guess_type(self.path)[0] or "application/octet-stream"
57
+ encoded = base64.b64encode(resource.read_bytes()).decode("ascii")
58
+ return Icon(
59
+ src=f"data:{mime_type};base64,{encoded}",
60
+ mime_type=mime_type,
61
+ sizes=list(self.sizes),
62
+ )
@@ -0,0 +1 @@
1
+ """C/C++ language analysis business services."""
@@ -0,0 +1,29 @@
1
+ """Expected language analysis failures, without protocol or transcript dumps."""
2
+
3
+
4
+ class ClangdError(Exception):
5
+ """Base error for an unavailable or unsuccessful analysis."""
6
+
7
+
8
+ class ClangdSessionError(ClangdError):
9
+ """A language-server session could not be established or was lost."""
10
+
11
+
12
+ class ClangdTimeoutError(ClangdError):
13
+ """A request or version-specific diagnostic exceeded its deadline."""
14
+
15
+
16
+ class ClangdProtocolError(ClangdError):
17
+ """The language server returned an unsupported or malformed result."""
18
+
19
+
20
+ class ClangdRequestError(ClangdError):
21
+ """The language server rejected an operation."""
22
+
23
+ def __init__(self, method: str, code: int, message: str) -> None:
24
+ super().__init__(f"{method} failed ({code}): {message}")
25
+ self.code = code
26
+
27
+
28
+ class ClangdStaleResultError(ClangdError):
29
+ """Workspace content changed while an analysis snapshot was being produced."""
@@ -0,0 +1,94 @@
1
+ """Language values shared by session decoding and service results."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Literal
6
+
7
+ from pydantic import BaseModel, Field, model_validator
8
+
9
+ from forgemcp.workspace.path import WorkspacePath
10
+
11
+
12
+ class Position(BaseModel):
13
+ line: int = Field(ge=1)
14
+ character: int = Field(ge=0, description="Zero-based Unicode code point offset.")
15
+
16
+
17
+ class SourceRange(BaseModel):
18
+ start: Position
19
+ end: Position
20
+
21
+ @model_validator(mode="after")
22
+ def ordered(self) -> SourceRange:
23
+ if (self.end.line, self.end.character) < (self.start.line, self.start.character):
24
+ raise ValueError("Source range end precedes its start.")
25
+ return self
26
+
27
+
28
+ class Location(BaseModel):
29
+ path: WorkspacePath
30
+ range: SourceRange
31
+
32
+
33
+ class SourceExcerpt(BaseModel):
34
+ """Immutable source context captured with a navigation answer."""
35
+
36
+ start_line: int = Field(ge=1)
37
+ text: str
38
+
39
+
40
+ class NavigationLocation(Location):
41
+ preview: SourceExcerpt | None = Field(
42
+ default=None,
43
+ description="Up to seven saved source lines near the target. External or unreadable files have no preview.",
44
+ )
45
+
46
+
47
+ class RelatedDiagnostic(BaseModel):
48
+ location: Location
49
+ message: str
50
+
51
+
52
+ class Diagnostic(BaseModel):
53
+ range: SourceRange
54
+ severity: Literal["error", "warning", "information", "hint"] | None = None
55
+ message: str
56
+ code: int | str | None = None
57
+ source: str | None = None
58
+ tags: list[int] = Field(default_factory=list)
59
+ related: list[RelatedDiagnostic] = Field(default_factory=list)
60
+
61
+
62
+ class HoverText(BaseModel):
63
+ kind: Literal["plaintext", "markdown", "code"]
64
+ text: str
65
+ language: str | None = None
66
+
67
+
68
+ class Hover(BaseModel):
69
+ contents: list[HoverText]
70
+ range: SourceRange | None = None
71
+
72
+
73
+ class DocumentSymbol(BaseModel):
74
+ name: str
75
+ kind: int
76
+ range: SourceRange
77
+ selection_range: SourceRange
78
+ detail: str | None = None
79
+ tags: list[int] = Field(default_factory=list)
80
+ children: list[DocumentSymbol] = Field(default_factory=list)
81
+
82
+
83
+ class WorkspaceSymbol(BaseModel):
84
+ name: str
85
+ kind: int
86
+ location: NavigationLocation
87
+ container_name: str | None = None
88
+ tags: list[int] = Field(default_factory=list)
89
+
90
+
91
+ class HighlightSpan(BaseModel):
92
+ range: SourceRange
93
+ kind: str
94
+ modifiers: list[str] = Field(default_factory=list)