@ia-ccun/code-agent-cli 0.0.52-beta.3 → 0.0.52-beta.4

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.
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: ponytail-review
3
+ description: >
4
+ Code review focused exclusively on over-engineering. Finds what to delete:
5
+ reinvented standard library, unneeded dependencies, speculative abstractions,
6
+ dead flexibility. One line per finding: location, what to cut, what replaces
7
+ it. Use when the user says "review for over-engineering", "what can we
8
+ delete", "is this over-engineered", "simplify review", or invokes
9
+ /ponytail-review. Complements correctness-focused review, this one only
10
+ hunts complexity.
11
+ ---
12
+
13
+ Review diffs for unnecessary complexity. One line per finding: location, what
14
+ to cut, what replaces it. The diff's best outcome is getting shorter.
15
+
16
+ ## Format
17
+
18
+ `L<line>: <tag> <what>. <replacement>.`, or `<file>:L<line>: ...` for
19
+ multi-file diffs.
20
+
21
+ Tags:
22
+
23
+ - `delete:` dead code, unused flexibility, speculative feature. Replacement: nothing.
24
+ - `stdlib:` hand-rolled thing the standard library ships. Name the function.
25
+ - `native:` dependency or code doing what the platform already does. Name the feature.
26
+ - `yagni:` abstraction with one implementation, config nobody sets, layer with one caller.
27
+ - `shrink:` same logic, fewer lines. Show the shorter form.
28
+
29
+ ## Examples
30
+
31
+ ❌ "This EmailValidator class might be more complex than necessary, have you
32
+ considered whether all these validation rules are needed at this stage?"
33
+
34
+ ✅ `L12-38: stdlib: 27-line validator class. "@" in email, 1 line, real validation is the confirmation mail.`
35
+
36
+ ✅ `L4: native: moment.js imported for one format call. Intl.DateTimeFormat, 0 deps.`
37
+
38
+ ✅ `repo.py:L88: yagni: AbstractRepository with one implementation. Inline it until a second one exists.`
39
+
40
+ ✅ `L52-71: delete: retry wrapper around an idempotent local call. Nothing replaces it.`
41
+
42
+ ✅ `L30-44: shrink: manual loop builds dict. dict(zip(keys, values)), 1 line.`
43
+
44
+ ## Scoring
45
+
46
+ End with the only metric that matters: `net: -<N> lines possible.`
47
+
48
+ If there is nothing to cut, say `Lean already. Ship.` and stop.
49
+
50
+ ## Boundaries
51
+
52
+ Complexity only, correctness bugs, security holes, and performance go to a
53
+ normal review pass, not this one. A single smoke test or `assert`-based
54
+ self-check is the ponytail minimum, not bloat, never flag it for deletion.
55
+ Does not apply the fixes, only lists them.
56
+ "stop ponytail-review" or "normal mode": revert to verbose review style.
@@ -0,0 +1,115 @@
1
+ # Zread Skill
2
+
3
+ This repository contains a skill for `zread`, a CLI that generates wiki-style
4
+ documentation for code repositories.
5
+
6
+ The skill is meant for one job: help an agent understand an unfamiliar codebase
7
+ through `zread` output instead of re-reading the entire repository file by file.
8
+
9
+ ## Installation
10
+
11
+ ### 1. Install the zread CLI
12
+
13
+ Install `zread` first. There are two supported installation methods:
14
+
15
+ ```bash
16
+ npm install -g zread_cli
17
+ ```
18
+
19
+ or
20
+
21
+ ```bash
22
+ brew tap ZreadAI/homebrew-tap
23
+ brew install zread
24
+ ```
25
+
26
+ Then verify the installation:
27
+
28
+ ```bash
29
+ zread version
30
+ ```
31
+
32
+ ### 2. Install this skill
33
+
34
+ Ask your AI agent to install the skill from GitHub:
35
+
36
+ ```text
37
+ install this skill https://github.com/ZreadAI/zread-skill
38
+ ```
39
+
40
+ If you prefer to install it manually, copy this directory into your local
41
+ skills directory:
42
+
43
+ | Agent | Skills directory |
44
+ | ----------- | ----------------------- |
45
+ | Claude Code | `~/.claude/skills/` |
46
+ | OpenClaw | `~/.openclaw/skills/` |
47
+ | Codex | `~/.agents/skills/` |
48
+
49
+ Example:
50
+
51
+ ```bash
52
+ cp -R zread ~/.claude/skills/zread
53
+ ```
54
+
55
+ Your final layout should look like this:
56
+
57
+ ```text
58
+ <skills-dir>/zread/
59
+ SKILL.md
60
+ README.md
61
+ references/
62
+ stdio-protocol.md
63
+ ```
64
+
65
+ Once the folder is in place, an agent that supports `SKILL.md`-based skills can
66
+ load and use it.
67
+
68
+ ## Features
69
+
70
+ - Read existing `./.zread/wiki/` output instead of crawling source files again
71
+ - Guide an agent to run `zread generate` safely when documentation does not
72
+ exist yet
73
+ - Use `--stdio` as the default mode for agent automation, instead of parsing
74
+ the interactive TUI
75
+ - Explain the role of `current`, `versions`, and `drafts` in zread output
76
+ - Include a reference for the `zread --stdio` JSON-line protocol
77
+
78
+ ## When To Use
79
+
80
+ Use this skill when you want to:
81
+
82
+ - understand an unfamiliar repository quickly
83
+ - read an existing zread-generated wiki
84
+ - generate a repository overview or project wiki
85
+ - serve docs locally with `zread browse`
86
+ - drive `zread` programmatically from a script or agent
87
+
88
+ ## How It Works
89
+
90
+ The skill follows a simple workflow:
91
+
92
+ 1. If `./.zread/wiki/current` exists, read the generated wiki files directly.
93
+ 2. If no wiki exists, run `zread generate` only when the user wants docs to be
94
+ generated.
95
+ 3. Before generation, confirm with the user because generation consumes LLM
96
+ tokens and writes under `./.zread/`.
97
+ 4. In automated workflows, use `--stdio`.
98
+
99
+ ## Repository Layout
100
+
101
+ - `SKILL.md`: the skill definition, trigger conditions, and operating rules
102
+ - `references/stdio-protocol.md`: the `zread --stdio` machine protocol
103
+ - `appmap.log`: local artifact, not part of the skill itself
104
+
105
+ ## zread Output
106
+
107
+ After a successful generation, zread typically writes:
108
+
109
+ - `./.zread/wiki/current`: the active wiki version id
110
+ - `./.zread/wiki/versions/<id>/wiki.json`: the generated page index
111
+ - `./.zread/wiki/versions/<id>/<file>`: the actual markdown pages
112
+ - `./.zread/wiki/drafts/`: unfinished generation state
113
+
114
+ If you need to integrate with `zread` programmatically, see
115
+ [references/stdio-protocol.md](./references/stdio-protocol.md).
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: zread
3
+ description: Produce and consume a wiki-style knowledge base for a code repository via the `zread` CLI and its on-disk output under `./.zread/wiki/`. Use this skill whenever the user wants to understand, onboard onto, explore, summarize, map, or get an overview of an unfamiliar codebase; asks for architecture docs, a project wiki, a repo walkthrough, module/package explanations, or "what does this repo do"; wants to generate, regenerate, resume, browse, or serve code documentation locally; or mentions zread / zread.ai directly. Also use it proactively before diving into a large unknown repo — if `./.zread/wiki/current` exists, read the generated pages instead of crawling source file-by-file; if it doesn't, consider offering to run `zread generate`. The trigger is the intent (understand a codebase through generated docs), not the literal word "zread".
4
+ ---
5
+
6
+ # zread skill
7
+
8
+ `zread` is a CLI that generates wiki documentation from code in the current
9
+ workspace using an LLM. Output lives under `./.zread/wiki/` in the workspace;
10
+ public repos can also be viewed at https://zread.ai.
11
+
12
+ This skill is intended for agent use. Read generated files directly from disk,
13
+ and use `--stdio` as the default mode for any zread command instead of trying
14
+ to parse the human TUI.
15
+
16
+ ## On-disk layout (read these directly)
17
+
18
+ Always run `zread` from the workspace root. After a successful generation:
19
+
20
+ - `./.zread/wiki/current` — text file containing the active version id
21
+ (e.g. `2026-03-12-010203`).
22
+ - `./.zread/wiki/versions/<id>/wiki.json` — TOC: `{id, generated_at, language,
23
+ pages: [{slug, title, file, section, group, level}]}`.
24
+ - `./.zread/wiki/versions/<id>/<file>` — page markdown referenced by `pages[*].file`.
25
+ - `./.zread/wiki/drafts/` — in-progress generation; presence means a previous
26
+ run did not finish. `drafts/wiki.json` exists once the catalog phase
27
+ completed.
28
+ - `~/.zread/config.yaml` — global config (LLM provider, language, concurrency).
29
+ - `~/.zread/login.json` — presence indicates the user has logged in.
30
+
31
+ To answer questions about a codebase that already has zread output, read these
32
+ files directly with the file tools — do not invoke `zread browse`.
33
+
34
+ ## Commands
35
+
36
+ | Command | Purpose | Key flags |
37
+ |---|---|---|
38
+ | `zread generate` | Generate wiki for cwd | `-y/--yes`, `--draft resume\|clear\|cancel`, `--skip-failed`, `--stdio` |
39
+ | `zread browse` | Serve docs at http://localhost:9681+ and open browser | `--generate`, `--version <id>`, `--host`, `--port`, `--stdio` |
40
+ | `zread login` | OAuth into BigModel/Z.AI to obtain an API key | `--custom`, `--model`, `--stdio` |
41
+ | `zread config` | Edit `~/.zread/config.yaml` | `--stdio` |
42
+ | `zread update` | Self-update CLI | `--stdio` |
43
+ | `zread version` | Print version | `--stdio` |
44
+
45
+ `--stdio` is supported on every command and turns the process into a JSON-line
46
+ machine protocol on stdin/stdout. See
47
+ [references/stdio-protocol.md](./references/stdio-protocol.md) for the wire
48
+ format (events, `waiting_for`, `done`, `quit`). Load it whenever zread is
49
+ invoked from another program/agent.
50
+
51
+ ## Decision tree for an AI agent
52
+
53
+ 1. **User wants to read existing wiki content?**
54
+ - Check `./.zread/wiki/current`. If present, read `wiki.json` and the page
55
+ markdown directly. No CLI invocation needed.
56
+ - For known *public* GitHub repos, prefer the `mcp__zread__*` tools
57
+ (`get_repo_structure`, `read_file`, `search_doc`) over running the CLI.
58
+
59
+ 2. **User wants to (re)generate docs?**
60
+ - Confirm with the user first — `generate` is long-running, calls an LLM,
61
+ and writes files. Get explicit consent in unfamiliar directories.
62
+ - Verify `~/.zread/login.json` exists or `~/.zread/config.yaml` has an
63
+ `llm.api_key`. If neither, run `zread login` first.
64
+ - If `./.zread/wiki/drafts/` exists, decide:
65
+ - resume previous run → `zread generate --draft resume -y`
66
+ - throw away and start fresh → `zread generate --draft clear -y`
67
+ - Otherwise: `zread generate -y`.
68
+ - To not block on a few failing pages: add `--skip-failed`.
69
+
70
+ 3. **User wants to view docs in a browser?**
71
+ - `zread browse` (add `--generate` to bootstrap if no wiki exists yet).
72
+
73
+ 4. **User wants to script zread / consume output programmatically?**
74
+ - Use `--stdio` and follow stdio-protocol.md. Do not screen-scrape the TUI.
75
+
76
+ ## Non-interactive invocation rules
77
+
78
+ - Always pass `-y` to `generate` when running unattended; otherwise it stops
79
+ at a catalog confirmation gate.
80
+ - Always set `--draft` explicitly when a draft may exist, so the command does
81
+ not prompt.
82
+ - For any command run from another agent/script, use `--stdio` so output is
83
+ parseable JSON instead of ANSI TUI frames.
84
+ - `zread` writes logs to `~/.zread/log/zread.log` — read this if a run fails
85
+ silently.
86
+
87
+ ## Safety / blast radius
88
+
89
+ - `generate` consumes LLM tokens (real cost) and can run for many minutes on
90
+ large repos. Confirm before launching.
91
+ - `generate` writes only under `./.zread/` and does not commit anything to
92
+ git. It is safe to delete `./.zread/wiki/drafts/` to recover from a stuck
93
+ state.
94
+ - `update` replaces the zread binary in place and is hard to reverse — only
95
+ run it when the user explicitly asks.
96
+ - `login` opens a browser for OAuth; do not run it in a non-interactive
97
+ context unless the user has asked for it.
98
+
99
+ ## Reference files
100
+
101
+ - [references/stdio-protocol.md](./references/stdio-protocol.md) — JSON-line
102
+ wire protocol shared by every command's `--stdio` mode. Load when
103
+ programmatically driving zread.
@@ -0,0 +1,312 @@
1
+ # zread `--stdio` protocol
2
+
3
+ Every zread command accepts `--stdio`, switching the process from an interactive
4
+ TUI into a JSON-line machine protocol on stdin/stdout. This is the contract used
5
+ by GUI / programmatic clients to drive zread.
6
+
7
+ ## Architecture
8
+
9
+ zread internally uses a Driver / Client split:
10
+
11
+ - **Driver** holds all business logic (loading config, calling LLMs, running the
12
+ doc server, managing drafts). It is framework-agnostic and only talks to a
13
+ `Transport`.
14
+ - **Client** is either a Bubbletea TUI or `StdioClient`. With `--stdio`, the
15
+ cobra command instantiates `transport.NewLocalTransport()` (a channel pair),
16
+ spawns the driver in a goroutine, then runs `StdioClient.Run(ctx)`.
17
+ - `StdioClient` reads JSON lines from `os.Stdin` and forwards them as commands
18
+ to the driver, while encoding `Event`s from the driver to `os.Stdout` (one
19
+ JSON object per line). It returns when an event with `"done": true` is
20
+ received.
21
+
22
+ Result: stdin = command stream, stdout = event stream, both newline-delimited
23
+ JSON. stderr is reserved for logs/errors and should not be parsed.
24
+
25
+ ## Event format (driver → client, stdout)
26
+
27
+ ```json
28
+ {
29
+ "vm": { ... },
30
+ "waiting_for": ["..."],
31
+ "done": false,
32
+ "error": ""
33
+ }
34
+ ```
35
+
36
+ - `vm`: full ViewModel snapshot for the current state (shape varies per command — see below).
37
+ - `waiting_for`: command `type` values the client may legally send right now. `quit` is always accepted regardless.
38
+ - `done`: `true` on the final event; the process will exit on its own.
39
+ - `error`: non-empty when the previous command was rejected; `vm`/`waiting_for` remain unchanged.
40
+
41
+ Rules:
42
+ - An event is emitted after every state transition. Treat `vm` as the full current state (no diffs).
43
+ - `waiting_for: []` with `done: false` means the driver is awaiting an internal async result — do not send any command; just keep reading.
44
+ - The very last event always has `done: true` and an empty `waiting_for`.
45
+
46
+ ## Command format (client → driver, stdin)
47
+
48
+ One JSON object per line:
49
+
50
+ ```json
51
+ {"type": "<command_type>", "params": { ... }}
52
+ ```
53
+
54
+ - `type` is required. `params` may be omitted (treated as `{}`).
55
+ - Universal command: `{"type":"quit","params":{}}` — every driver handles it and shuts down cleanly.
56
+ - Command types prefixed with `_` are driver-internal. They never appear in `waiting_for`; clients must not send them.
57
+ - Sending a command not in `waiting_for` returns an event with `error` set while `vm`/`waiting_for` remain unchanged.
58
+ - Error message format: `"command \"xxx\" not allowed in state yyy"` / `"invalid params: ..."` / `"invalid JSON: ..."`.
59
+
60
+ ## Driving a session
61
+
62
+ 1. Spawn `zread <command> --stdio` with piped stdin/stdout.
63
+ 2. Read the first event — it carries the initial ViewModel and `waiting_for`.
64
+ 3. Render or inspect `vm`; pick a legal command from `waiting_for` and write it as a single JSON line followed by `\n`.
65
+ 4. Loop: read next event, react, write next command.
66
+ 5. Stop when `done: true` arrives. The process will exit on its own. Sending `quit` at any time triggers the same shutdown.
67
+
68
+ ---
69
+
70
+ ## `zread browse --stdio`
71
+
72
+ ### ViewModel fields
73
+
74
+ | Field | Type | Notes |
75
+ |---|---|---|
76
+ | `state` | string | `"loading"` `"serving"` `"select_version"` `"no_wiki"` `"error"` |
77
+ | `url` | string | Local server URL; present when `state="serving"` |
78
+ | `browser_opened` | bool | Whether the browser was auto-launched |
79
+ | `has_current` | bool | Whether a "current" wiki version exists |
80
+ | `versions` | array | Present when `state="select_version"` |
81
+ | `versions[].id` | string | Wiki version ID |
82
+ | `versions[].timestamp` | string | Version timestamp |
83
+ | `versions[].is_current` | bool | Whether this is the current version |
84
+ | `error` | string | Present when `state="error"` |
85
+
86
+ ### Commands
87
+
88
+ | State | `waiting_for` | Command | Params |
89
+ |---|---|---|---|
90
+ | `select_version` | `["select_version","quit"]` | `select_version` | `{"wiki_id":"<id>"}` or `{"current":true}` |
91
+ | `serving` | `["quit"]` | — | — |
92
+ | `no_wiki` | `["quit"]` | — | — |
93
+ | `loading` | `[]` | *(wait for internal event)* | — |
94
+ | `error` | `[]` | — | — |
95
+
96
+ ### State machine
97
+
98
+ ```
99
+ loading ──(server ok)──────────────────► serving
100
+ loading ──(error)──────────────────────► error (terminal)
101
+ select_version ──(select_version cmd)──► loading ──► serving
102
+ no_wiki ───────────────────────────────► (terminal, done=true)
103
+ ```
104
+
105
+ ---
106
+
107
+ ## `zread generate --stdio`
108
+
109
+ ### ViewModel fields
110
+
111
+ | Field | Type | Notes |
112
+ |---|---|---|
113
+ | `state` | string | `"select_action"` `"running"` `"done"` `"error"` |
114
+ | `max_retries` | int | Configured max retries per page |
115
+ | `select_action.scenario` | string | `"has_wiki"` `"has_draft"` `"empty"` |
116
+ | `select_action.wiki_date` | string | Date of existing wiki (when `scenario="has_wiki"`) |
117
+ | `select_action.draft_done` | int | Pages already done in draft |
118
+ | `select_action.draft_total` | int | Total pages in draft |
119
+ | `select_action.next_action` | string | Pre-suggested action: `"generate"` `"browse"` `""` |
120
+ | `catalog.status` | string | `"idle"` `"running"` `"done"` `"resumed"` `"error"` |
121
+ | `catalog.tool_name` | string | Currently-running LLM tool (if any) |
122
+ | `catalog.error` | string | Catalog error message |
123
+ | `catalog.auto_retry` | int | Auto-retry count so far |
124
+ | `pages.tasks` | array | Per-page task list |
125
+ | `pages.tasks[].id` | int | Task ID (used for `retry` command) |
126
+ | `pages.tasks[].title` | string | Page title |
127
+ | `pages.tasks[].slug` | string | Page slug |
128
+ | `pages.tasks[].state` | string | `"pending"` `"running"` `"retry_pending"` `"done"` `"failed"` `"resumed"` |
129
+ | `pages.tasks[].retry_count` | int | Retries attempted so far |
130
+ | `pages.tasks[].max_retries` | int | Retry limit for this task |
131
+ | `pages.tasks[].error` | string | Error message if failed |
132
+ | `pages.done` | int | Completed page count |
133
+ | `pages.total` | int | Total page count |
134
+ | `pages.waiting_retry` | bool | `true` when driver is paused waiting for retry/skip decision |
135
+ | `done_total` | int | Total pages done (in `state="done"`) |
136
+ | `error` | string | Fatal error message |
137
+
138
+ ### Commands
139
+
140
+ | State / condition | `waiting_for` | Command | Params |
141
+ |---|---|---|---|
142
+ | `select_action` | `["select_action","cancel","quit"]` | `select_action` | `{"action":"generate"}` or `"browse"` or `"resume"` or `"clear"` or `"cancel"` |
143
+ | `running` (normal) | `["quit"]` | — | — |
144
+ | `running` (catalog error) | `["quit","retry_catalog"]` | `retry_catalog` | `{}` |
145
+ | `running` (pages waiting retry) | `["quit","retry","skip_all"]` | `retry` | `{"task_id":<int>}` |
146
+ | `running` (pages waiting retry) | `["quit","retry","skip_all"]` | `skip_all` | `{}` |
147
+ | `running` | `["quit","cancel"]` | `cancel` | `{}` |
148
+
149
+ ### CLI flags that affect stdio flow
150
+
151
+ - `--yes` / `-y`: skips the `select_action` gate; generation starts immediately.
152
+ - `--draft-action <resume|clear|cancel>`: pre-answers the draft prompt.
153
+ - `--skip-failed`: equivalent to auto-sending `skip_all` when pages fail.
154
+
155
+ ### State machine
156
+
157
+ ```
158
+ select_action ──(generate/resume)──► running ──(all done, no failures)──► done
159
+ select_action ──(cancel/browse)────► done (immediate)
160
+ running ──(pages failed)───────────► waiting_retry=true, accepts retry/skip_all
161
+ running ──(cancel)─────────────────► done
162
+ ```
163
+
164
+ ---
165
+
166
+ ## `zread config --stdio`
167
+
168
+ ### ViewModel fields
169
+
170
+ | Field | Type | Notes |
171
+ |---|---|---|
172
+ | `fields` | array (9 items) | Ordered config fields |
173
+ | `fields[].title_key` | string | Display label key |
174
+ | `fields[].json_key` | string | Key to use in `update_fields`; empty = read-only |
175
+ | `fields[].initial` | string | Value at load time |
176
+ | `fields[].value` | string | Current (possibly edited) value |
177
+ | `dirty` | bool | `true` if any field differs from `initial` |
178
+ | `saved` | bool | `true` after successful save |
179
+ | `error` | string | Validation error |
180
+
181
+ Field index → `json_key` mapping:
182
+
183
+ | Index | `json_key` | Notes |
184
+ |---|---|---|
185
+ | 0 | `language` | generation language |
186
+ | 1 | `doc_language` | doc language |
187
+ | 2 | *(empty)* | read-only LLM provider display |
188
+ | 3 | `max_concurrent` | int |
189
+ | 4 | `max_retries` | int |
190
+ | 5 | `llm_provider` | editable in stdio mode |
191
+ | 6 | `llm_base_url` | editable in stdio mode |
192
+ | 7 | `llm_model` | editable in stdio mode |
193
+ | 8 | `llm_api_key` | editable in stdio mode |
194
+
195
+ ### Commands
196
+
197
+ No state machine. Fixed `waiting_for`: `["update_fields","save","reload_llm","quit"]`.
198
+
199
+ | Command | Params | Effect |
200
+ |---|---|---|
201
+ | `update_fields` | `{"fields":{"<json_key>": "<value>", ...}}` | Partial update; only listed keys change |
202
+ | `save` | `{}` | Persists config and terminates (`done=true`) |
203
+ | `reload_llm` | `{}` | Re-validates LLM provider settings |
204
+ | `quit` | `{}` | Exits without saving |
205
+
206
+ ---
207
+
208
+ ## `zread login --stdio`
209
+
210
+ ### ViewModel fields
211
+
212
+ | Field | Type | Notes |
213
+ |---|---|---|
214
+ | `state` | string | See states below |
215
+ | `authorize_url` | string | OAuth URL to open; present in `open_browser` state |
216
+ | `auth_timeout` | int | Nanoseconds until auth expires; present in `waiting` state |
217
+ | `browser_warn` | string | Warning if browser launch failed |
218
+ | `username` | string | Logged-in username; present in `done` state |
219
+ | `avail_models` | array of string | Models to choose from; present in `select_model` state |
220
+ | `selected_model` | string | Currently selected model |
221
+ | `error` | string | Error message in `error` state |
222
+ | `wants_llm_provider_editor` | bool | `true` (with `done=true`) when `--custom` flag was used |
223
+
224
+ States: `"select_region"` → `"init_flow"` → `"open_browser"` → `"waiting"` → `"select_model"` → `"saving"` → `"done"` / `"error"`
225
+
226
+ ### Commands
227
+
228
+ | State | `waiting_for` | Command | Params |
229
+ |---|---|---|---|
230
+ | `select_region` | `["select_region","quit"]` | `select_region` | `{"region":"<provider_key>"}` or `{"region":"__use_own_key__"}` |
231
+ | `select_model` | `["select_model","quit"]` | `select_model` | `{"model":"<model_id>"}` |
232
+ | all others | `[]` | *(wait for internal auth events)* | — |
233
+
234
+ ### Special cases
235
+
236
+ - `--custom` flag: driver immediately emits `done: true` with `wants_llm_provider_editor: true`. Client should then launch `zread config --stdio` to configure a custom LLM provider.
237
+
238
+ ### State machine
239
+
240
+ ```
241
+ select_region ──(cmd)──► init_flow ──► open_browser ──► waiting ──► select_model
242
+ select_model ──(cmd)───► saving ──► done
243
+ any ────────────────────────────────────────────────────────────────► error
244
+ ```
245
+
246
+ ---
247
+
248
+ ## `zread update --stdio`
249
+
250
+ ### ViewModel fields
251
+
252
+ | Field | Type | Notes |
253
+ |---|---|---|
254
+ | `state` | string | See states below |
255
+ | `current_version` | string | Installed version |
256
+ | `latest_version` | string | Available version; present in `has_update`+ |
257
+ | `download_url` | string | Asset URL for the update binary |
258
+ | `package_manager` | string | e.g. `"brew"`; present in `package_manager` state |
259
+ | `downloaded_bytes` | int | Bytes downloaded so far |
260
+ | `total_bytes` | int | Total download size |
261
+ | `download_percent` | float | 0–100 |
262
+ | `error` | string | Error message in `error` state |
263
+
264
+ States: `"checking"` → `"up_to_date"` / `"package_manager"` / `"has_update"` → `"downloading"` → `"confirm_restart"` / `"error"`
265
+
266
+ Terminal states (emit `done=true`): `up_to_date`, `package_manager`, `error`, and after restart/skip.
267
+
268
+ ### Commands
269
+
270
+ | State | `waiting_for` | Command | Params |
271
+ |---|---|---|---|
272
+ | `has_update` | `["download","quit"]` | `download` | `{}` |
273
+ | `confirm_restart` | `["restart","skip_restart","quit"]` | `restart` | `{}` |
274
+ | `confirm_restart` | `["restart","skip_restart","quit"]` | `skip_restart` | `{}` |
275
+ | all others | `[]` | *(wait for internal events)* | — |
276
+
277
+ ### State machine
278
+
279
+ ```
280
+ checking ──► up_to_date (terminal)
281
+ ──► package_manager (terminal)
282
+ ──► has_update ──(download)──► downloading ──► confirm_restart
283
+ ──(restart/skip)──► done
284
+ checking / downloading ──(error)──► error (terminal)
285
+ ```
286
+
287
+ ---
288
+
289
+ ## `zread version --stdio`
290
+
291
+ Emits a single event with `done: true` immediately. No commands are accepted.
292
+
293
+ ### ViewModel fields
294
+
295
+ | Field | Type | Notes |
296
+ |---|---|---|
297
+ | `version` | string | e.g. `"1.2.3"` |
298
+ | `channel` | string | Release channel (if set) |
299
+ | `go_version` | string | Go runtime version |
300
+ | `os` | string | OS name |
301
+ | `arch` | string | CPU architecture |
302
+
303
+ ---
304
+
305
+ ## Practical tips
306
+
307
+ - Always flush stdin after writing a command (the driver reads line-by-line).
308
+ - Treat any line on stdout that fails to parse as JSON as a bug — log it but do not crash; zread should not print non-JSON to stdout in `--stdio` mode.
309
+ - When `waiting_for` is `[]` and `done` is `false`, keep reading — the driver is awaiting an internal async result and will emit the next event on its own.
310
+ - For long-running commands (`generate`), keep reading events continuously; there is no heartbeat, but progress events arrive whenever state changes.
311
+ - To cancel cleanly, send `{"type":"quit","params":{}}` and then drain events until `done` rather than killing the process.
312
+ - `done: true` events are always terminal. Do not send further commands.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ia-ccun/code-agent-cli",
3
- "version": "0.0.52-beta.3",
3
+ "version": "0.0.52-beta.4",
4
4
  "description": "AI Coding Agent CLI - 基于OpenClaw🦞底层Agent原理封装的编码智能体(供学习使用)。",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,7 +38,8 @@
38
38
  "@earendil-works/pi-agent-core": "^0.77.0",
39
39
  "@earendil-works/pi-ai": "^0.77.0",
40
40
  "@earendil-works/pi-coding-agent": "^0.77.0",
41
- "@earendil-works/pi-tui": "^0.77.0"
41
+ "@earendil-works/pi-tui": "^0.77.0",
42
+ "@firstpick/pi-utils": "^0.2.2"
42
43
  },
43
44
  "overrides": {
44
45
  "glob": "^11.0.0",
@@ -60,6 +61,7 @@
60
61
  "@typescript-eslint/parser": "^8.57.0",
61
62
  "eslint": "^10.0.3",
62
63
  "husky": "^9.1.7",
64
+ "pi-lean-ctx": "^3.8.11",
63
65
  "playwright": "^1.60.0",
64
66
  "shx": "^0.4.0",
65
67
  "typescript": "^5.7.2",
@@ -241,7 +241,6 @@ const FORCE_OVERWRITE_LIST = [
241
241
  'APPEND_SYSTEM.md',
242
242
  'SYSTEM.md',
243
243
  'dangerous-patterns.json',
244
- 'settings.json',
245
244
  'help.md',
246
245
  'extensions/*.ts',
247
246
  'prompts/*.md',