# workspace_browse.dspy - 浏览项目工作空间目录树 uid = await get_user() if not uid: uid = 'user-01' dbname = get_module_dbname('pipeline-sdlc') import os import json async with DBPools().sqlorContext(dbname) as sor: ws_dir, _ = await get_workspace_dir(sor, uid) if not ws_dir or not os.path.isdir(ws_dir): return json.dumps({"error": "工作空间不存在: " + ws_dir, "tree": {"name": "", "children": [], "files": []}}, ensure_ascii=False) def build_tree(path): result = {"name": os.path.basename(path) or path, "path": path, "children": [], "files": []} try: items = sorted(os.listdir(path)) except Exception: return result for item in items: full = os.path.join(path, item) if os.path.isdir(full) and not item.startswith('.') and item != '__pycache__': result["children"].append(build_tree(full)) elif os.path.isfile(full) and not item.startswith('.'): size = os.path.getsize(full) ext = os.path.splitext(item)[1].lower() result["files"].append({ "name": item, "path": full, "size": size, "ext": ext, "is_text": ext in ['.md','.py','.js','.html','.css','.json','.txt', '.xml','.yaml','.yml','.toml','.cfg','.sh','.sql', '.dspy','.ui','.java','.go','.rs','.ts','.tsx','.vue'], "is_media": ext in ['.png','.jpg','.jpeg','.gif','.svg','.mp4','.webm','.mp3','.wav'], }) return result tree = build_tree(ws_dir) return json.dumps({ "workspace": ws_dir, "tree": tree, }, ensure_ascii=False, default=str)