minder-cli 0.2.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 (132) hide show
  1. minder/__init__.py +12 -0
  2. minder/api/routers/prompts.py +177 -0
  3. minder/application/__init__.py +1 -0
  4. minder/application/admin/__init__.py +11 -0
  5. minder/application/admin/dto.py +453 -0
  6. minder/application/admin/jobs.py +327 -0
  7. minder/application/admin/use_cases.py +1895 -0
  8. minder/auth/__init__.py +12 -0
  9. minder/auth/context.py +26 -0
  10. minder/auth/middleware.py +70 -0
  11. minder/auth/principal.py +59 -0
  12. minder/auth/rate_limiter.py +89 -0
  13. minder/auth/rbac.py +60 -0
  14. minder/auth/service.py +541 -0
  15. minder/bootstrap/__init__.py +9 -0
  16. minder/bootstrap/providers.py +109 -0
  17. minder/bootstrap/transport.py +807 -0
  18. minder/cache/__init__.py +10 -0
  19. minder/cache/providers.py +140 -0
  20. minder/chunking/__init__.py +4 -0
  21. minder/chunking/code_splitter.py +184 -0
  22. minder/chunking/splitter.py +136 -0
  23. minder/cli.py +1542 -0
  24. minder/config.py +179 -0
  25. minder/continuity.py +363 -0
  26. minder/dev.py +160 -0
  27. minder/embedding/__init__.py +9 -0
  28. minder/embedding/base.py +7 -0
  29. minder/embedding/local.py +65 -0
  30. minder/embedding/openai.py +7 -0
  31. minder/graph/__init__.py +11 -0
  32. minder/graph/edges.py +13 -0
  33. minder/graph/executor.py +127 -0
  34. minder/graph/graph.py +263 -0
  35. minder/graph/nodes/__init__.py +27 -0
  36. minder/graph/nodes/evaluator.py +21 -0
  37. minder/graph/nodes/guard.py +64 -0
  38. minder/graph/nodes/llm.py +59 -0
  39. minder/graph/nodes/planning.py +30 -0
  40. minder/graph/nodes/reasoning.py +87 -0
  41. minder/graph/nodes/reranker.py +141 -0
  42. minder/graph/nodes/retriever.py +86 -0
  43. minder/graph/nodes/verification.py +230 -0
  44. minder/graph/nodes/workflow_planner.py +250 -0
  45. minder/graph/runtime.py +15 -0
  46. minder/graph/state.py +26 -0
  47. minder/llm/__init__.py +5 -0
  48. minder/llm/base.py +14 -0
  49. minder/llm/local.py +381 -0
  50. minder/llm/openai.py +89 -0
  51. minder/models/__init__.py +109 -0
  52. minder/models/base.py +10 -0
  53. minder/models/client.py +137 -0
  54. minder/models/document.py +34 -0
  55. minder/models/error.py +32 -0
  56. minder/models/graph.py +114 -0
  57. minder/models/history.py +32 -0
  58. minder/models/job.py +62 -0
  59. minder/models/prompt.py +41 -0
  60. minder/models/repository.py +62 -0
  61. minder/models/rule.py +68 -0
  62. minder/models/session.py +51 -0
  63. minder/models/skill.py +52 -0
  64. minder/models/user.py +41 -0
  65. minder/models/workflow.py +35 -0
  66. minder/observability/__init__.py +57 -0
  67. minder/observability/audit.py +243 -0
  68. minder/observability/logging.py +253 -0
  69. minder/observability/metrics.py +448 -0
  70. minder/observability/tracing.py +215 -0
  71. minder/presentation/__init__.py +1 -0
  72. minder/presentation/http/__init__.py +1 -0
  73. minder/presentation/http/admin/__init__.py +3 -0
  74. minder/presentation/http/admin/api.py +1309 -0
  75. minder/presentation/http/admin/context.py +94 -0
  76. minder/presentation/http/admin/dashboard.py +111 -0
  77. minder/presentation/http/admin/jobs.py +208 -0
  78. minder/presentation/http/admin/memories.py +185 -0
  79. minder/presentation/http/admin/prompts.py +219 -0
  80. minder/presentation/http/admin/routes.py +127 -0
  81. minder/presentation/http/admin/runtime.py +650 -0
  82. minder/presentation/http/admin/search.py +368 -0
  83. minder/presentation/http/admin/skills.py +230 -0
  84. minder/prompts/__init__.py +646 -0
  85. minder/prompts/formatter.py +142 -0
  86. minder/resources/__init__.py +318 -0
  87. minder/retrieval/__init__.py +5 -0
  88. minder/retrieval/hybrid.py +178 -0
  89. minder/retrieval/mmr.py +116 -0
  90. minder/retrieval/multi_hop.py +115 -0
  91. minder/runtime.py +15 -0
  92. minder/server.py +145 -0
  93. minder/store/__init__.py +64 -0
  94. minder/store/document.py +115 -0
  95. minder/store/error.py +82 -0
  96. minder/store/feedback.py +114 -0
  97. minder/store/graph.py +588 -0
  98. minder/store/history.py +57 -0
  99. minder/store/interfaces.py +512 -0
  100. minder/store/milvus/__init__.py +11 -0
  101. minder/store/milvus/client.py +26 -0
  102. minder/store/milvus/collections.py +15 -0
  103. minder/store/milvus/vector_store.py +232 -0
  104. minder/store/mongodb/__init__.py +11 -0
  105. minder/store/mongodb/client.py +49 -0
  106. minder/store/mongodb/indexes.py +90 -0
  107. minder/store/mongodb/operational_store.py +993 -0
  108. minder/store/relational.py +1087 -0
  109. minder/store/repo_state.py +58 -0
  110. minder/store/rule.py +93 -0
  111. minder/store/vector.py +79 -0
  112. minder/tools/__init__.py +47 -0
  113. minder/tools/auth.py +94 -0
  114. minder/tools/graph.py +839 -0
  115. minder/tools/ingest.py +353 -0
  116. minder/tools/memory.py +381 -0
  117. minder/tools/query.py +307 -0
  118. minder/tools/registry.py +269 -0
  119. minder/tools/repo_scanner.py +1266 -0
  120. minder/tools/search.py +15 -0
  121. minder/tools/session.py +316 -0
  122. minder/tools/skills.py +899 -0
  123. minder/tools/workflow.py +215 -0
  124. minder/transport/__init__.py +4 -0
  125. minder/transport/base.py +286 -0
  126. minder/transport/sse.py +252 -0
  127. minder/transport/stdio.py +29 -0
  128. minder_cli-0.2.0.dist-info/METADATA +318 -0
  129. minder_cli-0.2.0.dist-info/RECORD +132 -0
  130. minder_cli-0.2.0.dist-info/WHEEL +4 -0
  131. minder_cli-0.2.0.dist-info/entry_points.txt +2 -0
  132. minder_cli-0.2.0.dist-info/licenses/LICENSE +201 -0
