Write the leaf-first processing order to a workspace file and return its path.
(
arguments: Dict[str, Any],
store: SessionStore,
)
| 107 | return unmatched, leftover |
| 108 | |
| 109 | |
| 110 | def handle_save_module_tree( |
| 111 | arguments: Dict[str, Any], |
| 112 | store: SessionStore, |
| 113 | ) -> str: |
| 114 | """Persist the IDE agent's clustering result as the module tree.""" |
| 115 | session_id = arguments["session_id"] |
| 116 | session = store.get(session_id) |
| 117 | if session is None: |
| 118 | return json.dumps({"error": f"Session {session_id} not found or expired."}) |
| 119 | |
| 120 | module_tree = arguments["module_tree"] |
| 121 | output_dir = session.output_dir |
| 122 | known_ids = set(session.components.keys()) |
| 123 | candidate_ids = set(session.leaf_nodes) |
| 124 | |
| 125 | # Save both immutable snapshot and mutable working copy |
| 126 | first_path = os.path.join(output_dir, FIRST_MODULE_TREE_FILENAME) |
| 127 | working_path = os.path.join(output_dir, MODULE_TREE_FILENAME) |
| 128 | |
| 129 | os.makedirs(output_dir, exist_ok=True) |
| 130 | |
| 131 | with open(first_path, "w", encoding="utf-8") as f: |
| 132 | json.dump(module_tree, f, indent=2, ensure_ascii=False) |
| 133 | with open(working_path, "w", encoding="utf-8") as f: |
| 134 | json.dump(module_tree, f, indent=2, ensure_ascii=False) |
| 135 | |
| 136 | # Cache in session |
| 137 | session.module_tree = module_tree |
| 138 | |
| 139 | # Validate the tree so orphaned / stale ids surface instead of being |
| 140 | # silently dropped from docs. Unmatched ids are checked against the full |
| 141 | # index; leftovers only against the clustering candidate set (leaf nodes), |
| 142 | # since the cluster prompt deliberately excludes non-essential components. |
| 143 | unmatched_ids, leftover_ids = _validate_module_tree( |
| 144 | module_tree, known_ids, candidate_ids |
| 145 | ) |
| 146 | full_validation = { |
| 147 | "unmatched_ids": unmatched_ids, |
| 148 | "unmatched_count": len(unmatched_ids), |
| 149 | "leftover_component_ids": leftover_ids, |
nothing calls this directly
no test coverage detected