foundry-mcp 0.3.3__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 (135) hide show
  1. foundry_mcp/__init__.py +7 -0
  2. foundry_mcp/cli/__init__.py +80 -0
  3. foundry_mcp/cli/__main__.py +9 -0
  4. foundry_mcp/cli/agent.py +96 -0
  5. foundry_mcp/cli/commands/__init__.py +37 -0
  6. foundry_mcp/cli/commands/cache.py +137 -0
  7. foundry_mcp/cli/commands/dashboard.py +148 -0
  8. foundry_mcp/cli/commands/dev.py +446 -0
  9. foundry_mcp/cli/commands/journal.py +377 -0
  10. foundry_mcp/cli/commands/lifecycle.py +274 -0
  11. foundry_mcp/cli/commands/modify.py +824 -0
  12. foundry_mcp/cli/commands/plan.py +633 -0
  13. foundry_mcp/cli/commands/pr.py +393 -0
  14. foundry_mcp/cli/commands/review.py +652 -0
  15. foundry_mcp/cli/commands/session.py +479 -0
  16. foundry_mcp/cli/commands/specs.py +856 -0
  17. foundry_mcp/cli/commands/tasks.py +807 -0
  18. foundry_mcp/cli/commands/testing.py +676 -0
  19. foundry_mcp/cli/commands/validate.py +982 -0
  20. foundry_mcp/cli/config.py +98 -0
  21. foundry_mcp/cli/context.py +259 -0
  22. foundry_mcp/cli/flags.py +266 -0
  23. foundry_mcp/cli/logging.py +212 -0
  24. foundry_mcp/cli/main.py +44 -0
  25. foundry_mcp/cli/output.py +122 -0
  26. foundry_mcp/cli/registry.py +110 -0
  27. foundry_mcp/cli/resilience.py +178 -0
  28. foundry_mcp/cli/transcript.py +217 -0
  29. foundry_mcp/config.py +850 -0
  30. foundry_mcp/core/__init__.py +144 -0
  31. foundry_mcp/core/ai_consultation.py +1636 -0
  32. foundry_mcp/core/cache.py +195 -0
  33. foundry_mcp/core/capabilities.py +446 -0
  34. foundry_mcp/core/concurrency.py +898 -0
  35. foundry_mcp/core/context.py +540 -0
  36. foundry_mcp/core/discovery.py +1603 -0
  37. foundry_mcp/core/error_collection.py +728 -0
  38. foundry_mcp/core/error_store.py +592 -0
  39. foundry_mcp/core/feature_flags.py +592 -0
  40. foundry_mcp/core/health.py +749 -0
  41. foundry_mcp/core/journal.py +694 -0
  42. foundry_mcp/core/lifecycle.py +412 -0
  43. foundry_mcp/core/llm_config.py +1350 -0
  44. foundry_mcp/core/llm_patterns.py +510 -0
  45. foundry_mcp/core/llm_provider.py +1569 -0
  46. foundry_mcp/core/logging_config.py +374 -0
  47. foundry_mcp/core/metrics_persistence.py +584 -0
  48. foundry_mcp/core/metrics_registry.py +327 -0
  49. foundry_mcp/core/metrics_store.py +641 -0
  50. foundry_mcp/core/modifications.py +224 -0
  51. foundry_mcp/core/naming.py +123 -0
  52. foundry_mcp/core/observability.py +1216 -0
  53. foundry_mcp/core/otel.py +452 -0
  54. foundry_mcp/core/otel_stubs.py +264 -0
  55. foundry_mcp/core/pagination.py +255 -0
  56. foundry_mcp/core/progress.py +317 -0
  57. foundry_mcp/core/prometheus.py +577 -0
  58. foundry_mcp/core/prompts/__init__.py +464 -0
  59. foundry_mcp/core/prompts/fidelity_review.py +546 -0
  60. foundry_mcp/core/prompts/markdown_plan_review.py +511 -0
  61. foundry_mcp/core/prompts/plan_review.py +623 -0
  62. foundry_mcp/core/providers/__init__.py +225 -0
  63. foundry_mcp/core/providers/base.py +476 -0
  64. foundry_mcp/core/providers/claude.py +460 -0
  65. foundry_mcp/core/providers/codex.py +619 -0
  66. foundry_mcp/core/providers/cursor_agent.py +642 -0
  67. foundry_mcp/core/providers/detectors.py +488 -0
  68. foundry_mcp/core/providers/gemini.py +405 -0
  69. foundry_mcp/core/providers/opencode.py +616 -0
  70. foundry_mcp/core/providers/opencode_wrapper.js +302 -0
  71. foundry_mcp/core/providers/package-lock.json +24 -0
  72. foundry_mcp/core/providers/package.json +25 -0
  73. foundry_mcp/core/providers/registry.py +607 -0
  74. foundry_mcp/core/providers/test_provider.py +171 -0
  75. foundry_mcp/core/providers/validation.py +729 -0
  76. foundry_mcp/core/rate_limit.py +427 -0
  77. foundry_mcp/core/resilience.py +600 -0
  78. foundry_mcp/core/responses.py +934 -0
  79. foundry_mcp/core/review.py +366 -0
  80. foundry_mcp/core/security.py +438 -0
  81. foundry_mcp/core/spec.py +1650 -0
  82. foundry_mcp/core/task.py +1289 -0
  83. foundry_mcp/core/testing.py +450 -0
  84. foundry_mcp/core/validation.py +2081 -0
  85. foundry_mcp/dashboard/__init__.py +32 -0
  86. foundry_mcp/dashboard/app.py +119 -0
  87. foundry_mcp/dashboard/components/__init__.py +17 -0
  88. foundry_mcp/dashboard/components/cards.py +88 -0
  89. foundry_mcp/dashboard/components/charts.py +234 -0
  90. foundry_mcp/dashboard/components/filters.py +136 -0
  91. foundry_mcp/dashboard/components/tables.py +195 -0
  92. foundry_mcp/dashboard/data/__init__.py +11 -0
  93. foundry_mcp/dashboard/data/stores.py +433 -0
  94. foundry_mcp/dashboard/launcher.py +289 -0
  95. foundry_mcp/dashboard/views/__init__.py +12 -0
  96. foundry_mcp/dashboard/views/errors.py +217 -0
  97. foundry_mcp/dashboard/views/metrics.py +174 -0
  98. foundry_mcp/dashboard/views/overview.py +160 -0
  99. foundry_mcp/dashboard/views/providers.py +83 -0
  100. foundry_mcp/dashboard/views/sdd_workflow.py +255 -0
  101. foundry_mcp/dashboard/views/tool_usage.py +139 -0
  102. foundry_mcp/prompts/__init__.py +9 -0
  103. foundry_mcp/prompts/workflows.py +525 -0
  104. foundry_mcp/resources/__init__.py +9 -0
  105. foundry_mcp/resources/specs.py +591 -0
  106. foundry_mcp/schemas/__init__.py +38 -0
  107. foundry_mcp/schemas/sdd-spec-schema.json +386 -0
  108. foundry_mcp/server.py +164 -0
  109. foundry_mcp/tools/__init__.py +10 -0
  110. foundry_mcp/tools/unified/__init__.py +71 -0
  111. foundry_mcp/tools/unified/authoring.py +1487 -0
  112. foundry_mcp/tools/unified/context_helpers.py +98 -0
  113. foundry_mcp/tools/unified/documentation_helpers.py +198 -0
  114. foundry_mcp/tools/unified/environment.py +939 -0
  115. foundry_mcp/tools/unified/error.py +462 -0
  116. foundry_mcp/tools/unified/health.py +225 -0
  117. foundry_mcp/tools/unified/journal.py +841 -0
  118. foundry_mcp/tools/unified/lifecycle.py +632 -0
  119. foundry_mcp/tools/unified/metrics.py +777 -0
  120. foundry_mcp/tools/unified/plan.py +745 -0
  121. foundry_mcp/tools/unified/pr.py +294 -0
  122. foundry_mcp/tools/unified/provider.py +629 -0
  123. foundry_mcp/tools/unified/review.py +685 -0
  124. foundry_mcp/tools/unified/review_helpers.py +299 -0
  125. foundry_mcp/tools/unified/router.py +102 -0
  126. foundry_mcp/tools/unified/server.py +580 -0
  127. foundry_mcp/tools/unified/spec.py +808 -0
  128. foundry_mcp/tools/unified/task.py +2202 -0
  129. foundry_mcp/tools/unified/test.py +370 -0
  130. foundry_mcp/tools/unified/verification.py +520 -0
  131. foundry_mcp-0.3.3.dist-info/METADATA +337 -0
  132. foundry_mcp-0.3.3.dist-info/RECORD +135 -0
  133. foundry_mcp-0.3.3.dist-info/WHEEL +4 -0
  134. foundry_mcp-0.3.3.dist-info/entry_points.txt +3 -0
  135. foundry_mcp-0.3.3.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,171 @@
