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
@@ -0,0 +1,807 @@
1
+ from __future__ import annotations
2
+
3
+ import uuid
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from minder.auth.principal import ClientPrincipal, Principal
8
+ from minder.auth.service import AuthError
9
+ from minder.auth.service import AuthService
10
+ from minder.cache.providers import LRUCacheProvider
11
+ from minder.config import MinderConfig
12
+ from minder.presentation.http.admin.routes import build_http_routes
13
+ from minder.prompts import PromptRegistry
14
+ from minder.resources import ResourceRegistry
15
+ from minder.store.interfaces import (
16
+ ICacheProvider,
17
+ IGraphRepository,
18
+ IOperationalStore,
19
+ IVectorStore,
20
+ )
21
+ from minder.store.repo_state import RepoStateStore
22
+ from minder.tools.auth import AuthTools
23
+ from minder.tools.graph import GraphTools
24
+ from minder.tools.memory import MemoryTools
25
+ from minder.tools.query import QueryTools
26
+ from minder.tools.registry import TOOL_DESCRIPTIONS
27
+ from minder.tools.search import SearchTools
28
+ from minder.tools.session import SessionTools
29
+ from minder.tools.skills import SkillTools
30
+ from minder.tools.workflow import WorkflowTools
31
+ from minder.transport import SSETransport, StdioTransport
32
+
33
+
34
+ def build_transport(
35
+ *,
36
+ config: MinderConfig,
37
+ store: IOperationalStore,
38
+ vector_store: IVectorStore,
39
+ graph_store: IGraphRepository | None = None,
40
+ cache: ICacheProvider | None = None,
41
+ ) -> SSETransport | StdioTransport:
42
+ auth_service = AuthService(store, config, cache=cache)
43
+ cache_provider = cache or LRUCacheProvider()
44
+ repo_state_store = RepoStateStore(config.workflow.repo_state_dir)
45
+ auth_tools = AuthTools(store, auth_service)
46
+ session_tools = SessionTools(store)
47
+ workflow_tools = WorkflowTools(store, repo_state_store)
48
+ memory_tools = MemoryTools(store, config)
49
+ skill_tools = SkillTools(store, config)
50
+ search_tools = SearchTools(store, config)
51
+ graph_tools = GraphTools(graph_store, store)
52
+ query_tools = QueryTools(
53
+ store,
54
+ config,
55
+ vector_store=vector_store,
56
+ graph_tools=graph_tools,
57
+ )
58
+
59
+ transport: SSETransport | StdioTransport
60
+ if config.server.transport == "stdio":
61
+ transport = StdioTransport(
62
+ config=config,
63
+ auth_service=auth_service,
64
+ cache_provider=cache_provider,
65
+ store=store,
66
+ )
67
+ else:
68
+ transport = SSETransport(
69
+ config=config,
70
+ store=store,
71
+ auth_service=auth_service,
72
+ extra_routes=[],
73
+ cache_provider=cache_provider,
74
+ )
75
+
76
+ async def sync_prompts() -> None:
77
+ await PromptRegistry.sync(transport.app, store)
78
+
79
+ transport.extend_routes(
80
+ build_http_routes(
81
+ config=config,
82
+ store=store,
83
+ graph_store=graph_store,
84
+ cache=cache,
85
+ prompt_sync_hook=sync_prompts,
86
+ )
87
+ )
88
+
89
+ def ensure_client_repo_access(
90
+ principal: Principal | None,
91
+ *,
92
+ repo_path: str,
93
+ ) -> None:
94
+ if not isinstance(principal, ClientPrincipal):
95
+ return
96
+ scopes = [
97
+ scope.strip().rstrip("/")
98
+ for scope in principal.repo_scope
99
+ if scope and scope.strip()
100
+ ]
101
+ repo_root = Path(repo_path).resolve()
102
+ candidates = {repo_path.rstrip("/"), str(repo_root).rstrip("/"), repo_root.name}
103
+ if not scopes or (
104
+ "*" not in scopes
105
+ and not any(
106
+ any(
107
+ candidate == scope or candidate.startswith(f"{scope}/")
108
+ for candidate in candidates
109
+ )
110
+ for scope in scopes
111
+ )
112
+ ):
113
+ raise AuthError(
114
+ "AUTH_FORBIDDEN", "Client is not allowed to inspect this repository"
115
+ )
116
+
117
+ def require_authenticated_user(user: Any | None) -> Any:
118
+ if user is None:
119
+ raise AuthError("AUTH_FORBIDDEN", "Authenticated user required")
120
+ return user
121
+
122
+ def require_admin_user(user: Any | None) -> Any:
123
+ authenticated_user = require_authenticated_user(user)
124
+ if getattr(authenticated_user, "role", None) != "admin":
125
+ raise AuthError("AUTH_FORBIDDEN", "Admin role required")
126
+ return authenticated_user
127
+
128
+ async def minder_auth_login(api_key: str) -> dict[str, str]:
129
+ return await auth_tools.minder_auth_login(api_key)
130
+
131
+ async def minder_auth_exchange_client_key(
132
+ client_api_key: str,
133
+ requested_scopes: list[str] | None = None,
134
+ ) -> dict[str, object]:
135
+ return await auth_tools.minder_auth_exchange_client_key(
136
+ client_api_key,
137
+ requested_scopes=requested_scopes,
138
+ )
139
+
140
+ async def minder_auth_whoami(
141
+ *, user=None, principal: Principal | None = None
142
+ ) -> dict[str, Any]: # noqa: ANN001
143
+ if user is not None:
144
+ return {
145
+ "principal_type": "user",
146
+ "principal_id": str(user.id),
147
+ "email": user.email,
148
+ "username": user.username,
149
+ "role": user.role,
150
+ "scopes": [],
151
+ "repo_scope": [],
152
+ }
153
+ if principal is None:
154
+ raise AuthError("AUTH_MISSING_TOKEN", "Authenticated principal required")
155
+ return {
156
+ "principal_type": principal.principal_type,
157
+ "principal_id": str(principal.principal_id),
158
+ "role": principal.role,
159
+ "scopes": list(principal.scopes),
160
+ "repo_scope": list(principal.repo_scope),
161
+ "client_slug": getattr(principal, "client_slug", None),
162
+ }
163
+
164
+ async def minder_auth_manage(
165
+ *, user=None, action: str
166
+ ) -> dict[str, object]: # noqa: ANN001
167
+ authenticated_user = require_admin_user(user)
168
+ return await auth_tools.minder_auth_manage(
169
+ actor_user_id=authenticated_user.id, action=action
170
+ )
171
+
172
+ async def minder_auth_create_client(
173
+ *,
174
+ user=None,
175
+ name: str,
176
+ slug: str,
177
+ description: str = "",
178
+ tool_scopes: list[str] | None = None,
179
+ repo_scopes: list[str] | None = None,
180
+ ) -> dict[str, object]: # noqa: ANN001
181
+ authenticated_user = require_admin_user(user)
182
+ return await auth_tools.minder_auth_create_client(
183
+ actor_user_id=authenticated_user.id,
184
+ name=name,
185
+ slug=slug,
186
+ description=description,
187
+ tool_scopes=tool_scopes,
188
+ repo_scopes=repo_scopes,
189
+ )
190
+
191
+ async def minder_session_create(
192
+ *,
193
+ user=None, # noqa: ANN001
194
+ principal: Principal | None = None,
195
+ name: str | None = None,
196
+ repo_id: str | None = None,
197
+ project_context: dict[str, Any] | None = None,
198
+ ) -> dict[str, Any]:
199
+ if isinstance(principal, ClientPrincipal):
200
+ return await session_tools.minder_session_create(
201
+ client_id=principal.client_id,
202
+ name=name,
203
+ repo_id=uuid.UUID(repo_id) if repo_id else None,
204
+ project_context=project_context,
205
+ )
206
+ authenticated_user = require_authenticated_user(user)
207
+ return await session_tools.minder_session_create(
208
+ user_id=authenticated_user.id,
209
+ name=name,
210
+ repo_id=uuid.UUID(repo_id) if repo_id else None,
211
+ project_context=project_context,
212
+ )
213
+
214
+ async def minder_session_find(
215
+ *,
216
+ user=None, # noqa: ANN001
217
+ principal: Principal | None = None,
218
+ name: str,
219
+ ) -> dict[str, Any]:
220
+ if isinstance(principal, ClientPrincipal):
221
+ return await session_tools.minder_session_find(
222
+ name=name,
223
+ client_id=principal.client_id,
224
+ )
225
+ authenticated_user = require_authenticated_user(user)
226
+ return await session_tools.minder_session_find(
227
+ name=name,
228
+ user_id=authenticated_user.id,
229
+ )
230
+
231
+ async def minder_session_list(
232
+ *,
233
+ user=None, # noqa: ANN001
234
+ principal: Principal | None = None,
235
+ ) -> dict[str, Any]:
236
+ if isinstance(principal, ClientPrincipal):
237
+ return await session_tools.minder_session_list(
238
+ client_id=principal.client_id
239
+ )
240
+ authenticated_user = require_authenticated_user(user)
241
+ return await session_tools.minder_session_list(user_id=authenticated_user.id)
242
+
243
+ async def minder_session_save(
244
+ *,
245
+ user=None,
246
+ session_id: str,
247
+ state: dict[str, Any] | None = None,
248
+ active_skills: dict[str, Any] | None = None, # noqa: ANN001
249
+ ) -> dict[str, Any]:
250
+ del user
251
+ return await session_tools.minder_session_save(
252
+ uuid.UUID(session_id),
253
+ state=state,
254
+ active_skills=active_skills,
255
+ )
256
+
257
+ async def minder_session_restore(
258
+ *, user=None, session_id: str
259
+ ) -> dict[str, Any]: # noqa: ANN001
260
+ del user
261
+ return await session_tools.minder_session_restore(uuid.UUID(session_id))
262
+
263
+ async def minder_session_context(
264
+ *,
265
+ user=None,
266
+ session_id: str,
267
+ branch: str,
268
+ open_files: list[str], # noqa: ANN001
269
+ ) -> dict[str, Any]:
270
+ del user
271
+ return await session_tools.minder_session_context(
272
+ uuid.UUID(session_id),
273
+ branch=branch,
274
+ open_files=open_files,
275
+ )
276
+
277
+ async def minder_session_cleanup(
278
+ *,
279
+ user=None,
280
+ principal: Principal | None = None,
281
+ ) -> dict[str, int]:
282
+ if isinstance(principal, ClientPrincipal):
283
+ return await session_tools.minder_session_cleanup(
284
+ client_id=principal.client_id
285
+ )
286
+ authenticated_user = require_authenticated_user(user)
287
+ return await session_tools.minder_session_cleanup(user_id=authenticated_user.id)
288
+
289
+ async def minder_workflow_get(
290
+ *, user=None, repo_id: str, repo_path: str
291
+ ) -> dict[str, Any]: # noqa: ANN001
292
+ del user
293
+ return await workflow_tools.minder_workflow_get(
294
+ repo_id=uuid.UUID(repo_id),
295
+ repo_path=repo_path,
296
+ )
297
+
298
+ async def minder_workflow_step(
299
+ *, user=None, repo_id: str, repo_path: str
300
+ ) -> dict[str, Any]: # noqa: ANN001
301
+ del user
302
+ return await workflow_tools.minder_workflow_step(
303
+ repo_id=uuid.UUID(repo_id),
304
+ repo_path=repo_path,
305
+ )
306
+
307
+ async def minder_workflow_update(
308
+ *,
309
+ user=None,
310
+ repo_id: str,
311
+ repo_path: str,
312
+ completed_step: str,
313
+ artifact_name: str | None = None,
314
+ artifact_content: str | None = None,
315
+ ) -> dict[str, Any]: # noqa: ANN001
316
+ del user
317
+ return await workflow_tools.minder_workflow_update(
318
+ repo_id=uuid.UUID(repo_id),
319
+ repo_path=repo_path,
320
+ completed_step=completed_step,
321
+ artifact_name=artifact_name,
322
+ artifact_content=artifact_content,
323
+ )
324
+
325
+ async def minder_workflow_guard(
326
+ *, user=None, repo_id: str, requested_step: str, action: str | None = None
327
+ ) -> dict[str, Any]: # noqa: ANN001
328
+ del user
329
+ return await workflow_tools.minder_workflow_guard(
330
+ repo_id=uuid.UUID(repo_id),
331
+ requested_step=requested_step,
332
+ action=action,
333
+ )
334
+
335
+ async def minder_memory_store(
336
+ *,
337
+ user=None,
338
+ title: str,
339
+ content: str,
340
+ tags: list[str],
341
+ language: str, # noqa: ANN001
342
+ ) -> dict[str, Any]:
343
+ del user
344
+ return await memory_tools.minder_memory_store(
345
+ title=title,
346
+ content=content,
347
+ tags=tags,
348
+ language=language,
349
+ )
350
+
351
+ async def minder_memory_recall(
352
+ *,
353
+ user=None,
354
+ query: str,
355
+ limit: int = 5,
356
+ current_step: str | None = None,
357
+ artifact_type: str | None = None,
358
+ ) -> list[dict[str, Any]]: # noqa: ANN001
359
+ del user
360
+ return await memory_tools.minder_memory_recall(
361
+ query,
362
+ limit=limit,
363
+ current_step=current_step,
364
+ artifact_type=artifact_type,
365
+ )
366
+
367
+ async def minder_memory_list(*, user=None) -> list[dict[str, Any]]: # noqa: ANN001
368
+ del user
369
+ return await memory_tools.minder_memory_list()
370
+
371
+ async def minder_memory_delete(
372
+ *, user=None, skill_id: str
373
+ ) -> dict[str, bool]: # noqa: ANN001
374
+ del user
375
+ return await memory_tools.minder_memory_delete(skill_id)
376
+
377
+ async def minder_memory_compact(
378
+ *,
379
+ user=None,
380
+ memory_ids: list[str],
381
+ similarity_threshold: float = 0.92,
382
+ dry_run: bool = True,
383
+ ) -> dict[str, Any]: # noqa: ANN001
384
+ del user
385
+ return await memory_tools.minder_memory_compact(
386
+ memory_ids=memory_ids,
387
+ similarity_threshold=similarity_threshold,
388
+ dry_run=dry_run,
389
+ )
390
+
391
+ async def minder_skill_store(
392
+ *,
393
+ user=None,
394
+ title: str,
395
+ content: str,
396
+ language: str,
397
+ tags: list[str] | None = None,
398
+ workflow_steps: list[str] | None = None,
399
+ artifact_types: list[str] | None = None,
400
+ provenance: str | None = None,
401
+ quality_score: float = 0.0,
402
+ ) -> dict[str, Any]: # noqa: ANN001
403
+ del user
404
+ return await skill_tools.minder_skill_store(
405
+ title=title,
406
+ content=content,
407
+ language=language,
408
+ tags=tags,
409
+ workflow_steps=workflow_steps,
410
+ artifact_types=artifact_types,
411
+ provenance=provenance,
412
+ quality_score=quality_score,
413
+ )
414
+
415
+ async def minder_skill_recall(
416
+ *,
417
+ user=None,
418
+ query: str,
419
+ limit: int = 5,
420
+ current_step: str | None = None,
421
+ artifact_type: str | None = None,
422
+ min_quality_score: float = 0.0,
423
+ ) -> list[dict[str, Any]]: # noqa: ANN001
424
+ del user
425
+ return await skill_tools.minder_skill_recall(
426
+ query,
427
+ limit=limit,
428
+ current_step=current_step,
429
+ artifact_type=artifact_type,
430
+ min_quality_score=min_quality_score,
431
+ )
432
+
433
+ async def minder_skill_list(
434
+ *,
435
+ user=None,
436
+ current_step: str | None = None,
437
+ tag: str | None = None,
438
+ min_quality_score: float = 0.0,
439
+ ) -> list[dict[str, Any]]: # noqa: ANN001
440
+ del user
441
+ return await skill_tools.minder_skill_list(
442
+ current_step=current_step,
443
+ tag=tag,
444
+ min_quality_score=min_quality_score,
445
+ )
446
+
447
+ async def minder_skill_update(
448
+ *,
449
+ user=None,
450
+ skill_id: str,
451
+ title: str | None = None,
452
+ content: str | None = None,
453
+ language: str | None = None,
454
+ tags: list[str] | None = None,
455
+ workflow_steps: list[str] | None = None,
456
+ artifact_types: list[str] | None = None,
457
+ provenance: str | None = None,
458
+ quality_score: float | None = None,
459
+ ) -> dict[str, Any]: # noqa: ANN001
460
+ del user
461
+ return await skill_tools.minder_skill_update(
462
+ skill_id,
463
+ title=title,
464
+ content=content,
465
+ language=language,
466
+ tags=tags,
467
+ workflow_steps=workflow_steps,
468
+ artifact_types=artifact_types,
469
+ provenance=provenance,
470
+ quality_score=quality_score,
471
+ )
472
+
473
+ async def minder_skill_delete(
474
+ *, user=None, skill_id: str
475
+ ) -> dict[str, bool]: # noqa: ANN001
476
+ del user
477
+ return await skill_tools.minder_skill_delete(skill_id)
478
+
479
+ async def minder_skill_import_git(
480
+ *,
481
+ user=None,
482
+ repo_url: str,
483
+ source_path: str = "skills",
484
+ ref: str | None = None,
485
+ provider: str | None = None,
486
+ excerpt_kind: str = "none",
487
+ ) -> dict[str, Any]: # noqa: ANN001
488
+ del user
489
+ return await skill_tools.minder_skill_import_git(
490
+ repo_url=repo_url,
491
+ source_path=source_path,
492
+ ref=ref,
493
+ provider=provider,
494
+ excerpt_kind=excerpt_kind,
495
+ )
496
+
497
+ async def minder_search(
498
+ *, user=None, query: str, limit: int = 5
499
+ ) -> list[dict[str, Any]]: # noqa: ANN001
500
+ del user
501
+ return await search_tools.minder_search(query, limit=limit)
502
+
503
+ async def minder_query(
504
+ *,
505
+ user=None,
506
+ principal: Principal | None = None,
507
+ query: str,
508
+ repo_path: str,
509
+ session_id: str | None = None,
510
+ repo_id: str | None = None,
511
+ workflow_name: str | None = None,
512
+ ) -> dict[str, Any]: # noqa: ANN001
513
+ if user is None and principal is None:
514
+ raise AuthError("AUTH_MISSING_TOKEN", "Authenticated principal required")
515
+ ensure_client_repo_access(principal, repo_path=repo_path)
516
+ return await query_tools.minder_query(
517
+ query,
518
+ repo_path=repo_path,
519
+ session_id=uuid.UUID(session_id) if session_id else None,
520
+ user_id=user.id if user else None,
521
+ repo_id=uuid.UUID(repo_id) if repo_id else None,
522
+ workflow_name=workflow_name,
523
+ allowed_repo_scopes=(
524
+ principal.repo_scope if isinstance(principal, ClientPrincipal) else None
525
+ ),
526
+ )
527
+
528
+ async def minder_search_code(
529
+ *,
530
+ user=None,
531
+ principal: Principal | None = None,
532
+ query: str,
533
+ repo_path: str,
534
+ limit: int = 5,
535
+ ) -> list[dict[str, Any]]: # noqa: ANN001
536
+ if user is None and principal is None:
537
+ raise AuthError("AUTH_MISSING_TOKEN", "Authenticated principal required")
538
+ ensure_client_repo_access(principal, repo_path=repo_path)
539
+ return await query_tools.minder_search_code(
540
+ query, repo_path=repo_path, limit=limit
541
+ )
542
+
543
+ async def minder_search_errors(
544
+ *, user=None, query: str, limit: int = 5
545
+ ) -> list[dict[str, Any]]: # noqa: ANN001
546
+ del user
547
+ return await query_tools.minder_search_errors(query, limit=limit)
548
+
549
+ async def minder_search_graph(
550
+ *,
551
+ user=None,
552
+ principal: Principal | None = None,
553
+ query: str,
554
+ repo_path: str,
555
+ node_types: list[str] | None = None,
556
+ limit: int = 10,
557
+ ) -> dict[str, Any]: # noqa: ANN001
558
+ if user is None and principal is None:
559
+ raise AuthError("AUTH_MISSING_TOKEN", "Authenticated principal required")
560
+ ensure_client_repo_access(principal, repo_path=repo_path)
561
+ return await graph_tools.minder_search_graph(
562
+ query,
563
+ repo_path=repo_path,
564
+ node_types=node_types,
565
+ limit=limit,
566
+ include_linked_repos=True,
567
+ allowed_repo_scopes=(
568
+ principal.repo_scope if isinstance(principal, ClientPrincipal) else None
569
+ ),
570
+ )
571
+
572
+ async def minder_find_impact(
573
+ *,
574
+ user=None,
575
+ principal: Principal | None = None,
576
+ target: str,
577
+ repo_path: str,
578
+ depth: int = 2,
579
+ limit: int = 25,
580
+ ) -> dict[str, Any]: # noqa: ANN001
581
+ if user is None and principal is None:
582
+ raise AuthError("AUTH_MISSING_TOKEN", "Authenticated principal required")
583
+ ensure_client_repo_access(principal, repo_path=repo_path)
584
+
585
+ return await graph_tools.minder_find_impact(
586
+ target,
587
+ repo_path=repo_path,
588
+ depth=depth,
589
+ limit=limit,
590
+ include_linked_repos=True,
591
+ allowed_repo_scopes=(
592
+ principal.repo_scope if isinstance(principal, ClientPrincipal) else None
593
+ ),
594
+ )
595
+
596
+ async def minder_auth_ping(message: str, *, user=None) -> str: # noqa: ANN001
597
+ del user
598
+ return f"auth pong: {message}"
599
+
600
+ transport.register_tool(
601
+ "minder_auth_ping",
602
+ minder_auth_ping,
603
+ require_auth=True,
604
+ description=TOOL_DESCRIPTIONS["minder_auth_ping"],
605
+ )
606
+ transport.register_tool(
607
+ "minder_auth_login",
608
+ minder_auth_login,
609
+ require_auth=False,
610
+ description=TOOL_DESCRIPTIONS["minder_auth_login"],
611
+ )
612
+ transport.register_tool(
613
+ "minder_auth_exchange_client_key",
614
+ minder_auth_exchange_client_key,
615
+ require_auth=False,
616
+ description=TOOL_DESCRIPTIONS["minder_auth_exchange_client_key"],
617
+ )
618
+ transport.register_tool(
619
+ "minder_auth_whoami",
620
+ minder_auth_whoami,
621
+ require_auth=True,
622
+ description=TOOL_DESCRIPTIONS["minder_auth_whoami"],
623
+ )
624
+ transport.register_tool(
625
+ "minder_auth_manage",
626
+ minder_auth_manage,
627
+ require_auth=True,
628
+ description=TOOL_DESCRIPTIONS["minder_auth_manage"],
629
+ )
630
+ transport.register_tool(
631
+ "minder_auth_create_client",
632
+ minder_auth_create_client,
633
+ require_auth=True,
634
+ description=TOOL_DESCRIPTIONS["minder_auth_create_client"],
635
+ )
636
+ transport.register_tool(
637
+ "minder_session_create",
638
+ minder_session_create,
639
+ require_auth=True,
640
+ description=TOOL_DESCRIPTIONS["minder_session_create"],
641
+ )
642
+ transport.register_tool(
643
+ "minder_session_find",
644
+ minder_session_find,
645
+ require_auth=True,
646
+ description=TOOL_DESCRIPTIONS["minder_session_find"],
647
+ )
648
+ transport.register_tool(
649
+ "minder_session_list",
650
+ minder_session_list,
651
+ require_auth=True,
652
+ description=TOOL_DESCRIPTIONS["minder_session_list"],
653
+ )
654
+ transport.register_tool(
655
+ "minder_session_save",
656
+ minder_session_save,
657
+ require_auth=True,
658
+ description=TOOL_DESCRIPTIONS["minder_session_save"],
659
+ )
660
+ transport.register_tool(
661
+ "minder_session_restore",
662
+ minder_session_restore,
663
+ require_auth=True,
664
+ description=TOOL_DESCRIPTIONS["minder_session_restore"],
665
+ )
666
+ transport.register_tool(
667
+ "minder_session_context",
668
+ minder_session_context,
669
+ require_auth=True,
670
+ description=TOOL_DESCRIPTIONS["minder_session_context"],
671
+ )
672
+ transport.register_tool(
673
+ "minder_session_cleanup",
674
+ minder_session_cleanup,
675
+ require_auth=True,
676
+ description=TOOL_DESCRIPTIONS["minder_session_cleanup"],
677
+ )
678
+ transport.register_tool(
679
+ "minder_workflow_get",
680
+ minder_workflow_get,
681
+ require_auth=True,
682
+ description=TOOL_DESCRIPTIONS["minder_workflow_get"],
683
+ )
684
+ transport.register_tool(
685
+ "minder_workflow_step",
686
+ minder_workflow_step,
687
+ require_auth=True,
688
+ description=TOOL_DESCRIPTIONS["minder_workflow_step"],
689
+ )
690
+ transport.register_tool(
691
+ "minder_workflow_update",
692
+ minder_workflow_update,
693
+ require_auth=True,
694
+ description=TOOL_DESCRIPTIONS["minder_workflow_update"],
695
+ )
696
+ transport.register_tool(
697
+ "minder_workflow_guard",
698
+ minder_workflow_guard,
699
+ require_auth=True,
700
+ description=TOOL_DESCRIPTIONS["minder_workflow_guard"],
701
+ )
702
+ transport.register_tool(
703
+ "minder_memory_store",
704
+ minder_memory_store,
705
+ require_auth=True,
706
+ description=TOOL_DESCRIPTIONS["minder_memory_store"],
707
+ )
708
+ transport.register_tool(
709
+ "minder_memory_recall",
710
+ minder_memory_recall,
711
+ require_auth=True,
712
+ description=TOOL_DESCRIPTIONS["minder_memory_recall"],
713
+ )
714
+ transport.register_tool(
715
+ "minder_memory_list",
716
+ minder_memory_list,
717
+ require_auth=True,
718
+ description=TOOL_DESCRIPTIONS["minder_memory_list"],
719
+ )
720
+ transport.register_tool(
721
+ "minder_memory_delete",
722
+ minder_memory_delete,
723
+ require_auth=True,
724
+ description=TOOL_DESCRIPTIONS["minder_memory_delete"],
725
+ )
726
+ transport.register_tool(
727
+ "minder_memory_compact",
728
+ minder_memory_compact,
729
+ require_auth=True,
730
+ description=TOOL_DESCRIPTIONS["minder_memory_compact"],
731
+ )
732
+ transport.register_tool(
733
+ "minder_skill_store",
734
+ minder_skill_store,
735
+ require_auth=True,
736
+ description=TOOL_DESCRIPTIONS["minder_skill_store"],
737
+ )
738
+ transport.register_tool(
739
+ "minder_skill_recall",
740
+ minder_skill_recall,
741
+ require_auth=True,
742
+ description=TOOL_DESCRIPTIONS["minder_skill_recall"],
743
+ )
744
+ transport.register_tool(
745
+ "minder_skill_list",
746
+ minder_skill_list,
747
+ require_auth=True,
748
+ description=TOOL_DESCRIPTIONS["minder_skill_list"],
749
+ )
750
+ transport.register_tool(
751
+ "minder_skill_update",
752
+ minder_skill_update,
753
+ require_auth=True,
754
+ description=TOOL_DESCRIPTIONS["minder_skill_update"],
755
+ )
756
+ transport.register_tool(
757
+ "minder_skill_delete",
758
+ minder_skill_delete,
759
+ require_auth=True,
760
+ description=TOOL_DESCRIPTIONS["minder_skill_delete"],
761
+ )
762
+ transport.register_tool(
763
+ "minder_skill_import_git",
764
+ minder_skill_import_git,
765
+ require_auth=True,
766
+ description=TOOL_DESCRIPTIONS["minder_skill_import_git"],
767
+ )
768
+ transport.register_tool(
769
+ "minder_search",
770
+ minder_search,
771
+ require_auth=True,
772
+ description=TOOL_DESCRIPTIONS["minder_search"],
773
+ )
774
+ transport.register_tool(
775
+ "minder_query",
776
+ minder_query,
777
+ require_auth=True,
778
+ description=TOOL_DESCRIPTIONS["minder_query"],
779
+ )
780
+ transport.register_tool(
781
+ "minder_search_code",
782
+ minder_search_code,
783
+ require_auth=True,
784
+ description=TOOL_DESCRIPTIONS["minder_search_code"],
785
+ )
786
+ transport.register_tool(
787
+ "minder_search_errors",
788
+ minder_search_errors,
789
+ require_auth=True,
790
+ description=TOOL_DESCRIPTIONS["minder_search_errors"],
791
+ )
792
+ transport.register_tool(
793
+ "minder_search_graph",
794
+ minder_search_graph,
795
+ require_auth=True,
796
+ description=TOOL_DESCRIPTIONS["minder_search_graph"],
797
+ )
798
+ transport.register_tool(
799
+ "minder_find_impact",
800
+ minder_find_impact,
801
+ require_auth=True,
802
+ description=TOOL_DESCRIPTIONS["minder_find_impact"],
803
+ )
804
+
805
+ ResourceRegistry.register(transport.app, store, graph_store=graph_store)
806
+ PromptRegistry.register(transport.app, store=store)
807
+ return transport