zettcode 0.1.0__tar.gz → 0.1.2__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.2/.gitignore +21 -0
- zettcode-0.1.2/PKG-INFO +136 -0
- zettcode-0.1.2/README.md +107 -0
- zettcode-0.1.2/README.zh-CN.md +98 -0
- zettcode-0.1.2/pyproject.toml +101 -0
- zettcode-0.1.2/src/zettcode/__init__.py +47 -0
- zettcode-0.1.2/src/zettcode/_compat.py +35 -0
- zettcode-0.1.2/src/zettcode/app/__init__.py +63 -0
- zettcode-0.1.2/src/zettcode/app/agent/__init__.py +45 -0
- zettcode-0.1.2/src/zettcode/app/agent/agent.py +580 -0
- zettcode-0.1.2/src/zettcode/app/agent/approval.py +49 -0
- zettcode-0.1.2/src/zettcode/app/agent/blocks.py +381 -0
- zettcode-0.1.2/src/zettcode/app/agent/capabilities.py +44 -0
- zettcode-0.1.2/src/zettcode/app/agent/compaction.py +33 -0
- zettcode-0.1.2/src/zettcode/app/agent/context.py +293 -0
- zettcode-0.1.2/src/zettcode/app/agent/entries.py +189 -0
- zettcode-0.1.2/src/zettcode/app/agent/export.py +413 -0
- zettcode-0.1.2/src/zettcode/app/agent/mcp.py +29 -0
- zettcode-0.1.2/src/zettcode/app/agent/mentions.py +126 -0
- zettcode-0.1.2/src/zettcode/app/agent/projection.py +184 -0
- zettcode-0.1.2/src/zettcode/app/agent/rendering.py +381 -0
- zettcode-0.1.2/src/zettcode/app/agent/replay.py +79 -0
- zettcode-0.1.2/src/zettcode/app/agent/rows.py +215 -0
- zettcode-0.1.2/src/zettcode/app/agent/runtime.py +374 -0
- zettcode-0.1.2/src/zettcode/app/agent/storage/__init__.py +28 -0
- zettcode-0.1.2/src/zettcode/app/agent/storage/metadata.py +135 -0
- zettcode-0.1.2/src/zettcode/app/agent/storage/records.py +266 -0
- zettcode-0.1.2/src/zettcode/app/agent/storage/store.py +588 -0
- zettcode-0.1.2/src/zettcode/app/agent/subagents.py +123 -0
- zettcode-0.1.2/src/zettcode/app/agent/title.py +72 -0
- zettcode-0.1.2/src/zettcode/app/agent/trace/script.js +18 -0
- zettcode-0.1.2/src/zettcode/app/agent/trace/style.css +136 -0
- zettcode-0.1.2/src/zettcode/app/agent/trace/template.html +31 -0
- zettcode-0.1.2/src/zettcode/app/agent/transcript.py +520 -0
- zettcode-0.1.2/src/zettcode/app/agent/usage.py +211 -0
- zettcode-0.1.2/src/zettcode/app/commands.py +132 -0
- zettcode-0.1.2/src/zettcode/app/registry.py +61 -0
- zettcode-0.1.2/src/zettcode/app/ui/__init__.py +63 -0
- zettcode-0.1.2/src/zettcode/app/ui/app.py +398 -0
- zettcode-0.1.2/src/zettcode/app/ui/clipboard.py +314 -0
- zettcode-0.1.2/src/zettcode/app/ui/commands.py +194 -0
- zettcode-0.1.2/src/zettcode/app/ui/demo.py +160 -0
- zettcode-0.1.2/src/zettcode/app/ui/keys.py +181 -0
- zettcode-0.1.2/src/zettcode/app/ui/notices.py +98 -0
- zettcode-0.1.2/src/zettcode/app/ui/rows.py +113 -0
- zettcode-0.1.2/src/zettcode/app/ui/sessions.py +89 -0
- zettcode-0.1.2/src/zettcode/app/ui/settings.py +79 -0
- zettcode-0.1.2/src/zettcode/app/ui/shell.py +101 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/__init__.py +84 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/approval_page.py +242 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/completer.py +63 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/composer.py +299 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/context_page.py +70 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/model_page.py +55 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/panel.py +24 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/root.py +48 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/sessions_page.py +84 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/steering.py +119 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/transcript.py +228 -0
- zettcode-0.1.2/src/zettcode/app/ui/widgets/welcome.py +19 -0
- zettcode-0.1.2/src/zettcode/cli.py +162 -0
- zettcode-0.1.2/src/zettcode/config.py +407 -0
- zettcode-0.1.2/src/zettcode/plugins/__init__.py +98 -0
- zettcode-0.1.2/src/zettcode/plugins/builtins.py +68 -0
- zettcode-0.1.2/src/zettcode/plugins/container.py +294 -0
- zettcode-0.1.2/src/zettcode/plugins/extension.py +180 -0
- zettcode-0.1.2/src/zettcode/plugins/loader.py +191 -0
- zettcode-0.1.2/src/zettcode/plugins/mixins.py +214 -0
- zettcode-0.1.2/src/zettcode/plugins/plugin.py +99 -0
- zettcode-0.1.2/src/zettcode/plugins/state.py +196 -0
- zettcode-0.1.2/src/zettcode/tui/__init__.py +392 -0
- zettcode-0.1.2/src/zettcode/tui/capabilities.py +101 -0
- zettcode-0.1.2/src/zettcode/tui/console.py +229 -0
- zettcode-0.1.2/src/zettcode/tui/core/__init__.py +63 -0
- zettcode-0.1.2/src/zettcode/tui/core/app.py +520 -0
- zettcode-0.1.2/src/zettcode/tui/core/events.py +134 -0
- zettcode-0.1.2/src/zettcode/tui/core/focus.py +85 -0
- zettcode-0.1.2/src/zettcode/tui/core/geometry.py +212 -0
- zettcode-0.1.2/src/zettcode/tui/core/host.py +66 -0
- zettcode-0.1.2/src/zettcode/tui/core/keymap.py +218 -0
- zettcode-0.1.2/src/zettcode/tui/core/scheduler.py +96 -0
- zettcode-0.1.2/src/zettcode/tui/core/screen.py +80 -0
- zettcode-0.1.2/src/zettcode/tui/core/theme.py +172 -0
- zettcode-0.1.2/src/zettcode/tui/core/widget.py +187 -0
- zettcode-0.1.2/src/zettcode/tui/gallery.py +588 -0
- zettcode-0.1.2/src/zettcode/tui/glyphs.py +73 -0
- zettcode-0.1.2/src/zettcode/tui/input/__init__.py +18 -0
- zettcode-0.1.2/src/zettcode/tui/input/bridge.py +43 -0
- zettcode-0.1.2/src/zettcode/tui/input/decoder.py +165 -0
- zettcode-0.1.2/src/zettcode/tui/input/events.py +55 -0
- zettcode-0.1.2/src/zettcode/tui/input/keys.py +60 -0
- zettcode-0.1.2/src/zettcode/tui/input/reader.py +147 -0
- zettcode-0.1.2/src/zettcode/tui/layout/__init__.py +24 -0
- zettcode-0.1.2/src/zettcode/tui/layout/box.py +153 -0
- zettcode-0.1.2/src/zettcode/tui/layout/overlay.py +164 -0
- zettcode-0.1.2/src/zettcode/tui/layout/scroll.py +357 -0
- zettcode-0.1.2/src/zettcode/tui/layout/solver.py +95 -0
- zettcode-0.1.2/src/zettcode/tui/layout/spacing.py +136 -0
- zettcode-0.1.2/src/zettcode/tui/render/__init__.py +63 -0
- zettcode-0.1.2/src/zettcode/tui/render/canvas.py +153 -0
- zettcode-0.1.2/src/zettcode/tui/render/code.py +456 -0
- zettcode-0.1.2/src/zettcode/tui/render/color.py +177 -0
- zettcode-0.1.2/src/zettcode/tui/render/renderer.py +113 -0
- zettcode-0.1.2/src/zettcode/tui/render/rich_text.py +66 -0
- zettcode-0.1.2/src/zettcode/tui/render/style.py +102 -0
- zettcode-0.1.2/src/zettcode/tui/render/sweep.py +87 -0
- zettcode-0.1.2/src/zettcode/tui/render/text.py +217 -0
- zettcode-0.1.2/src/zettcode/tui/runner.py +223 -0
- zettcode-0.1.2/src/zettcode/tui/terminal.py +216 -0
- zettcode-0.1.2/src/zettcode/tui/testing/__init__.py +6 -0
- zettcode-0.1.2/src/zettcode/tui/testing/harness.py +220 -0
- zettcode-0.1.2/src/zettcode/tui/testing/snapshot.py +64 -0
- zettcode-0.1.2/src/zettcode/tui/theme_file.py +98 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/__init__.py +118 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/collapsible.py +115 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/completion.py +205 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/dialog.py +165 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/diff.py +236 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/list.py +251 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/list_page.py +100 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/markdown.py +589 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/progress.py +166 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/rich_text.py +84 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/status.py +86 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/table.py +101 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/tasks.py +129 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/text.py +108 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/textarea.py +627 -0
- zettcode-0.1.2/src/zettcode/tui/widgets/toast.py +136 -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.2}/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.2/PKG-INFO
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: zettcode
|
|
3
|
+
Version: 0.1.2
|
|
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: tomli<3,>=2; python_version < '3.11'
|
|
26
|
+
Requires-Dist: wcwidth<1,>=0.2
|
|
27
|
+
Requires-Dist: zett-agent==0.1.10
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# ZettCode
|
|
31
|
+
|
|
32
|
+
**English** · [简体中文](README.zh-CN.md)
|
|
33
|
+
|
|
34
|
+
A focused coding agent for your terminal. Point it at a workspace, describe the
|
|
35
|
+
change you want, and watch the work happen — files read, commands approved,
|
|
36
|
+
edits made, tests run — as a conversation you can scroll, select, and copy.
|
|
37
|
+
|
|
38
|
+
The terminal interface is this repository; the model loop is
|
|
39
|
+
[`zett-agent`](https://github.com/Chang-LeHung/zett-agent), published separately.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
ZettCode needs Python 3.10 or newer. It is published on PyPI as `zettcode`:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv tool install zettcode
|
|
47
|
+
# or
|
|
48
|
+
pip install zettcode
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Configure
|
|
52
|
+
|
|
53
|
+
Everything except the workspace lives in `~/.zettcode/config.toml`. At least one
|
|
54
|
+
model, and the first one is active at startup:
|
|
55
|
+
|
|
56
|
+
```toml
|
|
57
|
+
[[models]]
|
|
58
|
+
model = "gpt-4o"
|
|
59
|
+
token = "sk-..." # or set OPENAI_API_KEY
|
|
60
|
+
base_url = "http://localhost:8787/v1" # any OpenAI-compatible endpoint
|
|
61
|
+
context_window = 200000 # tokens this model can carry
|
|
62
|
+
multimodal = true # accepts images as well as text
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Project `AGENTS.md` files, [skills](https://chang-lehung.github.io/zettcode/guide/skills-and-mcp),
|
|
66
|
+
MCP servers, plugins, the palette, and the rest are all in the same file. The
|
|
67
|
+
full key list is in the [configuration reference](https://chang-lehung.github.io/zettcode/guide/config).
|
|
68
|
+
|
|
69
|
+
## Run
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
cd ~/projects/api
|
|
73
|
+
zettcode # workspace defaults to the cwd
|
|
74
|
+
zettcode -w /path/to/project # work somewhere else
|
|
75
|
+
zettcode --resume <session-id> # reopen a stored session
|
|
76
|
+
zettcode --dry-run # time the startup and exit
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Type a task and press **Enter**. `/` opens the command menu, `@` references a
|
|
80
|
+
skill, `Ctrl-C` stops a request, `Ctrl-D` on an empty composer exits — and
|
|
81
|
+
leaving prints the command that brings the session back.
|
|
82
|
+
|
|
83
|
+
## What it does
|
|
84
|
+
|
|
85
|
+
- **Streams a conversation, not a payload.** Reasoning, answers, and tool calls
|
|
86
|
+
arrive as rows in order; tool output reads like a log — `Read src/app.py`,
|
|
87
|
+
`Ran pytest -q` — never raw JSON.
|
|
88
|
+
- **Asks before it acts.** Every shell command is confirmed first, with
|
|
89
|
+
`a` to allow the rest of the run and `p` to remember one command.
|
|
90
|
+
- **Keeps the context honest.** The status line shows tokens, cache hit rate,
|
|
91
|
+
and how full the window is; `/context` breaks the request down, and compaction
|
|
92
|
+
summarizes before the window overflows.
|
|
93
|
+
- **Remembers the project.** `AGENTS.md` files from the workspace upward become
|
|
94
|
+
project instructions; skills and MCP servers extend what the model can do.
|
|
95
|
+
- **Respects the terminal.** Mouse selection and scrolling, panels for choices,
|
|
96
|
+
image paste, `Ctrl-L`, and a palette that follows your terminal's background —
|
|
97
|
+
or your own `theme.toml`.
|
|
98
|
+
|
|
99
|
+
## Documentation
|
|
100
|
+
|
|
101
|
+
The user guide is published at
|
|
102
|
+
**<https://chang-lehung.github.io/zettcode/>** (English, with
|
|
103
|
+
[中文](https://chang-lehung.github.io/zettcode/zh/) alongside it):
|
|
104
|
+
|
|
105
|
+
| | |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| [Getting started](https://chang-lehung.github.io/zettcode/guide/getting-started) | Install, first task, first approvals. |
|
|
108
|
+
| [The interface](https://chang-lehung.github.io/zettcode/guide/interface) | What each row of the screen tells you. |
|
|
109
|
+
| [Keys and mouse](https://chang-lehung.github.io/zettcode/guide/keys) | The full reference. |
|
|
110
|
+
| [Commands](https://chang-lehung.github.io/zettcode/guide/commands) | Every `/command` and `@resource`. |
|
|
111
|
+
| [Sessions](https://chang-lehung.github.io/zettcode/guide/sessions) | Resume, title, export. |
|
|
112
|
+
| [Configuration](https://chang-lehung.github.io/zettcode/guide/config) | One file, every key. |
|
|
113
|
+
| [Models and context](https://chang-lehung.github.io/zettcode/guide/models) | Effort, compaction, cache, images. |
|
|
114
|
+
| [Project instructions](https://chang-lehung.github.io/zettcode/guide/instructions) | Writing a good `AGENTS.md`. |
|
|
115
|
+
| [Skills and MCP](https://chang-lehung.github.io/zettcode/guide/skills-and-mcp) | Teaching it your own tools. |
|
|
116
|
+
| [Plugins](https://chang-lehung.github.io/zettcode/guide/plugins) | Adding commands and rows in Python. |
|
|
117
|
+
| [Problems and questions](https://chang-lehung.github.io/zettcode/guide/faq) | When something does not work. |
|
|
118
|
+
|
|
119
|
+
## Development
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
uv sync # install the environment
|
|
123
|
+
make check # ruff, mypy, and pytest
|
|
124
|
+
make hooks # run mypy before every commit
|
|
125
|
+
make demo # browse the widgets interactively
|
|
126
|
+
uv run zettcode -w . # run the checkout against a workspace
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Notes for working inside the repository — layering, the invariant list, the
|
|
130
|
+
platform seam — are in [`AGENTS.md`](AGENTS.md) and
|
|
131
|
+
[`docs/internal/`](docs/internal/). The docs site itself lives in
|
|
132
|
+
`docs/` and builds with `npm ci --prefix docs && npm run docs:build --prefix docs`.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT — see [`LICENSE`](LICENSE).
|
zettcode-0.1.2/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# ZettCode
|
|
2
|
+
|
|
3
|
+
**English** · [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
A focused coding agent for your terminal. Point it at a workspace, describe the
|
|
6
|
+
change you want, and watch the work happen — files read, commands approved,
|
|
7
|
+
edits made, tests run — as a conversation you can scroll, select, and copy.
|
|
8
|
+
|
|
9
|
+
The terminal interface is this repository; the model loop is
|
|
10
|
+
[`zett-agent`](https://github.com/Chang-LeHung/zett-agent), published separately.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
ZettCode needs Python 3.10 or newer. It is published on PyPI as `zettcode`:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
uv tool install zettcode
|
|
18
|
+
# or
|
|
19
|
+
pip install zettcode
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Configure
|
|
23
|
+
|
|
24
|
+
Everything except the workspace lives in `~/.zettcode/config.toml`. At least one
|
|
25
|
+
model, and the first one is active at startup:
|
|
26
|
+
|
|
27
|
+
```toml
|
|
28
|
+
[[models]]
|
|
29
|
+
model = "gpt-4o"
|
|
30
|
+
token = "sk-..." # or set OPENAI_API_KEY
|
|
31
|
+
base_url = "http://localhost:8787/v1" # any OpenAI-compatible endpoint
|
|
32
|
+
context_window = 200000 # tokens this model can carry
|
|
33
|
+
multimodal = true # accepts images as well as text
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Project `AGENTS.md` files, [skills](https://chang-lehung.github.io/zettcode/guide/skills-and-mcp),
|
|
37
|
+
MCP servers, plugins, the palette, and the rest are all in the same file. The
|
|
38
|
+
full key list is in the [configuration reference](https://chang-lehung.github.io/zettcode/guide/config).
|
|
39
|
+
|
|
40
|
+
## Run
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
cd ~/projects/api
|
|
44
|
+
zettcode # workspace defaults to the cwd
|
|
45
|
+
zettcode -w /path/to/project # work somewhere else
|
|
46
|
+
zettcode --resume <session-id> # reopen a stored session
|
|
47
|
+
zettcode --dry-run # time the startup and exit
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Type a task and press **Enter**. `/` opens the command menu, `@` references a
|
|
51
|
+
skill, `Ctrl-C` stops a request, `Ctrl-D` on an empty composer exits — and
|
|
52
|
+
leaving prints the command that brings the session back.
|
|
53
|
+
|
|
54
|
+
## What it does
|
|
55
|
+
|
|
56
|
+
- **Streams a conversation, not a payload.** Reasoning, answers, and tool calls
|
|
57
|
+
arrive as rows in order; tool output reads like a log — `Read src/app.py`,
|
|
58
|
+
`Ran pytest -q` — never raw JSON.
|
|
59
|
+
- **Asks before it acts.** Every shell command is confirmed first, with
|
|
60
|
+
`a` to allow the rest of the run and `p` to remember one command.
|
|
61
|
+
- **Keeps the context honest.** The status line shows tokens, cache hit rate,
|
|
62
|
+
and how full the window is; `/context` breaks the request down, and compaction
|
|
63
|
+
summarizes before the window overflows.
|
|
64
|
+
- **Remembers the project.** `AGENTS.md` files from the workspace upward become
|
|
65
|
+
project instructions; skills and MCP servers extend what the model can do.
|
|
66
|
+
- **Respects the terminal.** Mouse selection and scrolling, panels for choices,
|
|
67
|
+
image paste, `Ctrl-L`, and a palette that follows your terminal's background —
|
|
68
|
+
or your own `theme.toml`.
|
|
69
|
+
|
|
70
|
+
## Documentation
|
|
71
|
+
|
|
72
|
+
The user guide is published at
|
|
73
|
+
**<https://chang-lehung.github.io/zettcode/>** (English, with
|
|
74
|
+
[中文](https://chang-lehung.github.io/zettcode/zh/) alongside it):
|
|
75
|
+
|
|
76
|
+
| | |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| [Getting started](https://chang-lehung.github.io/zettcode/guide/getting-started) | Install, first task, first approvals. |
|
|
79
|
+
| [The interface](https://chang-lehung.github.io/zettcode/guide/interface) | What each row of the screen tells you. |
|
|
80
|
+
| [Keys and mouse](https://chang-lehung.github.io/zettcode/guide/keys) | The full reference. |
|
|
81
|
+
| [Commands](https://chang-lehung.github.io/zettcode/guide/commands) | Every `/command` and `@resource`. |
|
|
82
|
+
| [Sessions](https://chang-lehung.github.io/zettcode/guide/sessions) | Resume, title, export. |
|
|
83
|
+
| [Configuration](https://chang-lehung.github.io/zettcode/guide/config) | One file, every key. |
|
|
84
|
+
| [Models and context](https://chang-lehung.github.io/zettcode/guide/models) | Effort, compaction, cache, images. |
|
|
85
|
+
| [Project instructions](https://chang-lehung.github.io/zettcode/guide/instructions) | Writing a good `AGENTS.md`. |
|
|
86
|
+
| [Skills and MCP](https://chang-lehung.github.io/zettcode/guide/skills-and-mcp) | Teaching it your own tools. |
|
|
87
|
+
| [Plugins](https://chang-lehung.github.io/zettcode/guide/plugins) | Adding commands and rows in Python. |
|
|
88
|
+
| [Problems and questions](https://chang-lehung.github.io/zettcode/guide/faq) | When something does not work. |
|
|
89
|
+
|
|
90
|
+
## Development
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
uv sync # install the environment
|
|
94
|
+
make check # ruff, mypy, and pytest
|
|
95
|
+
make hooks # run mypy before every commit
|
|
96
|
+
make demo # browse the widgets interactively
|
|
97
|
+
uv run zettcode -w . # run the checkout against a workspace
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Notes for working inside the repository — layering, the invariant list, the
|
|
101
|
+
platform seam — are in [`AGENTS.md`](AGENTS.md) and
|
|
102
|
+
[`docs/internal/`](docs/internal/). The docs site itself lives in
|
|
103
|
+
`docs/` and builds with `npm ci --prefix docs && npm run docs:build --prefix docs`.
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT — see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# ZettCode
|
|
2
|
+
|
|
3
|
+
[English](README.md) · **简体中文**
|
|
4
|
+
|
|
5
|
+
一个专注的终端编码智能体。指向一个工作区,说清楚要改什么,然后看着它把活干出来 —— 读文件、
|
|
6
|
+
等你批准命令、改代码、跑测试 —— 整个过程是一段可以滚动、选中、复制的对话。
|
|
7
|
+
|
|
8
|
+
终端界面就是本仓库;模型循环在
|
|
9
|
+
[`zett-agent`](https://github.com/Chang-LeHung/zett-agent),单独发布。
|
|
10
|
+
|
|
11
|
+
## 安装
|
|
12
|
+
|
|
13
|
+
需要 Python 3.10 或更新版本,PyPI 包名是 `zettcode`:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
uv tool install zettcode
|
|
17
|
+
# 或者
|
|
18
|
+
pip install zettcode
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 配置
|
|
22
|
+
|
|
23
|
+
除了工作区,其他设置都在 `~/.zettcode/config.toml`。至少要有一个模型,第一张表在启动时生效:
|
|
24
|
+
|
|
25
|
+
```toml
|
|
26
|
+
[[models]]
|
|
27
|
+
model = "gpt-4o"
|
|
28
|
+
token = "sk-..." # 也可以设置 OPENAI_API_KEY
|
|
29
|
+
base_url = "http://localhost:8787/v1" # 任何 OpenAI 兼容的接入点
|
|
30
|
+
context_window = 200000 # 这个模型能装多少 token
|
|
31
|
+
multimodal = true # 除文本外还接受图片
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
项目里的 `AGENTS.md`、[skills](https://chang-lehung.github.io/zettcode/zh/guide/skills-and-mcp)、
|
|
35
|
+
MCP 服务器、插件、配色等等都在同一个文件里,完整的键见
|
|
36
|
+
[配置文件](https://chang-lehung.github.io/zettcode/zh/guide/config)。
|
|
37
|
+
|
|
38
|
+
## 运行
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cd ~/projects/api
|
|
42
|
+
zettcode # 工作区默认是当前目录
|
|
43
|
+
zettcode -w /path/to/project # 在别处工作
|
|
44
|
+
zettcode --resume <session-id> # 重新打开一个已保存的会话
|
|
45
|
+
zettcode --dry-run # 只测启动耗时后退出
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
输入任务并按 **Enter**。`/` 打开命令菜单,`@` 引用 skill,`Ctrl-C` 停止请求,输入框为空时
|
|
49
|
+
`Ctrl-D` 退出 —— 退出时会打印把会话找回来的命令。
|
|
50
|
+
|
|
51
|
+
## 它能做什么
|
|
52
|
+
|
|
53
|
+
- **流式地呈现对话,而不是丢一堆数据。** 思考、回答、工具调用按顺序各占一行;工具输出读起来像
|
|
54
|
+
日志 —— `Read src/app.py`、`Ran pytest -q` —— 永远不会甩出原始 JSON。
|
|
55
|
+
- **动手之前先问你。** 每条 shell 命令都要先确认,`a` 放行本轮剩余命令,`p` 记住某一条。
|
|
56
|
+
- **把上下文讲清楚。** 状态行显示 token、缓存命中率和窗口占用;`/context` 拆开当前请求,
|
|
57
|
+
压缩会在窗口溢出之前完成。
|
|
58
|
+
- **记住项目。** 从工作区逐级向上的 `AGENTS.md` 会变成项目指令;skills 和 MCP 服务器扩展模型
|
|
59
|
+
能做的事。
|
|
60
|
+
- **尊重终端。** 鼠标选中与滚动、用面板做选择、粘贴图片、`Ctrl-L`,以及跟随终端背景的配色 ——
|
|
61
|
+
也可以用你自己的 `theme.toml`。
|
|
62
|
+
|
|
63
|
+
## 文档
|
|
64
|
+
|
|
65
|
+
用户指南发布在 **<https://chang-lehung.github.io/zettcode/zh/>**(
|
|
66
|
+
[English](https://chang-lehung.github.io/zettcode/) 与之并列):
|
|
67
|
+
|
|
68
|
+
| | |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| [快速开始](https://chang-lehung.github.io/zettcode/zh/guide/getting-started) | 安装、第一个任务、第一次审批。 |
|
|
71
|
+
| [界面](https://chang-lehung.github.io/zettcode/zh/guide/interface) | 屏幕上每一行在说什么。 |
|
|
72
|
+
| [快捷键与鼠标](https://chang-lehung.github.io/zettcode/zh/guide/keys) | 完整对照表。 |
|
|
73
|
+
| [命令](https://chang-lehung.github.io/zettcode/zh/guide/commands) | 所有 `/命令` 与 `@资源`。 |
|
|
74
|
+
| [会话](https://chang-lehung.github.io/zettcode/zh/guide/sessions) | 恢复、命名、导出。 |
|
|
75
|
+
| [配置文件](https://chang-lehung.github.io/zettcode/zh/guide/config) | 一个文件,所有键。 |
|
|
76
|
+
| [模型与上下文](https://chang-lehung.github.io/zettcode/zh/guide/models) | 推理档位、压缩、缓存、图片。 |
|
|
77
|
+
| [项目指令](https://chang-lehung.github.io/zettcode/zh/guide/instructions) | 怎么写出好用的 `AGENTS.md`。 |
|
|
78
|
+
| [Skills 与 MCP](https://chang-lehung.github.io/zettcode/zh/guide/skills-and-mcp) | 接入你自己的工具。 |
|
|
79
|
+
| [插件](https://chang-lehung.github.io/zettcode/zh/guide/plugins) | 用 Python 添加命令和界面行。 |
|
|
80
|
+
| [常见问题](https://chang-lehung.github.io/zettcode/zh/guide/faq) | 出问题的时候。 |
|
|
81
|
+
|
|
82
|
+
## 开发
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uv sync # 安装环境
|
|
86
|
+
make check # ruff、mypy、pytest
|
|
87
|
+
make hooks # 每次提交前跑 mypy
|
|
88
|
+
make demo # 交互式浏览所有组件
|
|
89
|
+
uv run zettcode -w . # 用源码运行
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
仓库内部的约定 —— 分层、不变量清单、平台适配 —— 见 [`AGENTS.md`](AGENTS.md) 和
|
|
93
|
+
[`docs/internal/`](docs/internal/)。文档站在 `docs/`,构建命令是
|
|
94
|
+
`npm ci --prefix docs && npm run docs:build --prefix docs`。
|
|
95
|
+
|
|
96
|
+
## 许可证
|
|
97
|
+
|
|
98
|
+
MIT,见 [`LICENSE`](LICENSE)。
|
|
@@ -0,0 +1,101 @@
|
|
|
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
|
+
"tomli>=2,<3; python_version < '3.11'",
|
|
29
|
+
"wcwidth>=0.2,<1",
|
|
30
|
+
"zett-agent==0.1.10",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
zettcode = "zettcode.cli:main"
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Repository = "https://github.com/Chang-LeHung/zettcode"
|
|
38
|
+
Issues = "https://github.com/Chang-LeHung/zettcode/issues"
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["hatchling"]
|
|
42
|
+
build-backend = "hatchling.build"
|
|
43
|
+
|
|
44
|
+
[tool.hatch.version]
|
|
45
|
+
# Single source of truth: the version is written once, in the package.
|
|
46
|
+
path = "src/zettcode/__init__.py"
|
|
47
|
+
|
|
48
|
+
[tool.hatch.build.targets.wheel]
|
|
49
|
+
packages = ["src/zettcode"]
|
|
50
|
+
|
|
51
|
+
[tool.hatch.build.targets.sdist]
|
|
52
|
+
include = ["/src", "/README.md", "/README.zh-CN.md", "/LICENSE", "/pyproject.toml"]
|
|
53
|
+
|
|
54
|
+
[dependency-groups]
|
|
55
|
+
dev = [
|
|
56
|
+
# Unlike the conditional runtime deps, these are installed on every
|
|
57
|
+
# interpreter so mypy can check the 3.10 branch of ``_compat`` for real.
|
|
58
|
+
"exceptiongroup>=1.2,<2",
|
|
59
|
+
"mypy>=1.14,<2",
|
|
60
|
+
"pytest>=8,<9",
|
|
61
|
+
"pytest-asyncio>=0.26,<2",
|
|
62
|
+
"pytest-cov>=7.1.0",
|
|
63
|
+
"ruff>=0.11,<1",
|
|
64
|
+
"tomli>=2,<3",
|
|
65
|
+
"viztracer>=1.1.1",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[tool.pytest.ini_options]
|
|
69
|
+
testpaths = ["tests"]
|
|
70
|
+
asyncio_mode = "auto"
|
|
71
|
+
|
|
72
|
+
[tool.mypy]
|
|
73
|
+
python_version = "3.10"
|
|
74
|
+
files = ["src", "perf"]
|
|
75
|
+
# Check the pydantic storage models as models, not as plain classes.
|
|
76
|
+
plugins = ["pydantic.mypy"]
|
|
77
|
+
warn_unused_ignores = true
|
|
78
|
+
warn_redundant_casts = true
|
|
79
|
+
no_implicit_optional = true
|
|
80
|
+
|
|
81
|
+
[[tool.mypy.overrides]]
|
|
82
|
+
# Ships no stubs; the runner only calls the two documented functions.
|
|
83
|
+
module = ["pyperclip"]
|
|
84
|
+
ignore_missing_imports = true
|
|
85
|
+
|
|
86
|
+
[tool.ruff]
|
|
87
|
+
line-length = 120
|
|
88
|
+
target-version = "py310"
|
|
89
|
+
src = ["src", "tests", "perf"]
|
|
90
|
+
|
|
91
|
+
[tool.ruff.lint]
|
|
92
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
93
|
+
ignore = ["E501"]
|
|
94
|
+
|
|
95
|
+
[tool.ruff.lint.isort]
|
|
96
|
+
known-first-party = ["zettcode"]
|
|
97
|
+
|
|
98
|
+
[tool.ruff.format]
|
|
99
|
+
quote-style = "double"
|
|
100
|
+
indent-style = "space"
|
|
101
|
+
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.2"
|
|
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
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Agent-facing glue: the conversation model and the events that fill it."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
#: Where each public name lives; read by :func:`__getattr__` on first use.
|
|
9
|
+
_EXPORTS = {
|
|
10
|
+
"Entry": ".transcript",
|
|
11
|
+
"Transcript": ".transcript",
|
|
12
|
+
"TranscriptProjector": ".projection",
|
|
13
|
+
"ZettCodeAgent": ".agent",
|
|
14
|
+
"ZettCodeRuntime": ".runtime",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING: # pragma: no cover - for type checkers, not the runtime
|
|
19
|
+
from .agent import ZettCodeAgent
|
|
20
|
+
from .projection import TranscriptProjector
|
|
21
|
+
from .runtime import ZettCodeRuntime
|
|
22
|
+
from .transcript import Entry, Transcript
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def __getattr__(name: str) -> object:
|
|
26
|
+
"""Import the module a public name lives in, the first time it is asked for.
|
|
27
|
+
|
|
28
|
+
This package is a facade over several subpackages, and a caller that wants
|
|
29
|
+
one name should not pay for the rest of them — the TUI alone holds the
|
|
30
|
+
widget library, the Markdown parser, the diff viewer, and the syntax
|
|
31
|
+
scanners. ``__all__`` is still the public surface.
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
module = _EXPORTS[name]
|
|
35
|
+
except KeyError:
|
|
36
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None
|
|
37
|
+
return getattr(importlib.import_module(module, __name__), name)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def __dir__() -> list[str]:
|
|
41
|
+
"""Return the names this package publishes."""
|
|
42
|
+
return sorted(__all__)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = ["Entry", "Transcript", "TranscriptProjector", "ZettCodeAgent", "ZettCodeRuntime"]
|