1
+ """Fixture-backed provider used for offline verification.
2
+
3
+ This provider is intentionally *disabled by default* and only becomes available
4
+ when explicitly enabled via environment variables. It exists to support:
5
+
6
+ - deterministic unit/integration tests
7
+ - offline generation of fidelity/plan review artifacts for SDD specs
8
+
9
+ Security notes:
10
+ - No network access
11
+ - No shell execution
12
+ - Reads only from a configured fixture directory
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ import os
19
+ import time
20
+ from pathlib import Path
21
+ from typing import Any, Dict, Optional
22
+
23
+ from foundry_mcp.core.providers.base import (
24
+ ModelDescriptor,
25
+ ProviderCapability,
26
+ ProviderContext,
27
+ ProviderHooks,
28
+ ProviderMetadata,
29
+ ProviderRequest,
30
+ ProviderResult,
31
+ ProviderStatus,
32
+ TokenUsage,
33
+ )
34
+ from foundry_mcp.core.providers.registry import register_provider
35
+
36
+
37
+ _PROVIDER_ID = "test-provider"
38
+ _ENABLE_ENV = "FOUNDRY_TEST_PROVIDER_ENABLED"
39
+ _FIXTURES_DIR_ENV = "FOUNDRY_TEST_PROVIDER_FIXTURES_DIR"
40
+ _DEFAULT_FIXTURES_DIR = Path("tests/fixtures/ai_responses")
41
+
42
+ _WORKFLOW_TO_DEFAULT_FILE = {
43
+ "plan_review": "plan_review_response.json",
44
+ "fidelity_review": "fidelity_review_response.json",
45
+ "markdown_plan_review": "plan_review_response.json",
46
+ }
47
+
48
+
49
+ def _is_enabled() -> bool:
50
+ value = os.environ.get(_ENABLE_ENV, "").strip().lower()
51
+ return value in {"1", "true", "yes", "on"}
52
+
53
+
54
+ def _resolve_fixtures_dir() -> Path:
55
+ override = os.environ.get(_FIXTURES_DIR_ENV)
56
+ if override:
57
+ return Path(override)
58
+ return _DEFAULT_FIXTURES_DIR
59
+
60
+
61
+ def _load_fixture(*, workflow: str) -> Dict[str, Any]:
62
+ fixtures_dir = _resolve_fixtures_dir()
63
+ filename = _WORKFLOW_TO_DEFAULT_FILE.get(workflow)
64
+ if not filename:
65
+ raise FileNotFoundError(f"No fixture mapping for workflow '{workflow}'")
66
+
67
+ fixture_path = fixtures_dir / filename
68
+ if not fixture_path.exists():
69
+ raise FileNotFoundError(f"Fixture file not found: {fixture_path}")
70
+
71
+ return json.loads(fixture_path.read_text(encoding="utf-8"))
72
+
73
+
74
+ _TEST_PROVIDER_MODELS = [
75
+ ModelDescriptor(
76
+ id="fixture",
77
+ display_name="Fixture Provider (offline)",
78
+ capabilities={ProviderCapability.TEXT},
79
+ routing_hints={"offline": True, "fixtures": True},
80
+ )
81
+ ]
82
+
83
+ _TEST_PROVIDER_METADATA = ProviderMetadata(
84
+ provider_id=_PROVIDER_ID,
85
+ display_name="Test Fixture Provider",
86
+ models=_TEST_PROVIDER_MODELS,
87
+ default_model="fixture",
88
+ capabilities={ProviderCapability.TEXT},
89
+ security_flags={"writes_allowed": False, "read_only": True, "offline": True},
90
+ extra={
91
+ "enabled_env": _ENABLE_ENV,
92
+ "fixtures_dir_env": _FIXTURES_DIR_ENV,
93
+ "default_fixtures_dir": str(_DEFAULT_FIXTURES_DIR),
94
+ },
95
+ )
96
+
97
+
98
+ class TestFixtureProvider(ProviderContext):
99
+ """ProviderContext that returns canned responses from fixtures."""
100
+
101
+ def __init__(
102
+ self,
103
+ metadata: ProviderMetadata,
104
+ hooks: Optional[ProviderHooks] = None,
105
+ *,
106
+ model: Optional[str] = None,
107
+ ):
108
+ super().__init__(metadata, hooks)
109
+ self._model = model or metadata.default_model or "fixture"
110
+
111
+ def _execute(self, request: ProviderRequest) -> ProviderResult:
112
+ start_time = time.perf_counter()
113
+
114
+ workflow = None
115
+ if isinstance(request.metadata, dict):
116
+ workflow = request.metadata.get("workflow")
117
+
118
+ if not isinstance(workflow, str) or not workflow:
119
+ workflow = "plan_review"
120
+
121
+ fixture = _load_fixture(workflow=workflow)
122
+ tokens = fixture.get("tokens", {}) if isinstance(fixture, dict) else {}
123
+
124
+ duration_ms = (time.perf_counter() - start_time) * 1000
125
+
126
+ return ProviderResult(
127
+ content=str(fixture.get("content", "")),
128
+ provider_id=self._metadata.provider_id,
129
+ model_used=str(fixture.get("model", self._model)),
130
+ status=ProviderStatus.SUCCESS,
131
+ tokens=TokenUsage(
132
+ input_tokens=int(tokens.get("prompt", 0) or 0),
133
+ output_tokens=int(tokens.get("completion", 0) or 0),
134
+ total_tokens=int(tokens.get("total", 0) or 0),
135
+ ),
136
+ duration_ms=round(duration_ms, 2),
137
+ raw_payload={
138
+ "fixture_version": fixture.get("fixture_version"),
139
+ "workflow": fixture.get("workflow"),
140
+ "prompt_id": fixture.get("prompt_id"),
141
+ "cached": fixture.get("cached"),
142
+ "timestamp": fixture.get("timestamp"),
143
+ },
144
+ )
145
+
146
+
147
+ def _factory(
148
+ *,
149
+ hooks: ProviderHooks,
150
+ model: Optional[str] = None,
151
+ dependencies: Optional[Dict[str, object]] = None,
152
+ overrides: Optional[Dict[str, object]] = None,
153
+ ) -> ProviderContext:
154
+ return TestFixtureProvider(_TEST_PROVIDER_METADATA, hooks, model=model)
155
+
156
+
157
+ def _availability_check() -> bool:
158
+ if not _is_enabled():
159
+ return False
160
+ return _resolve_fixtures_dir().exists()
161
+
162
+
163
+ register_provider(
164
+ _PROVIDER_ID,
165
+ factory=_factory,
166
+ metadata=_TEST_PROVIDER_METADATA,
167
+ availability_check=_availability_check,
168
+ priority=0,
169
+ description="Offline fixture-backed provider (tests/verification only)",
170
+ tags=("test", "offline"),
171
+ )