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.
Files changed (156) hide show
  1. zettcode-0.1.3/.gitignore +21 -0
  2. zettcode-0.1.3/PKG-INFO +142 -0
  3. zettcode-0.1.3/README.md +111 -0
  4. zettcode-0.1.3/README.zh-CN.md +106 -0
  5. zettcode-0.1.3/pyproject.toml +110 -0
  6. zettcode-0.1.3/src/zettcode/__init__.py +47 -0
  7. zettcode-0.1.3/src/zettcode/_compat.py +35 -0
  8. zettcode-0.1.3/src/zettcode/app/__init__.py +63 -0
  9. zettcode-0.1.3/src/zettcode/app/agent/__init__.py +45 -0
  10. zettcode-0.1.3/src/zettcode/app/agent/agent.py +626 -0
  11. zettcode-0.1.3/src/zettcode/app/agent/approval.py +49 -0
  12. zettcode-0.1.3/src/zettcode/app/agent/ask.py +96 -0
  13. zettcode-0.1.3/src/zettcode/app/agent/blocks.py +367 -0
  14. zettcode-0.1.3/src/zettcode/app/agent/capabilities.py +44 -0
  15. zettcode-0.1.3/src/zettcode/app/agent/compaction.py +47 -0
  16. zettcode-0.1.3/src/zettcode/app/agent/context.py +293 -0
  17. zettcode-0.1.3/src/zettcode/app/agent/entries.py +191 -0
  18. zettcode-0.1.3/src/zettcode/app/agent/export.py +418 -0
  19. zettcode-0.1.3/src/zettcode/app/agent/mcp.py +29 -0
  20. zettcode-0.1.3/src/zettcode/app/agent/mentions.py +126 -0
  21. zettcode-0.1.3/src/zettcode/app/agent/projection.py +198 -0
  22. zettcode-0.1.3/src/zettcode/app/agent/rendering.py +381 -0
  23. zettcode-0.1.3/src/zettcode/app/agent/replay.py +84 -0
  24. zettcode-0.1.3/src/zettcode/app/agent/rows.py +215 -0
  25. zettcode-0.1.3/src/zettcode/app/agent/runtime.py +411 -0
  26. zettcode-0.1.3/src/zettcode/app/agent/side.py +109 -0
  27. zettcode-0.1.3/src/zettcode/app/agent/storage/__init__.py +28 -0
  28. zettcode-0.1.3/src/zettcode/app/agent/storage/metadata.py +135 -0
  29. zettcode-0.1.3/src/zettcode/app/agent/storage/records.py +266 -0
  30. zettcode-0.1.3/src/zettcode/app/agent/storage/store.py +603 -0
  31. zettcode-0.1.3/src/zettcode/app/agent/subagents.py +140 -0
  32. zettcode-0.1.3/src/zettcode/app/agent/title.py +72 -0
  33. zettcode-0.1.3/src/zettcode/app/agent/trace/script.js +18 -0
  34. zettcode-0.1.3/src/zettcode/app/agent/trace/style.css +136 -0
  35. zettcode-0.1.3/src/zettcode/app/agent/trace/template.html +31 -0
  36. zettcode-0.1.3/src/zettcode/app/agent/transcript.py +531 -0
  37. zettcode-0.1.3/src/zettcode/app/agent/usage.py +211 -0
  38. zettcode-0.1.3/src/zettcode/app/brand.py +63 -0
  39. zettcode-0.1.3/src/zettcode/app/commands.py +144 -0
  40. zettcode-0.1.3/src/zettcode/app/registry.py +61 -0
  41. zettcode-0.1.3/src/zettcode/app/ui/__init__.py +63 -0
  42. zettcode-0.1.3/src/zettcode/app/ui/app.py +550 -0
  43. zettcode-0.1.3/src/zettcode/app/ui/boot.py +101 -0
  44. zettcode-0.1.3/src/zettcode/app/ui/clipboard.py +314 -0
  45. zettcode-0.1.3/src/zettcode/app/ui/commands.py +215 -0
  46. zettcode-0.1.3/src/zettcode/app/ui/demo.py +160 -0
  47. zettcode-0.1.3/src/zettcode/app/ui/keys.py +188 -0
  48. zettcode-0.1.3/src/zettcode/app/ui/labels.py +69 -0
  49. zettcode-0.1.3/src/zettcode/app/ui/notices.py +177 -0
  50. zettcode-0.1.3/src/zettcode/app/ui/rows.py +113 -0
  51. zettcode-0.1.3/src/zettcode/app/ui/sessions.py +89 -0
  52. zettcode-0.1.3/src/zettcode/app/ui/settings.py +79 -0
  53. zettcode-0.1.3/src/zettcode/app/ui/shell.py +125 -0
  54. zettcode-0.1.3/src/zettcode/app/ui/updating.py +97 -0
  55. zettcode-0.1.3/src/zettcode/app/ui/widgets/__init__.py +96 -0
  56. zettcode-0.1.3/src/zettcode/app/ui/widgets/approval_page.py +242 -0
  57. zettcode-0.1.3/src/zettcode/app/ui/widgets/ask_page.py +386 -0
  58. zettcode-0.1.3/src/zettcode/app/ui/widgets/completer.py +63 -0
  59. zettcode-0.1.3/src/zettcode/app/ui/widgets/composer.py +299 -0
  60. zettcode-0.1.3/src/zettcode/app/ui/widgets/context_page.py +70 -0
  61. zettcode-0.1.3/src/zettcode/app/ui/widgets/model_page.py +55 -0
  62. zettcode-0.1.3/src/zettcode/app/ui/widgets/panel.py +24 -0
  63. zettcode-0.1.3/src/zettcode/app/ui/widgets/root.py +48 -0
  64. zettcode-0.1.3/src/zettcode/app/ui/widgets/sessions_page.py +84 -0
  65. zettcode-0.1.3/src/zettcode/app/ui/widgets/steering.py +119 -0
  66. zettcode-0.1.3/src/zettcode/app/ui/widgets/transcript.py +228 -0
  67. zettcode-0.1.3/src/zettcode/app/ui/widgets/update_page.py +62 -0
  68. zettcode-0.1.3/src/zettcode/app/ui/widgets/welcome.py +21 -0
  69. zettcode-0.1.3/src/zettcode/cli.py +293 -0
  70. zettcode-0.1.3/src/zettcode/config.py +412 -0
  71. zettcode-0.1.3/src/zettcode/paths.py +29 -0
  72. zettcode-0.1.3/src/zettcode/plugins/__init__.py +98 -0
  73. zettcode-0.1.3/src/zettcode/plugins/builtins.py +67 -0
  74. zettcode-0.1.3/src/zettcode/plugins/container.py +294 -0
  75. zettcode-0.1.3/src/zettcode/plugins/extension.py +180 -0
  76. zettcode-0.1.3/src/zettcode/plugins/loader.py +191 -0
  77. zettcode-0.1.3/src/zettcode/plugins/mixins.py +214 -0
  78. zettcode-0.1.3/src/zettcode/plugins/plugin.py +99 -0
  79. zettcode-0.1.3/src/zettcode/plugins/state.py +196 -0
  80. zettcode-0.1.3/src/zettcode/tui/__init__.py +392 -0
  81. zettcode-0.1.3/src/zettcode/tui/capabilities.py +101 -0
  82. zettcode-0.1.3/src/zettcode/tui/console.py +229 -0
  83. zettcode-0.1.3/src/zettcode/tui/core/__init__.py +63 -0
  84. zettcode-0.1.3/src/zettcode/tui/core/app.py +545 -0
  85. zettcode-0.1.3/src/zettcode/tui/core/events.py +134 -0
  86. zettcode-0.1.3/src/zettcode/tui/core/focus.py +85 -0
  87. zettcode-0.1.3/src/zettcode/tui/core/geometry.py +212 -0
  88. zettcode-0.1.3/src/zettcode/tui/core/host.py +66 -0
  89. zettcode-0.1.3/src/zettcode/tui/core/keymap.py +218 -0
  90. zettcode-0.1.3/src/zettcode/tui/core/scheduler.py +96 -0
  91. zettcode-0.1.3/src/zettcode/tui/core/screen.py +80 -0
  92. zettcode-0.1.3/src/zettcode/tui/core/theme.py +180 -0
  93. zettcode-0.1.3/src/zettcode/tui/core/widget.py +187 -0
  94. zettcode-0.1.3/src/zettcode/tui/gallery.py +588 -0
  95. zettcode-0.1.3/src/zettcode/tui/glyphs.py +73 -0
  96. zettcode-0.1.3/src/zettcode/tui/input/__init__.py +18 -0
  97. zettcode-0.1.3/src/zettcode/tui/input/bridge.py +43 -0
  98. zettcode-0.1.3/src/zettcode/tui/input/decoder.py +187 -0
  99. zettcode-0.1.3/src/zettcode/tui/input/events.py +59 -0
  100. zettcode-0.1.3/src/zettcode/tui/input/keys.py +60 -0
  101. zettcode-0.1.3/src/zettcode/tui/input/reader.py +147 -0
  102. zettcode-0.1.3/src/zettcode/tui/layout/__init__.py +24 -0
  103. zettcode-0.1.3/src/zettcode/tui/layout/box.py +153 -0
  104. zettcode-0.1.3/src/zettcode/tui/layout/overlay.py +164 -0
  105. zettcode-0.1.3/src/zettcode/tui/layout/scroll.py +357 -0
  106. zettcode-0.1.3/src/zettcode/tui/layout/solver.py +95 -0
  107. zettcode-0.1.3/src/zettcode/tui/layout/spacing.py +136 -0
  108. zettcode-0.1.3/src/zettcode/tui/render/__init__.py +63 -0
  109. zettcode-0.1.3/src/zettcode/tui/render/canvas.py +153 -0
  110. zettcode-0.1.3/src/zettcode/tui/render/code.py +456 -0
  111. zettcode-0.1.3/src/zettcode/tui/render/color.py +177 -0
  112. zettcode-0.1.3/src/zettcode/tui/render/renderer.py +113 -0
  113. zettcode-0.1.3/src/zettcode/tui/render/rich_text.py +66 -0
  114. zettcode-0.1.3/src/zettcode/tui/render/style.py +102 -0
  115. zettcode-0.1.3/src/zettcode/tui/render/sweep.py +87 -0
  116. zettcode-0.1.3/src/zettcode/tui/render/text.py +217 -0
  117. zettcode-0.1.3/src/zettcode/tui/runner.py +234 -0
  118. zettcode-0.1.3/src/zettcode/tui/terminal.py +203 -0
  119. zettcode-0.1.3/src/zettcode/tui/testing/__init__.py +6 -0
  120. zettcode-0.1.3/src/zettcode/tui/testing/harness.py +220 -0
  121. zettcode-0.1.3/src/zettcode/tui/testing/snapshot.py +64 -0
  122. zettcode-0.1.3/src/zettcode/tui/theme_file.py +99 -0
  123. zettcode-0.1.3/src/zettcode/tui/widgets/__init__.py +118 -0
  124. zettcode-0.1.3/src/zettcode/tui/widgets/collapsible.py +115 -0
  125. zettcode-0.1.3/src/zettcode/tui/widgets/completion.py +205 -0
  126. zettcode-0.1.3/src/zettcode/tui/widgets/dialog.py +165 -0
  127. zettcode-0.1.3/src/zettcode/tui/widgets/diff.py +236 -0
  128. zettcode-0.1.3/src/zettcode/tui/widgets/list.py +251 -0
  129. zettcode-0.1.3/src/zettcode/tui/widgets/list_page.py +100 -0
  130. zettcode-0.1.3/src/zettcode/tui/widgets/markdown.py +589 -0
  131. zettcode-0.1.3/src/zettcode/tui/widgets/progress.py +166 -0
  132. zettcode-0.1.3/src/zettcode/tui/widgets/rich_text.py +84 -0
  133. zettcode-0.1.3/src/zettcode/tui/widgets/status.py +86 -0
  134. zettcode-0.1.3/src/zettcode/tui/widgets/table.py +101 -0
  135. zettcode-0.1.3/src/zettcode/tui/widgets/tasks.py +129 -0
  136. zettcode-0.1.3/src/zettcode/tui/widgets/text.py +108 -0
  137. zettcode-0.1.3/src/zettcode/tui/widgets/textarea.py +627 -0
  138. zettcode-0.1.3/src/zettcode/tui/widgets/toast.py +136 -0
  139. zettcode-0.1.3/src/zettcode/update.py +301 -0
  140. zettcode-0.1.0/.gitignore +0 -12
  141. zettcode-0.1.0/PKG-INFO +0 -109
  142. zettcode-0.1.0/README.md +0 -89
  143. zettcode-0.1.0/pyproject.toml +0 -66
  144. zettcode-0.1.0/src/zettcode/__init__.py +0 -6
  145. zettcode-0.1.0/src/zettcode/cli.py +0 -78
  146. zettcode-0.1.0/src/zettcode/config.py +0 -72
  147. zettcode-0.1.0/src/zettcode/runtime.py +0 -121
  148. zettcode-0.1.0/src/zettcode/tui.py +0 -924
  149. zettcode-0.1.0/src/zettcode/tui_framework/__init__.py +0 -29
  150. zettcode-0.1.0/src/zettcode/tui_framework/application.py +0 -91
  151. zettcode-0.1.0/src/zettcode/tui_framework/components.py +0 -821
  152. zettcode-0.1.0/src/zettcode/tui_framework/events.py +0 -37
  153. zettcode-0.1.0/src/zettcode/tui_framework/input.py +0 -163
  154. zettcode-0.1.0/src/zettcode/tui_framework/screen.py +0 -214
  155. zettcode-0.1.0/src/zettcode/tui_framework/terminal.py +0 -118
  156. {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/
@@ -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).
@@ -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
+ ]