# notebook-snapshot JupyterLab 扩展:**手动保存 .ipynb 快照**,无 Git 依赖。 左侧栏查看版本时间轴、Cell 级 diff、一键无刷新恢复。 ## 功能 - 工具栏「保存快照」按钮 / 命令面板 `snapshot:commit` 触发 - 对话框填写 `name`(必填)+ `description`(可选)后保存 - 内容与最近版本相同时自动跳过(弹 warning),避免重复快照 - 左侧栏时间轴,支持对比(Cell 级 diff,行级红绿高亮)和恢复 - 恢复走 `model.fromJSON()` + `context.save()`,无页面刷新 - 历史 append-only,永不删除 / 改写 ## 存储后端 - **Local**(默认):`/.notebook_versions` 或自定义路径 - **S3**(pip extra):通过 boto3 对接 AWS S3 / MinIO / 任何 S3-API 兼容服务 ## 环境要求 - JupyterLab >= 4.0.0 - Python >= 3.10 - Node.js(构建前端用) ## 安装 ```bash # 1. 后端(基础包零依赖) pip install snapshot # 2. 前端构建 jlpm install jlpm build # 3. 启用 server extension jupyter server extension enable snapshot jupyter labextension develop . --overwrite # dev 安装;正式版 wheel 跳过此步 ``` 可选 S3 后端: ```bash pip install "snapshot[s3]" # 装 boto3 ``` ## 配置 写在 `~/.jupyter/jupyter_server_config.py`(用户级)或 `<项目>/jupyter_server_config.py`(项目级): | 字段 | 默认 | 说明 | |------|------|------| | `storage_type` | `"local"` | `"local"` 或 `"s3"` | | `local_root` | `""` → `/.notebook_versions` | Local 存储根目录;**建议显式设置**避免污染 notebook 目录 | | `s3_endpoint` | `""`(env: `S3_ENDPOINT`) | `localhost:9000`(MinIO)/ `s3.us-east-1.amazonaws.com`(AWS) | | `s3_access_key` | `""`(env: `S3_ACCESS_KEY`) | | | `s3_secret_key` | `""`(env: `S3_SECRET_KEY`) | | | `s3_bucket` | `"notebook-snapshot"` | 不存在自动建 | | `s3_secure` | `False` | HTTPS | | `s3_prefix` | `""` | 桶内 key 前缀 | ### 示例 ```python # 切到自定义 local 目录 c.SnapshotConfig.local_root = "/var/lib/jupyter/snapshots" # 切到 MinIO c.SnapshotConfig.storage_type = "s3" c.SnapshotConfig.s3_endpoint = "minio.example.com:9000" c.SnapshotConfig.s3_bucket = "team-snapshots" # 凭证走 env:export S3_ACCESS_KEY=... ; export S3_SECRET_KEY=... # 切到 AWS S3 c.SnapshotConfig.storage_type = "s3" c.SnapshotConfig.s3_endpoint = "s3.us-east-1.amazonaws.com" c.SnapshotConfig.s3_secure = True # 用 AWS 标准凭证:export AWS_ACCESS_KEY_ID=... ; export AWS_SECRET_ACCESS_KEY=... # (注:当前版本仅读取 S3_* 环境变量;如需 AWS_* 自动识别,参考 boto3 文档配置) ``` 环境变量 / 命令行 / 配置文件三种方式优先级遵循 traitlets 规则;改完配置**必须重启 `jupyter lab`**。 ## 开发 ```bash source .venv/bin/activate # 本仓库用 uv/venv pip install -e ".[dev,test,s3]" # 后端装 dev/test/s3 依赖 .venv/bin/jlpm install # 前端依赖 .venv/bin/jlpm build # 一次性构建(tsc + rspack + labextension) .venv/bin/jlpm watch # 终端 1:监听 src/ 自动重编 jupyter lab # 终端 2:启动 JupyterLab ``` **改了 Python 后端**:重启 `jupyter lab`(不需要 rebuild 前端)。 **改了前端 TypeScript**:`jlpm watch` 自动重编,浏览器刷新即可。 ## 验证 ```bash # 后端 .venv/bin/pytest snapshot/tests/ -vv # 前端类型检查 + 打包 .venv/bin/jlpm build # Lint .venv/bin/jlpm lint:check ``` ## 架构 参见 [design.md](design.md)。 简要: - **后端**:`/snapshot/` 命名空间下三个端点(commit / list / content);`SnapshotStore` 包装 `StorageAdapter`(Local + S3),gzip + envelope 存盘,manifest 是可重建的索引 - **前端**:`SnapshotModel` + `SnapshotPanel`(左侧栏) + `DiffWidget`(主区) + `snapshot:commit` 命令(工具栏 + 命令面板) 硬约定(实现时不得违背)见 [AGENTS.md](AGENTS.md)。 ## 排错 ```bash jupyter server extension list # 后端 extension 状态 jupyter labextension list # 前端 extension 状态 ``` - **工具栏没有「保存快照」按钮**:刷新浏览器;确认 `jupyter labextension list` 显示 enabled + OK - **保存时 400**:检查 `path` / `content` / `name` 是否齐全 - **保存后弹"内容未变更"**:正常行为——内容与最近版本 hash 相同会自动跳过,改动 cell 后再保存即可 - **S3 连不上**:确认 `endpoint`(不带 scheme)、`secure`(http/https)、bucket 存在性;凭证走 env 别写进配置 ## 卸载 ```bash jupyter server extension disable snapshot pip uninstall snapshot ``` ## AI 工具支持 本项目遵循 [AGENTS.md](https://agents.md) 标准,配套符号链接: - `CLAUDE.md` → `AGENTS.md`(Claude Code) - 其他工具:Cursor / Copilot / Windsurf / Aider 等直接读取 `AGENTS.md` 详细开发规范见 [AGENTS.md](AGENTS.md),设计文档见 [design.md](design.md)。