diff --git a/README.md b/README.md
index 84301ee..7a47886 100644
--- a/README.md
+++ b/README.md
@@ -55,105 +55,235 @@ facade.
## Architecture
```mermaid
-flowchart LR
- User[User / CLI / JSON batch]
+flowchart TD
+ CLI["CLI / JSON batch
python -m automation_file"]
+ GUIUser["PySide6 GUI
launch_ui"]
+ ClientSDK["HTTPActionClient SDK"]
+ MCPHost["MCP hosts
Claude Desktop · MCP CLIs"]
+ Plugins["Entry-point plugins
automation_file.actions"]
+
+ subgraph Facade["automation_file — facade (__init__.py)"]
+ PublicAPI["Public API
execute_action · execute_action_parallel · execute_action_dag
validate_action · driver_instance · s3_instance · azure_blob_instance
dropbox_instance · sftp_instance · ftp_instance · onedrive_instance · box_instance
start_autocontrol_socket_server · start_http_action_server
start_metrics_server · start_web_ui · MCPServer
notification_manager · scheduler · trigger_manager
AutomationConfig · progress_registry · Quota · retry_on_transient"]
+ end
+
+ subgraph Core["core"]
+ Registry[("ActionRegistry
FA_* commands")]
+ Executor["ActionExecutor
serial · parallel · dry-run · validate-first"]
+ DAG["dag_executor
topological fan-out"]
+ Callback["CallbackExecutor"]
+ Loader["PackageLoader
+ entry-point plugins"]
+ Queue["ActionQueue"]
+ Json["json_store"]
+ Sub["substitution
${env:} ${date:} ${uuid}"]
+ end
+
+ subgraph Reliability["reliability"]
+ Retry["retry
@retry_on_transient"]
+ QuotaMod["Quota
bytes + time budget"]
+ Breaker["CircuitBreaker"]
+ RL["RateLimiter"]
+ Locks["FileLock · SQLiteLock"]
+ end
+
+ subgraph Observability["observability"]
+ Progress["progress
CancellationToken · Reporter"]
+ Metrics["metrics
Prometheus counters + histograms"]
+ Audit["AuditLog
SQLite"]
+ Tracing["tracing
OpenTelemetry spans"]
+ FIM["IntegrityMonitor"]
+ end
- subgraph Facade["automation_file (facade)"]
- Public["Public API
execute_action, execute_action_parallel,
validate_action, driver_instance,
start_autocontrol_socket_server,
start_http_action_server, Quota,
retry_on_transient, safe_join, ..."]
+ subgraph Security["security & config"]
+ Secrets["Secret providers
Env · File · Chained"]
+ Config["AutomationConfig
TOML loader"]
+ ConfW["ConfigWatcher
hot reload"]
+ Crypto["crypto
AES-256-GCM"]
+ Check["checksum / manifest"]
+ SafeP["safe_paths
safe_join · is_within"]
+ ACL["ActionACL"]
end
- subgraph Core["core"]
- Registry[(ActionRegistry
FA_* commands)]
- Executor[ActionExecutor]
- Callback[CallbackExecutor]
- Loader[PackageLoader]
- Json[json_store]
- Retry[retry]
- QuotaMod[quota]
- Progress[progress
Token + Reporter]
+ subgraph Events["event-driven"]
+ Trigger["TriggerManager
watchdog file watcher"]
+ Sched["Scheduler
5-field cron + overlap guard"]
end
- subgraph Events["event-driven"]
- TriggerMod["trigger
watchdog file watcher"]
- SchedulerMod["scheduler
cron background thread"]
+ subgraph Servers["servers"]
+ TCP["TCPActionServer
loopback · AUTH secret"]
+ HTTPS["HTTPActionServer
POST /actions · Bearer
/healthz /readyz /progress /openapi.json"]
+ MCP["MCPServer
JSON-RPC 2.0 (stdio)"]
+ MetSrv["MetricsServer
/metrics"]
+ WebUI["WebUIServer
HTMX dashboard"]
end
- subgraph Local["local"]
- FileOps[file_ops]
- DirOps[dir_ops]
- ZipOps[zip_ops]
- Safe[safe_paths]
+ subgraph UI["ui (PySide6)"]
+ MainWin["MainWindow
Home · Local · HTTP · Drive · S3 · Azure · Dropbox
SFTP · OneDrive · Box · JSON · Triggers · Scheduler
Progress · Transfer · Servers"]
+ Worker["ActionWorker
QRunnable on QThreadPool"]
end
- subgraph Remote["remote"]
- UrlVal[url_validator]
- Http[http_download]
- Drive["google_drive
client + *_ops"]
- S3["s3"]
- Azure["azure_blob"]
- Dropbox["dropbox_api"]
- SFTP["sftp"]
+ subgraph Local["local ops"]
+ FileOps["file_ops · dir_ops"]
+ Archives["zip_ops · tar_ops · archive_ops"]
+ DataOps["data_ops
csv · jsonl · parquet · yaml"]
+ TextOps["text_ops · diff_ops
json_edit · templates"]
+ Misc["shell_ops · sync_ops · trash
versioning · conditional · mime"]
end
- subgraph Server["server"]
- TCP[TCPActionServer]
- HTTP[HTTPActionServer]
+ subgraph Remote["remote backends"]
+ UrlVal["url_validator
SSRF guard"]
+ Http["http_download
retry · resume · SHA-256"]
+ Drive["google_drive"]
+ S3M["s3"]
+ Azure["azure_blob"]
+ Dropbox["dropbox_api"]
+ SFTP["sftp (RejectPolicy)"]
+ FTP["ftp / FTPS"]
+ OneD["onedrive"]
+ Box["box"]
+ WebDAV["webdav"]
+ SMB["smb / cifs"]
+ Fsspec["fsspec_bridge"]
+ Cross["cross_backend
local:// s3:// drive:// azure://
dropbox:// sftp:// ftp://"]
end
- subgraph UI["ui (PySide6)"]
- Launcher[launch_ui]
- MainWindow["MainWindow
9-tab control surface"]
+ subgraph Notify["notifications"]
+ NM["NotificationManager
fanout · dedup · SSRF guard"]
+ Sinks["Sinks
Webhook · Slack · Email
Telegram · Discord · Teams · PagerDuty"]
end
- subgraph Project["project / utils"]
- Builder[ProjectBuilder]
- Templates[templates]
- Discovery[file_discovery]
+ subgraph Utils["utils / project"]
+ Fast["fast_find
mdfind / locate / es.exe"]
+ Dedup["find_duplicates"]
+ Grep["grep_files"]
+ Rotate["rotate_backups"]
+ Discovery["file_discovery"]
+ Builder["ProjectBuilder + templates"]
end
- User --> Public
- User --> Launcher
- Launcher --> MainWindow
- MainWindow --> Public
- Public --> Executor
- Public --> Callback
- Public --> Loader
- Public --> TCP
- Public --> HTTP
-
- Executor --> Registry
- Executor --> Retry
- Executor --> QuotaMod
- Callback --> Registry
- Loader --> Registry
- TCP --> Executor
- HTTP --> Executor
- Executor --> Json
-
- Registry --> FileOps
- Registry --> DirOps
- Registry --> ZipOps
- Registry --> Safe
- Registry --> Http
- Registry --> Drive
- Registry --> S3
- Registry --> Azure
- Registry --> Dropbox
- Registry --> SFTP
- Registry --> Builder
- Registry --> TriggerMod
- Registry --> SchedulerMod
- Registry --> Progress
-
- TriggerMod --> Executor
- SchedulerMod --> Executor
- Http --> Progress
- S3 --> Progress
-
- Http --> UrlVal
- Http --> Retry
- Builder --> Templates
- Builder --> Discovery
+ CLI ==> PublicAPI
+ GUIUser ==> MainWin
+ ClientSDK ==> HTTPS
+ MCPHost ==> MCP
+ Plugins ==> Loader
+
+ MainWin ==> Worker
+ Worker ==> PublicAPI
+
+ PublicAPI ==> Executor
+ PublicAPI ==> DAG
+ PublicAPI ==> Callback
+ PublicAPI ==> Queue
+ PublicAPI ==> Config
+ PublicAPI ==> NM
+ PublicAPI ==> Trigger
+ PublicAPI ==> Sched
+
+ TCP ==> Executor
+ HTTPS ==> Executor
+ MCP ==> Registry
+ MetSrv ==> Metrics
+ WebUI ==> Registry
+ ACL ==> TCP
+ ACL ==> HTTPS
+
+ Executor ==> Registry
+ Executor ==> Sub
+ Executor ==> Retry
+ Executor ==> QuotaMod
+ Executor ==> Metrics
+ Executor ==> Audit
+ Executor ==> Tracing
+ Executor ==> Json
+ DAG ==> Executor
+ Callback ==> Registry
+ Loader ==> Registry
+
+ Trigger ==> Executor
+ Sched ==> Executor
+ Trigger -. on failure .-> NM
+ Sched -. on failure .-> NM
+ FIM -. on drift .-> NM
+ ConfW ==> Config
+ Config ==> Secrets
+ Config ==> NM
+
+ Registry ==> FileOps
+ Registry ==> Archives
+ Registry ==> DataOps
+ Registry ==> TextOps
+ Registry ==> Misc
+ Registry ==> Http
+ Registry ==> Drive
+ Registry ==> S3M
+ Registry ==> Azure
+ Registry ==> Dropbox
+ Registry ==> SFTP
+ Registry ==> FTP
+ Registry ==> OneD
+ Registry ==> Box
+ Registry ==> WebDAV
+ Registry ==> SMB
+ Registry ==> Fsspec
+ Registry ==> Cross
+ Registry ==> Crypto
+ Registry ==> Check
+ Registry ==> Fast
+ Registry ==> Dedup
+ Registry ==> Grep
+ Registry ==> Rotate
+ Registry ==> Discovery
+ Registry ==> Builder
+ Registry ==> Progress
+
+ FileOps ==> SafeP
+ Archives ==> SafeP
+ Misc ==> SafeP
+
+ Http ==> UrlVal
+ Http ==> Retry
+ Http ==> Progress
+ Http ==> Check
+ S3M ==> Progress
+ WebDAV ==> UrlVal
+ NM ==> UrlVal
+ NM ==> Sinks
+
+ Cross ==> Drive
+ Cross ==> S3M
+ Cross ==> Azure
+ Cross ==> Dropbox
+ Cross ==> SFTP
+ Cross ==> FTP
+
+ classDef entry fill:#FDEDEC,stroke:#641E16,stroke-width:3px,color:#000,font-weight:bold;
+ classDef facade fill:#D6EAF8,stroke:#154360,stroke-width:4px,color:#000,font-weight:bold;
+ classDef core fill:#FEF9E7,stroke:#1F3A93,stroke-width:3px,color:#000,font-weight:bold;
+ classDef rel fill:#D1F2EB,stroke:#0B5345,stroke-width:3px,color:#000,font-weight:bold;
+ classDef obs fill:#FDEBD0,stroke:#9C640C,stroke-width:3px,color:#000,font-weight:bold;
+ classDef sec fill:#F5B7B1,stroke:#78281F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef event fill:#FCF3CF,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef server fill:#FADBD8,stroke:#922B21,stroke-width:3px,color:#000,font-weight:bold;
+ classDef ui fill:#AED6F1,stroke:#1B4F72,stroke-width:3px,color:#000,font-weight:bold;
+ classDef localOps fill:#E8DAEF,stroke:#512E5F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef remote fill:#D5F5E3,stroke:#196F3D,stroke-width:3px,color:#000,font-weight:bold;
+ classDef notify fill:#F9E79F,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef utils fill:#EAEDED,stroke:#212F3C,stroke-width:3px,color:#000,font-weight:bold;
+
+ class CLI,GUIUser,ClientSDK,MCPHost,Plugins entry;
+ class PublicAPI facade;
+ class Registry,Executor,DAG,Callback,Loader,Queue,Json,Sub core;
+ class Retry,QuotaMod,Breaker,RL,Locks rel;
+ class Progress,Metrics,Audit,Tracing,FIM obs;
+ class Secrets,Config,ConfW,Crypto,Check,SafeP,ACL sec;
+ class Trigger,Sched event;
+ class TCP,HTTPS,MCP,MetSrv,WebUI server;
+ class MainWin,Worker ui;
+ class FileOps,Archives,DataOps,TextOps,Misc localOps;
+ class UrlVal,Http,Drive,S3M,Azure,Dropbox,SFTP,FTP,OneD,Box,WebDAV,SMB,Fsspec,Cross remote;
+ class NM,Sinks notify;
+ class Fast,Dedup,Grep,Rotate,Discovery,Builder utils;
+
+ linkStyle default stroke:#1F2A44,stroke-width:2.5px;
```
The `ActionRegistry` built by `build_default_registry()` is the single source
diff --git a/README.zh-CN.md b/README.zh-CN.md
index c45eeba..e81979b 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -53,105 +53,235 @@ TCP / HTTP 服务器执行的 JSON 驱动动作。内附 PySide6 GUI,每个功
## 架构
```mermaid
-flowchart LR
- User[User / CLI / JSON batch]
+flowchart TD
+ CLI["CLI / JSON 批次
python -m automation_file"]
+ GUIUser["PySide6 GUI
launch_ui"]
+ ClientSDK["HTTPActionClient SDK"]
+ MCPHost["MCP 主机
Claude Desktop · MCP CLIs"]
+ Plugins["入口点插件
automation_file.actions"]
+
+ subgraph Facade["automation_file — 门面 (__init__.py)"]
+ PublicAPI["Public API
execute_action · execute_action_parallel · execute_action_dag
validate_action · driver_instance · s3_instance · azure_blob_instance
dropbox_instance · sftp_instance · ftp_instance · onedrive_instance · box_instance
start_autocontrol_socket_server · start_http_action_server
start_metrics_server · start_web_ui · MCPServer
notification_manager · scheduler · trigger_manager
AutomationConfig · progress_registry · Quota · retry_on_transient"]
+ end
+
+ subgraph Core["core 核心"]
+ Registry[("ActionRegistry
FA_* 命令")]
+ Executor["ActionExecutor
串行 · 并行 · dry-run · validate-first"]
+ DAG["dag_executor
拓扑调度 fan-out"]
+ Callback["CallbackExecutor"]
+ Loader["PackageLoader
+ 入口点插件"]
+ Queue["ActionQueue"]
+ Json["json_store"]
+ Sub["substitution
${env:} ${date:} ${uuid}"]
+ end
+
+ subgraph Reliability["可靠性"]
+ Retry["retry
@retry_on_transient"]
+ QuotaMod["Quota
字节 + 时间配额"]
+ Breaker["CircuitBreaker"]
+ RL["RateLimiter"]
+ Locks["FileLock · SQLiteLock"]
+ end
+
+ subgraph Observability["可观测性"]
+ Progress["progress
CancellationToken · Reporter"]
+ Metrics["metrics
Prometheus counters + histograms"]
+ Audit["AuditLog
SQLite 审计日志"]
+ Tracing["tracing
OpenTelemetry spans"]
+ FIM["IntegrityMonitor"]
+ end
- subgraph Facade["automation_file (facade)"]
- Public["Public API
execute_action, execute_action_parallel,
validate_action, driver_instance,
start_autocontrol_socket_server,
start_http_action_server, Quota,
retry_on_transient, safe_join, ..."]
+ subgraph Security["安全 & 配置"]
+ Secrets["Secret providers
Env · File · Chained"]
+ Config["AutomationConfig
TOML 加载器"]
+ ConfW["ConfigWatcher
热重载"]
+ Crypto["crypto
AES-256-GCM"]
+ Check["checksum / manifest"]
+ SafeP["safe_paths
safe_join · is_within"]
+ ACL["ActionACL"]
end
- subgraph Core["core"]
- Registry[(ActionRegistry
FA_* commands)]
- Executor[ActionExecutor]
- Callback[CallbackExecutor]
- Loader[PackageLoader]
- Json[json_store]
- Retry[retry]
- QuotaMod[quota]
- Progress[progress
Token + Reporter]
+ subgraph Events["事件驱动"]
+ Trigger["TriggerManager
watchdog 文件监听"]
+ Sched["Scheduler
5-field cron + overlap guard"]
end
- subgraph Events["event-driven"]
- TriggerMod["trigger
watchdog file watcher"]
- SchedulerMod["scheduler
cron background thread"]
+ subgraph Servers["服务器"]
+ TCP["TCPActionServer
loopback · AUTH secret"]
+ HTTPS["HTTPActionServer
POST /actions · Bearer
/healthz /readyz /progress /openapi.json"]
+ MCP["MCPServer
JSON-RPC 2.0 (stdio)"]
+ MetSrv["MetricsServer
/metrics"]
+ WebUI["WebUIServer
HTMX dashboard"]
end
- subgraph Local["local"]
- FileOps[file_ops]
- DirOps[dir_ops]
- ZipOps[zip_ops]
- Safe[safe_paths]
+ subgraph UI["ui (PySide6)"]
+ MainWin["MainWindow
Home · Local · HTTP · Drive · S3 · Azure · Dropbox
SFTP · OneDrive · Box · JSON · Triggers · Scheduler
Progress · Transfer · Servers"]
+ Worker["ActionWorker
QRunnable on QThreadPool"]
end
- subgraph Remote["remote"]
- UrlVal[url_validator]
- Http[http_download]
- Drive["google_drive
client + *_ops"]
- S3["s3"]
- Azure["azure_blob"]
- Dropbox["dropbox_api"]
- SFTP["sftp"]
+ subgraph Local["本地 ops"]
+ FileOps["file_ops · dir_ops"]
+ Archives["zip_ops · tar_ops · archive_ops"]
+ DataOps["data_ops
csv · jsonl · parquet · yaml"]
+ TextOps["text_ops · diff_ops
json_edit · templates"]
+ Misc["shell_ops · sync_ops · trash
versioning · conditional · mime"]
end
- subgraph Server["server"]
- TCP[TCPActionServer]
- HTTP[HTTPActionServer]
+ subgraph Remote["远程后端"]
+ UrlVal["url_validator
SSRF 保护"]
+ Http["http_download
retry · resume · SHA-256"]
+ Drive["google_drive"]
+ S3M["s3"]
+ Azure["azure_blob"]
+ Dropbox["dropbox_api"]
+ SFTP["sftp (RejectPolicy)"]
+ FTP["ftp / FTPS"]
+ OneD["onedrive"]
+ Box["box"]
+ WebDAV["webdav"]
+ SMB["smb / cifs"]
+ Fsspec["fsspec_bridge"]
+ Cross["cross_backend
local:// s3:// drive:// azure://
dropbox:// sftp:// ftp://"]
end
- subgraph UI["ui (PySide6)"]
- Launcher[launch_ui]
- MainWindow["MainWindow
9-tab control surface"]
+ subgraph Notify["通知"]
+ NM["NotificationManager
fanout · dedup · SSRF guard"]
+ Sinks["Sinks
Webhook · Slack · Email
Telegram · Discord · Teams · PagerDuty"]
end
- subgraph Project["project / utils"]
- Builder[ProjectBuilder]
- Templates[templates]
- Discovery[file_discovery]
+ subgraph Utils["工具 / 项目"]
+ Fast["fast_find
mdfind / locate / es.exe"]
+ Dedup["find_duplicates"]
+ Grep["grep_files"]
+ Rotate["rotate_backups"]
+ Discovery["file_discovery"]
+ Builder["ProjectBuilder + templates"]
end
- User --> Public
- User --> Launcher
- Launcher --> MainWindow
- MainWindow --> Public
- Public --> Executor
- Public --> Callback
- Public --> Loader
- Public --> TCP
- Public --> HTTP
-
- Executor --> Registry
- Executor --> Retry
- Executor --> QuotaMod
- Callback --> Registry
- Loader --> Registry
- TCP --> Executor
- HTTP --> Executor
- Executor --> Json
-
- Registry --> FileOps
- Registry --> DirOps
- Registry --> ZipOps
- Registry --> Safe
- Registry --> Http
- Registry --> Drive
- Registry --> S3
- Registry --> Azure
- Registry --> Dropbox
- Registry --> SFTP
- Registry --> Builder
- Registry --> TriggerMod
- Registry --> SchedulerMod
- Registry --> Progress
-
- TriggerMod --> Executor
- SchedulerMod --> Executor
- Http --> Progress
- S3 --> Progress
-
- Http --> UrlVal
- Http --> Retry
- Builder --> Templates
- Builder --> Discovery
+ CLI ==> PublicAPI
+ GUIUser ==> MainWin
+ ClientSDK ==> HTTPS
+ MCPHost ==> MCP
+ Plugins ==> Loader
+
+ MainWin ==> Worker
+ Worker ==> PublicAPI
+
+ PublicAPI ==> Executor
+ PublicAPI ==> DAG
+ PublicAPI ==> Callback
+ PublicAPI ==> Queue
+ PublicAPI ==> Config
+ PublicAPI ==> NM
+ PublicAPI ==> Trigger
+ PublicAPI ==> Sched
+
+ TCP ==> Executor
+ HTTPS ==> Executor
+ MCP ==> Registry
+ MetSrv ==> Metrics
+ WebUI ==> Registry
+ ACL ==> TCP
+ ACL ==> HTTPS
+
+ Executor ==> Registry
+ Executor ==> Sub
+ Executor ==> Retry
+ Executor ==> QuotaMod
+ Executor ==> Metrics
+ Executor ==> Audit
+ Executor ==> Tracing
+ Executor ==> Json
+ DAG ==> Executor
+ Callback ==> Registry
+ Loader ==> Registry
+
+ Trigger ==> Executor
+ Sched ==> Executor
+ Trigger -. 失败时 .-> NM
+ Sched -. 失败时 .-> NM
+ FIM -. 检测到变动 .-> NM
+ ConfW ==> Config
+ Config ==> Secrets
+ Config ==> NM
+
+ Registry ==> FileOps
+ Registry ==> Archives
+ Registry ==> DataOps
+ Registry ==> TextOps
+ Registry ==> Misc
+ Registry ==> Http
+ Registry ==> Drive
+ Registry ==> S3M
+ Registry ==> Azure
+ Registry ==> Dropbox
+ Registry ==> SFTP
+ Registry ==> FTP
+ Registry ==> OneD
+ Registry ==> Box
+ Registry ==> WebDAV
+ Registry ==> SMB
+ Registry ==> Fsspec
+ Registry ==> Cross
+ Registry ==> Crypto
+ Registry ==> Check
+ Registry ==> Fast
+ Registry ==> Dedup
+ Registry ==> Grep
+ Registry ==> Rotate
+ Registry ==> Discovery
+ Registry ==> Builder
+ Registry ==> Progress
+
+ FileOps ==> SafeP
+ Archives ==> SafeP
+ Misc ==> SafeP
+
+ Http ==> UrlVal
+ Http ==> Retry
+ Http ==> Progress
+ Http ==> Check
+ S3M ==> Progress
+ WebDAV ==> UrlVal
+ NM ==> UrlVal
+ NM ==> Sinks
+
+ Cross ==> Drive
+ Cross ==> S3M
+ Cross ==> Azure
+ Cross ==> Dropbox
+ Cross ==> SFTP
+ Cross ==> FTP
+
+ classDef entry fill:#FDEDEC,stroke:#641E16,stroke-width:3px,color:#000,font-weight:bold;
+ classDef facade fill:#D6EAF8,stroke:#154360,stroke-width:4px,color:#000,font-weight:bold;
+ classDef core fill:#FEF9E7,stroke:#1F3A93,stroke-width:3px,color:#000,font-weight:bold;
+ classDef rel fill:#D1F2EB,stroke:#0B5345,stroke-width:3px,color:#000,font-weight:bold;
+ classDef obs fill:#FDEBD0,stroke:#9C640C,stroke-width:3px,color:#000,font-weight:bold;
+ classDef sec fill:#F5B7B1,stroke:#78281F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef event fill:#FCF3CF,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef server fill:#FADBD8,stroke:#922B21,stroke-width:3px,color:#000,font-weight:bold;
+ classDef ui fill:#AED6F1,stroke:#1B4F72,stroke-width:3px,color:#000,font-weight:bold;
+ classDef localOps fill:#E8DAEF,stroke:#512E5F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef remote fill:#D5F5E3,stroke:#196F3D,stroke-width:3px,color:#000,font-weight:bold;
+ classDef notify fill:#F9E79F,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef utils fill:#EAEDED,stroke:#212F3C,stroke-width:3px,color:#000,font-weight:bold;
+
+ class CLI,GUIUser,ClientSDK,MCPHost,Plugins entry;
+ class PublicAPI facade;
+ class Registry,Executor,DAG,Callback,Loader,Queue,Json,Sub core;
+ class Retry,QuotaMod,Breaker,RL,Locks rel;
+ class Progress,Metrics,Audit,Tracing,FIM obs;
+ class Secrets,Config,ConfW,Crypto,Check,SafeP,ACL sec;
+ class Trigger,Sched event;
+ class TCP,HTTPS,MCP,MetSrv,WebUI server;
+ class MainWin,Worker ui;
+ class FileOps,Archives,DataOps,TextOps,Misc localOps;
+ class UrlVal,Http,Drive,S3M,Azure,Dropbox,SFTP,FTP,OneD,Box,WebDAV,SMB,Fsspec,Cross remote;
+ class NM,Sinks notify;
+ class Fast,Dedup,Grep,Rotate,Discovery,Builder utils;
+
+ linkStyle default stroke:#1F2A44,stroke-width:2.5px;
```
`build_default_registry()` 构建的 `ActionRegistry` 是所有 `FA_*` 命令的唯一
diff --git a/README.zh-TW.md b/README.zh-TW.md
index 8d2a086..6f5804d 100644
--- a/README.zh-TW.md
+++ b/README.zh-TW.md
@@ -53,105 +53,235 @@ TCP / HTTP 伺服器執行的 JSON 驅動動作。內附 PySide6 GUI,每個功
## 架構
```mermaid
-flowchart LR
- User[User / CLI / JSON batch]
+flowchart TD
+ CLI["CLI / JSON 批次
python -m automation_file"]
+ GUIUser["PySide6 GUI
launch_ui"]
+ ClientSDK["HTTPActionClient SDK"]
+ MCPHost["MCP 主機
Claude Desktop · MCP CLIs"]
+ Plugins["進入點外掛
automation_file.actions"]
+
+ subgraph Facade["automation_file — 門面 (__init__.py)"]
+ PublicAPI["Public API
execute_action · execute_action_parallel · execute_action_dag
validate_action · driver_instance · s3_instance · azure_blob_instance
dropbox_instance · sftp_instance · ftp_instance · onedrive_instance · box_instance
start_autocontrol_socket_server · start_http_action_server
start_metrics_server · start_web_ui · MCPServer
notification_manager · scheduler · trigger_manager
AutomationConfig · progress_registry · Quota · retry_on_transient"]
+ end
+
+ subgraph Core["core 核心"]
+ Registry[("ActionRegistry
FA_* 指令")]
+ Executor["ActionExecutor
序列 · 並行 · dry-run · validate-first"]
+ DAG["dag_executor
拓樸排程 fan-out"]
+ Callback["CallbackExecutor"]
+ Loader["PackageLoader
+ 進入點外掛"]
+ Queue["ActionQueue"]
+ Json["json_store"]
+ Sub["substitution
${env:} ${date:} ${uuid}"]
+ end
+
+ subgraph Reliability["可靠性"]
+ Retry["retry
@retry_on_transient"]
+ QuotaMod["Quota
位元組 + 時間配額"]
+ Breaker["CircuitBreaker"]
+ RL["RateLimiter"]
+ Locks["FileLock · SQLiteLock"]
+ end
+
+ subgraph Observability["可觀測性"]
+ Progress["progress
CancellationToken · Reporter"]
+ Metrics["metrics
Prometheus counters + histograms"]
+ Audit["AuditLog
SQLite 稽核紀錄"]
+ Tracing["tracing
OpenTelemetry spans"]
+ FIM["IntegrityMonitor"]
+ end
- subgraph Facade["automation_file (facade)"]
- Public["Public API
execute_action, execute_action_parallel,
validate_action, driver_instance,
start_autocontrol_socket_server,
start_http_action_server, Quota,
retry_on_transient, safe_join, ..."]
+ subgraph Security["安全 & 設定"]
+ Secrets["Secret providers
Env · File · Chained"]
+ Config["AutomationConfig
TOML 載入器"]
+ ConfW["ConfigWatcher
熱重載"]
+ Crypto["crypto
AES-256-GCM"]
+ Check["checksum / manifest"]
+ SafeP["safe_paths
safe_join · is_within"]
+ ACL["ActionACL"]
end
- subgraph Core["core"]
- Registry[(ActionRegistry
FA_* commands)]
- Executor[ActionExecutor]
- Callback[CallbackExecutor]
- Loader[PackageLoader]
- Json[json_store]
- Retry[retry]
- QuotaMod[quota]
- Progress[progress
Token + Reporter]
+ subgraph Events["事件驅動"]
+ Trigger["TriggerManager
watchdog 檔案監聽"]
+ Sched["Scheduler
5-field cron + overlap guard"]
end
- subgraph Events["event-driven"]
- TriggerMod["trigger
watchdog file watcher"]
- SchedulerMod["scheduler
cron background thread"]
+ subgraph Servers["伺服器"]
+ TCP["TCPActionServer
loopback · AUTH secret"]
+ HTTPS["HTTPActionServer
POST /actions · Bearer
/healthz /readyz /progress /openapi.json"]
+ MCP["MCPServer
JSON-RPC 2.0 (stdio)"]
+ MetSrv["MetricsServer
/metrics"]
+ WebUI["WebUIServer
HTMX dashboard"]
end
- subgraph Local["local"]
- FileOps[file_ops]
- DirOps[dir_ops]
- ZipOps[zip_ops]
- Safe[safe_paths]
+ subgraph UI["ui (PySide6)"]
+ MainWin["MainWindow
Home · Local · HTTP · Drive · S3 · Azure · Dropbox
SFTP · OneDrive · Box · JSON · Triggers · Scheduler
Progress · Transfer · Servers"]
+ Worker["ActionWorker
QRunnable on QThreadPool"]
end
- subgraph Remote["remote"]
- UrlVal[url_validator]
- Http[http_download]
- Drive["google_drive
client + *_ops"]
- S3["s3"]
- Azure["azure_blob"]
- Dropbox["dropbox_api"]
- SFTP["sftp"]
+ subgraph Local["本地 ops"]
+ FileOps["file_ops · dir_ops"]
+ Archives["zip_ops · tar_ops · archive_ops"]
+ DataOps["data_ops
csv · jsonl · parquet · yaml"]
+ TextOps["text_ops · diff_ops
json_edit · templates"]
+ Misc["shell_ops · sync_ops · trash
versioning · conditional · mime"]
end
- subgraph Server["server"]
- TCP[TCPActionServer]
- HTTP[HTTPActionServer]
+ subgraph Remote["遠端後端"]
+ UrlVal["url_validator
SSRF 防護"]
+ Http["http_download
retry · resume · SHA-256"]
+ Drive["google_drive"]
+ S3M["s3"]
+ Azure["azure_blob"]
+ Dropbox["dropbox_api"]
+ SFTP["sftp (RejectPolicy)"]
+ FTP["ftp / FTPS"]
+ OneD["onedrive"]
+ Box["box"]
+ WebDAV["webdav"]
+ SMB["smb / cifs"]
+ Fsspec["fsspec_bridge"]
+ Cross["cross_backend
local:// s3:// drive:// azure://
dropbox:// sftp:// ftp://"]
end
- subgraph UI["ui (PySide6)"]
- Launcher[launch_ui]
- MainWindow["MainWindow
9-tab control surface"]
+ subgraph Notify["通知"]
+ NM["NotificationManager
fanout · dedup · SSRF guard"]
+ Sinks["Sinks
Webhook · Slack · Email
Telegram · Discord · Teams · PagerDuty"]
end
- subgraph Project["project / utils"]
- Builder[ProjectBuilder]
- Templates[templates]
- Discovery[file_discovery]
+ subgraph Utils["工具 / 專案"]
+ Fast["fast_find
mdfind / locate / es.exe"]
+ Dedup["find_duplicates"]
+ Grep["grep_files"]
+ Rotate["rotate_backups"]
+ Discovery["file_discovery"]
+ Builder["ProjectBuilder + templates"]
end
- User --> Public
- User --> Launcher
- Launcher --> MainWindow
- MainWindow --> Public
- Public --> Executor
- Public --> Callback
- Public --> Loader
- Public --> TCP
- Public --> HTTP
-
- Executor --> Registry
- Executor --> Retry
- Executor --> QuotaMod
- Callback --> Registry
- Loader --> Registry
- TCP --> Executor
- HTTP --> Executor
- Executor --> Json
-
- Registry --> FileOps
- Registry --> DirOps
- Registry --> ZipOps
- Registry --> Safe
- Registry --> Http
- Registry --> Drive
- Registry --> S3
- Registry --> Azure
- Registry --> Dropbox
- Registry --> SFTP
- Registry --> Builder
- Registry --> TriggerMod
- Registry --> SchedulerMod
- Registry --> Progress
-
- TriggerMod --> Executor
- SchedulerMod --> Executor
- Http --> Progress
- S3 --> Progress
-
- Http --> UrlVal
- Http --> Retry
- Builder --> Templates
- Builder --> Discovery
+ CLI ==> PublicAPI
+ GUIUser ==> MainWin
+ ClientSDK ==> HTTPS
+ MCPHost ==> MCP
+ Plugins ==> Loader
+
+ MainWin ==> Worker
+ Worker ==> PublicAPI
+
+ PublicAPI ==> Executor
+ PublicAPI ==> DAG
+ PublicAPI ==> Callback
+ PublicAPI ==> Queue
+ PublicAPI ==> Config
+ PublicAPI ==> NM
+ PublicAPI ==> Trigger
+ PublicAPI ==> Sched
+
+ TCP ==> Executor
+ HTTPS ==> Executor
+ MCP ==> Registry
+ MetSrv ==> Metrics
+ WebUI ==> Registry
+ ACL ==> TCP
+ ACL ==> HTTPS
+
+ Executor ==> Registry
+ Executor ==> Sub
+ Executor ==> Retry
+ Executor ==> QuotaMod
+ Executor ==> Metrics
+ Executor ==> Audit
+ Executor ==> Tracing
+ Executor ==> Json
+ DAG ==> Executor
+ Callback ==> Registry
+ Loader ==> Registry
+
+ Trigger ==> Executor
+ Sched ==> Executor
+ Trigger -. 失敗時 .-> NM
+ Sched -. 失敗時 .-> NM
+ FIM -. 偵測到異動 .-> NM
+ ConfW ==> Config
+ Config ==> Secrets
+ Config ==> NM
+
+ Registry ==> FileOps
+ Registry ==> Archives
+ Registry ==> DataOps
+ Registry ==> TextOps
+ Registry ==> Misc
+ Registry ==> Http
+ Registry ==> Drive
+ Registry ==> S3M
+ Registry ==> Azure
+ Registry ==> Dropbox
+ Registry ==> SFTP
+ Registry ==> FTP
+ Registry ==> OneD
+ Registry ==> Box
+ Registry ==> WebDAV
+ Registry ==> SMB
+ Registry ==> Fsspec
+ Registry ==> Cross
+ Registry ==> Crypto
+ Registry ==> Check
+ Registry ==> Fast
+ Registry ==> Dedup
+ Registry ==> Grep
+ Registry ==> Rotate
+ Registry ==> Discovery
+ Registry ==> Builder
+ Registry ==> Progress
+
+ FileOps ==> SafeP
+ Archives ==> SafeP
+ Misc ==> SafeP
+
+ Http ==> UrlVal
+ Http ==> Retry
+ Http ==> Progress
+ Http ==> Check
+ S3M ==> Progress
+ WebDAV ==> UrlVal
+ NM ==> UrlVal
+ NM ==> Sinks
+
+ Cross ==> Drive
+ Cross ==> S3M
+ Cross ==> Azure
+ Cross ==> Dropbox
+ Cross ==> SFTP
+ Cross ==> FTP
+
+ classDef entry fill:#FDEDEC,stroke:#641E16,stroke-width:3px,color:#000,font-weight:bold;
+ classDef facade fill:#D6EAF8,stroke:#154360,stroke-width:4px,color:#000,font-weight:bold;
+ classDef core fill:#FEF9E7,stroke:#1F3A93,stroke-width:3px,color:#000,font-weight:bold;
+ classDef rel fill:#D1F2EB,stroke:#0B5345,stroke-width:3px,color:#000,font-weight:bold;
+ classDef obs fill:#FDEBD0,stroke:#9C640C,stroke-width:3px,color:#000,font-weight:bold;
+ classDef sec fill:#F5B7B1,stroke:#78281F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef event fill:#FCF3CF,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef server fill:#FADBD8,stroke:#922B21,stroke-width:3px,color:#000,font-weight:bold;
+ classDef ui fill:#AED6F1,stroke:#1B4F72,stroke-width:3px,color:#000,font-weight:bold;
+ classDef localOps fill:#E8DAEF,stroke:#512E5F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef remote fill:#D5F5E3,stroke:#196F3D,stroke-width:3px,color:#000,font-weight:bold;
+ classDef notify fill:#F9E79F,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef utils fill:#EAEDED,stroke:#212F3C,stroke-width:3px,color:#000,font-weight:bold;
+
+ class CLI,GUIUser,ClientSDK,MCPHost,Plugins entry;
+ class PublicAPI facade;
+ class Registry,Executor,DAG,Callback,Loader,Queue,Json,Sub core;
+ class Retry,QuotaMod,Breaker,RL,Locks rel;
+ class Progress,Metrics,Audit,Tracing,FIM obs;
+ class Secrets,Config,ConfW,Crypto,Check,SafeP,ACL sec;
+ class Trigger,Sched event;
+ class TCP,HTTPS,MCP,MetSrv,WebUI server;
+ class MainWin,Worker ui;
+ class FileOps,Archives,DataOps,TextOps,Misc localOps;
+ class UrlVal,Http,Drive,S3M,Azure,Dropbox,SFTP,FTP,OneD,Box,WebDAV,SMB,Fsspec,Cross remote;
+ class NM,Sinks notify;
+ class Fast,Dedup,Grep,Rotate,Discovery,Builder utils;
+
+ linkStyle default stroke:#1F2A44,stroke-width:2.5px;
```
`build_default_registry()` 建立的 `ActionRegistry` 是所有 `FA_*` 指令的唯一
diff --git a/docs/requirements.txt b/docs/requirements.txt
index e26f13e..c3d2bd2 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,3 +1,4 @@
sphinx>=7.4.7
sphinx-rtd-theme
myst-parser
+sphinxcontrib-mermaid
diff --git a/docs/source.zh-CN/architecture.rst b/docs/source.zh-CN/architecture.rst
index 6ce07d9..3cb95b4 100644
--- a/docs/source.zh-CN/architecture.rst
+++ b/docs/source.zh-CN/architecture.rst
@@ -3,6 +3,249 @@
``automation_file`` 采用分层架构,核心由五种设计模式组成:
+系统总览
+--------
+
+下图展示完整的派发表面:任何调用方——CLI、GUI、HTTP/MCP 客户端、入口点插件
+——最终都会落到由 ``build_default_registry()`` 填充的共享 ``ActionRegistry``,
+再从 registry 向本地 ops、远程后端、可靠性 / 安全 / 可观测性辅助工具、通知,
+以及事件驱动的触发器与 cron 调度器扇出。
+
+.. mermaid::
+
+ flowchart TD
+ CLI["CLI / JSON 批次
python -m automation_file"]
+ GUIUser["PySide6 GUI
launch_ui"]
+ ClientSDK["HTTPActionClient SDK"]
+ MCPHost["MCP 主机
Claude Desktop · MCP CLIs"]
+ Plugins["入口点插件
automation_file.actions"]
+
+ subgraph Facade["automation_file — 门面 (__init__.py)"]
+ PublicAPI["Public API
execute_action · execute_action_parallel · execute_action_dag
validate_action · driver_instance · s3_instance · azure_blob_instance
dropbox_instance · sftp_instance · ftp_instance · onedrive_instance · box_instance
start_autocontrol_socket_server · start_http_action_server
start_metrics_server · start_web_ui · MCPServer
notification_manager · scheduler · trigger_manager
AutomationConfig · progress_registry · Quota · retry_on_transient"]
+ end
+
+ subgraph Core["core 核心"]
+ Registry[("ActionRegistry
FA_* 命令")]
+ Executor["ActionExecutor
串行 · 并行 · dry-run · validate-first"]
+ DAG["dag_executor
拓扑调度 fan-out"]
+ Callback["CallbackExecutor"]
+ Loader["PackageLoader
+ 入口点插件"]
+ Queue["ActionQueue"]
+ Json["json_store"]
+ Sub["substitution
${env:} ${date:} ${uuid}"]
+ end
+
+ subgraph Reliability["可靠性"]
+ Retry["retry
@retry_on_transient"]
+ QuotaMod["Quota
字节 + 时间配额"]
+ Breaker["CircuitBreaker"]
+ RL["RateLimiter"]
+ Locks["FileLock · SQLiteLock"]
+ end
+
+ subgraph Observability["可观测性"]
+ Progress["progress
CancellationToken · Reporter"]
+ Metrics["metrics
Prometheus counters + histograms"]
+ Audit["AuditLog
SQLite 审计日志"]
+ Tracing["tracing
OpenTelemetry spans"]
+ FIM["IntegrityMonitor"]
+ end
+
+ subgraph Security["安全 & 配置"]
+ Secrets["Secret providers
Env · File · Chained"]
+ Config["AutomationConfig
TOML 加载器"]
+ ConfW["ConfigWatcher
热重载"]
+ Crypto["crypto
AES-256-GCM"]
+ Check["checksum / manifest"]
+ SafeP["safe_paths
safe_join · is_within"]
+ ACL["ActionACL"]
+ end
+
+ subgraph Events["事件驱动"]
+ Trigger["TriggerManager
watchdog 文件监听"]
+ Sched["Scheduler
5-field cron + overlap guard"]
+ end
+
+ subgraph Servers["服务器"]
+ TCP["TCPActionServer
loopback · AUTH secret"]
+ HTTPS["HTTPActionServer
POST /actions · Bearer
/healthz /readyz /progress /openapi.json"]
+ MCP["MCPServer
JSON-RPC 2.0 (stdio)"]
+ MetSrv["MetricsServer
/metrics"]
+ WebUI["WebUIServer
HTMX dashboard"]
+ end
+
+ subgraph UI["ui (PySide6)"]
+ MainWin["MainWindow
Home · Local · HTTP · Drive · S3 · Azure · Dropbox
SFTP · OneDrive · Box · JSON · Triggers · Scheduler
Progress · Transfer · Servers"]
+ Worker["ActionWorker
QRunnable on QThreadPool"]
+ end
+
+ subgraph Local["本地 ops"]
+ FileOps["file_ops · dir_ops"]
+ Archives["zip_ops · tar_ops · archive_ops"]
+ DataOps["data_ops
csv · jsonl · parquet · yaml"]
+ TextOps["text_ops · diff_ops
json_edit · templates"]
+ Misc["shell_ops · sync_ops · trash
versioning · conditional · mime"]
+ end
+
+ subgraph Remote["远程后端"]
+ UrlVal["url_validator
SSRF 保护"]
+ Http["http_download
retry · resume · SHA-256"]
+ Drive["google_drive"]
+ S3M["s3"]
+ Azure["azure_blob"]
+ Dropbox["dropbox_api"]
+ SFTP["sftp (RejectPolicy)"]
+ FTP["ftp / FTPS"]
+ OneD["onedrive"]
+ Box["box"]
+ WebDAV["webdav"]
+ SMB["smb / cifs"]
+ Fsspec["fsspec_bridge"]
+ Cross["cross_backend
local:// s3:// drive:// azure://
dropbox:// sftp:// ftp://"]
+ end
+
+ subgraph Notify["通知"]
+ NM["NotificationManager
fanout · dedup · SSRF guard"]
+ Sinks["Sinks
Webhook · Slack · Email
Telegram · Discord · Teams · PagerDuty"]
+ end
+
+ subgraph Utils["工具 / 项目"]
+ Fast["fast_find
mdfind / locate / es.exe"]
+ Dedup["find_duplicates"]
+ Grep["grep_files"]
+ Rotate["rotate_backups"]
+ Discovery["file_discovery"]
+ Builder["ProjectBuilder + templates"]
+ end
+
+ CLI ==> PublicAPI
+ GUIUser ==> MainWin
+ ClientSDK ==> HTTPS
+ MCPHost ==> MCP
+ Plugins ==> Loader
+
+ MainWin ==> Worker
+ Worker ==> PublicAPI
+
+ PublicAPI ==> Executor
+ PublicAPI ==> DAG
+ PublicAPI ==> Callback
+ PublicAPI ==> Queue
+ PublicAPI ==> Config
+ PublicAPI ==> NM
+ PublicAPI ==> Trigger
+ PublicAPI ==> Sched
+
+ TCP ==> Executor
+ HTTPS ==> Executor
+ MCP ==> Registry
+ MetSrv ==> Metrics
+ WebUI ==> Registry
+ ACL ==> TCP
+ ACL ==> HTTPS
+
+ Executor ==> Registry
+ Executor ==> Sub
+ Executor ==> Retry
+ Executor ==> QuotaMod
+ Executor ==> Metrics
+ Executor ==> Audit
+ Executor ==> Tracing
+ Executor ==> Json
+ DAG ==> Executor
+ Callback ==> Registry
+ Loader ==> Registry
+
+ Trigger ==> Executor
+ Sched ==> Executor
+ Trigger -. 失败时 .-> NM
+ Sched -. 失败时 .-> NM
+ FIM -. 检测到变动 .-> NM
+ ConfW ==> Config
+ Config ==> Secrets
+ Config ==> NM
+
+ Registry ==> FileOps
+ Registry ==> Archives
+ Registry ==> DataOps
+ Registry ==> TextOps
+ Registry ==> Misc
+ Registry ==> Http
+ Registry ==> Drive
+ Registry ==> S3M
+ Registry ==> Azure
+ Registry ==> Dropbox
+ Registry ==> SFTP
+ Registry ==> FTP
+ Registry ==> OneD
+ Registry ==> Box
+ Registry ==> WebDAV
+ Registry ==> SMB
+ Registry ==> Fsspec
+ Registry ==> Cross
+ Registry ==> Crypto
+ Registry ==> Check
+ Registry ==> Fast
+ Registry ==> Dedup
+ Registry ==> Grep
+ Registry ==> Rotate
+ Registry ==> Discovery
+ Registry ==> Builder
+ Registry ==> Progress
+
+ FileOps ==> SafeP
+ Archives ==> SafeP
+ Misc ==> SafeP
+
+ Http ==> UrlVal
+ Http ==> Retry
+ Http ==> Progress
+ Http ==> Check
+ S3M ==> Progress
+ WebDAV ==> UrlVal
+ NM ==> UrlVal
+ NM ==> Sinks
+
+ Cross ==> Drive
+ Cross ==> S3M
+ Cross ==> Azure
+ Cross ==> Dropbox
+ Cross ==> SFTP
+ Cross ==> FTP
+
+ classDef entry fill:#FDEDEC,stroke:#641E16,stroke-width:3px,color:#000,font-weight:bold;
+ classDef facade fill:#D6EAF8,stroke:#154360,stroke-width:4px,color:#000,font-weight:bold;
+ classDef core fill:#FEF9E7,stroke:#1F3A93,stroke-width:3px,color:#000,font-weight:bold;
+ classDef rel fill:#D1F2EB,stroke:#0B5345,stroke-width:3px,color:#000,font-weight:bold;
+ classDef obs fill:#FDEBD0,stroke:#9C640C,stroke-width:3px,color:#000,font-weight:bold;
+ classDef sec fill:#F5B7B1,stroke:#78281F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef event fill:#FCF3CF,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef server fill:#FADBD8,stroke:#922B21,stroke-width:3px,color:#000,font-weight:bold;
+ classDef ui fill:#AED6F1,stroke:#1B4F72,stroke-width:3px,color:#000,font-weight:bold;
+ classDef localOps fill:#E8DAEF,stroke:#512E5F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef remote fill:#D5F5E3,stroke:#196F3D,stroke-width:3px,color:#000,font-weight:bold;
+ classDef notify fill:#F9E79F,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef utils fill:#EAEDED,stroke:#212F3C,stroke-width:3px,color:#000,font-weight:bold;
+
+ class CLI,GUIUser,ClientSDK,MCPHost,Plugins entry;
+ class PublicAPI facade;
+ class Registry,Executor,DAG,Callback,Loader,Queue,Json,Sub core;
+ class Retry,QuotaMod,Breaker,RL,Locks rel;
+ class Progress,Metrics,Audit,Tracing,FIM obs;
+ class Secrets,Config,ConfW,Crypto,Check,SafeP,ACL sec;
+ class Trigger,Sched event;
+ class TCP,HTTPS,MCP,MetSrv,WebUI server;
+ class MainWin,Worker ui;
+ class FileOps,Archives,DataOps,TextOps,Misc localOps;
+ class UrlVal,Http,Drive,S3M,Azure,Dropbox,SFTP,FTP,OneD,Box,WebDAV,SMB,Fsspec,Cross remote;
+ class NM,Sinks notify;
+ class Fast,Dedup,Grep,Rotate,Discovery,Builder utils;
+
+ linkStyle default stroke:#1F2A44,stroke-width:2.5px;
+
+设计模式
+--------
+
**Facade(外观)**
:mod:`automation_file`(顶层 ``__init__``)是使用者唯一需要导入的名称。
所有公开函数与单例都从这里重新导出。
diff --git a/docs/source.zh-CN/conf.py b/docs/source.zh-CN/conf.py
index e806d0c..4eb678b 100644
--- a/docs/source.zh-CN/conf.py
+++ b/docs/source.zh-CN/conf.py
@@ -22,6 +22,7 @@
"sphinx.ext.viewcode",
"sphinx.ext.intersphinx",
"myst_parser",
+ "sphinxcontrib.mermaid",
]
templates_path = ["../source/_templates"]
diff --git a/docs/source.zh-TW/architecture.rst b/docs/source.zh-TW/architecture.rst
index 18dccbb..706d584 100644
--- a/docs/source.zh-TW/architecture.rst
+++ b/docs/source.zh-TW/architecture.rst
@@ -3,6 +3,249 @@
``automation_file`` 採用分層架構,核心由五種設計模式組成:
+系統總覽
+--------
+
+下圖展示完整的派送表面:任何呼叫端——CLI、GUI、HTTP/MCP 客戶端、進入點外掛
+——最終都會落到由 ``build_default_registry()`` 填充的共用 ``ActionRegistry``,
+再從 registry 向本地 ops、遠端後端、可靠性 / 安全 / 可觀測性輔助工具、通知、
+以及事件驅動的觸發器與 cron 排程器扇出。
+
+.. mermaid::
+
+ flowchart TD
+ CLI["CLI / JSON 批次
python -m automation_file"]
+ GUIUser["PySide6 GUI
launch_ui"]
+ ClientSDK["HTTPActionClient SDK"]
+ MCPHost["MCP 主機
Claude Desktop · MCP CLIs"]
+ Plugins["進入點外掛
automation_file.actions"]
+
+ subgraph Facade["automation_file — 門面 (__init__.py)"]
+ PublicAPI["Public API
execute_action · execute_action_parallel · execute_action_dag
validate_action · driver_instance · s3_instance · azure_blob_instance
dropbox_instance · sftp_instance · ftp_instance · onedrive_instance · box_instance
start_autocontrol_socket_server · start_http_action_server
start_metrics_server · start_web_ui · MCPServer
notification_manager · scheduler · trigger_manager
AutomationConfig · progress_registry · Quota · retry_on_transient"]
+ end
+
+ subgraph Core["core 核心"]
+ Registry[("ActionRegistry
FA_* 指令")]
+ Executor["ActionExecutor
序列 · 並行 · dry-run · validate-first"]
+ DAG["dag_executor
拓樸排程 fan-out"]
+ Callback["CallbackExecutor"]
+ Loader["PackageLoader
+ 進入點外掛"]
+ Queue["ActionQueue"]
+ Json["json_store"]
+ Sub["substitution
${env:} ${date:} ${uuid}"]
+ end
+
+ subgraph Reliability["可靠性"]
+ Retry["retry
@retry_on_transient"]
+ QuotaMod["Quota
位元組 + 時間配額"]
+ Breaker["CircuitBreaker"]
+ RL["RateLimiter"]
+ Locks["FileLock · SQLiteLock"]
+ end
+
+ subgraph Observability["可觀測性"]
+ Progress["progress
CancellationToken · Reporter"]
+ Metrics["metrics
Prometheus counters + histograms"]
+ Audit["AuditLog
SQLite 稽核紀錄"]
+ Tracing["tracing
OpenTelemetry spans"]
+ FIM["IntegrityMonitor"]
+ end
+
+ subgraph Security["安全 & 設定"]
+ Secrets["Secret providers
Env · File · Chained"]
+ Config["AutomationConfig
TOML 載入器"]
+ ConfW["ConfigWatcher
熱重載"]
+ Crypto["crypto
AES-256-GCM"]
+ Check["checksum / manifest"]
+ SafeP["safe_paths
safe_join · is_within"]
+ ACL["ActionACL"]
+ end
+
+ subgraph Events["事件驅動"]
+ Trigger["TriggerManager
watchdog 檔案監聽"]
+ Sched["Scheduler
5-field cron + overlap guard"]
+ end
+
+ subgraph Servers["伺服器"]
+ TCP["TCPActionServer
loopback · AUTH secret"]
+ HTTPS["HTTPActionServer
POST /actions · Bearer
/healthz /readyz /progress /openapi.json"]
+ MCP["MCPServer
JSON-RPC 2.0 (stdio)"]
+ MetSrv["MetricsServer
/metrics"]
+ WebUI["WebUIServer
HTMX dashboard"]
+ end
+
+ subgraph UI["ui (PySide6)"]
+ MainWin["MainWindow
Home · Local · HTTP · Drive · S3 · Azure · Dropbox
SFTP · OneDrive · Box · JSON · Triggers · Scheduler
Progress · Transfer · Servers"]
+ Worker["ActionWorker
QRunnable on QThreadPool"]
+ end
+
+ subgraph Local["本地 ops"]
+ FileOps["file_ops · dir_ops"]
+ Archives["zip_ops · tar_ops · archive_ops"]
+ DataOps["data_ops
csv · jsonl · parquet · yaml"]
+ TextOps["text_ops · diff_ops
json_edit · templates"]
+ Misc["shell_ops · sync_ops · trash
versioning · conditional · mime"]
+ end
+
+ subgraph Remote["遠端後端"]
+ UrlVal["url_validator
SSRF 防護"]
+ Http["http_download
retry · resume · SHA-256"]
+ Drive["google_drive"]
+ S3M["s3"]
+ Azure["azure_blob"]
+ Dropbox["dropbox_api"]
+ SFTP["sftp (RejectPolicy)"]
+ FTP["ftp / FTPS"]
+ OneD["onedrive"]
+ Box["box"]
+ WebDAV["webdav"]
+ SMB["smb / cifs"]
+ Fsspec["fsspec_bridge"]
+ Cross["cross_backend
local:// s3:// drive:// azure://
dropbox:// sftp:// ftp://"]
+ end
+
+ subgraph Notify["通知"]
+ NM["NotificationManager
fanout · dedup · SSRF guard"]
+ Sinks["Sinks
Webhook · Slack · Email
Telegram · Discord · Teams · PagerDuty"]
+ end
+
+ subgraph Utils["工具 / 專案"]
+ Fast["fast_find
mdfind / locate / es.exe"]
+ Dedup["find_duplicates"]
+ Grep["grep_files"]
+ Rotate["rotate_backups"]
+ Discovery["file_discovery"]
+ Builder["ProjectBuilder + templates"]
+ end
+
+ CLI ==> PublicAPI
+ GUIUser ==> MainWin
+ ClientSDK ==> HTTPS
+ MCPHost ==> MCP
+ Plugins ==> Loader
+
+ MainWin ==> Worker
+ Worker ==> PublicAPI
+
+ PublicAPI ==> Executor
+ PublicAPI ==> DAG
+ PublicAPI ==> Callback
+ PublicAPI ==> Queue
+ PublicAPI ==> Config
+ PublicAPI ==> NM
+ PublicAPI ==> Trigger
+ PublicAPI ==> Sched
+
+ TCP ==> Executor
+ HTTPS ==> Executor
+ MCP ==> Registry
+ MetSrv ==> Metrics
+ WebUI ==> Registry
+ ACL ==> TCP
+ ACL ==> HTTPS
+
+ Executor ==> Registry
+ Executor ==> Sub
+ Executor ==> Retry
+ Executor ==> QuotaMod
+ Executor ==> Metrics
+ Executor ==> Audit
+ Executor ==> Tracing
+ Executor ==> Json
+ DAG ==> Executor
+ Callback ==> Registry
+ Loader ==> Registry
+
+ Trigger ==> Executor
+ Sched ==> Executor
+ Trigger -. 失敗時 .-> NM
+ Sched -. 失敗時 .-> NM
+ FIM -. 偵測到異動 .-> NM
+ ConfW ==> Config
+ Config ==> Secrets
+ Config ==> NM
+
+ Registry ==> FileOps
+ Registry ==> Archives
+ Registry ==> DataOps
+ Registry ==> TextOps
+ Registry ==> Misc
+ Registry ==> Http
+ Registry ==> Drive
+ Registry ==> S3M
+ Registry ==> Azure
+ Registry ==> Dropbox
+ Registry ==> SFTP
+ Registry ==> FTP
+ Registry ==> OneD
+ Registry ==> Box
+ Registry ==> WebDAV
+ Registry ==> SMB
+ Registry ==> Fsspec
+ Registry ==> Cross
+ Registry ==> Crypto
+ Registry ==> Check
+ Registry ==> Fast
+ Registry ==> Dedup
+ Registry ==> Grep
+ Registry ==> Rotate
+ Registry ==> Discovery
+ Registry ==> Builder
+ Registry ==> Progress
+
+ FileOps ==> SafeP
+ Archives ==> SafeP
+ Misc ==> SafeP
+
+ Http ==> UrlVal
+ Http ==> Retry
+ Http ==> Progress
+ Http ==> Check
+ S3M ==> Progress
+ WebDAV ==> UrlVal
+ NM ==> UrlVal
+ NM ==> Sinks
+
+ Cross ==> Drive
+ Cross ==> S3M
+ Cross ==> Azure
+ Cross ==> Dropbox
+ Cross ==> SFTP
+ Cross ==> FTP
+
+ classDef entry fill:#FDEDEC,stroke:#641E16,stroke-width:3px,color:#000,font-weight:bold;
+ classDef facade fill:#D6EAF8,stroke:#154360,stroke-width:4px,color:#000,font-weight:bold;
+ classDef core fill:#FEF9E7,stroke:#1F3A93,stroke-width:3px,color:#000,font-weight:bold;
+ classDef rel fill:#D1F2EB,stroke:#0B5345,stroke-width:3px,color:#000,font-weight:bold;
+ classDef obs fill:#FDEBD0,stroke:#9C640C,stroke-width:3px,color:#000,font-weight:bold;
+ classDef sec fill:#F5B7B1,stroke:#78281F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef event fill:#FCF3CF,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef server fill:#FADBD8,stroke:#922B21,stroke-width:3px,color:#000,font-weight:bold;
+ classDef ui fill:#AED6F1,stroke:#1B4F72,stroke-width:3px,color:#000,font-weight:bold;
+ classDef localOps fill:#E8DAEF,stroke:#512E5F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef remote fill:#D5F5E3,stroke:#196F3D,stroke-width:3px,color:#000,font-weight:bold;
+ classDef notify fill:#F9E79F,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef utils fill:#EAEDED,stroke:#212F3C,stroke-width:3px,color:#000,font-weight:bold;
+
+ class CLI,GUIUser,ClientSDK,MCPHost,Plugins entry;
+ class PublicAPI facade;
+ class Registry,Executor,DAG,Callback,Loader,Queue,Json,Sub core;
+ class Retry,QuotaMod,Breaker,RL,Locks rel;
+ class Progress,Metrics,Audit,Tracing,FIM obs;
+ class Secrets,Config,ConfW,Crypto,Check,SafeP,ACL sec;
+ class Trigger,Sched event;
+ class TCP,HTTPS,MCP,MetSrv,WebUI server;
+ class MainWin,Worker ui;
+ class FileOps,Archives,DataOps,TextOps,Misc localOps;
+ class UrlVal,Http,Drive,S3M,Azure,Dropbox,SFTP,FTP,OneD,Box,WebDAV,SMB,Fsspec,Cross remote;
+ class NM,Sinks notify;
+ class Fast,Dedup,Grep,Rotate,Discovery,Builder utils;
+
+ linkStyle default stroke:#1F2A44,stroke-width:2.5px;
+
+設計模式
+--------
+
**Facade(外觀)**
:mod:`automation_file`(頂層 ``__init__``)是使用者唯一需要匯入的名稱。
所有公開函式與單例都從這裡重新匯出。
diff --git a/docs/source.zh-TW/conf.py b/docs/source.zh-TW/conf.py
index 9304ca5..318e9eb 100644
--- a/docs/source.zh-TW/conf.py
+++ b/docs/source.zh-TW/conf.py
@@ -22,6 +22,7 @@
"sphinx.ext.viewcode",
"sphinx.ext.intersphinx",
"myst_parser",
+ "sphinxcontrib.mermaid",
]
templates_path = ["../source/_templates"]
diff --git a/docs/source/architecture.rst b/docs/source/architecture.rst
index cc58f07..dc23e8a 100644
--- a/docs/source/architecture.rst
+++ b/docs/source/architecture.rst
@@ -4,6 +4,251 @@ Architecture
``automation_file`` follows a layered architecture built around five design
patterns:
+System overview
+---------------
+
+The diagram below shows the full dispatch surface: every caller — CLI, GUI,
+HTTP/MCP clients, entry-point plugins — eventually lands in the shared
+``ActionRegistry`` that ``build_default_registry()`` populates, and the
+registry fans out to local ops, remote backends, reliability / security /
+observability helpers, notifications, and the event-driven trigger + cron
+dispatchers.
+
+.. mermaid::
+
+ flowchart TD
+ CLI["CLI / JSON batch
python -m automation_file"]
+ GUIUser["PySide6 GUI
launch_ui"]
+ ClientSDK["HTTPActionClient SDK"]
+ MCPHost["MCP hosts
Claude Desktop · MCP CLIs"]
+ Plugins["Entry-point plugins
automation_file.actions"]
+
+ subgraph Facade["automation_file — facade (__init__.py)"]
+ PublicAPI["Public API
execute_action · execute_action_parallel · execute_action_dag
validate_action · driver_instance · s3_instance · azure_blob_instance
dropbox_instance · sftp_instance · ftp_instance · onedrive_instance · box_instance
start_autocontrol_socket_server · start_http_action_server
start_metrics_server · start_web_ui · MCPServer
notification_manager · scheduler · trigger_manager
AutomationConfig · progress_registry · Quota · retry_on_transient"]
+ end
+
+ subgraph Core["core"]
+ Registry[("ActionRegistry
FA_* commands")]
+ Executor["ActionExecutor
serial · parallel · dry-run · validate-first"]
+ DAG["dag_executor
topological fan-out"]
+ Callback["CallbackExecutor"]
+ Loader["PackageLoader
+ entry-point plugins"]
+ Queue["ActionQueue"]
+ Json["json_store"]
+ Sub["substitution
${env:} ${date:} ${uuid}"]
+ end
+
+ subgraph Reliability["reliability"]
+ Retry["retry
@retry_on_transient"]
+ QuotaMod["Quota
bytes + time budget"]
+ Breaker["CircuitBreaker"]
+ RL["RateLimiter"]
+ Locks["FileLock · SQLiteLock"]
+ end
+
+ subgraph Observability["observability"]
+ Progress["progress
CancellationToken · Reporter"]
+ Metrics["metrics
Prometheus counters + histograms"]
+ Audit["AuditLog
SQLite"]
+ Tracing["tracing
OpenTelemetry spans"]
+ FIM["IntegrityMonitor"]
+ end
+
+ subgraph Security["security & config"]
+ Secrets["Secret providers
Env · File · Chained"]
+ Config["AutomationConfig
TOML loader"]
+ ConfW["ConfigWatcher
hot reload"]
+ Crypto["crypto
AES-256-GCM"]
+ Check["checksum / manifest"]
+ SafeP["safe_paths
safe_join · is_within"]
+ ACL["ActionACL"]
+ end
+
+ subgraph Events["event-driven"]
+ Trigger["TriggerManager
watchdog file watcher"]
+ Sched["Scheduler
5-field cron + overlap guard"]
+ end
+
+ subgraph Servers["servers"]
+ TCP["TCPActionServer
loopback · AUTH secret"]
+ HTTPS["HTTPActionServer
POST /actions · Bearer
/healthz /readyz /progress /openapi.json"]
+ MCP["MCPServer
JSON-RPC 2.0 (stdio)"]
+ MetSrv["MetricsServer
/metrics"]
+ WebUI["WebUIServer
HTMX dashboard"]
+ end
+
+ subgraph UI["ui (PySide6)"]
+ MainWin["MainWindow
Home · Local · HTTP · Drive · S3 · Azure · Dropbox
SFTP · OneDrive · Box · JSON · Triggers · Scheduler
Progress · Transfer · Servers"]
+ Worker["ActionWorker
QRunnable on QThreadPool"]
+ end
+
+ subgraph Local["local ops"]
+ FileOps["file_ops · dir_ops"]
+ Archives["zip_ops · tar_ops · archive_ops"]
+ DataOps["data_ops
csv · jsonl · parquet · yaml"]
+ TextOps["text_ops · diff_ops
json_edit · templates"]
+ Misc["shell_ops · sync_ops · trash
versioning · conditional · mime"]
+ end
+
+ subgraph Remote["remote backends"]
+ UrlVal["url_validator
SSRF guard"]
+ Http["http_download
retry · resume · SHA-256"]
+ Drive["google_drive"]
+ S3M["s3"]
+ Azure["azure_blob"]
+ Dropbox["dropbox_api"]
+ SFTP["sftp (RejectPolicy)"]
+ FTP["ftp / FTPS"]
+ OneD["onedrive"]
+ Box["box"]
+ WebDAV["webdav"]
+ SMB["smb / cifs"]
+ Fsspec["fsspec_bridge"]
+ Cross["cross_backend
local:// s3:// drive:// azure://
dropbox:// sftp:// ftp://"]
+ end
+
+ subgraph Notify["notifications"]
+ NM["NotificationManager
fanout · dedup · SSRF guard"]
+ Sinks["Sinks
Webhook · Slack · Email
Telegram · Discord · Teams · PagerDuty"]
+ end
+
+ subgraph Utils["utils / project"]
+ Fast["fast_find
mdfind / locate / es.exe"]
+ Dedup["find_duplicates"]
+ Grep["grep_files"]
+ Rotate["rotate_backups"]
+ Discovery["file_discovery"]
+ Builder["ProjectBuilder + templates"]
+ end
+
+ CLI ==> PublicAPI
+ GUIUser ==> MainWin
+ ClientSDK ==> HTTPS
+ MCPHost ==> MCP
+ Plugins ==> Loader
+
+ MainWin ==> Worker
+ Worker ==> PublicAPI
+
+ PublicAPI ==> Executor
+ PublicAPI ==> DAG
+ PublicAPI ==> Callback
+ PublicAPI ==> Queue
+ PublicAPI ==> Config
+ PublicAPI ==> NM
+ PublicAPI ==> Trigger
+ PublicAPI ==> Sched
+
+ TCP ==> Executor
+ HTTPS ==> Executor
+ MCP ==> Registry
+ MetSrv ==> Metrics
+ WebUI ==> Registry
+ ACL ==> TCP
+ ACL ==> HTTPS
+
+ Executor ==> Registry
+ Executor ==> Sub
+ Executor ==> Retry
+ Executor ==> QuotaMod
+ Executor ==> Metrics
+ Executor ==> Audit
+ Executor ==> Tracing
+ Executor ==> Json
+ DAG ==> Executor
+ Callback ==> Registry
+ Loader ==> Registry
+
+ Trigger ==> Executor
+ Sched ==> Executor
+ Trigger -. on failure .-> NM
+ Sched -. on failure .-> NM
+ FIM -. on drift .-> NM
+ ConfW ==> Config
+ Config ==> Secrets
+ Config ==> NM
+
+ Registry ==> FileOps
+ Registry ==> Archives
+ Registry ==> DataOps
+ Registry ==> TextOps
+ Registry ==> Misc
+ Registry ==> Http
+ Registry ==> Drive
+ Registry ==> S3M
+ Registry ==> Azure
+ Registry ==> Dropbox
+ Registry ==> SFTP
+ Registry ==> FTP
+ Registry ==> OneD
+ Registry ==> Box
+ Registry ==> WebDAV
+ Registry ==> SMB
+ Registry ==> Fsspec
+ Registry ==> Cross
+ Registry ==> Crypto
+ Registry ==> Check
+ Registry ==> Fast
+ Registry ==> Dedup
+ Registry ==> Grep
+ Registry ==> Rotate
+ Registry ==> Discovery
+ Registry ==> Builder
+ Registry ==> Progress
+
+ FileOps ==> SafeP
+ Archives ==> SafeP
+ Misc ==> SafeP
+
+ Http ==> UrlVal
+ Http ==> Retry
+ Http ==> Progress
+ Http ==> Check
+ S3M ==> Progress
+ WebDAV ==> UrlVal
+ NM ==> UrlVal
+ NM ==> Sinks
+
+ Cross ==> Drive
+ Cross ==> S3M
+ Cross ==> Azure
+ Cross ==> Dropbox
+ Cross ==> SFTP
+ Cross ==> FTP
+
+ classDef entry fill:#FDEDEC,stroke:#641E16,stroke-width:3px,color:#000,font-weight:bold;
+ classDef facade fill:#D6EAF8,stroke:#154360,stroke-width:4px,color:#000,font-weight:bold;
+ classDef core fill:#FEF9E7,stroke:#1F3A93,stroke-width:3px,color:#000,font-weight:bold;
+ classDef rel fill:#D1F2EB,stroke:#0B5345,stroke-width:3px,color:#000,font-weight:bold;
+ classDef obs fill:#FDEBD0,stroke:#9C640C,stroke-width:3px,color:#000,font-weight:bold;
+ classDef sec fill:#F5B7B1,stroke:#78281F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef event fill:#FCF3CF,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef server fill:#FADBD8,stroke:#922B21,stroke-width:3px,color:#000,font-weight:bold;
+ classDef ui fill:#AED6F1,stroke:#1B4F72,stroke-width:3px,color:#000,font-weight:bold;
+ classDef localOps fill:#E8DAEF,stroke:#512E5F,stroke-width:3px,color:#000,font-weight:bold;
+ classDef remote fill:#D5F5E3,stroke:#196F3D,stroke-width:3px,color:#000,font-weight:bold;
+ classDef notify fill:#F9E79F,stroke:#7D6608,stroke-width:3px,color:#000,font-weight:bold;
+ classDef utils fill:#EAEDED,stroke:#212F3C,stroke-width:3px,color:#000,font-weight:bold;
+
+ class CLI,GUIUser,ClientSDK,MCPHost,Plugins entry;
+ class PublicAPI facade;
+ class Registry,Executor,DAG,Callback,Loader,Queue,Json,Sub core;
+ class Retry,QuotaMod,Breaker,RL,Locks rel;
+ class Progress,Metrics,Audit,Tracing,FIM obs;
+ class Secrets,Config,ConfW,Crypto,Check,SafeP,ACL sec;
+ class Trigger,Sched event;
+ class TCP,HTTPS,MCP,MetSrv,WebUI server;
+ class MainWin,Worker ui;
+ class FileOps,Archives,DataOps,TextOps,Misc localOps;
+ class UrlVal,Http,Drive,S3M,Azure,Dropbox,SFTP,FTP,OneD,Box,WebDAV,SMB,Fsspec,Cross remote;
+ class NM,Sinks notify;
+ class Fast,Dedup,Grep,Rotate,Discovery,Builder utils;
+
+ linkStyle default stroke:#1F2A44,stroke-width:2.5px;
+
+Design patterns
+---------------
+
**Facade**
:mod:`automation_file` (the top-level ``__init__``) is the only name users
should need to import. Every public function and singleton is re-exported
diff --git a/docs/source/conf.py b/docs/source/conf.py
index edee8d7..9130b09 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -20,6 +20,7 @@
"sphinx.ext.viewcode",
"sphinx.ext.intersphinx",
"myst_parser",
+ "sphinxcontrib.mermaid",
]
templates_path = ["_templates"]