(self, sub_module_specs: dict[str, list[str]])
| 269 | # emits MCP progress notifications so the CLI does not treat the long |
| 270 | # tool call as a stalled / cancelled invocation. |
| 271 | work = asyncio.create_task(asyncio.to_thread(self._run_sub_modules, sub_module_specs)) |
| 272 | heartbeat = asyncio.create_task(_heartbeat(ctx, work)) |
| 273 | try: |
| 274 | return await work |
| 275 | finally: |
| 276 | heartbeat.cancel() |
| 277 | with contextlib.suppress(asyncio.CancelledError): |
| 278 | await heartbeat |
| 279 | |
| 280 | # ------------------------------------------------------------------ |
| 281 | # Internal: synchronous recursion driver |
| 282 | # ------------------------------------------------------------------ |
| 283 | |
| 284 | def _run_sub_modules(self, sub_module_specs: dict[str, list[str]]) -> str: |
| 285 | deps = self._deps |
| 286 | previous_module_name = deps.current_module_name |
| 287 | |
| 288 | # Resolve name collisions against the module tree and files already on |
| 289 | # disk before touching the tree (issue #76): names are unique across the wiki. |
| 290 | # A request that is already documented (plain or parent-prefixed name) is |
| 291 | # skipped rather than renamed x_2, x_3, ... (issue #113). |
| 292 | plan = plan_sub_module_specs( |
| 293 | sub_module_specs, |
| 294 | previous_module_name, |
| 295 | deps.module_tree, |
| 296 | deps.absolute_docs_path, |
| 297 | ) |
| 298 | name_map = plan.name_map |
| 299 | layout = config_layout(deps.config) |
| 300 | parent_path = list(deps.path_to_current_module) |
| 301 | if not name_map: |
| 302 | return skipped_report( |
| 303 | plan.skipped, module_doc_file(previous_module_name, parent_path, layout) |
| 304 | ) |
| 305 | final_specs = { |
| 306 | name_map[requested_name]: core_ids |
| 307 | for requested_name, core_ids in sub_module_specs.items() |
| 308 | if requested_name in name_map |
| 309 | } |
| 310 | |
| 311 | # Add sub-modules to the in-memory module tree. |
| 312 | value = deps.module_tree |
| 313 | for key in deps.path_to_current_module: |
| 314 | value = value[key]["children"] |
| 315 | for sub_name, core_ids in final_specs.items(): |
| 316 | value[sub_name] = {"components": core_ids, "children": {}} |
| 317 | |
| 318 | try: |
| 319 | for sub_name, core_ids in final_specs.items(): |
nothing calls this directly
no test coverage detected