zettcode 0.1.0__tar.gz → 0.1.3__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.
- zettcode-0.1.3/.gitignore +21 -0
- zettcode-0.1.3/PKG-INFO +142 -0
- zettcode-0.1.3/README.md +111 -0
- zettcode-0.1.3/README.zh-CN.md +106 -0
- zettcode-0.1.3/pyproject.toml +110 -0
- zettcode-0.1.3/src/zettcode/__init__.py +47 -0
- zettcode-0.1.3/src/zettcode/_compat.py +35 -0
- zettcode-0.1.3/src/zettcode/app/__init__.py +63 -0
- zettcode-0.1.3/src/zettcode/app/agent/__init__.py +45 -0
- zettcode-0.1.3/src/zettcode/app/agent/agent.py +626 -0
- zettcode-0.1.3/src/zettcode/app/agent/approval.py +49 -0
- zettcode-0.1.3/src/zettcode/app/agent/ask.py +96 -0
- zettcode-0.1.3/src/zettcode/app/agent/blocks.py +367 -0
- zettcode-0.1.3/src/zettcode/app/agent/capabilities.py +44 -0
- zettcode-0.1.3/src/zettcode/app/agent/compaction.py +47 -0
- zettcode-0.1.3/src/zettcode/app/agent/context.py +293 -0
- zettcode-0.1.3/src/zettcode/app/agent/entries.py +191 -0
- zettcode-0.1.3/src/zettcode/app/agent/export.py +418 -0
- zettcode-0.1.3/src/zettcode/app/agent/mcp.py +29 -0
- zettcode-0.1.3/src/zettcode/app/agent/mentions.py +126 -0
- zettcode-0.1.3/src/zettcode/app/agent/projection.py +198 -0
- zettcode-0.1.3/src/zettcode/app/agent/rendering.py +381 -0
- zettcode-0.1.3/src/zettcode/app/agent/replay.py +84 -0
- zettcode-0.1.3/src/zettcode/app/agent/rows.py +215 -0
- zettcode-0.1.3/src/zettcode/app/agent/runtime.py +411 -0
- zettcode-0.1.3/src/zettcode/app/agent/side.py +109 -0
- zettcode-0.1.3/src/zettcode/app/agent/storage/__init__.py +28 -0
- zettcode-0.1.3/src/zettcode/app/agent/storage/metadata.py +135 -0
- zettcode-0.1.3/src/zettcode/app/agent/storage/records.py +266 -0
- zettcode-0.1.3/src/zettcode/app/agent/storage/store.py +603 -0
- zettcode-0.1.3/src/zettcode/app/agent/subagents.py +140 -0
- zettcode-0.1.3/src/zettcode/app/agent/title.py +72 -0
- zettcode-0.1.3/src/zettcode/app/agent/trace/script.js +18 -0
- zettcode-0.1.3/src/zettcode/app/agent/trace/style.css +136 -0
- zettcode-0.1.3/src/zettcode/app/agent/trace/template.html +31 -0
- zettcode-0.1.3/src/zettcode/app/agent/transcript.py +531 -0
- zettcode-0.1.3/src/zettcode/app/agent/usage.py +211 -0
- zettcode-0.1.3/src/zettcode/app/brand.py +63 -0
- zettcode-0.1.3/src/zettcode/app/commands.py +144 -0
- zettcode-0.1.3/src/zettcode/app/registry.py +61 -0
- zettcode-0.1.3/src/zettcode/app/ui/__init__.py +63 -0
- zettcode-0.1.3/src/zettcode/app/ui/app.py +550 -0
- zettcode-0.1.3/src/zettcode/app/ui/boot.py +101 -0
- zettcode-0.1.3/src/zettcode/app/ui/clipboard.py +314 -0
- zettcode-0.1.3/src/zettcode/app/ui/commands.py +215 -0
- zettcode-0.1.3/src/zettcode/app/ui/demo.py +160 -0
- zettcode-0.1.3/src/zettcode/app/ui/keys.py +188 -0
- zettcode-0.1.3/src/zettcode/app/ui/labels.py +69 -0
- zettcode-0.1.3/src/zettcode/app/ui/notices.py +177 -0
- zettcode-0.1.3/src/zettcode/app/ui/rows.py +113 -0
- zettcode-0.1.3/src/zettcode/app/ui/sessions.py +89 -0
- zettcode-0.1.3/src/zettcode/app/ui/settings.py +79 -0
- zettcode-0.1.3/src/zettcode/app/ui/shell.py +125 -0
- zettcode-0.1.3/src/zettcode/app/ui/updating.py +97 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/__init__.py +96 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/approval_page.py +242 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/ask_page.py +386 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/completer.py +63 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/composer.py +299 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/context_page.py +70 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/model_page.py +55 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/panel.py +24 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/root.py +48 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/sessions_page.py +84 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/steering.py +119 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/transcript.py +228 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/update_page.py +62 -0
- zettcode-0.1.3/src/zettcode/app/ui/widgets/welcome.py +21 -0
- zettcode-0.1.3/src/zettcode/cli.py +293 -0
- zettcode-0.1.3/src/zettcode/config.py +412 -0
- zettcode-0.1.3/src/zettcode/paths.py +29 -0
- zettcode-0.1.3/src/zettcode/plugins/__init__.py +98 -0
- zettcode-0.1.3/src/zettcode/plugins/builtins.py +67 -0
- zettcode-0.1.3/src/zettcode/plugins/container.py +294 -0
- zettcode-0.1.3/src/zettcode/plugins/extension.py +180 -0
- zettcode-0.1.3/src/zettcode/plugins/loader.py +191 -0
- zettcode-0.1.3/src/zettcode/plugins/mixins.py +214 -0
- zettcode-0.1.3/src/zettcode/plugins/plugin.py +99 -0
- zettcode-0.1.3/src/zettcode/plugins/state.py +196 -0
- zettcode-0.1.3/src/zettcode/tui/__init__.py +392 -0
- zettcode-0.1.3/src/zettcode/tui/capabilities.py +101 -0
- zettcode-0.1.3/src/zettcode/tui/console.py +229 -0
- zettcode-0.1.3/src/zettcode/tui/core/__init__.py +63 -0
- zettcode-0.1.3/src/zettcode/tui/core/app.py +545 -0
- zettcode-0.1.3/src/zettcode/tui/core/events.py +134 -0
- zettcode-0.1.3/src/zettcode/tui/core/focus.py +85 -0
- zettcode-0.1.3/src/zettcode/tui/core/geometry.py +212 -0
- zettcode-0.1.3/src/zettcode/tui/core/host.py +66 -0
- zettcode-0.1.3/src/zettcode/tui/core/keymap.py +218 -0
- zettcode-0.1.3/src/zettcode/tui/core/scheduler.py +96 -0
- zettcode-0.1.3/src/zettcode/tui/core/screen.py +80 -0
- zettcode-0.1.3/src/zettcode/tui/core/theme.py +180 -0
- zettcode-0.1.3/src/zettcode/tui/core/widget.py +187 -0
- zettcode-0.1.3/src/zettcode/tui/gallery.py +588 -0
- zettcode-0.1.3/src/zettcode/tui/glyphs.py +73 -0
- zettcode-0.1.3/src/zettcode/tui/input/__init__.py +18 -0
- zettcode-0.1.3/src/zettcode/tui/input/bridge.py +43 -0
- zettcode-0.1.3/src/zettcode/tui/input/decoder.py +187 -0
- zettcode-0.1.3/src/zettcode/tui/input/events.py +59 -0
- zettcode-0.1.3/src/zettcode/tui/input/keys.py +60 -0
- zettcode-0.1.3/src/zettcode/tui/input/reader.py +147 -0
- zettcode-0.1.3/src/zettcode/tui/layout/__init__.py +24 -0
- zettcode-0.1.3/src/zettcode/tui/layout/box.py +153 -0
- zettcode-0.1.3/src/zettcode/tui/layout/overlay.py +164 -0
- zettcode-0.1.3/src/zettcode/tui/layout/scroll.py +357 -0
- zettcode-0.1.3/src/zettcode/tui/layout/solver.py +95 -0
- zettcode-0.1.3/src/zettcode/tui/layout/spacing.py +136 -0
- zettcode-0.1.3/src/zettcode/tui/render/__init__.py +63 -0
- zettcode-0.1.3/src/zettcode/tui/render/canvas.py +153 -0
- zettcode-0.1.3/src/zettcode/tui/render/code.py +456 -0
- zettcode-0.1.3/src/zettcode/tui/render/color.py +177 -0
- zettcode-0.1.3/src/zettcode/tui/render/renderer.py +113 -0
- zettcode-0.1.3/src/zettcode/tui/render/rich_text.py +66 -0
- zettcode-0.1.3/src/zettcode/tui/render/style.py +102 -0
- zettcode-0.1.3/src/zettcode/tui/render/sweep.py +87 -0
- zettcode-0.1.3/src/zettcode/tui/render/text.py +217 -0
- zettcode-0.1.3/src/zettcode/tui/runner.py +234 -0
- zettcode-0.1.3/src/zettcode/tui/terminal.py +203 -0
- zettcode-0.1.3/src/zettcode/tui/testing/__init__.py +6 -0
- zettcode-0.1.3/src/zettcode/tui/testing/harness.py +220 -0
- zettcode-0.1.3/src/zettcode/tui/testing/snapshot.py +64 -0
- zettcode-0.1.3/src/zettcode/tui/theme_file.py +99 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/__init__.py +118 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/collapsible.py +115 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/completion.py +205 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/dialog.py +165 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/diff.py +236 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/list.py +251 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/list_page.py +100 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/markdown.py +589 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/progress.py +166 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/rich_text.py +84 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/status.py +86 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/table.py +101 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/tasks.py +129 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/text.py +108 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/textarea.py +627 -0
- zettcode-0.1.3/src/zettcode/tui/widgets/toast.py +136 -0
- zettcode-0.1.3/src/zettcode/update.py +301 -0
- zettcode-0.1.0/.gitignore +0 -12
- zettcode-0.1.0/PKG-INFO +0 -109
- zettcode-0.1.0/README.md +0 -89
- zettcode-0.1.0/pyproject.toml +0 -66
- zettcode-0.1.0/src/zettcode/__init__.py +0 -6
- zettcode-0.1.0/src/zettcode/cli.py +0 -78
- zettcode-0.1.0/src/zettcode/config.py +0 -72
- zettcode-0.1.0/src/zettcode/runtime.py +0 -121
- zettcode-0.1.0/src/zettcode/tui.py +0 -924
- zettcode-0.1.0/src/zettcode/tui_framework/__init__.py +0 -29
- zettcode-0.1.0/src/zettcode/tui_framework/application.py +0 -91
- zettcode-0.1.0/src/zettcode/tui_framework/components.py +0 -821
- zettcode-0.1.0/src/zettcode/tui_framework/events.py +0 -37
- zettcode-0.1.0/src/zettcode/tui_framework/input.py +0 -163
- zettcode-0.1.0/src/zettcode/tui_framework/screen.py +0 -214
- zettcode-0.1.0/src/zettcode/tui_framework/terminal.py +0 -118
- {zettcode-0.1.0 → zettcode-0.1.3}/LICENSE +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
**/.venv/
|
|
2
|
+
**/__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.coverage
|
|
8
|
+
**/.pytest_cache/
|
|
9
|
+
**/.ruff_cache/
|
|
10
|
+
.zett-tool-output/
|
|
11
|
+
.env
|
|
12
|
+
.DS_Store
|
|
13
|
+
|
|
14
|
+
# viztracer writes its trace here by default.
|
|
15
|
+
/result.json
|
|
16
|
+
|
|
17
|
+
# The docs site: dependencies, build output, and VitePress' cache.
|
|
18
|
+
node_modules/
|
|
19
|
+
docs/.vitepress/dist/
|
|
20
|
+
docs/.vitepress/cache/
|
|
21
|
+
docs/.vitepress/.temp/
|
zettcode-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: zettcode
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: A focused terminal coding agent powered by zett-agent
|
|
5
|
+
Project-URL: Repository, https://github.com/Chang-LeHung/zettcode
|
|
6
|
+
Project-URL: Issues, https://github.com/Chang-LeHung/zettcode/issues
|
|
7
|
+
Author: Chang-LeHung
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agent,coding-agent,llm,terminal,tui
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Operating System :: MacOS
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: exceptiongroup<2,>=1.2; python_version < '3.11'
|
|
24
|
+
Requires-Dist: pyperclip<2,>=1.9
|
|
25
|
+
Requires-Dist: setproctitle<2,>=1.3.7; os_name == 'posix'
|
|
26
|
+
Requires-Dist: tomli<3,>=2; python_version < '3.11'
|
|
27
|
+
Requires-Dist: truststore<1,>=0.10
|
|
28
|
+
Requires-Dist: wcwidth<1,>=0.2
|
|
29
|
+
Requires-Dist: zett-agent<0.2,>=0.1.11
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
<p align="center">
|
|
33
|
+
<img src="docs/public/logo.svg" width="88" height="88" alt="ZettCode pixel robot with a warm heart" />
|
|
34
|
+
</p>
|
|
35
|
+
<h1 align="center">ZettCode</h1>
|
|
36
|
+
<p align="center"><strong>Your terminal. Your coding partner.</strong></p>
|
|
37
|
+
<p align="center">A focused coding agent that reads your project, shows its work, and keeps you in control.</p>
|
|
38
|
+
<p align="center">
|
|
39
|
+
<strong>English</strong> · <a href="README.zh-CN.md">简体中文</a><br />
|
|
40
|
+
<a href="https://chang-lehung.github.io/zettcode/guide/getting-started">Get started</a> ·
|
|
41
|
+
<a href="https://chang-lehung.github.io/zettcode/">Documentation</a> ·
|
|
42
|
+
<a href="https://chang-lehung.github.io/zettcode/guide/commands">Commands</a>
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
<p align="center">
|
|
46
|
+
<img src="docs/public/terminal.svg" width="1000" alt="ZettCode showing a task, thinking, file reads, a code edit, passing tests, and a Markdown answer" />
|
|
47
|
+
</p>
|
|
48
|
+
<p align="center"><sub>Illustrative conversation, rendered with ZettCode’s actual terminal widgets.</sub></p>
|
|
49
|
+
|
|
50
|
+
## Get running
|
|
51
|
+
|
|
52
|
+
You need **Python 3.10+**, a UTF-8 terminal, and an **OpenAI-compatible API**.
|
|
53
|
+
Works on macOS, Linux, and Windows (use Windows Terminal).
|
|
54
|
+
|
|
55
|
+
### 1. Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
uv tool install zettcode
|
|
59
|
+
# or: pip install zettcode
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 2. Connect a model
|
|
63
|
+
|
|
64
|
+
Create `~/.zettcode/config.toml` (and its parent directory) with one model:
|
|
65
|
+
|
|
66
|
+
```toml
|
|
67
|
+
[[models]]
|
|
68
|
+
model = "deepseek-v4-pro" # the model id sent to DeepSeek
|
|
69
|
+
display_model = "DeepSeek Pro" # the name shown in ZettCode
|
|
70
|
+
token = "sk-..." # replace with your DeepSeek API key
|
|
71
|
+
base_url = "https://api.deepseek.com" # DeepSeek's OpenAI-compatible API root
|
|
72
|
+
context_window = 1000000 # verify against the endpoint's current limits
|
|
73
|
+
multimodal = false # this model accepts text, not images
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Get a key from the [DeepSeek platform](https://platform.deepseek.com/), not from
|
|
77
|
+
the chat website. Alternatively, omit `token` and set `OPENAI_API_KEY` to that
|
|
78
|
+
key. Add more `[[models]]` entries to switch with `/model`; the first is selected
|
|
79
|
+
at startup. See the
|
|
80
|
+
[configuration reference](https://chang-lehung.github.io/zettcode/guide/config)
|
|
81
|
+
for complete examples, defaults, and troubleshooting.
|
|
82
|
+
|
|
83
|
+
### 3. Start a task
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
cd /path/to/project
|
|
87
|
+
zettcode
|
|
88
|
+
# or: zettcode --workspace /path/to/project
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Describe a change and press **Enter**. Type `/` for commands, `@` to reference a
|
|
92
|
+
skill, and **Ctrl-C** to stop a request. **Ctrl-D** with an empty composer exits
|
|
93
|
+
and prints the command to resume your session.
|
|
94
|
+
|
|
95
|
+
## Built for the way you work
|
|
96
|
+
|
|
97
|
+
| | |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| **See every step** | Reasoning, answers, and tool calls stream as readable rows — not raw JSON. |
|
|
100
|
+
| **Keep the decision** | Review shell commands before they run. When the agent needs your input, choose an option or type an answer. |
|
|
101
|
+
| **Keep moving** | Send a steering message during a reply. Use `/btw` for a side question that stays out of later context. |
|
|
102
|
+
| **Come back later** | `/resume` restores a conversation; `/export` saves a readable HTML record. |
|
|
103
|
+
| **Understand the context** | Monitor token usage and caching, inspect `/context`, and compact when needed. |
|
|
104
|
+
| **Bring your tools** | Use project `AGENTS.md` instructions, skills, MCP servers, and Python plugins. |
|
|
105
|
+
|
|
106
|
+
The palette follows your terminal’s background, or your own `theme.toml`.
|
|
107
|
+
Select and copy text, scroll through answers, and paste images when your model
|
|
108
|
+
supports them.
|
|
109
|
+
|
|
110
|
+
## Find your next step
|
|
111
|
+
|
|
112
|
+
The **[user guide](https://chang-lehung.github.io/zettcode/guide/overview)** is
|
|
113
|
+
available in English and [简体中文](https://chang-lehung.github.io/zettcode/zh/guide/overview).
|
|
114
|
+
|
|
115
|
+
| First time | Everyday use | Configuration & extensions |
|
|
116
|
+
| --- | --- | --- |
|
|
117
|
+
| [Getting started](https://chang-lehung.github.io/zettcode/guide/getting-started) | [Keys & mouse](https://chang-lehung.github.io/zettcode/guide/keys) | [Configuration](https://chang-lehung.github.io/zettcode/guide/config) |
|
|
118
|
+
| [The interface](https://chang-lehung.github.io/zettcode/guide/interface) | [Commands](https://chang-lehung.github.io/zettcode/guide/commands) | [Models & context](https://chang-lehung.github.io/zettcode/guide/models) |
|
|
119
|
+
| [Problems & questions](https://chang-lehung.github.io/zettcode/guide/faq) | [Sessions](https://chang-lehung.github.io/zettcode/guide/sessions) | [Project instructions](https://chang-lehung.github.io/zettcode/guide/instructions) |
|
|
120
|
+
| | | [Skills & MCP](https://chang-lehung.github.io/zettcode/guide/skills-and-mcp) · [Plugins](https://chang-lehung.github.io/zettcode/guide/plugins) |
|
|
121
|
+
|
|
122
|
+
## Development
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
uv sync # install dependencies
|
|
126
|
+
make check # Ruff, mypy, and tests
|
|
127
|
+
make hooks # enforce mypy before commits
|
|
128
|
+
make demo # browse terminal widgets
|
|
129
|
+
make docs # preview the user guide locally
|
|
130
|
+
uv run zettcode --workspace . # run from the checkout
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
ZettCode provides the terminal application; the agent runtime is
|
|
134
|
+
[`zett-agent`](https://github.com/Chang-LeHung/zett-agent). Contributor notes and
|
|
135
|
+
invariants live in [`AGENTS.md`](AGENTS.md) and
|
|
136
|
+
[`docs/internal/`](docs/internal/), separately from the user guide. See
|
|
137
|
+
[`docs/internal/site-design.md`](docs/internal/site-design.md) for preview and
|
|
138
|
+
asset-generation instructions.
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
MIT. See [`LICENSE`](LICENSE).
|
zettcode-0.1.3/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/public/logo.svg" width="88" height="88" alt="ZettCode pixel robot with a warm heart" />
|
|
3
|
+
</p>
|
|
4
|
+
<h1 align="center">ZettCode</h1>
|
|
5
|
+
<p align="center"><strong>Your terminal. Your coding partner.</strong></p>
|
|
6
|
+
<p align="center">A focused coding agent that reads your project, shows its work, and keeps you in control.</p>
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>English</strong> · <a href="README.zh-CN.md">简体中文</a><br />
|
|
9
|
+
<a href="https://chang-lehung.github.io/zettcode/guide/getting-started">Get started</a> ·
|
|
10
|
+
<a href="https://chang-lehung.github.io/zettcode/">Documentation</a> ·
|
|
11
|
+
<a href="https://chang-lehung.github.io/zettcode/guide/commands">Commands</a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<img src="docs/public/terminal.svg" width="1000" alt="ZettCode showing a task, thinking, file reads, a code edit, passing tests, and a Markdown answer" />
|
|
16
|
+
</p>
|
|
17
|
+
<p align="center"><sub>Illustrative conversation, rendered with ZettCode’s actual terminal widgets.</sub></p>
|
|
18
|
+
|
|
19
|
+
## Get running
|
|
20
|
+
|
|
21
|
+
You need **Python 3.10+**, a UTF-8 terminal, and an **OpenAI-compatible API**.
|
|
22
|
+
Works on macOS, Linux, and Windows (use Windows Terminal).
|
|
23
|
+
|
|
24
|
+
### 1. Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
uv tool install zettcode
|
|
28
|
+
# or: pip install zettcode
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. Connect a model
|
|
32
|
+
|
|
33
|
+
Create `~/.zettcode/config.toml` (and its parent directory) with one model:
|
|
34
|
+
|
|
35
|
+
```toml
|
|
36
|
+
[[models]]
|
|
37
|
+
model = "deepseek-v4-pro" # the model id sent to DeepSeek
|
|
38
|
+
display_model = "DeepSeek Pro" # the name shown in ZettCode
|
|
39
|
+
token = "sk-..." # replace with your DeepSeek API key
|
|
40
|
+
base_url = "https://api.deepseek.com" # DeepSeek's OpenAI-compatible API root
|
|
41
|
+
context_window = 1000000 # verify against the endpoint's current limits
|
|
42
|
+
multimodal = false # this model accepts text, not images
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Get a key from the [DeepSeek platform](https://platform.deepseek.com/), not from
|
|
46
|
+
the chat website. Alternatively, omit `token` and set `OPENAI_API_KEY` to that
|
|
47
|
+
key. Add more `[[models]]` entries to switch with `/model`; the first is selected
|
|
48
|
+
at startup. See the
|
|
49
|
+
[configuration reference](https://chang-lehung.github.io/zettcode/guide/config)
|
|
50
|
+
for complete examples, defaults, and troubleshooting.
|
|
51
|
+
|
|
52
|
+
### 3. Start a task
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
cd /path/to/project
|
|
56
|
+
zettcode
|
|
57
|
+
# or: zettcode --workspace /path/to/project
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Describe a change and press **Enter**. Type `/` for commands, `@` to reference a
|
|
61
|
+
skill, and **Ctrl-C** to stop a request. **Ctrl-D** with an empty composer exits
|
|
62
|
+
and prints the command to resume your session.
|
|
63
|
+
|
|
64
|
+
## Built for the way you work
|
|
65
|
+
|
|
66
|
+
| | |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| **See every step** | Reasoning, answers, and tool calls stream as readable rows — not raw JSON. |
|
|
69
|
+
| **Keep the decision** | Review shell commands before they run. When the agent needs your input, choose an option or type an answer. |
|
|
70
|
+
| **Keep moving** | Send a steering message during a reply. Use `/btw` for a side question that stays out of later context. |
|
|
71
|
+
| **Come back later** | `/resume` restores a conversation; `/export` saves a readable HTML record. |
|
|
72
|
+
| **Understand the context** | Monitor token usage and caching, inspect `/context`, and compact when needed. |
|
|
73
|
+
| **Bring your tools** | Use project `AGENTS.md` instructions, skills, MCP servers, and Python plugins. |
|
|
74
|
+
|
|
75
|
+
The palette follows your terminal’s background, or your own `theme.toml`.
|
|
76
|
+
Select and copy text, scroll through answers, and paste images when your model
|
|
77
|
+
supports them.
|
|
78
|
+
|
|
79
|
+
## Find your next step
|
|
80
|
+
|
|
81
|
+
The **[user guide](https://chang-lehung.github.io/zettcode/guide/overview)** is
|
|
82
|
+
available in English and [简体中文](https://chang-lehung.github.io/zettcode/zh/guide/overview).
|
|
83
|
+
|
|
84
|
+
| First time | Everyday use | Configuration & extensions |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| [Getting started](https://chang-lehung.github.io/zettcode/guide/getting-started) | [Keys & mouse](https://chang-lehung.github.io/zettcode/guide/keys) | [Configuration](https://chang-lehung.github.io/zettcode/guide/config) |
|
|
87
|
+
| [The interface](https://chang-lehung.github.io/zettcode/guide/interface) | [Commands](https://chang-lehung.github.io/zettcode/guide/commands) | [Models & context](https://chang-lehung.github.io/zettcode/guide/models) |
|
|
88
|
+
| [Problems & questions](https://chang-lehung.github.io/zettcode/guide/faq) | [Sessions](https://chang-lehung.github.io/zettcode/guide/sessions) | [Project instructions](https://chang-lehung.github.io/zettcode/guide/instructions) |
|
|
89
|
+
| | | [Skills & MCP](https://chang-lehung.github.io/zettcode/guide/skills-and-mcp) · [Plugins](https://chang-lehung.github.io/zettcode/guide/plugins) |
|
|
90
|
+
|
|
91
|
+
## Development
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
uv sync # install dependencies
|
|
95
|
+
make check # Ruff, mypy, and tests
|
|
96
|
+
make hooks # enforce mypy before commits
|
|
97
|
+
make demo # browse terminal widgets
|
|
98
|
+
make docs # preview the user guide locally
|
|
99
|
+
uv run zettcode --workspace . # run from the checkout
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
ZettCode provides the terminal application; the agent runtime is
|
|
103
|
+
[`zett-agent`](https://github.com/Chang-LeHung/zett-agent). Contributor notes and
|
|
104
|
+
invariants live in [`AGENTS.md`](AGENTS.md) and
|
|
105
|
+
[`docs/internal/`](docs/internal/), separately from the user guide. See
|
|
106
|
+
[`docs/internal/site-design.md`](docs/internal/site-design.md) for preview and
|
|
107
|
+
asset-generation instructions.
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT. See [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/public/logo.svg" width="88" height="88" alt="ZettCode 像素机器人,中间是一颗暖色的心" />
|
|
3
|
+
</p>
|
|
4
|
+
<h1 align="center">ZettCode</h1>
|
|
5
|
+
<p align="center"><strong>你的终端。你的编码伙伴。</strong></p>
|
|
6
|
+
<p align="center">专注的编码智能体:读懂项目、展示过程,把决定权留给你。</p>
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="README.md">English</a> · <strong>简体中文</strong><br />
|
|
9
|
+
<a href="https://chang-lehung.github.io/zettcode/zh/guide/getting-started">快速开始</a> ·
|
|
10
|
+
<a href="https://chang-lehung.github.io/zettcode/zh/">使用文档</a> ·
|
|
11
|
+
<a href="https://chang-lehung.github.io/zettcode/zh/guide/commands">命令参考</a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<img src="docs/public/terminal.svg" width="1000" alt="ZettCode 依次展示任务、思考、读文件、改代码、通过的测试和 Markdown 回答" />
|
|
16
|
+
</p>
|
|
17
|
+
<p align="center"><sub>示例对话由 ZettCode 的实际终端组件渲染。</sub></p>
|
|
18
|
+
|
|
19
|
+
## 先跑起来
|
|
20
|
+
|
|
21
|
+
需要 **Python 3.10+**、支持 UTF-8 的终端和 **OpenAI 兼容接口**。
|
|
22
|
+
支持 macOS、Linux 和 Windows(请使用 Windows Terminal)。
|
|
23
|
+
|
|
24
|
+
### 1. 安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
uv tool install zettcode
|
|
28
|
+
# 或者:pip install zettcode
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. 连接模型
|
|
32
|
+
|
|
33
|
+
创建 `~/.zettcode/config.toml`(以及父目录),先配置一个模型:
|
|
34
|
+
|
|
35
|
+
```toml
|
|
36
|
+
[[models]]
|
|
37
|
+
model = "deepseek-v4-pro" # 发给 DeepSeek 的模型 id
|
|
38
|
+
display_model = "DeepSeek Pro" # ZettCode 界面中显示的名字
|
|
39
|
+
token = "sk-..." # 替换成你的 DeepSeek API key
|
|
40
|
+
base_url = "https://api.deepseek.com" # DeepSeek 的 OpenAI 兼容接口根地址
|
|
41
|
+
context_window = 1000000 # 以接入点当前公布的实际限制为准
|
|
42
|
+
multimodal = false # 这个模型接受文本,不接受图片
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
在 [DeepSeek 开放平台](https://platform.deepseek.com/)创建 API key,不是聊天网页的登录信息。
|
|
46
|
+
也可以省略 `token`,改用 `OPENAI_API_KEY` 环境变量保存这个 key。
|
|
47
|
+
添加更多 `[[models]]`,就能用 `/model` 切换;启动时默认选择第一项。
|
|
48
|
+
完整示例、默认值和排错步骤见[配置参考](https://chang-lehung.github.io/zettcode/zh/guide/config)。
|
|
49
|
+
|
|
50
|
+
### 3. 发出任务
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
cd /path/to/project
|
|
54
|
+
zettcode
|
|
55
|
+
# 或者:zettcode --workspace /path/to/project
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
描述要改什么,按 **Enter**。`/` 打开命令菜单,`@` 引用 skill,**Ctrl-C** 停止请求。
|
|
59
|
+
输入框为空时按 **Ctrl-D** 退出,终端会打印恢复当前会话的命令。
|
|
60
|
+
|
|
61
|
+
## 按你的方式工作
|
|
62
|
+
|
|
63
|
+
| | |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| **看清每一步** | 思考、回答和工具调用实时呈现为可读的行,不是原始 JSON。 |
|
|
66
|
+
| **决定权在你手上** | 执行 shell 命令前先审阅;智能体需要你的决定时,可以选选项,也可以打字回答。 |
|
|
67
|
+
| **工作不中断** | 回复过程中发送 steering(引导)消息;用 `/btw` 问一句,不让它进入后续上下文。 |
|
|
68
|
+
| **随时接着做** | `/resume` 恢复对话,`/export` 导出便于阅读的 HTML。 |
|
|
69
|
+
| **看懂上下文** | 查看 token 与缓存统计,用 `/context` 检查占用,在需要时压缩。 |
|
|
70
|
+
| **接入你的工具** | 使用项目 `AGENTS.md` 指令、skills、MCP 服务器和 Python 插件。 |
|
|
71
|
+
|
|
72
|
+
主题跟随终端背景,也可以使用你自己的 `theme.toml`。
|
|
73
|
+
选中复制文字、滚动查看回答;模型支持多模态时,还能粘贴图片。
|
|
74
|
+
|
|
75
|
+
## 找到你的下一步
|
|
76
|
+
|
|
77
|
+
**[用户指南](https://chang-lehung.github.io/zettcode/zh/guide/overview)** 提供简体中文与
|
|
78
|
+
[English](https://chang-lehung.github.io/zettcode/guide/overview) 两个版本。
|
|
79
|
+
|
|
80
|
+
| 第一次使用 | 日常使用 | 配置与扩展 |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| [快速开始](https://chang-lehung.github.io/zettcode/zh/guide/getting-started) | [快捷键与鼠标](https://chang-lehung.github.io/zettcode/zh/guide/keys) | [配置参考](https://chang-lehung.github.io/zettcode/zh/guide/config) |
|
|
83
|
+
| [认识界面](https://chang-lehung.github.io/zettcode/zh/guide/interface) | [命令参考](https://chang-lehung.github.io/zettcode/zh/guide/commands) | [模型与上下文](https://chang-lehung.github.io/zettcode/zh/guide/models) |
|
|
84
|
+
| [常见问题](https://chang-lehung.github.io/zettcode/zh/guide/faq) | [会话管理](https://chang-lehung.github.io/zettcode/zh/guide/sessions) | [项目指令](https://chang-lehung.github.io/zettcode/zh/guide/instructions) |
|
|
85
|
+
| | | [Skills 与 MCP](https://chang-lehung.github.io/zettcode/zh/guide/skills-and-mcp) · [插件](https://chang-lehung.github.io/zettcode/zh/guide/plugins) |
|
|
86
|
+
|
|
87
|
+
## 开发
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv sync # 安装依赖
|
|
91
|
+
make check # Ruff、mypy 与测试
|
|
92
|
+
make hooks # 每次提交前强制检查 mypy
|
|
93
|
+
make demo # 浏览终端组件
|
|
94
|
+
make docs # 本地预览使用文档
|
|
95
|
+
uv run zettcode --workspace . # 从源码运行
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
ZettCode 提供终端应用,智能体运行时来自
|
|
99
|
+
[`zett-agent`](https://github.com/Chang-LeHung/zett-agent)。贡献者约定和不变量放在
|
|
100
|
+
[`AGENTS.md`](AGENTS.md) 与 [`docs/internal/`](docs/internal/),不进入用户指南。
|
|
101
|
+
本地预览、重新生成效果图的方法见
|
|
102
|
+
[`docs/internal/site-design.md`](docs/internal/site-design.md)。
|
|
103
|
+
|
|
104
|
+
## 许可证
|
|
105
|
+
|
|
106
|
+
MIT,见 [`LICENSE`](LICENSE)。
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "zettcode"
|
|
3
|
+
description = "A focused terminal coding agent powered by zett-agent"
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
requires-python = ">=3.10"
|
|
6
|
+
dynamic = ["version"]
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{name = "Chang-LeHung"}]
|
|
10
|
+
keywords = ["agent", "llm", "tui", "terminal", "coding-agent"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 3 - Alpha",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Operating System :: MacOS",
|
|
15
|
+
"Operating System :: Microsoft :: Windows :: Windows 10",
|
|
16
|
+
"Operating System :: POSIX :: Linux",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
# The stdlib gained both of these in 3.11; older runtimes take the backports.
|
|
26
|
+
"exceptiongroup>=1.2,<2; python_version < '3.11'",
|
|
27
|
+
"pyperclip>=1.9,<2",
|
|
28
|
+
"setproctitle>=1.3.7,<2; os_name == 'posix'",
|
|
29
|
+
"tomli>=2,<3; python_version < '3.11'",
|
|
30
|
+
# The system trust store, so the release check works behind a proxy.
|
|
31
|
+
"truststore>=0.10,<1",
|
|
32
|
+
"wcwidth>=0.2,<1",
|
|
33
|
+
# A range, not a pin: 0.1.11 is the oldest runtime with the APIs this client
|
|
34
|
+
# uses (``AgentsMdExtension`` among them) and the first whose subagent
|
|
35
|
+
# extension imports its SQLite store lazily, so warming a runtime no longer
|
|
36
|
+
# loads SQLAlchemy. An exact pin would make zettcode fight every other tool
|
|
37
|
+
# that shares the dependency — including an upgrade of zett-agent itself,
|
|
38
|
+
# which pip would downgrade to satisfy it.
|
|
39
|
+
"zett-agent>=0.1.11,<0.2",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.scripts]
|
|
43
|
+
zettcode = "zettcode.cli:main"
|
|
44
|
+
|
|
45
|
+
[project.urls]
|
|
46
|
+
Repository = "https://github.com/Chang-LeHung/zettcode"
|
|
47
|
+
Issues = "https://github.com/Chang-LeHung/zettcode/issues"
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["hatchling"]
|
|
51
|
+
build-backend = "hatchling.build"
|
|
52
|
+
|
|
53
|
+
[tool.hatch.version]
|
|
54
|
+
# Single source of truth: the version is written once, in the package.
|
|
55
|
+
path = "src/zettcode/__init__.py"
|
|
56
|
+
|
|
57
|
+
[tool.hatch.build.targets.wheel]
|
|
58
|
+
packages = ["src/zettcode"]
|
|
59
|
+
|
|
60
|
+
[tool.hatch.build.targets.sdist]
|
|
61
|
+
include = ["/src", "/README.md", "/README.zh-CN.md", "/LICENSE", "/pyproject.toml"]
|
|
62
|
+
|
|
63
|
+
[dependency-groups]
|
|
64
|
+
dev = [
|
|
65
|
+
# Unlike the conditional runtime deps, these are installed on every
|
|
66
|
+
# interpreter so mypy can check the 3.10 branch of ``_compat`` for real.
|
|
67
|
+
"exceptiongroup>=1.2,<2",
|
|
68
|
+
"mypy>=1.14,<2",
|
|
69
|
+
"pytest>=8,<9",
|
|
70
|
+
"pytest-asyncio>=0.26,<2",
|
|
71
|
+
"pytest-cov>=7.1.0",
|
|
72
|
+
"ruff>=0.11,<1",
|
|
73
|
+
"tomli>=2,<3",
|
|
74
|
+
"viztracer>=1.1.1",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
[tool.pytest.ini_options]
|
|
78
|
+
testpaths = ["tests"]
|
|
79
|
+
asyncio_mode = "auto"
|
|
80
|
+
|
|
81
|
+
[tool.mypy]
|
|
82
|
+
python_version = "3.10"
|
|
83
|
+
files = ["src", "perf"]
|
|
84
|
+
# Check the pydantic storage models as models, not as plain classes.
|
|
85
|
+
plugins = ["pydantic.mypy"]
|
|
86
|
+
warn_unused_ignores = true
|
|
87
|
+
warn_redundant_casts = true
|
|
88
|
+
no_implicit_optional = true
|
|
89
|
+
|
|
90
|
+
[[tool.mypy.overrides]]
|
|
91
|
+
# Ships no stubs; the runner only calls the two documented functions.
|
|
92
|
+
module = ["pyperclip"]
|
|
93
|
+
ignore_missing_imports = true
|
|
94
|
+
|
|
95
|
+
[tool.ruff]
|
|
96
|
+
line-length = 120
|
|
97
|
+
target-version = "py310"
|
|
98
|
+
src = ["src", "tests", "perf"]
|
|
99
|
+
|
|
100
|
+
[tool.ruff.lint]
|
|
101
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
102
|
+
ignore = ["E501"]
|
|
103
|
+
|
|
104
|
+
[tool.ruff.lint.isort]
|
|
105
|
+
known-first-party = ["zettcode"]
|
|
106
|
+
|
|
107
|
+
[tool.ruff.format]
|
|
108
|
+
quote-style = "double"
|
|
109
|
+
indent-style = "space"
|
|
110
|
+
line-ending = "lf"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Terminal coding agent built on zett-agent."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
#: The one place the version is written. ``pyproject.toml`` reads it from here
|
|
9
|
+
#: and the release workflow checks the tag against it, so a bump is one edit.
|
|
10
|
+
__version__ = "0.1.3"
|
|
11
|
+
|
|
12
|
+
#: Where each public name lives; read by :func:`__getattr__` on first use.
|
|
13
|
+
_EXPORTS = {
|
|
14
|
+
"ModelConfig": ".config",
|
|
15
|
+
"ZettCodeAgent": ".app.agent.agent",
|
|
16
|
+
"ZettCodeConfig": ".config",
|
|
17
|
+
"ZettCodeRuntime": ".app.agent.runtime",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING: # pragma: no cover - for type checkers, not the runtime
|
|
22
|
+
from .app.agent.agent import ZettCodeAgent
|
|
23
|
+
from .app.agent.runtime import ZettCodeRuntime
|
|
24
|
+
from .config import ModelConfig, ZettCodeConfig
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def __getattr__(name: str) -> object:
|
|
28
|
+
"""Import the module a public name lives in, the first time it is asked for.
|
|
29
|
+
|
|
30
|
+
This package is a facade over several subpackages, and a caller that wants
|
|
31
|
+
one name should not pay for the rest of them — the TUI alone holds the
|
|
32
|
+
widget library, the Markdown parser, the diff viewer, and the syntax
|
|
33
|
+
scanners. ``__all__`` is still the public surface.
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
module = _EXPORTS[name]
|
|
37
|
+
except KeyError:
|
|
38
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None
|
|
39
|
+
return getattr(importlib.import_module(module, __name__), name)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def __dir__() -> list[str]:
|
|
43
|
+
"""Return the names this package publishes."""
|
|
44
|
+
return sorted(__all__)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
__all__ = ["ModelConfig", "ZettCodeAgent", "ZettCodeConfig", "ZettCodeRuntime"]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Small shims for the language versions this project supports.
|
|
2
|
+
|
|
3
|
+
ZettCode runs on Python 3.10 through 3.14, so the few things the standard
|
|
4
|
+
library grew in between live here instead of behind version checks at each use.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
from enum import Enum
|
|
11
|
+
|
|
12
|
+
if sys.version_info >= (3, 11):
|
|
13
|
+
from builtins import BaseExceptionGroup, ExceptionGroup
|
|
14
|
+
|
|
15
|
+
import tomllib
|
|
16
|
+
else: # pragma: no cover - the branch only the 3.10 runtime takes
|
|
17
|
+
import tomli as tomllib
|
|
18
|
+
from exceptiongroup import BaseExceptionGroup, ExceptionGroup
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
__all__ = ["BaseExceptionGroup", "ExceptionGroup", "StrEnum", "tomllib"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class StrEnum(str, Enum):
|
|
25
|
+
"""A string-valued enum, for the versions before ``enum.StrEnum``.
|
|
26
|
+
|
|
27
|
+
The standard library's version formats as its value, so ``f"{member}"`` is
|
|
28
|
+
``"ready"`` rather than ``"Activity.READY"``; the status line and the stored
|
|
29
|
+
metadata rely on that, so every interpreter uses this class instead of the
|
|
30
|
+
standard one and the wording cannot drift with the version.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __str__(self) -> str:
|
|
34
|
+
"""Return the member's value, as ``enum.StrEnum`` does."""
|
|
35
|
+
return str(self.value)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""ZettCode's application layer, split into its interface and its agent glue.
|
|
2
|
+
|
|
3
|
+
``ui`` holds what the user sees and drives: the transcript and the application
|
|
4
|
+
shell. ``agent`` holds the adapter that turns agent events into transcript
|
|
5
|
+
entries. This module is the facade over both, so ``from zettcode.app import
|
|
6
|
+
ZettCodeApp`` keeps working for callers that do not care where it lives.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import importlib
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
13
|
+
|
|
14
|
+
#: Where each public name lives; read by :func:`__getattr__` on first use.
|
|
15
|
+
_EXPORTS = {
|
|
16
|
+
"Entry": ".agent",
|
|
17
|
+
"Transcript": ".agent",
|
|
18
|
+
"TranscriptProjector": ".agent",
|
|
19
|
+
"TranscriptSource": ".ui",
|
|
20
|
+
"TranscriptView": ".ui",
|
|
21
|
+
"ZettCodeAgent": ".agent",
|
|
22
|
+
"ZettCodeApp": ".ui",
|
|
23
|
+
"ZettCodeRoot": ".ui",
|
|
24
|
+
"ZettCodeRuntime": ".agent",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING: # pragma: no cover - for type checkers, not the runtime
|
|
29
|
+
from .agent import Entry, Transcript, TranscriptProjector, ZettCodeAgent, ZettCodeRuntime
|
|
30
|
+
from .ui import TranscriptSource, TranscriptView, ZettCodeApp, ZettCodeRoot
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def __getattr__(name: str) -> object:
|
|
34
|
+
"""Import the module a public name lives in, the first time it is asked for.
|
|
35
|
+
|
|
36
|
+
This package is a facade over several subpackages, and a caller that wants
|
|
37
|
+
one name should not pay for the rest of them — the TUI alone holds the
|
|
38
|
+
widget library, the Markdown parser, the diff viewer, and the syntax
|
|
39
|
+
scanners. ``__all__`` is still the public surface.
|
|
40
|
+
"""
|
|
41
|
+
try:
|
|
42
|
+
module = _EXPORTS[name]
|
|
43
|
+
except KeyError:
|
|
44
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None
|
|
45
|
+
return getattr(importlib.import_module(module, __name__), name)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def __dir__() -> list[str]:
|
|
49
|
+
"""Return the names this package publishes."""
|
|
50
|
+
return sorted(__all__)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
"Entry",
|
|
55
|
+
"Transcript",
|
|
56
|
+
"TranscriptProjector",
|
|
57
|
+
"TranscriptSource",
|
|
58
|
+
"TranscriptView",
|
|
59
|
+
"ZettCodeApp",
|
|
60
|
+
"ZettCodeAgent",
|
|
61
|
+
"ZettCodeRoot",
|
|
62
|
+
"ZettCodeRuntime",
|
|
63
|
+
]
|