python-tty 0.1.7__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. python_tty-0.2.0/PKG-INFO +215 -0
  2. python_tty-0.2.0/README.md +184 -0
  3. python_tty-0.2.0/README_zh.md +184 -0
  4. {python_tty-0.1.7 → python_tty-0.2.0}/docs/LOG.md +221 -1
  5. {python_tty-0.1.7 → python_tty-0.2.0}/docs/context.md +1792 -53
  6. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/commands/decorators.py +4 -3
  7. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/commands/registry.py +21 -6
  8. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/config/__init__.py +6 -0
  9. python_tty-0.2.0/src/python_tty/config/config.py +201 -0
  10. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/console_factory.py +45 -0
  11. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/executor/execution.py +7 -0
  12. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/executor/executor.py +77 -13
  13. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/executor/models.py +13 -0
  14. python_tty-0.2.0/src/python_tty/frontends/rpc/__init__.py +10 -0
  15. python_tty-0.2.0/src/python_tty/frontends/rpc/core.py +319 -0
  16. python_tty-0.2.0/src/python_tty/frontends/rpc/proto/runtime.proto +54 -0
  17. python_tty-0.2.0/src/python_tty/frontends/rpc/server.py +68 -0
  18. python_tty-0.2.0/src/python_tty/frontends/web/__init__.py +9 -0
  19. python_tty-0.2.0/src/python_tty/frontends/web/core.py +65 -0
  20. python_tty-0.2.0/src/python_tty/frontends/web/server.py +31 -0
  21. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/meta/__init__.py +1 -0
  22. python_tty-0.2.0/src/python_tty/runtime/context.py +112 -0
  23. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/runtime/event_bus.py +6 -3
  24. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/runtime/jobs.py +27 -24
  25. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/runtime/router.py +26 -1
  26. python_tty-0.2.0/src/python_tty/session/__init__.py +13 -0
  27. python_tty-0.2.0/src/python_tty/session/callbacks.py +163 -0
  28. python_tty-0.2.0/src/python_tty/session/manager.py +469 -0
  29. python_tty-0.2.0/src/python_tty/session/models.py +17 -0
  30. python_tty-0.2.0/src/python_tty/session/policy.py +11 -0
  31. python_tty-0.2.0/src/python_tty/session/store.py +101 -0
  32. python_tty-0.2.0/src/python_tty/utils/table.py +276 -0
  33. python_tty-0.2.0/src/python_tty.egg-info/PKG-INFO +215 -0
  34. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty.egg-info/SOURCES.txt +11 -0
  35. python_tty-0.1.7/PKG-INFO +0 -79
  36. python_tty-0.1.7/README.md +0 -48
  37. python_tty-0.1.7/README_zh.md +0 -46
  38. python_tty-0.1.7/src/python_tty/config/config.py +0 -96
  39. python_tty-0.1.7/src/python_tty/frontends/web/__init__.py +0 -0
  40. python_tty-0.1.7/src/python_tty/runtime/context.py +0 -48
  41. python_tty-0.1.7/src/python_tty/utils/table.py +0 -126
  42. python_tty-0.1.7/src/python_tty.egg-info/PKG-INFO +0 -79
  43. python_tty-0.1.7/tests/__init__.py +0 -0
  44. {python_tty-0.1.7 → python_tty-0.2.0}/.github/workflows/python-publish.yml +0 -0
  45. {python_tty-0.1.7 → python_tty-0.2.0}/.gitignore +0 -0
  46. {python_tty-0.1.7 → python_tty-0.2.0}/LICENSE +0 -0
  47. {python_tty-0.1.7 → python_tty-0.2.0}/MANIFEST.in +0 -0
  48. {python_tty-0.1.7 → python_tty-0.2.0}/NOTICE +0 -0
  49. {python_tty-0.1.7 → python_tty-0.2.0}/demos/__init__.py +0 -0
  50. {python_tty-0.1.7 → python_tty-0.2.0}/demos/chat_room/__init__.py +0 -0
  51. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/__init__.py +0 -0
  52. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/commands/__init__.py +0 -0
  53. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/commands/root_commands.py +0 -0
  54. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/consoles/__init__.py +0 -0
  55. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/consoles/root.py +0 -0
  56. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/core/__init__.py +0 -0
  57. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/core/file_manager.py +0 -0
  58. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/exceptions/__init__.py +0 -0
  59. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/exceptions/console_exception.py +0 -0
  60. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/main.py +0 -0
  61. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/setup.py +0 -0
  62. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/utils/__init__.py +0 -0
  63. {python_tty-0.1.7 → python_tty-0.2.0}/demos/file_manager/utils/table.py +0 -0
  64. {python_tty-0.1.7 → python_tty-0.2.0}/pyproject.toml +0 -0
  65. {python_tty-0.1.7 → python_tty-0.2.0}/requirements.txt +0 -0
  66. {python_tty-0.1.7 → python_tty-0.2.0}/setup.cfg +0 -0
  67. {python_tty-0.1.7 → python_tty-0.2.0}/setup.py +0 -0
  68. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/__init__.py +0 -0
  69. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/audit/__init__.py +0 -0
  70. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/audit/sink.py +0 -0
  71. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/audit/ui_logger.py +0 -0
  72. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/commands/__init__.py +0 -0
  73. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/commands/core.py +0 -0
  74. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/commands/examples/__init__.py +0 -0
  75. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/commands/examples/root_commands.py +0 -0
  76. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/commands/examples/sub_commands.py +0 -0
  77. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/commands/general.py +0 -0
  78. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/commands/mixins.py +0 -0
  79. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/consoles/__init__.py +0 -0
  80. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/consoles/core.py +0 -0
  81. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/consoles/decorators.py +0 -0
  82. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/consoles/examples/__init__.py +0 -0
  83. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/consoles/examples/root_console.py +0 -0
  84. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/consoles/examples/sub_console.py +0 -0
  85. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/consoles/loader.py +0 -0
  86. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/consoles/manager.py +0 -0
  87. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/consoles/registry.py +0 -0
  88. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/exceptions/__init__.py +0 -0
  89. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/exceptions/console_exception.py +0 -0
  90. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/executor/__init__.py +0 -0
  91. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/frontends/__init__.py +0 -0
  92. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/runtime/__init__.py +0 -0
  93. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/runtime/events.py +0 -0
  94. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/runtime/provider.py +0 -0
  95. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/runtime/sinks.py +0 -0
  96. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/utils/__init__.py +0 -0
  97. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty/utils/tokenize.py +0 -0
  98. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty.egg-info/dependency_links.txt +0 -0
  99. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty.egg-info/requires.txt +0 -0
  100. {python_tty-0.1.7 → python_tty-0.2.0}/src/python_tty.egg-info/top_level.txt +0 -0
  101. {python_tty-0.1.7/src/python_tty/frontends/rpc → python_tty-0.2.0/tests}/__init__.py +0 -0
