basic-memory 0.16.1__py3-none-any.whl → 0.17.4__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.

Potentially problematic release.


This version of basic-memory might be problematic. Click here for more details.

Files changed (143) hide show
  1. basic_memory/__init__.py +1 -1
  2. basic_memory/alembic/env.py +112 -26
  3. basic_memory/alembic/versions/314f1ea54dc4_add_postgres_full_text_search_support_.py +131 -0
  4. basic_memory/alembic/versions/5fe1ab1ccebe_add_projects_table.py +15 -3
  5. basic_memory/alembic/versions/647e7a75e2cd_project_constraint_fix.py +44 -36
  6. basic_memory/alembic/versions/6830751f5fb6_merge_multiple_heads.py +24 -0
  7. basic_memory/alembic/versions/a2b3c4d5e6f7_add_search_index_entity_cascade.py +56 -0
  8. basic_memory/alembic/versions/cc7172b46608_update_search_index_schema.py +13 -0
  9. basic_memory/alembic/versions/f8a9b2c3d4e5_add_pg_trgm_for_fuzzy_link_resolution.py +239 -0
  10. basic_memory/alembic/versions/g9a0b3c4d5e6_add_external_id_to_project_and_entity.py +173 -0
  11. basic_memory/api/app.py +45 -24
  12. basic_memory/api/container.py +133 -0
  13. basic_memory/api/routers/knowledge_router.py +17 -5
  14. basic_memory/api/routers/project_router.py +68 -14
  15. basic_memory/api/routers/resource_router.py +37 -27
  16. basic_memory/api/routers/utils.py +53 -14
  17. basic_memory/api/v2/__init__.py +35 -0
  18. basic_memory/api/v2/routers/__init__.py +21 -0
  19. basic_memory/api/v2/routers/directory_router.py +93 -0
  20. basic_memory/api/v2/routers/importer_router.py +181 -0
  21. basic_memory/api/v2/routers/knowledge_router.py +427 -0
  22. basic_memory/api/v2/routers/memory_router.py +130 -0
  23. basic_memory/api/v2/routers/project_router.py +359 -0
  24. basic_memory/api/v2/routers/prompt_router.py +269 -0
  25. basic_memory/api/v2/routers/resource_router.py +286 -0
  26. basic_memory/api/v2/routers/search_router.py +73 -0
  27. basic_memory/cli/app.py +43 -7
  28. basic_memory/cli/auth.py +27 -4
  29. basic_memory/cli/commands/__init__.py +3 -1
  30. basic_memory/cli/commands/cloud/api_client.py +20 -5
  31. basic_memory/cli/commands/cloud/cloud_utils.py +13 -6
  32. basic_memory/cli/commands/cloud/rclone_commands.py +110 -14
  33. basic_memory/cli/commands/cloud/rclone_installer.py +18 -4
  34. basic_memory/cli/commands/cloud/upload.py +10 -3
  35. basic_memory/cli/commands/command_utils.py +52 -4
  36. basic_memory/cli/commands/db.py +78 -19
  37. basic_memory/cli/commands/format.py +198 -0
  38. basic_memory/cli/commands/import_chatgpt.py +12 -8
  39. basic_memory/cli/commands/import_claude_conversations.py +12 -8
  40. basic_memory/cli/commands/import_claude_projects.py +12 -8
  41. basic_memory/cli/commands/import_memory_json.py +12 -8
  42. basic_memory/cli/commands/mcp.py +8 -26
  43. basic_memory/cli/commands/project.py +22 -9
  44. basic_memory/cli/commands/status.py +3 -2
  45. basic_memory/cli/commands/telemetry.py +81 -0
  46. basic_memory/cli/container.py +84 -0
  47. basic_memory/cli/main.py +7 -0
  48. basic_memory/config.py +177 -77
  49. basic_memory/db.py +183 -77
  50. basic_memory/deps/__init__.py +293 -0
  51. basic_memory/deps/config.py +26 -0
  52. basic_memory/deps/db.py +56 -0
  53. basic_memory/deps/importers.py +200 -0
  54. basic_memory/deps/projects.py +238 -0
  55. basic_memory/deps/repositories.py +179 -0
  56. basic_memory/deps/services.py +480 -0
  57. basic_memory/deps.py +14 -409
  58. basic_memory/file_utils.py +212 -3
  59. basic_memory/ignore_utils.py +5 -5
  60. basic_memory/importers/base.py +40 -19
  61. basic_memory/importers/chatgpt_importer.py +17 -4
  62. basic_memory/importers/claude_conversations_importer.py +27 -12
  63. basic_memory/importers/claude_projects_importer.py +50 -14
  64. basic_memory/importers/memory_json_importer.py +36 -16
  65. basic_memory/importers/utils.py +5 -2
  66. basic_memory/markdown/entity_parser.py +62 -23
  67. basic_memory/markdown/markdown_processor.py +67 -4
  68. basic_memory/markdown/plugins.py +4 -2
  69. basic_memory/markdown/utils.py +10 -1
  70. basic_memory/mcp/async_client.py +1 -0
  71. basic_memory/mcp/clients/__init__.py +28 -0
  72. basic_memory/mcp/clients/directory.py +70 -0
  73. basic_memory/mcp/clients/knowledge.py +176 -0
  74. basic_memory/mcp/clients/memory.py +120 -0
  75. basic_memory/mcp/clients/project.py +89 -0
  76. basic_memory/mcp/clients/resource.py +71 -0
  77. basic_memory/mcp/clients/search.py +65 -0
  78. basic_memory/mcp/container.py +110 -0
  79. basic_memory/mcp/project_context.py +47 -33
  80. basic_memory/mcp/prompts/ai_assistant_guide.py +2 -2
  81. basic_memory/mcp/prompts/recent_activity.py +2 -2
  82. basic_memory/mcp/prompts/utils.py +3 -3
  83. basic_memory/mcp/server.py +58 -0
  84. basic_memory/mcp/tools/build_context.py +14 -14
  85. basic_memory/mcp/tools/canvas.py +34 -12
  86. basic_memory/mcp/tools/chatgpt_tools.py +4 -1
  87. basic_memory/mcp/tools/delete_note.py +31 -7
  88. basic_memory/mcp/tools/edit_note.py +14 -9
  89. basic_memory/mcp/tools/list_directory.py +7 -17
  90. basic_memory/mcp/tools/move_note.py +35 -31
  91. basic_memory/mcp/tools/project_management.py +29 -25
  92. basic_memory/mcp/tools/read_content.py +13 -3
  93. basic_memory/mcp/tools/read_note.py +24 -14
  94. basic_memory/mcp/tools/recent_activity.py +32 -38
  95. basic_memory/mcp/tools/search.py +17 -10
  96. basic_memory/mcp/tools/utils.py +28 -0
  97. basic_memory/mcp/tools/view_note.py +2 -1
  98. basic_memory/mcp/tools/write_note.py +37 -14
  99. basic_memory/models/knowledge.py +15 -2
  100. basic_memory/models/project.py +7 -1
  101. basic_memory/models/search.py +58 -2
  102. basic_memory/project_resolver.py +222 -0
  103. basic_memory/repository/entity_repository.py +210 -3
  104. basic_memory/repository/observation_repository.py +1 -0
  105. basic_memory/repository/postgres_search_repository.py +451 -0
  106. basic_memory/repository/project_repository.py +38 -1
  107. basic_memory/repository/relation_repository.py +58 -2
  108. basic_memory/repository/repository.py +1 -0
  109. basic_memory/repository/search_index_row.py +95 -0
  110. basic_memory/repository/search_repository.py +77 -615
  111. basic_memory/repository/search_repository_base.py +241 -0
  112. basic_memory/repository/sqlite_search_repository.py +437 -0
  113. basic_memory/runtime.py +61 -0
  114. basic_memory/schemas/base.py +36 -6
  115. basic_memory/schemas/directory.py +2 -1
  116. basic_memory/schemas/memory.py +9 -2
  117. basic_memory/schemas/project_info.py +2 -0
  118. basic_memory/schemas/response.py +84 -27
  119. basic_memory/schemas/search.py +5 -0
  120. basic_memory/schemas/sync_report.py +1 -1
  121. basic_memory/schemas/v2/__init__.py +27 -0
  122. basic_memory/schemas/v2/entity.py +133 -0
  123. basic_memory/schemas/v2/resource.py +47 -0
  124. basic_memory/services/context_service.py +219 -43
  125. basic_memory/services/directory_service.py +26 -11
  126. basic_memory/services/entity_service.py +68 -33
  127. basic_memory/services/file_service.py +131 -16
  128. basic_memory/services/initialization.py +51 -26
  129. basic_memory/services/link_resolver.py +1 -0
  130. basic_memory/services/project_service.py +68 -43
  131. basic_memory/services/search_service.py +75 -16
  132. basic_memory/sync/__init__.py +2 -1
  133. basic_memory/sync/coordinator.py +160 -0
  134. basic_memory/sync/sync_service.py +135 -115
  135. basic_memory/sync/watch_service.py +32 -12
  136. basic_memory/telemetry.py +249 -0
  137. basic_memory/utils.py +96 -75
  138. {basic_memory-0.16.1.dist-info → basic_memory-0.17.4.dist-info}/METADATA +129 -5
  139. basic_memory-0.17.4.dist-info/RECORD +193 -0
  140. {basic_memory-0.16.1.dist-info → basic_memory-0.17.4.dist-info}/WHEEL +1 -1
  141. basic_memory-0.16.1.dist-info/RECORD +0 -148
  142. {basic_memory-0.16.1.dist-info → basic_memory-0.17.4.dist-info}/entry_points.txt +0 -0
  143. {basic_memory-0.16.1.dist-info → basic_memory-0.17.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,480 @@
1
+ """Service dependency injection for basic-memory.
2
+
3
+ This module provides service-layer dependencies:
4
+ - EntityParser, MarkdownProcessor
5
+ - FileService, EntityService
6
+ - SearchService, LinkResolver, ContextService
7
+ - SyncService, ProjectService, DirectoryService
8
+ """
9
+
10
+ from typing import Annotated
11
+
12
+ from fastapi import Depends
13
+ from loguru import logger
14
+
15
+ from basic_memory.deps.config import AppConfigDep
16
+ from basic_memory.deps.projects import (
17
+ ProjectConfigDep,
18
+ ProjectConfigV2Dep,
19
+ ProjectConfigV2ExternalDep,
20
+ ProjectRepositoryDep,
21
+ )
22
+ from basic_memory.deps.repositories import (
23
+ EntityRepositoryDep,
24
+ EntityRepositoryV2Dep,
25
+ EntityRepositoryV2ExternalDep,
26
+ ObservationRepositoryDep,
27
+ ObservationRepositoryV2Dep,
28
+ ObservationRepositoryV2ExternalDep,
29
+ RelationRepositoryDep,
30
+ RelationRepositoryV2Dep,
31
+ RelationRepositoryV2ExternalDep,
32
+ SearchRepositoryDep,
33
+ SearchRepositoryV2Dep,
34
+ SearchRepositoryV2ExternalDep,
35
+ )
36
+ from basic_memory.markdown import EntityParser
37
+ from basic_memory.markdown.markdown_processor import MarkdownProcessor
38
+ from basic_memory.services import EntityService, ProjectService
39
+ from basic_memory.services.context_service import ContextService
40
+ from basic_memory.services.directory_service import DirectoryService
41
+ from basic_memory.services.file_service import FileService
42
+ from basic_memory.services.link_resolver import LinkResolver
43
+ from basic_memory.services.search_service import SearchService
44
+ from basic_memory.sync import SyncService
45
+
46
+
47
+ # --- Entity Parser ---
48
+
49
+
50
+ async def get_entity_parser(project_config: ProjectConfigDep) -> EntityParser:
51
+ return EntityParser(project_config.home)
52
+
53
+
54
+ EntityParserDep = Annotated["EntityParser", Depends(get_entity_parser)]
55
+
56
+
57
+ async def get_entity_parser_v2(project_config: ProjectConfigV2Dep) -> EntityParser: # pragma: no cover
58
+ return EntityParser(project_config.home)
59
+
60
+
61
+ EntityParserV2Dep = Annotated["EntityParser", Depends(get_entity_parser_v2)]
62
+
63
+
64
+ async def get_entity_parser_v2_external(project_config: ProjectConfigV2ExternalDep) -> EntityParser:
65
+ return EntityParser(project_config.home)
66
+
67
+
68
+ EntityParserV2ExternalDep = Annotated["EntityParser", Depends(get_entity_parser_v2_external)]
69
+
70
+
71
+ # --- Markdown Processor ---
72
+
73
+
74
+ async def get_markdown_processor(
75
+ entity_parser: EntityParserDep, app_config: AppConfigDep
76
+ ) -> MarkdownProcessor:
77
+ return MarkdownProcessor(entity_parser, app_config=app_config)
78
+
79
+
80
+ MarkdownProcessorDep = Annotated[MarkdownProcessor, Depends(get_markdown_processor)]
81
+
82
+
83
+ async def get_markdown_processor_v2( # pragma: no cover
84
+ entity_parser: EntityParserV2Dep, app_config: AppConfigDep
85
+ ) -> MarkdownProcessor:
86
+ return MarkdownProcessor(entity_parser, app_config=app_config)
87
+
88
+
89
+ MarkdownProcessorV2Dep = Annotated[MarkdownProcessor, Depends(get_markdown_processor_v2)]
90
+
91
+
92
+ async def get_markdown_processor_v2_external(
93
+ entity_parser: EntityParserV2ExternalDep, app_config: AppConfigDep
94
+ ) -> MarkdownProcessor:
95
+ return MarkdownProcessor(entity_parser, app_config=app_config)
96
+
97
+
98
+ MarkdownProcessorV2ExternalDep = Annotated[
99
+ MarkdownProcessor, Depends(get_markdown_processor_v2_external)
100
+ ]
101
+
102
+
103
+ # --- File Service ---
104
+
105
+
106
+ async def get_file_service(
107
+ project_config: ProjectConfigDep,
108
+ markdown_processor: MarkdownProcessorDep,
109
+ app_config: AppConfigDep,
110
+ ) -> FileService:
111
+ file_service = FileService(project_config.home, markdown_processor, app_config=app_config)
112
+ logger.debug(
113
+ f"Created FileService for project: {project_config.name}, base_path: {project_config.home} "
114
+ )
115
+ return file_service
116
+
117
+
118
+ FileServiceDep = Annotated[FileService, Depends(get_file_service)]
119
+
120
+
121
+ async def get_file_service_v2( # pragma: no cover
122
+ project_config: ProjectConfigV2Dep,
123
+ markdown_processor: MarkdownProcessorV2Dep,
124
+ app_config: AppConfigDep,
125
+ ) -> FileService:
126
+ file_service = FileService(project_config.home, markdown_processor, app_config=app_config)
127
+ logger.debug(
128
+ f"Created FileService for project: {project_config.name}, base_path: {project_config.home}"
129
+ )
130
+ return file_service
131
+
132
+
133
+ FileServiceV2Dep = Annotated[FileService, Depends(get_file_service_v2)]
134
+
135
+
136
+ async def get_file_service_v2_external(
137
+ project_config: ProjectConfigV2ExternalDep,
138
+ markdown_processor: MarkdownProcessorV2ExternalDep,
139
+ app_config: AppConfigDep,
140
+ ) -> FileService:
141
+ file_service = FileService(project_config.home, markdown_processor, app_config=app_config)
142
+ logger.debug(
143
+ f"Created FileService for project: {project_config.name}, base_path: {project_config.home}"
144
+ )
145
+ return file_service
146
+
147
+
148
+ FileServiceV2ExternalDep = Annotated[FileService, Depends(get_file_service_v2_external)]
149
+
150
+
151
+ # --- Search Service ---
152
+
153
+
154
+ async def get_search_service(
155
+ search_repository: SearchRepositoryDep,
156
+ entity_repository: EntityRepositoryDep,
157
+ file_service: FileServiceDep,
158
+ ) -> SearchService:
159
+ """Create SearchService with dependencies."""
160
+ return SearchService(search_repository, entity_repository, file_service)
161
+
162
+
163
+ SearchServiceDep = Annotated[SearchService, Depends(get_search_service)]
164
+
165
+
166
+ async def get_search_service_v2( # pragma: no cover
167
+ search_repository: SearchRepositoryV2Dep,
168
+ entity_repository: EntityRepositoryV2Dep,
169
+ file_service: FileServiceV2Dep,
170
+ ) -> SearchService:
171
+ """Create SearchService for v2 API."""
172
+ return SearchService(search_repository, entity_repository, file_service)
173
+
174
+
175
+ SearchServiceV2Dep = Annotated[SearchService, Depends(get_search_service_v2)]
176
+
177
+
178
+ async def get_search_service_v2_external(
179
+ search_repository: SearchRepositoryV2ExternalDep,
180
+ entity_repository: EntityRepositoryV2ExternalDep,
181
+ file_service: FileServiceV2ExternalDep,
182
+ ) -> SearchService:
183
+ """Create SearchService for v2 API (uses external_id)."""
184
+ return SearchService(search_repository, entity_repository, file_service)
185
+
186
+
187
+ SearchServiceV2ExternalDep = Annotated[SearchService, Depends(get_search_service_v2_external)]
188
+
189
+
190
+ # --- Link Resolver ---
191
+
192
+
193
+ async def get_link_resolver(
194
+ entity_repository: EntityRepositoryDep, search_service: SearchServiceDep
195
+ ) -> LinkResolver:
196
+ return LinkResolver(entity_repository=entity_repository, search_service=search_service)
197
+
198
+
199
+ LinkResolverDep = Annotated[LinkResolver, Depends(get_link_resolver)]
200
+
201
+
202
+ async def get_link_resolver_v2( # pragma: no cover
203
+ entity_repository: EntityRepositoryV2Dep, search_service: SearchServiceV2Dep
204
+ ) -> LinkResolver:
205
+ return LinkResolver(entity_repository=entity_repository, search_service=search_service)
206
+
207
+
208
+ LinkResolverV2Dep = Annotated[LinkResolver, Depends(get_link_resolver_v2)]
209
+
210
+
211
+ async def get_link_resolver_v2_external(
212
+ entity_repository: EntityRepositoryV2ExternalDep, search_service: SearchServiceV2ExternalDep
213
+ ) -> LinkResolver:
214
+ return LinkResolver(entity_repository=entity_repository, search_service=search_service)
215
+
216
+
217
+ LinkResolverV2ExternalDep = Annotated[LinkResolver, Depends(get_link_resolver_v2_external)]
218
+
219
+
220
+ # --- Entity Service ---
221
+
222
+
223
+ async def get_entity_service(
224
+ entity_repository: EntityRepositoryDep,
225
+ observation_repository: ObservationRepositoryDep,
226
+ relation_repository: RelationRepositoryDep,
227
+ entity_parser: EntityParserDep,
228
+ file_service: FileServiceDep,
229
+ link_resolver: LinkResolverDep,
230
+ search_service: SearchServiceDep,
231
+ app_config: AppConfigDep,
232
+ ) -> EntityService:
233
+ """Create EntityService with repository."""
234
+ return EntityService(
235
+ entity_repository=entity_repository,
236
+ observation_repository=observation_repository,
237
+ relation_repository=relation_repository,
238
+ entity_parser=entity_parser,
239
+ file_service=file_service,
240
+ link_resolver=link_resolver,
241
+ search_service=search_service,
242
+ app_config=app_config,
243
+ )
244
+
245
+
246
+ EntityServiceDep = Annotated[EntityService, Depends(get_entity_service)]
247
+
248
+
249
+ async def get_entity_service_v2( # pragma: no cover
250
+ entity_repository: EntityRepositoryV2Dep,
251
+ observation_repository: ObservationRepositoryV2Dep,
252
+ relation_repository: RelationRepositoryV2Dep,
253
+ entity_parser: EntityParserV2Dep,
254
+ file_service: FileServiceV2Dep,
255
+ link_resolver: LinkResolverV2Dep,
256
+ search_service: SearchServiceV2Dep,
257
+ app_config: AppConfigDep,
258
+ ) -> EntityService:
259
+ """Create EntityService for v2 API."""
260
+ return EntityService(
261
+ entity_repository=entity_repository,
262
+ observation_repository=observation_repository,
263
+ relation_repository=relation_repository,
264
+ entity_parser=entity_parser,
265
+ file_service=file_service,
266
+ link_resolver=link_resolver,
267
+ search_service=search_service,
268
+ app_config=app_config,
269
+ )
270
+
271
+
272
+ EntityServiceV2Dep = Annotated[EntityService, Depends(get_entity_service_v2)]
273
+
274
+
275
+ async def get_entity_service_v2_external(
276
+ entity_repository: EntityRepositoryV2ExternalDep,
277
+ observation_repository: ObservationRepositoryV2ExternalDep,
278
+ relation_repository: RelationRepositoryV2ExternalDep,
279
+ entity_parser: EntityParserV2ExternalDep,
280
+ file_service: FileServiceV2ExternalDep,
281
+ link_resolver: LinkResolverV2ExternalDep,
282
+ search_service: SearchServiceV2ExternalDep,
283
+ app_config: AppConfigDep,
284
+ ) -> EntityService:
285
+ """Create EntityService for v2 API (uses external_id)."""
286
+ return EntityService(
287
+ entity_repository=entity_repository,
288
+ observation_repository=observation_repository,
289
+ relation_repository=relation_repository,
290
+ entity_parser=entity_parser,
291
+ file_service=file_service,
292
+ link_resolver=link_resolver,
293
+ search_service=search_service,
294
+ app_config=app_config,
295
+ )
296
+
297
+
298
+ EntityServiceV2ExternalDep = Annotated[EntityService, Depends(get_entity_service_v2_external)]
299
+
300
+
301
+ # --- Context Service ---
302
+
303
+
304
+ async def get_context_service(
305
+ search_repository: SearchRepositoryDep,
306
+ entity_repository: EntityRepositoryDep,
307
+ observation_repository: ObservationRepositoryDep,
308
+ ) -> ContextService:
309
+ return ContextService(
310
+ search_repository=search_repository,
311
+ entity_repository=entity_repository,
312
+ observation_repository=observation_repository,
313
+ )
314
+
315
+
316
+ ContextServiceDep = Annotated[ContextService, Depends(get_context_service)]
317
+
318
+
319
+ async def get_context_service_v2( # pragma: no cover
320
+ search_repository: SearchRepositoryV2Dep,
321
+ entity_repository: EntityRepositoryV2Dep,
322
+ observation_repository: ObservationRepositoryV2Dep,
323
+ ) -> ContextService:
324
+ """Create ContextService for v2 API."""
325
+ return ContextService(
326
+ search_repository=search_repository,
327
+ entity_repository=entity_repository,
328
+ observation_repository=observation_repository,
329
+ )
330
+
331
+
332
+ ContextServiceV2Dep = Annotated[ContextService, Depends(get_context_service_v2)]
333
+
334
+
335
+ async def get_context_service_v2_external(
336
+ search_repository: SearchRepositoryV2ExternalDep,
337
+ entity_repository: EntityRepositoryV2ExternalDep,
338
+ observation_repository: ObservationRepositoryV2ExternalDep,
339
+ ) -> ContextService:
340
+ """Create ContextService for v2 API (uses external_id)."""
341
+ return ContextService(
342
+ search_repository=search_repository,
343
+ entity_repository=entity_repository,
344
+ observation_repository=observation_repository,
345
+ )
346
+
347
+
348
+ ContextServiceV2ExternalDep = Annotated[ContextService, Depends(get_context_service_v2_external)]
349
+
350
+
351
+ # --- Sync Service ---
352
+
353
+
354
+ async def get_sync_service(
355
+ app_config: AppConfigDep,
356
+ entity_service: EntityServiceDep,
357
+ entity_parser: EntityParserDep,
358
+ entity_repository: EntityRepositoryDep,
359
+ relation_repository: RelationRepositoryDep,
360
+ project_repository: ProjectRepositoryDep,
361
+ search_service: SearchServiceDep,
362
+ file_service: FileServiceDep,
363
+ ) -> SyncService: # pragma: no cover
364
+ return SyncService(
365
+ app_config=app_config,
366
+ entity_service=entity_service,
367
+ entity_parser=entity_parser,
368
+ entity_repository=entity_repository,
369
+ relation_repository=relation_repository,
370
+ project_repository=project_repository,
371
+ search_service=search_service,
372
+ file_service=file_service,
373
+ )
374
+
375
+
376
+ SyncServiceDep = Annotated[SyncService, Depends(get_sync_service)]
377
+
378
+
379
+ async def get_sync_service_v2(
380
+ app_config: AppConfigDep,
381
+ entity_service: EntityServiceV2Dep,
382
+ entity_parser: EntityParserV2Dep,
383
+ entity_repository: EntityRepositoryV2Dep,
384
+ relation_repository: RelationRepositoryV2Dep,
385
+ project_repository: ProjectRepositoryDep,
386
+ search_service: SearchServiceV2Dep,
387
+ file_service: FileServiceV2Dep,
388
+ ) -> SyncService: # pragma: no cover
389
+ """Create SyncService for v2 API."""
390
+ return SyncService(
391
+ app_config=app_config,
392
+ entity_service=entity_service,
393
+ entity_parser=entity_parser,
394
+ entity_repository=entity_repository,
395
+ relation_repository=relation_repository,
396
+ project_repository=project_repository,
397
+ search_service=search_service,
398
+ file_service=file_service,
399
+ )
400
+
401
+
402
+ SyncServiceV2Dep = Annotated[SyncService, Depends(get_sync_service_v2)]
403
+
404
+
405
+ async def get_sync_service_v2_external(
406
+ app_config: AppConfigDep,
407
+ entity_service: EntityServiceV2ExternalDep,
408
+ entity_parser: EntityParserV2ExternalDep,
409
+ entity_repository: EntityRepositoryV2ExternalDep,
410
+ relation_repository: RelationRepositoryV2ExternalDep,
411
+ project_repository: ProjectRepositoryDep,
412
+ search_service: SearchServiceV2ExternalDep,
413
+ file_service: FileServiceV2ExternalDep,
414
+ ) -> SyncService: # pragma: no cover
415
+ """Create SyncService for v2 API (uses external_id)."""
416
+ return SyncService(
417
+ app_config=app_config,
418
+ entity_service=entity_service,
419
+ entity_parser=entity_parser,
420
+ entity_repository=entity_repository,
421
+ relation_repository=relation_repository,
422
+ project_repository=project_repository,
423
+ search_service=search_service,
424
+ file_service=file_service,
425
+ )
426
+
427
+
428
+ SyncServiceV2ExternalDep = Annotated[SyncService, Depends(get_sync_service_v2_external)]
429
+
430
+
431
+ # --- Project Service ---
432
+
433
+
434
+ async def get_project_service(
435
+ project_repository: ProjectRepositoryDep,
436
+ ) -> ProjectService:
437
+ """Create ProjectService with repository."""
438
+ return ProjectService(repository=project_repository)
439
+
440
+
441
+ ProjectServiceDep = Annotated[ProjectService, Depends(get_project_service)]
442
+
443
+
444
+ # --- Directory Service ---
445
+
446
+
447
+ async def get_directory_service(
448
+ entity_repository: EntityRepositoryDep,
449
+ ) -> DirectoryService:
450
+ """Create DirectoryService with dependencies."""
451
+ return DirectoryService(
452
+ entity_repository=entity_repository,
453
+ )
454
+
455
+
456
+ DirectoryServiceDep = Annotated[DirectoryService, Depends(get_directory_service)]
457
+
458
+
459
+ async def get_directory_service_v2( # pragma: no cover
460
+ entity_repository: EntityRepositoryV2Dep,
461
+ ) -> DirectoryService:
462
+ """Create DirectoryService for v2 API (uses integer project_id from path)."""
463
+ return DirectoryService(
464
+ entity_repository=entity_repository,
465
+ )
466
+
467
+
468
+ DirectoryServiceV2Dep = Annotated[DirectoryService, Depends(get_directory_service_v2)]
469
+
470
+
471
+ async def get_directory_service_v2_external(
472
+ entity_repository: EntityRepositoryV2ExternalDep,
473
+ ) -> DirectoryService:
474
+ """Create DirectoryService for v2 API (uses external_id from path)."""
475
+ return DirectoryService(
476
+ entity_repository=entity_repository,
477
+ )
478
+
479
+
480
+ DirectoryServiceV2ExternalDep = Annotated[DirectoryService, Depends(get_directory_service_v2_external)]