minder/__init__.py ADDED
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ import warnings
5
+
6
+ if sys.version_info >= (3, 14):
7
+ warnings.filterwarnings(
8
+ "ignore",
9
+ message=r"Core Pydantic V1 functionality isn't compatible with Python 3\.14 or greater\.",
10
+ category=UserWarning,
11
+ module=r"langchain_core\._api\.deprecation",
12
+ )
@@ -0,0 +1,177 @@
1
+ import uuid
2
+ import logging
3
+ from typing import List, Optional
4
+ from datetime import datetime
5
+
6
+ from fastapi import APIRouter, Depends, HTTPException, Request
7
+ from pydantic import BaseModel, Field
8
+
9
+ from minder.observability.metrics import record_admin_operation
10
+ from minder.store.interfaces import IOperationalStore
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ router = APIRouter(
15
+ prefix="/api/v1/prompts",
16
+ tags=["prompts"],
17
+ )
18
+
19
+
20
+ class PromptCreate(BaseModel):
21
+ name: str
22
+ title: str
23
+ description: str
24
+ content_template: str
25
+ arguments: List[str] = Field(default_factory=list)
26
+
27
+
28
+ class PromptUpdate(BaseModel):
29
+ name: Optional[str] = None
30
+ title: Optional[str] = None
31
+ description: Optional[str] = None
32
+ content_template: Optional[str] = None
33
+ arguments: Optional[List[str]] = None
34
+
35
+
36
+ class PromptResponse(BaseModel):
37
+ id: str
38
+ name: str
39
+ title: str
40
+ description: str
41
+ content_template: str
42
+ arguments: List[str]
43
+ created_at: Optional[datetime] = None
44
+ updated_at: Optional[datetime] = None
45
+
46
+
47
+ def get_store(request: Request) -> IOperationalStore:
48
+ return request.app.state.store
49
+
50
+
51
+ @router.get("", response_model=List[PromptResponse])
52
+ async def list_prompts(store: IOperationalStore = Depends(get_store)):
53
+ await record_admin_operation(
54
+ operation="list_prompts", outcome="success", actor_id="system", store=store
55
+ )
56
+ try:
57
+ prompts = await store.list_prompts()
58
+ return [
59
+ PromptResponse(
60
+ id=str(p.id),
61
+ name=p.name,
62
+ title=p.title,
63
+ description=p.description,
64
+ content_template=p.content_template,
65
+ arguments=p.arguments,
66
+ created_at=p.created_at,
67
+ updated_at=p.updated_at,
68
+ )
69
+ for p in prompts
70
+ ]
71
+ except Exception as e:
72
+ logger.exception("Failed to list prompts", exc_info=e)
73
+ raise HTTPException(status_code=500, detail=str(e))
74
+
75
+
76
+ @router.post("", response_model=PromptResponse, status_code=201)
77
+ async def create_prompt(
78
+ payload: PromptCreate, store: IOperationalStore = Depends(get_store)
79
+ ):
80
+ await record_admin_operation(
81
+ operation="create_prompt", outcome="success", actor_id="system", store=store
82
+ )
83
+ try:
84
+ prompt = await store.create_prompt(
85
+ name=payload.name,
86
+ title=payload.title,
87
+ description=payload.description,
88
+ content_template=payload.content_template,
89
+ arguments=payload.arguments,
90
+ )
91
+ return PromptResponse(
92
+ id=str(prompt.id),
93
+ name=prompt.name,
94
+ title=prompt.title,
95
+ description=prompt.description,
96
+ content_template=prompt.content_template,
97
+ arguments=prompt.arguments,
98
+ created_at=prompt.created_at,
99
+ updated_at=prompt.updated_at,
100
+ )
101
+ except Exception as e:
102
+ logger.exception("Failed to create prompt", exc_info=e)
103
+ raise HTTPException(status_code=400, detail=str(e))
104
+
105
+
106
+ @router.get("/{prompt_id}", response_model=PromptResponse)
107
+ async def get_prompt(
108
+ prompt_id: uuid.UUID, store: IOperationalStore = Depends(get_store)
109
+ ):
110
+ await record_admin_operation(
111
+ operation="get_prompt", outcome="success", actor_id="system", store=store
112
+ )
113
+ try:
114
+ prompt = await store.get_prompt_by_id(prompt_id)
115
+ if not prompt:
116
+ raise HTTPException(status_code=404, detail="Prompt not found")
117
+ return PromptResponse(
118
+ id=str(prompt.id),
119
+ name=prompt.name,
120
+ title=prompt.title,
121
+ description=prompt.description,
122
+ content_template=prompt.content_template,
123
+ arguments=prompt.arguments,
124
+ created_at=prompt.created_at,
125
+ updated_at=prompt.updated_at,
126
+ )
127
+ except HTTPException:
128
+ raise
129
+ except Exception as e:
130
+ logger.exception("Failed to get prompt", exc_info=e)
131
+ raise HTTPException(status_code=500, detail=str(e))
132
+
133
+
134
+ @router.patch("/{prompt_id}", response_model=PromptResponse)
135
+ @router.put("/{prompt_id}", response_model=PromptResponse)
136
+ async def update_prompt(
137
+ prompt_id: uuid.UUID,
138
+ payload: PromptUpdate,
139
+ store: IOperationalStore = Depends(get_store),
140
+ ):
141
+ await record_admin_operation(
142
+ operation="update_prompt", outcome="success", actor_id="system", store=store
143
+ )
144
+ try:
145
+ update_data = payload.model_dump(exclude_unset=True)
146
+ prompt = await store.update_prompt(prompt_id, **update_data)
147
+ if not prompt:
148
+ raise HTTPException(status_code=404, detail="Prompt not found")
149
+ return PromptResponse(
150
+ id=str(prompt.id),
151
+ name=prompt.name,
152
+ title=prompt.title,
153
+ description=prompt.description,
154
+ content_template=prompt.content_template,
155
+ arguments=prompt.arguments,
156
+ created_at=prompt.created_at,
157
+ updated_at=prompt.updated_at,
158
+ )
159
+ except HTTPException:
160
+ raise
161
+ except Exception as e:
162
+ logger.exception("Failed to update prompt", exc_info=e)
163
+ raise HTTPException(status_code=400, detail=str(e))
164
+
165
+
166
+ @router.delete("/{prompt_id}", status_code=204)
167
+ async def delete_prompt(
168
+ prompt_id: uuid.UUID, store: IOperationalStore = Depends(get_store)
169
+ ):
170
+ await record_admin_operation(
171
+ operation="delete_prompt", outcome="success", actor_id="system", store=store
172
+ )
173
+ try:
174
+ await store.delete_prompt(prompt_id)
175
+ except Exception as e:
176
+ logger.exception("Failed to delete prompt", exc_info=e)
177
+ raise HTTPException(status_code=500, detail=str(e))
@@ -0,0 +1 @@
1
+ __all__: list[str] = []
@@ -0,0 +1,11 @@
1
+ from minder.application.admin.use_cases import (
2
+ AdminConsoleUseCases,
3
+ DASHBOARD_TOOL_SCOPE_OPTIONS,
4
+ DASHBOARD_TOOL_SCOPE_PRESETS,
5
+ )
6
+
7
+ __all__ = [
8
+ "AdminConsoleUseCases",
9
+ "DASHBOARD_TOOL_SCOPE_OPTIONS",
10
+ "DASHBOARD_TOOL_SCOPE_PRESETS",
11
+ ]
@@ -0,0 +1,453 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Literal, TypedDict
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ GraphSyncNodeType = Literal[
8
+ "repository",
9
+ "service",
10
+ "module",
11
+ "file",
12
+ "function",
13
+ "class",
14
+ "interface",
15
+ "abstract_class",
16
+ "controller",
17
+ "route",
18
+ "todo",
19
+ "external_service_api",
20
+ "mq_topic",
21
+ # v2 — new node types
22
+ "api_endpoint",
23
+ "websocket_endpoint",
24
+ "mq_producer",
25
+ "mq_consumer",
26
+ ]
27
+
28
+ GraphSyncRelationType = Literal[
29
+ "contains",
30
+ "imports",
31
+ "depends_on",
32
+ "calls",
33
+ "implements",
34
+ "extends",
35
+ "exposes_route",
36
+ "uses_external_service",
37
+ "publishes",
38
+ "consumes",
39
+ "tracks",
40
+ # v2 — new relation types
41
+ "websocket",
42
+ "cross_repo_calls",
43
+ "exposes_websocket",
44
+ ]
45
+
46
+
47
+ class ClientPayload(TypedDict):
48
+ id: str
49
+ name: str
50
+ slug: str
51
+ description: str
52
+ status: str
53
+ tool_scopes: list[str]
54
+ repo_scopes: list[str]
55
+ workflow_scopes: list[str]
56
+ transport_modes: list[str]
57
+
58
+
59
+ class ActivityEventPayload(TypedDict):
60
+ event_type: str
61
+ created_at: str
62
+
63
+
64
+ class AuditEventPayload(TypedDict):
65
+ id: str
66
+ actor_type: str
67
+ actor_id: str
68
+ actor_name: str | None # display_name or slug for context
69
+ event_type: str
70
+ resource_type: str
71
+ resource_id: str
72
+ resource_name: str | None # human-readable name for the resource
73
+ outcome: str
74
+ created_at: str | None
75
+
76
+
77
+ class ClientListPayload(TypedDict):
78
+ clients: list[ClientPayload]
79
+
80
+
81
+ class CreateClientPayload(TypedDict):
82
+ client: ClientPayload
83
+ client_api_key: str
84
+
85
+
86
+ class ClientDetailPayload(TypedDict):
87
+ client: ClientPayload
88
+
89
+
90
+ class OnboardingPayload(TypedDict):
91
+ client: ClientPayload
92
+ templates: dict[str, str]
93
+
94
+
95
+ class ClientConnectionTestPayload(TypedDict):
96
+ ok: bool
97
+ client: ClientPayload
98
+ templates: dict[str, str]
99
+
100
+
101
+ class ClientKeyPayload(TypedDict):
102
+ client_api_key: str
103
+
104
+
105
+ class RevokeKeysPayload(TypedDict):
106
+ revoked: bool
107
+
108
+
109
+ class AuditListPayload(TypedDict):
110
+ events: list[AuditEventPayload]
111
+ total: int
112
+ limit: int
113
+ offset: int
114
+
115
+
116
+ class SetupResultPayload(TypedDict):
117
+ api_key: str
118
+
119
+
120
+ class AdminLoginPayload(TypedDict):
121
+ jwt: str
122
+
123
+
124
+ class AdminSessionPayload(TypedDict):
125
+ id: str
126
+ username: str
127
+ email: str
128
+ display_name: str
129
+ role: str
130
+
131
+
132
+ # ---------------------------------------------------------------------------
133
+ # User management
134
+ # ---------------------------------------------------------------------------
135
+
136
+
137
+ class UserPayload(TypedDict):
138
+ id: str
139
+ username: str
140
+ email: str
141
+ display_name: str
142
+ role: str
143
+ is_active: bool
144
+ created_at: str | None
145
+
146
+
147
+ class UserListPayload(TypedDict):
148
+ users: list[UserPayload]
149
+
150
+
151
+ class UserDetailPayload(TypedDict):
152
+ user: UserPayload
153
+ clients: list[ClientPayload] # MCP clients created by this user
154
+
155
+
156
+ class CreateUserPayload(TypedDict):
157
+ user: UserPayload
158
+ api_key: str
159
+
160
+
161
+ # ---------------------------------------------------------------------------
162
+ # Workflow management
163
+ # ---------------------------------------------------------------------------
164
+
165
+
166
+ class WorkflowStepPayload(TypedDict):
167
+ name: str
168
+ description: str
169
+ gate: str | None
170
+
171
+
172
+ class WorkflowPayload(TypedDict):
173
+ id: str
174
+ name: str
175
+ description: str
176
+ enforcement: str
177
+ steps: list[WorkflowStepPayload]
178
+ created_at: str | None
179
+
180
+
181
+ class WorkflowListPayload(TypedDict):
182
+ workflows: list[WorkflowPayload]
183
+
184
+
185
+ class WorkflowDetailPayload(TypedDict):
186
+ workflow: WorkflowPayload
187
+
188
+
189
+ # ---------------------------------------------------------------------------
190
+ # Repository management
191
+ # ---------------------------------------------------------------------------
192
+
193
+
194
+ class RepositoryPayload(TypedDict):
195
+ id: str
196
+ name: str
197
+ path: str
198
+ remote_url: str | None
199
+ default_branch: str | None
200
+ tracked_branches: list[str]
201
+ workflow_name: str | None
202
+ workflow_state: str | None
203
+ current_step: str | None
204
+ created_at: str | None
205
+
206
+
207
+ class RepositoryBranchPayload(TypedDict):
208
+ branch: str
209
+ is_default: bool
210
+ last_synced: str | None
211
+ payload_version: str | None
212
+ source: str | None
213
+ node_count: int
214
+ edge_count: int
215
+ deleted_nodes: int
216
+ repo_path: str | None
217
+ diff_base: str | None
218
+
219
+
220
+ class RepositoryBranchListPayload(TypedDict):
221
+ repo_id: str
222
+ default_branch: str | None
223
+ tracked_branches: list[RepositoryBranchPayload]
224
+
225
+
226
+ class RepositoryBranchLinkPayload(TypedDict):
227
+ id: str
228
+ source_repo_id: str
229
+ source_repo_name: str
230
+ source_repo_url: str | None
231
+ source_branch: str
232
+ target_repo_id: str | None
233
+ target_repo_name: str
234
+ target_repo_url: str | None
235
+ target_branch: str
236
+ relation: str
237
+ direction: str
238
+ confidence: float
239
+ last_seen_at: str | None
240
+ source: str | None
241
+ metadata: dict[str, Any]
242
+
243
+
244
+ class RepositoryBranchLinkListPayload(TypedDict):
245
+ repo_id: str
246
+ branch: str | None
247
+ links: list[RepositoryBranchLinkPayload]
248
+
249
+
250
+ class RepositoryListPayload(TypedDict):
251
+ repositories: list[RepositoryPayload]
252
+
253
+
254
+ class RepositoryDetailPayload(TypedDict):
255
+ repository: RepositoryPayload
256
+
257
+
258
+ class UpdateRepositoryPayload(TypedDict, total=False):
259
+ name: str
260
+ remote_url: str | None
261
+ default_branch: str | None
262
+ path: str
263
+
264
+
265
+ class DeleteRepositoryPayload(TypedDict):
266
+ deleted: bool
267
+
268
+
269
+ class ClientRepositoryResolveRequest(BaseModel):
270
+ repo_name: str
271
+ repo_path: str
272
+ repo_url: str | None = None
273
+ default_branch: str | None = None
274
+
275
+
276
+ class ClientRepositoryResolvePayload(TypedDict):
277
+ repository: RepositoryPayload
278
+ created: bool
279
+
280
+
281
+ class GraphSyncNodeRefRequest(BaseModel):
282
+ node_type: GraphSyncNodeType
283
+ name: str
284
+
285
+
286
+ class GraphSyncNodeRequest(BaseModel):
287
+ node_type: GraphSyncNodeType
288
+ name: str
289
+ metadata: dict[str, Any] = Field(default_factory=dict)
290
+
291
+
292
+ class GraphSyncEdgeRequest(BaseModel):
293
+ source: GraphSyncNodeRefRequest
294
+ target: GraphSyncNodeRefRequest
295
+ relation: GraphSyncRelationType
296
+ weight: float = 1.0
297
+
298
+
299
+ class GraphSyncBranchLinkRequest(BaseModel):
300
+ source_branch: str | None = None
301
+ target_repo_id: str | None = None
302
+ target_repo_name: str
303
+ target_repo_url: str | None = None
304
+ target_branch: str
305
+ relation: str = "depends_on"
306
+ direction: Literal["outbound", "inbound", "bidirectional"] = "outbound"
307
+ confidence: float = 1.0
308
+ metadata: dict[str, Any] = Field(default_factory=dict)
309
+
310
+
311
+ class GraphSyncRequest(BaseModel):
312
+ payload_version: str
313
+ source: str = "minder-cli"
314
+ repo_path: str | None = None
315
+ branch: str | None = None
316
+ diff_base: str | None = None
317
+ deleted_files: list[str] = Field(default_factory=list)
318
+ sync_metadata: dict[str, Any] = Field(default_factory=dict)
319
+ nodes: list[GraphSyncNodeRequest] = Field(default_factory=list)
320
+ edges: list[GraphSyncEdgeRequest] = Field(default_factory=list)
321
+ branch_relationships: list[GraphSyncBranchLinkRequest] = Field(default_factory=list)
322
+
323
+
324
+ class UpsertRepositoryBranchLinkRequest(BaseModel):
325
+ source_branch: str
326
+ target_repo_id: str | None = None
327
+ target_repo_name: str | None = None
328
+ target_repo_url: str | None = None
329
+ target_branch: str
330
+ relation: str = "depends_on"
331
+ direction: Literal["outbound", "inbound", "bidirectional"] = "outbound"
332
+ confidence: float = 1.0
333
+ metadata: dict[str, Any] = Field(default_factory=dict)
334
+
335
+
336
+ class GraphSyncResultPayload(TypedDict):
337
+ repo_id: str
338
+ repository_name: str
339
+ payload_version: str
340
+ source: str
341
+ branch: str | None
342
+ deleted_nodes: int
343
+ nodes_upserted: int
344
+ edges_upserted: int
345
+ accepted_at: str
346
+
347
+
348
+ class RepositoryGraphNodePayload(TypedDict):
349
+ id: str
350
+ node_type: str
351
+ name: str
352
+ metadata: dict[str, Any]
353
+
354
+
355
+ class RepositoryGraphScopePayload(TypedDict):
356
+ repo_id: str
357
+ repo_name: str
358
+ repo_path: str | None
359
+ branch: str | None
360
+ distance: int
361
+ via_link: dict[str, Any] | None
362
+
363
+
364
+ class RepositoryGraphResultNodePayload(RepositoryGraphNodePayload, total=False):
365
+ score: int
366
+ direction: str
367
+ distance: int
368
+ repo_id: str
369
+ repo_name: str
370
+ branch: str | None
371
+ landscape_distance: int
372
+ via_link: dict[str, Any] | None
373
+
374
+
375
+ class RepositoryGraphEdgePayload(TypedDict):
376
+ id: str
377
+ source_id: str
378
+ target_id: str
379
+ relation: str
380
+ weight: float
381
+
382
+
383
+ class RepositoryGraphSummaryPayload(TypedDict):
384
+ repository: RepositoryPayload
385
+ graph_available: bool
386
+ active_branch: str | None
387
+ branch_state: RepositoryBranchPayload | None
388
+ branch_links: list[RepositoryBranchLinkPayload]
389
+ last_sync: dict[str, Any] | None
390
+ node_count: int
391
+ counts_by_type: dict[str, int]
392
+ routes: list[RepositoryGraphNodePayload]
393
+ todos: list[RepositoryGraphNodePayload]
394
+ external_services: list[RepositoryGraphNodePayload]
395
+ dependencies: list[dict[str, Any]]
396
+
397
+
398
+ class RepositoryGraphSearchPayload(TypedDict):
399
+ repository: RepositoryPayload
400
+ active_branch: str | None
401
+ query: str
402
+ filters: dict[str, Any]
403
+ scope_count: int
404
+ searched_scopes: list[RepositoryGraphScopePayload]
405
+ count: int
406
+ results: list[RepositoryGraphResultNodePayload]
407
+
408
+
409
+ class RepositoryGraphImpactPayload(TypedDict):
410
+ repository: RepositoryPayload
411
+ active_branch: str | None
412
+ target: str
413
+ searched_scopes: list[RepositoryGraphScopePayload]
414
+ matches: list[RepositoryGraphResultNodePayload]
415
+ impacted: list[RepositoryGraphResultNodePayload]
416
+ summary: dict[str, Any]
417
+
418
+
419
+ class RepositoryGraphMapPayload(TypedDict):
420
+ repository: RepositoryPayload
421
+ graph_available: bool
422
+ branch: str | None
423
+ branch_state: RepositoryBranchPayload | None
424
+ branch_links: list[RepositoryBranchLinkPayload]
425
+ nodes: list[RepositoryGraphNodePayload]
426
+ edges: list[RepositoryGraphEdgePayload]
427
+ summary: dict[str, Any]
428
+
429
+
430
+ class RepositoryLandscapeNodePayload(TypedDict):
431
+ id: str
432
+ repo_id: str
433
+ repo_name: str
434
+ branch: str
435
+ remote_url: str | None
436
+ is_default: bool
437
+ last_synced: str | None
438
+
439
+
440
+ class RepositoryLandscapeEdgePayload(TypedDict):
441
+ id: str
442
+ source_id: str
443
+ target_id: str
444
+ relation: str
445
+ direction: str
446
+ confidence: float
447
+
448
+
449
+ class RepositoryLandscapePayload(TypedDict):
450
+ repositories: list[RepositoryPayload]
451
+ nodes: list[RepositoryLandscapeNodePayload]
452
+ edges: list[RepositoryLandscapeEdgePayload]
453
+ summary: dict[str, int]