@@ -0,0 +1,215 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-tty
3
+ Version: 0.2.0
4
+ Summary: A multi-console TTY framework for complex CLI/TTY apps
5
+ Home-page: https://github.com/ROOKIEMIE/python-tty
6
+ Author: ROOKIEMIE
7
+ License: Apache-2.0
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ License-File: NOTICE
15
+ Requires-Dist: fastapi>=0.110.0
16
+ Requires-Dist: grpcio>=1.60.0
17
+ Requires-Dist: prompt_toolkit>=3.0.32
18
+ Requires-Dist: protobuf>=4.25.0
19
+ Requires-Dist: tqdm
20
+ Requires-Dist: uvicorn>=0.27.0
21
+ Dynamic: author
22
+ Dynamic: classifier
23
+ Dynamic: description
24
+ Dynamic: description-content-type
25
+ Dynamic: home-page
26
+ Dynamic: license
27
+ Dynamic: license-file
28
+ Dynamic: requires-dist
29
+ Dynamic: requires-python
30
+ Dynamic: summary
31
+
32
+ # Command Line Framework (TTY + Executor + RPC/Web)
33
+
34
+ [中文](README_zh.md)
35
+
36
+ This project focuses on the TTY core while providing a unified executor, runtime events, RPC/Web frontends, and session management for complex CLI/TTY apps and lightweight service endpoints.
37
+
38
+ ## Concepts
39
+
40
+ Console layer:
41
+ - `python_tty/consoles/core.py`: `BaseConsole`, `MainConsole`, `SubConsole`
42
+ - `python_tty/consoles/manager.py` and `python_tty/consoles/registry.py` for lifecycle and registration
43
+
44
+ Commands layer:
45
+ - `python_tty/commands/core.py`: `BaseCommands`, `CommandValidator`
46
+ - `python_tty/commands/registry.py`: `CommandRegistry`, `ArgSpec`
47
+ - `python_tty/commands/general.py`: `GeneralValidator`, `GeneralCompleter`
48
+ - `python_tty/commands/mixins.py`: `CommandMixin` and built-in mixins
49
+
50
+ Execution and runtime:
51
+ - `python_tty/executor/executor.py`: `CommandExecutor` (unified execution entry)
52
+ - `python_tty/runtime/jobs.py`: `JobStore` (RunState/Invocation/event history)
53
+ - `python_tty/runtime/events.py`: `RuntimeEvent`, `UIEvent`, `UIEventLevel`
54
+ - `python_tty/runtime/router.py`: `proxy_print` and output routing
55
+
56
+ Session and callbacks:
57
+ - `python_tty/session/manager.py`: `SessionManager` (lifecycle + submit + constraints)
58
+ - `python_tty/session/store.py`: `SessionStore` (in-memory session state)
59
+ - `python_tty/session/callbacks.py`: callback subscriptions (thread-safe cancel)
60
+
61
+ RPC/Web:
62
+ - `python_tty/frontends/rpc`: gRPC Invoke + event streaming
63
+ - `python_tty/frontends/web`: FastAPI + WS snapshot (Meta)
64
+
65
+ Table rendering:
66
+ - `python_tty/utils/table.py`: table rendering (auto wrap supported)
67
+
68
+ TTY / RPC scheduling logic in Executor:
69
+ - TTY: builds `Invocation`, submits via `executor.submit_threadsafe()`, workers emit `RuntimeEvent`.
70
+ - RPC: builds `Invocation`, enforces exposure/allowlist/audit, `StreamEvents` subscribes to event queues.
71
+
72
+ ## Configuration
73
+
74
+ Config entry is `python_tty/config/config.py`.
75
+
76
+ ConsoleFactoryConfig:
77
+ - `run_mode`: `"tty"` or `"concurrent"`; decides whether the main thread runs the loop + TTY thread.
78
+ - `start_executor`: auto-start executor on factory start.
79
+ - `executor_in_thread`: start executor in a background thread in TTY mode.
80
+ - `executor_thread_name`: executor loop thread name.
81
+ - `tty_thread_name`: TTY thread name in concurrent mode.
82
+ - `shutdown_executor`: shutdown executor when factory stops.
83
+
84
+ ExecutorConfig:
85
+ - `workers`: number of workers (execution concurrency).
86
+ - `retain_last_n`: keep last N completed runs in memory.
87
+ - `ttl_seconds`: TTL for completed runs.
88
+ - `pop_on_wait`: drop run state after wait_result.
89
+ - `exempt_exceptions`: treat these as cancellation.
90
+ - `emit_run_events`: emit start/success/failure state events.
91
+ - `event_history_max`: max events per run.
92
+ - `event_history_ttl`: TTL for per-run history.
93
+ - `sync_in_threadpool`: run sync handlers in a thread pool.
94
+ - `threadpool_workers`: max thread pool workers.
95
+ - `audit`: `AuditConfig` for audit sink.
96
+
97
+ AuditConfig:
98
+ - `enabled`: enable audit.
99
+ - `file_path`: JSONL file output.
100
+ - `stream`: stream output (exclusive with file_path).
101
+ - `async_mode`: async writer mode.
102
+ - `flush_interval`: async flush interval.
103
+ - `keep_in_memory`: keep records in memory (tests).
104
+ - `sink`: custom AuditSink instance.
105
+
106
+ RPCConfig:
107
+ - `enabled`: start RPC server.
108
+ - `bind_host` / `port`: listen address and port.
109
+ - `max_message_bytes`: max gRPC message size.
110
+ - `keepalive_time_ms` / `keepalive_timeout_ms` / `keepalive_permit_without_calls`: keepalive options.
111
+ - `max_concurrent_rpcs`: max RPC concurrency.
112
+ - `max_streams_per_client`: max concurrent streams per client.
113
+ - `stream_backpressure_queue_size`: per-stream queue limit.
114
+ - `default_deny`: deny when exposure is missing.
115
+ - `require_rpc_exposed`: require `exposure.rpc=True`.
116
+ - `allowed_principals`: principal allowlist.
117
+ - `admin_principals`: admin principals (bypass allowlist only).
118
+ - `require_audit`: RPC requires audit sink.
119
+ - `trust_client_principal`: trust `request.principal` (default False).
120
+ - `mtls`: `MTLSServerConfig`.
121
+
122
+ MTLSServerConfig:
123
+ - `enabled`: enable mTLS.
124
+ - `server_cert_file` / `server_key_file`: server cert/key.
125
+ - `client_ca_file`: client CA bundle.
126
+ - `require_client_cert`: require client certs.
127
+ - `principal_keys`: auth_context keys for principal extraction.
128
+
129
+ WebConfig:
130
+ - `enabled`: start Web server.
131
+ - `bind_host` / `port`: listen address and port.
132
+ - `root_path`: reverse-proxy root path.
133
+ - `cors_*`: CORS options.
134
+ - `meta_enabled`: enable `/meta`.
135
+ - `meta_cache_control_max_age`: cache max-age for `/meta`.
136
+ - `ws_snapshot_enabled`: enable `/meta/snapshot` websocket.
137
+ - `ws_snapshot_include_jobs`: include running job summary.
138
+ - `ws_max_connections`: max WS connections.
139
+ - `ws_heartbeat_interval`: WS heartbeat seconds.
140
+ - `ws_send_queue_size`: WS send queue size.
141
+
142
+ Factory impact:
143
+ - `run_mode="tty"`: TTY runs on main thread; executor can be started in main or background thread.
144
+ - `run_mode="concurrent"`: main thread runs asyncio loop; TTY runs in background thread.
145
+ - `rpc.enabled=True` / `web.enabled=True`: services are attached during factory startup.
146
+ - `start_executor=False`: RPC/Web/Session submit will be unavailable or raise (no executor loop).
147
+
148
+ ## Examples
149
+
150
+ Quick start (TTY core):
151
+ 1. Define your consoles and commands (see examples in `python_tty/consoles/examples` and `python_tty/commands/examples`).
152
+ 2. Ensure console modules are imported so decorators can register them: update `DEFAULT_CONSOLE_MODULES` in `python_tty/consoles/loader.py` or call `load_consoles([...])`.
153
+ 3. Start the factory:
154
+ ```python
155
+ from python_tty.console_factory import ConsoleFactory
156
+
157
+ factory = ConsoleFactory(service=my_business_core)
158
+ factory.start()
159
+ ```
160
+
161
+ Job/Session basic usage:
162
+ ```python
163
+ from python_tty.console_factory import ConsoleFactory
164
+
165
+ factory = ConsoleFactory(service=my_service)
166
+ factory.start_executor()
167
+ sm = factory.session_manager
168
+
169
+ sid = sm.open_session(principal="local")
170
+ run_id = sm.submit_command(sid, "cmd:root:help")
171
+ result = await sm.result(run_id)
172
+ ```
173
+
174
+ Mode A: synchronous orchestration (outer awaits inner)
175
+ ```python
176
+ async def outer():
177
+ inner_id = sm.submit_command(sid, "cmd:root:long_task", await_result=True)
178
+ inner_result = await sm.result(inner_id)
179
+ return inner_result
180
+ ```
181
+
182
+ Mode B: async orchestration (callbacks)
183
+ ```python
184
+ def on_event(evt):
185
+ pass
186
+
187
+ def on_done(evt):
188
+ pass
189
+
190
+ inner_id = sm.submit_command(sid, "cmd:root:long_task")
191
+ sub_id = sm.register_callback(inner_id, on_event=on_event, on_done=on_done)
192
+ ```
193
+
194
+ Table rendering:
195
+ ```python
196
+ from python_tty.utils import Table
197
+
198
+ header = ["name", "status", "detail"]
199
+ data = [
200
+ ["job-1", "running", "very long text ..."],
201
+ ["job-2", "done", "short"],
202
+ ]
203
+
204
+ table = Table(header, data, title="jobs", wrap=True)
205
+ print(table)
206
+ ```
207
+
208
+ Single row (debug):
209
+ ```python
210
+ print(table.print_line(["job-3", "queued", "pending"]))
211
+ ```
212
+
213
+ ## 展望
214
+
215
+ 待定
@@ -0,0 +1,184 @@
1
+ # Command Line Framework (TTY + Executor + RPC/Web)
2
+
3
+ [中文](README_zh.md)
4
+
5
+ This project focuses on the TTY core while providing a unified executor, runtime events, RPC/Web frontends, and session management for complex CLI/TTY apps and lightweight service endpoints.
6
+
7
+ ## Concepts
8
+
9
+ Console layer:
10
+ - `python_tty/consoles/core.py`: `BaseConsole`, `MainConsole`, `SubConsole`
11
+ - `python_tty/consoles/manager.py` and `python_tty/consoles/registry.py` for lifecycle and registration
12
+
13
+ Commands layer:
14
+ - `python_tty/commands/core.py`: `BaseCommands`, `CommandValidator`
15
+ - `python_tty/commands/registry.py`: `CommandRegistry`, `ArgSpec`
16
+ - `python_tty/commands/general.py`: `GeneralValidator`, `GeneralCompleter`
17
+ - `python_tty/commands/mixins.py`: `CommandMixin` and built-in mixins
18
+
19
+ Execution and runtime:
20
+ - `python_tty/executor/executor.py`: `CommandExecutor` (unified execution entry)
21
+ - `python_tty/runtime/jobs.py`: `JobStore` (RunState/Invocation/event history)
22
+ - `python_tty/runtime/events.py`: `RuntimeEvent`, `UIEvent`, `UIEventLevel`
23
+ - `python_tty/runtime/router.py`: `proxy_print` and output routing
24
+
25
+ Session and callbacks:
26
+ - `python_tty/session/manager.py`: `SessionManager` (lifecycle + submit + constraints)
27
+ - `python_tty/session/store.py`: `SessionStore` (in-memory session state)
28
+ - `python_tty/session/callbacks.py`: callback subscriptions (thread-safe cancel)
29
+
30
+ RPC/Web:
31
+ - `python_tty/frontends/rpc`: gRPC Invoke + event streaming
32
+ - `python_tty/frontends/web`: FastAPI + WS snapshot (Meta)
33
+
34
+ Table rendering:
35
+ - `python_tty/utils/table.py`: table rendering (auto wrap supported)
36
+
37
+ TTY / RPC scheduling logic in Executor:
38
+ - TTY: builds `Invocation`, submits via `executor.submit_threadsafe()`, workers emit `RuntimeEvent`.
39
+ - RPC: builds `Invocation`, enforces exposure/allowlist/audit, `StreamEvents` subscribes to event queues.
40
+
41
+ ## Configuration
42
+
43
+ Config entry is `python_tty/config/config.py`.
44
+
45
+ ConsoleFactoryConfig:
46
+ - `run_mode`: `"tty"` or `"concurrent"`; decides whether the main thread runs the loop + TTY thread.
47
+ - `start_executor`: auto-start executor on factory start.
48
+ - `executor_in_thread`: start executor in a background thread in TTY mode.
49
+ - `executor_thread_name`: executor loop thread name.
50
+ - `tty_thread_name`: TTY thread name in concurrent mode.
51
+ - `shutdown_executor`: shutdown executor when factory stops.
52
+
53
+ ExecutorConfig:
54
+ - `workers`: number of workers (execution concurrency).
55
+ - `retain_last_n`: keep last N completed runs in memory.
56
+ - `ttl_seconds`: TTL for completed runs.
57
+ - `pop_on_wait`: drop run state after wait_result.
58
+ - `exempt_exceptions`: treat these as cancellation.
59
+ - `emit_run_events`: emit start/success/failure state events.
60
+ - `event_history_max`: max events per run.
61
+ - `event_history_ttl`: TTL for per-run history.
62
+ - `sync_in_threadpool`: run sync handlers in a thread pool.
63
+ - `threadpool_workers`: max thread pool workers.
64
+ - `audit`: `AuditConfig` for audit sink.
65
+
66
+ AuditConfig:
67
+ - `enabled`: enable audit.
68
+ - `file_path`: JSONL file output.
69
+ - `stream`: stream output (exclusive with file_path).
70
+ - `async_mode`: async writer mode.
71
+ - `flush_interval`: async flush interval.
72
+ - `keep_in_memory`: keep records in memory (tests).
73
+ - `sink`: custom AuditSink instance.
74
+
75
+ RPCConfig:
76
+ - `enabled`: start RPC server.
77
+ - `bind_host` / `port`: listen address and port.
78
+ - `max_message_bytes`: max gRPC message size.
79
+ - `keepalive_time_ms` / `keepalive_timeout_ms` / `keepalive_permit_without_calls`: keepalive options.
80
+ - `max_concurrent_rpcs`: max RPC concurrency.
81
+ - `max_streams_per_client`: max concurrent streams per client.
82
+ - `stream_backpressure_queue_size`: per-stream queue limit.
83
+ - `default_deny`: deny when exposure is missing.
84
+ - `require_rpc_exposed`: require `exposure.rpc=True`.
85
+ - `allowed_principals`: principal allowlist.
86
+ - `admin_principals`: admin principals (bypass allowlist only).
87
+ - `require_audit`: RPC requires audit sink.
88
+ - `trust_client_principal`: trust `request.principal` (default False).
89
+ - `mtls`: `MTLSServerConfig`.
90
+
91
+ MTLSServerConfig:
92
+ - `enabled`: enable mTLS.
93
+ - `server_cert_file` / `server_key_file`: server cert/key.
94
+ - `client_ca_file`: client CA bundle.
95
+ - `require_client_cert`: require client certs.
96
+ - `principal_keys`: auth_context keys for principal extraction.
97
+
98
+ WebConfig:
99
+ - `enabled`: start Web server.
100
+ - `bind_host` / `port`: listen address and port.
101
+ - `root_path`: reverse-proxy root path.
102
+ - `cors_*`: CORS options.
103
+ - `meta_enabled`: enable `/meta`.
104
+ - `meta_cache_control_max_age`: cache max-age for `/meta`.
105
+ - `ws_snapshot_enabled`: enable `/meta/snapshot` websocket.
106
+ - `ws_snapshot_include_jobs`: include running job summary.
107
+ - `ws_max_connections`: max WS connections.
108
+ - `ws_heartbeat_interval`: WS heartbeat seconds.
109
+ - `ws_send_queue_size`: WS send queue size.
110
+
111
+ Factory impact:
112
+ - `run_mode="tty"`: TTY runs on main thread; executor can be started in main or background thread.
113
+ - `run_mode="concurrent"`: main thread runs asyncio loop; TTY runs in background thread.
114
+ - `rpc.enabled=True` / `web.enabled=True`: services are attached during factory startup.
115
+ - `start_executor=False`: RPC/Web/Session submit will be unavailable or raise (no executor loop).
116
+
117
+ ## Examples
118
+
119
+ Quick start (TTY core):
120
+ 1. Define your consoles and commands (see examples in `python_tty/consoles/examples` and `python_tty/commands/examples`).
121
+ 2. Ensure console modules are imported so decorators can register them: update `DEFAULT_CONSOLE_MODULES` in `python_tty/consoles/loader.py` or call `load_consoles([...])`.
122
+ 3. Start the factory:
123
+ ```python
124
+ from python_tty.console_factory import ConsoleFactory
125
+
126
+ factory = ConsoleFactory(service=my_business_core)
127
+ factory.start()
128
+ ```
129
+
130
+ Job/Session basic usage:
131
+ ```python
132
+ from python_tty.console_factory import ConsoleFactory
133
+
134
+ factory = ConsoleFactory(service=my_service)
135
+ factory.start_executor()
136
+ sm = factory.session_manager
137
+
138
+ sid = sm.open_session(principal="local")
139
+ run_id = sm.submit_command(sid, "cmd:root:help")
140
+ result = await sm.result(run_id)
141
+ ```
142
+
143
+ Mode A: synchronous orchestration (outer awaits inner)
144
+ ```python
145
+ async def outer():
146
+ inner_id = sm.submit_command(sid, "cmd:root:long_task", await_result=True)
147
+ inner_result = await sm.result(inner_id)
148
+ return inner_result
149
+ ```
150
+
151
+ Mode B: async orchestration (callbacks)
152
+ ```python
153
+ def on_event(evt):
154
+ pass
155
+
156
+ def on_done(evt):
157
+ pass
158
+
159
+ inner_id = sm.submit_command(sid, "cmd:root:long_task")
160
+ sub_id = sm.register_callback(inner_id, on_event=on_event, on_done=on_done)
161
+ ```
162
+
163
+ Table rendering:
164
+ ```python
165
+ from python_tty.utils import Table
166
+
167
+ header = ["name", "status", "detail"]
168
+ data = [
169
+ ["job-1", "running", "very long text ..."],
170
+ ["job-2", "done", "short"],
171
+ ]
172
+
173
+ table = Table(header, data, title="jobs", wrap=True)
174
+ print(table)
175
+ ```
176
+
177
+ Single row (debug):
178
+ ```python
179
+ print(table.print_line(["job-3", "queued", "pending"]))
180
+ ```
181
+
182
+ ## 展望
183
+
184
+ 待定
@@ -0,0 +1,184 @@
1
+ # 命令行框架(TTY + Executor + RPC/Web)
2
+
3
+ [English](README.md)
4
+
5
+ 项目以 TTY 交互为核心,提供统一执行器、运行态事件、RPC/Web 前端与会话管理能力,适合构建复杂 CLI/TTY 应用与轻量服务化入口。
6
+
7
+ ## 概念
8
+
9
+ Console 层:
10
+ - `python_tty/consoles/core.py`:`BaseConsole`、`MainConsole`、`SubConsole`
11
+ - `python_tty/consoles/manager.py` 与 `python_tty/consoles/registry.py` 负责生命周期与注册
12
+
13
+ Commands 层:
14
+ - `python_tty/commands/core.py`:`BaseCommands`、`CommandValidator`
15
+ - `python_tty/commands/registry.py`:`CommandRegistry`、`ArgSpec`
16
+ - `python_tty/commands/general.py`:`GeneralValidator`、`GeneralCompleter`
17
+ - `python_tty/commands/mixins.py`:`CommandMixin` 及内置 mixins
18
+
19
+ 执行与运行态:
20
+ - `python_tty/executor/executor.py`:`CommandExecutor`(统一运行入口)
21
+ - `python_tty/runtime/jobs.py`:`JobStore`(RunState/Invocation/事件历史)
22
+ - `python_tty/runtime/events.py`:`RuntimeEvent`、`UIEvent`、`UIEventLevel`
23
+ - `python_tty/runtime/router.py`:`proxy_print` 与输出路由
24
+
25
+ 会话与回调:
26
+ - `python_tty/session/manager.py`:`SessionManager`(会话生命周期 + submit + 约束)
27
+ - `python_tty/session/store.py`:`SessionStore`(内存会话状态)
28
+ - `python_tty/session/callbacks.py`:回调订阅(线程安全取消)
29
+
30
+ RPC/Web:
31
+ - `python_tty/frontends/rpc`:gRPC Invoke + 事件流
32
+ - `python_tty/frontends/web`:FastAPI + WS snapshot(Meta)
33
+
34
+ 表格渲染:
35
+ - `python_tty/utils/table.py`:表格渲染(支持自动折行)
36
+
37
+ TTY / RPC 在 Executor 中的调度逻辑:
38
+ - TTY:构造 `Invocation`,通过 `executor.submit_threadsafe()` 提交,worker 执行并产出 `RuntimeEvent`。
39
+ - RPC:构造 `Invocation`,强制审计与 exposure/allowlist 校验后提交,`StreamEvents` 订阅事件队列。
40
+
41
+ ## 配置
42
+
43
+ Config 入口在 `python_tty/config/config.py`。
44
+
45
+ ConsoleFactoryConfig:
46
+ - `run_mode`: `"tty"` 或 `"concurrent"`,决定是否在主线程跑 loop + TTY 子线程。
47
+ - `start_executor`: 启动时是否自动启动 executor(影响 TTY/RPC/Web 是否可用)。
48
+ - `executor_in_thread`: TTY 模式下 executor 是否在后台线程运行。
49
+ - `executor_thread_name`: executor loop 线程名。
50
+ - `tty_thread_name`: concurrent 模式下 TTY 线程名。
51
+ - `shutdown_executor`: Factory 关闭时是否自动关闭 executor。
52
+
53
+ ExecutorConfig:
54
+ - `workers`: worker 数量,决定并发执行能力。
55
+ - `retain_last_n`: 内存中保留最近 N 条完成 run。
56
+ - `ttl_seconds`: 完成 run 的超时回收时间。
57
+ - `pop_on_wait`: `wait_result` 后是否移除 run。
58
+ - `exempt_exceptions`: 视为取消的异常类型。
59
+ - `emit_run_events`: 是否产生 start/success/failure 等状态事件。
60
+ - `event_history_max`: 每个 run 的事件缓存上限。
61
+ - `event_history_ttl`: 每个 run 的事件缓存 TTL。
62
+ - `sync_in_threadpool`: 同步 handler 是否进线程池。
63
+ - `threadpool_workers`: 同步线程池大小。
64
+ - `audit`: `AuditConfig` 审计配置。
65
+
66
+ AuditConfig:
67
+ - `enabled`: 启用审计。
68
+ - `file_path`: JSONL 文件路径。
69
+ - `stream`: 写入的 stream(与 file_path 二选一)。
70
+ - `async_mode`: 异步写入。
71
+ - `flush_interval`: 异步 flush 间隔。
72
+ - `keep_in_memory`: 内存缓冲(测试用)。
73
+ - `sink`: 自定义 AuditSink。
74
+
75
+ RPCConfig:
76
+ - `enabled`: 是否启动 RPC server。
77
+ - `bind_host` / `port`: 监听地址与端口。
78
+ - `max_message_bytes`: 最大消息大小。
79
+ - `keepalive_time_ms` / `keepalive_timeout_ms` / `keepalive_permit_without_calls`: keepalive 参数。
80
+ - `max_concurrent_rpcs`: RPC 并发上限。
81
+ - `max_streams_per_client`: 单客户端并发 stream 上限。
82
+ - `stream_backpressure_queue_size`: 每个 stream 的队列上限。
83
+ - `default_deny`: exposure 未设置时默认拒绝。
84
+ - `require_rpc_exposed`: 必须 `exposure.rpc=True` 才可 Invoke。
85
+ - `allowed_principals`: principal allowlist。
86
+ - `admin_principals`: 管理员 principal(仅绕过 allowlist,不绕过 exposure)。
87
+ - `require_audit`: RPC 必须启用审计。
88
+ - `trust_client_principal`: 是否信任 `request.principal`(默认 False)。
89
+ - `mtls`: `MTLSServerConfig`。
90
+
91
+ MTLSServerConfig:
92
+ - `enabled`: 是否启用 mTLS。
93
+ - `server_cert_file` / `server_key_file`: 服务端证书与私钥。
94
+ - `client_ca_file`: 客户端 CA。
95
+ - `require_client_cert`: 是否强制客户端证书。
96
+ - `principal_keys`: 从 auth_context 提取 principal 的 key 列表。
97
+
98
+ WebConfig:
99
+ - `enabled`: 是否启动 Web server。
100
+ - `bind_host` / `port`: 监听地址与端口。
101
+ - `root_path`: 反向代理根路径。
102
+ - `cors_*`: CORS 配置。
103
+ - `meta_enabled`: `/meta` 开关。
104
+ - `meta_cache_control_max_age`: `/meta` 缓存秒数。
105
+ - `ws_snapshot_enabled`: `/meta/snapshot` WS 开关。
106
+ - `ws_snapshot_include_jobs`: 是否包含运行中任务摘要。
107
+ - `ws_max_connections`: WS 最大连接数。
108
+ - `ws_heartbeat_interval`: WS 心跳间隔。
109
+ - `ws_send_queue_size`: WS 发送队列大小。
110
+
111
+ 对 Factory 启动的影响:
112
+ - `run_mode="tty"`: TTY 在主线程运行;executor 可在后台线程或主线程启动。
113
+ - `run_mode="concurrent"`: 主线程跑 asyncio loop,TTY 在后台线程运行;RPC/Web 与 executor 挂在主 loop。
114
+ - `rpc.enabled=True` / `web.enabled=True`: 会在 Factory 启动阶段挂载 RPC/Web 服务。
115
+ - `start_executor=False`: RPC/Web/Session submit 会不可用或抛错(依赖 executor loop)。
116
+
117
+ ## 示例
118
+
119
+ 快速开始(TTY 核心):
120
+ 1. 定义 consoles 与 commands(示例见 `python_tty/consoles/examples` 与 `python_tty/commands/examples`)。
121
+ 2. 确保 console 模块被导入以触发装饰器注册:修改 `python_tty/consoles/loader.py` 中的 `DEFAULT_CONSOLE_MODULES`,或手动调用 `load_consoles([...])`。
122
+ 3. 启动工厂:
123
+ ```python
124
+ from python_tty.console_factory import ConsoleFactory
125
+
126
+ factory = ConsoleFactory(service=my_business_core)
127
+ factory.start()
128
+ ```
129
+
130
+ Job/Session 基本使用:
131
+ ```python
132
+ from python_tty.console_factory import ConsoleFactory
133
+
134
+ factory = ConsoleFactory(service=my_service)
135
+ factory.start_executor()
136
+ sm = factory.session_manager
137
+
138
+ sid = sm.open_session(principal="local")
139
+ run_id = sm.submit_command(sid, "cmd:root:help")
140
+ result = await sm.result(run_id)
141
+ ```
142
+
143
+ 模式 A:同步编排(外层 await 内层):
144
+ ```python
145
+ async def outer():
146
+ inner_id = sm.submit_command(sid, "cmd:root:long_task", await_result=True)
147
+ inner_result = await sm.result(inner_id)
148
+ return inner_result
149
+ ```
150
+
151
+ 模式 B:异步编排(回调消费):
152
+ ```python
153
+ def on_event(evt):
154
+ pass
155
+
156
+ def on_done(evt):
157
+ pass
158
+
159
+ inner_id = sm.submit_command(sid, "cmd:root:long_task")
160
+ sub_id = sm.register_callback(inner_id, on_event=on_event, on_done=on_done)
161
+ ```
162
+
163
+ Table 渲染示例:
164
+ ```python
165
+ from python_tty.utils import Table
166
+
167
+ header = ["name", "status", "detail"]
168
+ data = [
169
+ ["job-1", "running", "very long text ..."],
170
+ ["job-2", "done", "short"],
171
+ ]
172
+
173
+ table = Table(header, data, title="jobs", wrap=True)
174
+ print(table)
175
+ ```
176
+
177
+ 单行渲染(调试):
178
+ ```python
179
+ print(table.print_line(["job-3", "queued", "pending"]))
180
+ ```
181
+
182
+ ## 展望
183
+
184
+ 待定