From 0501502995e24e9862a184cb8f210afd63647c17 Mon Sep 17 00:00:00 2001 From: Sidney Zhang Date: Mon, 3 Nov 2025 17:22:25 +0800 Subject: [PATCH] first commit: New project --- .gitignore | 11 ++ .python-version | 1 + CLAUDE.md | 128 +++++++++++++++ README.md | 31 ++++ examples/config_example.py | 72 +++++++++ examples/send_example.py | 55 +++++++ main.py | 35 ++++ memos.py | 5 + pyproject.toml | 10 ++ src/__init__.py | 11 ++ src/config.py | 318 +++++++++++++++++++++++++++++++++++++ src/send.py | 149 +++++++++++++++++ uv.lock | 126 +++++++++++++++ 13 files changed, 952 insertions(+) create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 CLAUDE.md create mode 100644 README.md create mode 100644 examples/config_example.py create mode 100644 examples/send_example.py create mode 100644 main.py create mode 100644 memos.py create mode 100644 pyproject.toml create mode 100644 src/__init__.py create mode 100644 src/config.py create mode 100644 src/send.py create mode 100644 uv.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9562d3e --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv +.env \ No newline at end of file diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..04b18b6 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,128 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Memos CLI is a command-line tool for interacting with Memos (a self-hosted note-taking application) via its API. The project is in early development stage with minimal implementation. + +## Development Commands + +### Environment Setup +```bash +# Create virtual environment (Python 3.13 required) +python -m venv .venv + +# Activate virtual environment +# Windows: +.venv\Scripts\activate +# Unix/macOS: +source .venv/bin/activate + +# Install project in development mode +pip install -e . +``` + +### Running the Application +```bash +# Run main module +python -m memoscli +# or +python main.py +``` + +## Architecture + +### Project Structure +- `main.py` - Entry point with basic Memos API integration +- `memos.py` - Main module file (currently minimal) +- `src/send.py` - Memos API client implementation for content posting +- `src/config.py` - Configuration management for .env file operations +- `src/__init__.py` - Package initialization +- `pyproject.toml` - Project configuration with dependencies +- `.env` - Environment variables template (auto-generated if missing) +- `examples/send_example.py` - API usage examples +- `examples/config_example.py` - Configuration usage examples + +### Planned Features +1. **Content submission**: `memos send [--type ]` +2. **AI-powered summaries**: `memos summary [--date ] [--tags ]` +3. **Configuration management**: `memos config set ` + +### Required Environment Variables +``` +MEMOS_BASE_URL= +MEMOS_TOKEN= +MEMOS_AI_MODEL_NAME= +MEMOS_AI_MODEL_API_KEY= +MEMOS_AI_MODEL_API_URL= +``` + +### Technical Requirements +- Python 3.13 (specified in `.python-version`) +- Dependencies: `requests>=2.31.0`, `python-dotenv>=1.0.0` +- Uses Memos API with Bearer token authentication +- Environment variable configuration via python-dotenv + +### Implementation Status +- ✅ **Memos API client**: Basic implementation in `src/send.py` +- ✅ **Content posting**: Can send memos with content, visibility, and tags +- ✅ **Connection testing**: Built-in connection validation +- ✅ **Error handling**: Proper exception handling for API errors +- 🔄 **CLI interface**: Basic implementation in `main.py` +- ✅ **Configuration management**: Complete implementation in `src/config.py` +- ⏳ **AI integration**: Planned but not implemented +- ⏳ **Content summarization**: Planned but not implemented + +### Usage Examples + +#### Memos API 使用示例 +```python +# 方法1:使用便捷函数 +from src.send import send_memo +result = send_memo("内容", visibility="PRIVATE", tags=["标签1", "标签2"]) + +# 方法2:使用API客户端类 +from src.send import MemosAPI +api = MemosAPI() +result = api.send_memo("内容", visibility="PUBLIC", tags=["测试"]) +``` + +#### 配置管理使用示例 +```python +# 方法1:使用ConfigManager类 +from src.config import ConfigManager +config = ConfigManager() +config.set('MEMOS_BASE_URL', 'https://memos.example.com') +url = config.get('MEMOS_BASE_URL') +config.show_config() + +# 方法2:使用便捷函数 +from src.config import set_config, get_config +set_config('MEMOS_TOKEN', 'your-token-here') +token = get_config('MEMOS_TOKEN') +``` + +#### 命令行配置管理 +```bash +# 显示当前配置 +python src/config.py show + +# 设置配置项 +python src/config.py set MEMOS_BASE_URL https://memos.example.com +python src/config.py set MEMOS_TOKEN your-token-here + +# 获取配置项 +python src/config.py get MEMOS_BASE_URL + +# 验证配置 +python src/config.py validate +``` + +## Development Notes + +This project now has a functional Memos API client implementation. The core functionality for content posting is complete and tested. Remaining work includes: +- CLI argument parsing for command-line interface +- AI model integration for tag recommendations and summarization +- Enhanced configuration management +- Testing framework setup \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e6d8c0a --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# Memos CLI + +这是一个在命令行中提交Memos内容的小工具。使用 [Memos API](https://memos.apidocumentation.com/reference) 进行内容提交。 + +用户验证基于Memos的Token 验证,官方的Python例子: + +```python +import requests +headers = {"Authorization": f"Bearer {token}"} +response = requests.get("https://memos.example.com/api/v1/memos", headers=headers) +``` + +由于Memos是私有化部署的简洁笔记软件,所以,需要在`.env`文件中,配置Memos的Base URL和对应的Token,以及需要用到的AI模型关键信息: + +``` +MEMOS_BASE_URL= +MEMOS_TOKEN= +MEMOS_AI_MODEL_NAME= +MEMOS_AI_MODEL_API_KEY= +MEMOS_AI_MODEL_API_URL= +``` + +计划在memoscli中实现内容提交功能,并能自动根据内容使用AI进行标签推荐,但需要用户自己确认使用那些标签。另外根据用户的要求,使用AI总结当日或者指定周期或/和某些标签的AI内容总结。 + +Memos CLI 的命令形式如下: + +```bash +memos send [--type ] +memos summary [--date ] [--tags ] +memos config set +``` \ No newline at end of file diff --git a/examples/config_example.py b/examples/config_example.py new file mode 100644 index 0000000..2043ef4 --- /dev/null +++ b/examples/config_example.py @@ -0,0 +1,72 @@ +""" +配置管理使用示例 +演示如何使用配置管理模块 +""" + +import sys +import os +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from src.config import ConfigManager, set_config, get_config + +def main(): + """配置管理示例""" + print("=== 配置管理示例 ===") + + # 方法1:使用ConfigManager类 + print("\n--- 方法1:使用ConfigManager类 ---") + config_manager = ConfigManager() + + # 显示当前配置 + print("当前配置:") + config_manager.show_config() + + # 设置配置 + print("\n设置新的配置值...") + config_manager.set('MEMOS_BASE_URL', 'https://demo.memos.com') + config_manager.set('MEMOS_TOKEN', 'your-token-here') + + # 获取配置 + base_url = config_manager.get('MEMOS_BASE_URL') + print(f"获取到的MEMOS_BASE_URL: {base_url}") + + # 验证配置 + validation = config_manager.validate_config() + print(f"配置验证结果: {validation['is_valid']}") + + # 方法2:使用便捷函数 + print("\n--- 方法2:使用便捷函数 ---") + + # 设置配置 + set_config('MEMOS_AI_MODEL_NAME', 'gpt-3.5-turbo') + + # 获取配置 + model_name = get_config('MEMOS_AI_MODEL_NAME') + print(f"获取到的AI模型名称: {model_name}") + + # 批量设置配置 + print("\n--- 批量设置配置 ---") + new_configs = { + 'MEMOS_AI_MODEL_API_KEY': 'sk-your-api-key', + 'MEMOS_AI_MODEL_API_URL': 'https://api.openai.com/v1' + } + + results = config_manager.set_multiple(new_configs) + for key, success in results.items(): + status = "成功" if success else "失败" + print(f"设置 {key}: {status}") + + # 显示所有配置 + print("\n--- 所有配置 ---") + all_config = config_manager.get_all() + for key, value in all_config.items(): + if 'TOKEN' in key or 'API_KEY' in key: + masked_value = '*' * 8 if value else '未设置' + print(f"{key}: {masked_value}") + else: + print(f"{key}: {value}") + + print("\n=== 配置管理示例完成 ===") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/send_example.py b/examples/send_example.py new file mode 100644 index 0000000..3ab477f --- /dev/null +++ b/examples/send_example.py @@ -0,0 +1,55 @@ +""" +使用示例:发送Memo到Memos服务器 + +在使用前,请确保在 .env 文件中配置以下环境变量: +MEMOS_BASE_URL= +MEMOS_TOKEN= +""" + +import sys +import os +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from src.send import MemosAPI, send_memo + +def main(): + """发送Memo示例""" + try: + # 方法1:使用便捷函数 + print("=== 方法1:使用便捷函数 ===") + result = send_memo( + content="这是通过Memos CLI发送的测试内容", + visibility="PRIVATE", + tags=["测试", "CLI"] + ) + print(f"Memo发送成功!ID: {result.get('id')}") + print(f"内容: {result.get('content')}") + print(f"创建时间: {result.get('createdTs')}") + + except Exception as e: + print(f"便捷函数发送失败: {e}") + + try: + # 方法2:使用API客户端类 + print("\n=== 方法2:使用API客户端类 ===") + api = MemosAPI() + + # 测试连接 + if api.test_connection(): + print("成功连接到Memos服务器") + + # 发送Memo + result = api.send_memo( + content="这是通过Memos API客户端发送的内容", + visibility="PUBLIC", + tags=["API测试", "Python"] + ) + print(f"Memo发送成功!ID: {result.get('id')}") + else: + print("无法连接到Memos服务器") + + except Exception as e: + print(f"API客户端发送失败: {e}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..26fb624 --- /dev/null +++ b/main.py @@ -0,0 +1,35 @@ +import sys +import os +from src.send import MemosAPI, send_memo + +def main(): + """Memos CLI 主函数""" + print("=== Memos CLI ===") + print("一个命令行Memos内容发布工具") + + try: + # 测试API连接 + api = MemosAPI() + if api.test_connection(): + print("[SUCCESS] 成功连接到Memos服务器") + + # 发送欢迎消息 + result = api.send_memo( + content="欢迎使用Memos CLI!", + visibility="PRIVATE", + tags=["欢迎", "CLI"] + ) + print(f"[SUCCESS] 欢迎消息已发送,Memo ID: {result.get('id')}") + else: + print("[ERROR] 无法连接到Memos服务器") + print("请检查 .env 文件中的配置") + + except ValueError as e: + print(f"[ERROR] 配置错误: {e}") + print("请确保已正确配置 .env 文件") + except Exception as e: + print(f"[ERROR] 发生错误: {e}") + + +if __name__ == "__main__": + main() diff --git a/memos.py b/memos.py new file mode 100644 index 0000000..4a716a9 --- /dev/null +++ b/memos.py @@ -0,0 +1,5 @@ +# Memos CLI +# 命令行 Memos 小工具 +# Author: Sidney Zhang +# License: MIT + diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f22562b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "memoscli" +version = "0.1.0" +description = "Memos CLI 是一个在命令行中提交Memos内容的小工具。" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "requests>=2.31.0", + "python-dotenv>=1.0.0" +] diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e1970a1 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,11 @@ +""" +Memos CLI 模块包 +""" + +from .send import MemosAPI, send_memo +from .config import ConfigManager, set_config, get_config + +__all__ = [ + 'MemosAPI', 'send_memo', + 'ConfigManager', 'set_config', 'get_config' +] \ No newline at end of file diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..cc049a5 --- /dev/null +++ b/src/config.py @@ -0,0 +1,318 @@ +""" +配置管理模块 +用于管理.env文件中的配置信息,支持命令行设置和读取 +""" + +import os +import sys +from typing import Dict, Optional, Any +from pathlib import Path +from dotenv import load_dotenv, set_key, get_key + + +class ConfigManager: + """配置管理器类""" + + # 默认配置项 + DEFAULT_CONFIG = { + 'MEMOS_BASE_URL': '', + 'MEMOS_TOKEN': '', + 'MEMOS_AI_MODEL_NAME': '', + 'MEMOS_AI_MODEL_API_KEY': '', + 'MEMOS_AI_MODEL_API_URL': '' + } + + # 配置项描述 + CONFIG_DESCRIPTIONS = { + 'MEMOS_BASE_URL': 'Memos服务器的基础URL (例如: https://memos.example.com)', + 'MEMOS_TOKEN': 'Memos API访问令牌', + 'MEMOS_AI_MODEL_NAME': 'AI模型名称 (例如: gpt-3.5-turbo)', + 'MEMOS_AI_MODEL_API_KEY': 'AI模型API密钥', + 'MEMOS_AI_MODEL_API_URL': 'AI模型API基础URL (例如: https://api.openai.com/v1)' + } + + def __init__(self, env_file: str = '.env'): + """ + 初始化配置管理器 + + Args: + env_file: .env文件路径,默认为项目根目录下的.env文件 + """ + self.env_file = self._get_env_file_path(env_file) + self._ensure_env_file_exists() + + def _get_env_file_path(self, env_file: str) -> Path: + """获取.env文件的完整路径""" + # 如果提供了相对路径,则相对于项目根目录 + if not os.path.isabs(env_file): + # 获取项目根目录(包含pyproject.toml的目录) + project_root = self._find_project_root() + return Path(project_root) / env_file + return Path(env_file) + + def _find_project_root(self) -> str: + """查找项目根目录""" + current_dir = Path.cwd() + + # 向上查找包含pyproject.toml的目录 + while current_dir != current_dir.parent: + if (current_dir / 'pyproject.toml').exists(): + return str(current_dir) + current_dir = current_dir.parent + + # 如果找不到,则使用当前工作目录 + return str(Path.cwd()) + + def _ensure_env_file_exists(self): + """确保.env文件存在,如果不存在则创建""" + if not self.env_file.exists(): + self.env_file.touch() + # 写入默认配置模板 + self._write_default_config() + + def _write_default_config(self): + """写入默认配置模板""" + with open(self.env_file, 'w', encoding='utf-8') as f: + f.write("# Memos CLI 配置文件\n") + f.write("# 请根据您的实际配置修改以下值\n\n") + + for key, description in self.CONFIG_DESCRIPTIONS.items(): + f.write(f"# {description}\n") + f.write(f"{key}=\n\n") + + def get(self, key: str, default: Optional[str] = None) -> Optional[str]: + """ + 获取配置项的值 + + Args: + key: 配置项名称 + default: 默认值 + + Returns: + 配置项的值,如果不存在则返回默认值 + """ + # 首先尝试从环境变量获取 + value = os.getenv(key) + if value is not None: + return value + + # 然后从.env文件获取 + value = get_key(str(self.env_file), key) + if value is not None: + return value + + return default + + def set(self, key: str, value: str) -> bool: + """ + 设置配置项的值 + + Args: + key: 配置项名称 + value: 配置项值 + + Returns: + 设置成功返回True,失败返回False + """ + try: + # 验证配置项是否有效 + if key not in self.DEFAULT_CONFIG and not key.startswith('MEMOS_'): + print(f"警告: '{key}' 不是标准的Memos配置项") + + # 使用dotenv的set_key函数 + set_key(str(self.env_file), key, value) + + # 同时更新当前环境变量 + os.environ[key] = value + + return True + except Exception as e: + print(f"设置配置项失败: {e}") + return False + + def get_all(self) -> Dict[str, str]: + """ + 获取所有配置项 + + Returns: + 包含所有配置项的字典 + """ + config = {} + + # 加载.env文件 + load_dotenv(str(self.env_file)) + + # 获取所有配置项 + for key in self.DEFAULT_CONFIG.keys(): + value = self.get(key) + if value is not None and value != '': + config[key] = value + + return config + + def set_multiple(self, config_dict: Dict[str, str]) -> Dict[str, bool]: + """ + 批量设置配置项 + + Args: + config_dict: 配置项字典 + + Returns: + 每个配置项设置结果的字典 + """ + results = {} + for key, value in config_dict.items(): + results[key] = self.set(key, value) + return results + + def validate_config(self) -> Dict[str, Any]: + """ + 验证配置是否完整 + + Returns: + 验证结果字典,包含状态和缺失的配置项 + """ + missing_configs = [] + invalid_configs = [] + + # 检查必需配置项 + required_configs = ['MEMOS_BASE_URL', 'MEMOS_TOKEN'] + + for config in required_configs: + value = self.get(config) + if not value or value.strip() == '': + missing_configs.append(config) + + # 检查URL格式 + base_url = self.get('MEMOS_BASE_URL') + if base_url and not base_url.startswith(('http://', 'https://')): + invalid_configs.append('MEMOS_BASE_URL (必须是有效的URL)') + + return { + 'is_valid': len(missing_configs) == 0 and len(invalid_configs) == 0, + 'missing_configs': missing_configs, + 'invalid_configs': invalid_configs + } + + def show_config(self): + """显示当前配置信息""" + print("=== 当前配置信息 ===") + print(f"配置文件路径: {self.env_file}") + print() + + config = self.get_all() + if not config: + print("当前没有任何配置") + return + + for key, value in config.items(): + # 隐藏敏感信息 + if 'TOKEN' in key or 'API_KEY' in key: + masked_value = '*' * 8 if value else '未设置' + print(f"{key}: {masked_value}") + else: + print(f"{key}: {value or '未设置'}") + + # 验证配置 + print("\n=== 配置验证 ===") + validation = self.validate_config() + if validation['is_valid']: + print("[SUCCESS] 配置有效") + else: + print("[ERROR] 配置无效:") + if validation['missing_configs']: + print(f" 缺失配置: {', '.join(validation['missing_configs'])}") + if validation['invalid_configs']: + print(f" 无效配置: {', '.join(validation['invalid_configs'])}") + + +def set_config(key: str, value: str, env_file: str = '.env') -> bool: + """ + 设置单个配置项的便捷函数 + + Args: + key: 配置项名称 + value: 配置项值 + env_file: .env文件路径 + + Returns: + 设置成功返回True,失败返回False + """ + config_manager = ConfigManager(env_file) + return config_manager.set(key, value) + + +def get_config(key: str, default: Optional[str] = None, env_file: str = '.env') -> Optional[str]: + """ + 获取单个配置项的便捷函数 + + Args: + key: 配置项名称 + default: 默认值 + env_file: .env文件路径 + + Returns: + 配置项的值 + """ + config_manager = ConfigManager(env_file) + return config_manager.get(key, default) + + +def main(): + """命令行接口""" + if len(sys.argv) < 2: + print("用法:") + print(" python config.py show # 显示当前配置") + print(" python config.py set # 设置配置项") + print(" python config.py get # 获取配置项") + print(" python config.py validate # 验证配置") + print("\n支持的配置项:") + for key, description in ConfigManager.CONFIG_DESCRIPTIONS.items(): + print(f" {key}: {description}") + return + + command = sys.argv[1] + config_manager = ConfigManager() + + if command == 'show': + config_manager.show_config() + + elif command == 'set': + if len(sys.argv) != 4: + print("用法: python config.py set ") + return + key, value = sys.argv[2], sys.argv[3] + if config_manager.set(key, value): + print(f"[SUCCESS] 成功设置 {key} = {value}") + else: + print(f"[ERROR] 设置 {key} 失败") + + elif command == 'get': + if len(sys.argv) != 3: + print("用法: python config.py get ") + return + key = sys.argv[2] + value = config_manager.get(key) + if value is not None: + print(f"{key}: {value}") + else: + print(f"{key}: 未设置") + + elif command == 'validate': + validation = config_manager.validate_config() + if validation['is_valid']: + print("[SUCCESS] 配置有效") + else: + print("[ERROR] 配置无效:") + if validation['missing_configs']: + print(f" 缺失配置: {', '.join(validation['missing_configs'])}") + if validation['invalid_configs']: + print(f" 无效配置: {', '.join(validation['invalid_configs'])}") + + else: + print(f"未知命令: {command}") + print("使用 'python config.py' 查看帮助") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/send.py b/src/send.py new file mode 100644 index 0000000..52d567a --- /dev/null +++ b/src/send.py @@ -0,0 +1,149 @@ +""" +Memos API content posting module +用于向Memos API发送内容的基本模块 +""" + +import os +import requests +from typing import Optional, Dict, Any +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + + +class MemosAPI: + """Memos API客户端类""" + + def __init__(self, base_url: Optional[str] = None, token: Optional[str] = None): + """ + 初始化Memos API客户端 + + Args: + base_url: Memos实例的基础URL,如果不提供则从环境变量读取 + token: 认证令牌,如果不提供则从环境变量读取 + """ + self.base_url = base_url or os.getenv('MEMOS_BASE_URL') + self.token = token or os.getenv('MEMOS_TOKEN') + + if not self.base_url: + raise ValueError("MEMOS_BASE_URL 未设置,请在 .env 文件中配置") + if not self.token: + raise ValueError("MEMOS_TOKEN 未设置,请在 .env 文件中配置") + + # 确保URL格式正确 + self.base_url = self.base_url.rstrip('/') + + # 设置请求头 + self.headers = { + 'Authorization': f'Bearer {self.token}', + 'Content-Type': 'application/json' + } + + def send_memo(self, content: str, visibility: str = "PRIVATE", + tags: Optional[list] = None, + resource_id_list: Optional[list] = None) -> Dict[str, Any]: + """ + 发送Memo到Memos服务器 + + Args: + content: Memo内容 + visibility: 可见性设置 ("PRIVATE", "PROTECTED", "PUBLIC") + tags: 标签列表 + resource_id_list: 资源ID列表 + + Returns: + API响应数据 + + Raises: + requests.RequestException: API请求失败时 + """ + # 构建请求数据 + data = { + "content": content, + "visibility": visibility, + "tags": tags or [], + "resourceIdList": resource_id_list or [] + } + + # Memos API endpoint + endpoint = f"{self.base_url}/api/v1/memos" + + try: + response = requests.post( + endpoint, + headers=self.headers, + json=data, + timeout=30 + ) + response.raise_for_status() + + return response.json() + + except requests.exceptions.RequestException as e: + raise requests.RequestException(f"发送Memo失败: {str(e)}") + + def test_connection(self) -> bool: + """ + 测试与Memos服务器的连接 + + Returns: + 连接成功返回True,否则返回False + """ + try: + endpoint = f"{self.base_url}/api/v1/memos" + response = requests.get( + endpoint, + headers=self.headers, + timeout=10 + ) + return response.status_code == 200 + except: + return False + + +def send_memo(content: str, visibility: str = "PRIVATE", + tags: Optional[list] = None) -> Dict[str, Any]: + """ + 发送Memo的便捷函数 + + Args: + content: Memo内容 + visibility: 可见性设置 + tags: 标签列表 + + Returns: + API响应数据 + + Raises: + ValueError: 配置错误时 + requests.RequestException: API请求失败时 + """ + api = MemosAPI() + return api.send_memo(content, visibility, tags) + + +def main(): + """测试函数""" + try: + # 测试连接 + api = MemosAPI() + if api.test_connection(): + print("[SUCCESS] 成功连接到Memos服务器") + + # 发送测试Memo + result = api.send_memo("测试内容 - 来自Memos CLI") + print(f"[SUCCESS] Memo发送成功: {result.get('id', '未知ID')}") + else: + print("[ERROR] 无法连接到Memos服务器,请检查配置") + + except ValueError as e: + print(f"[ERROR] 配置错误: {e}") + except requests.RequestException as e: + print(f"[ERROR] API请求失败: {e}") + except Exception as e: + print(f"[ERROR] 未知错误: {e}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..dcb49c7 --- /dev/null +++ b/uv.lock @@ -0,0 +1,126 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "certifi" +version = "2025.10.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "memoscli" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "python-dotenv" }, + { name = "requests" }, +] + +[package.metadata] +requires-dist = [ + { name = "python-dotenv", specifier = ">=1.0.0" }, + { name = "requests", specifier = ">=2.31.0" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +]