pyrepowiki-cli 0.1.0__py3-none-any.whl

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,875 @@
1
+ Metadata-Version: 2.5
2
+ Name: pyrepowiki-cli
3
+ Version: 0.1.0
4
+ Summary: CLI tool for querying DeepWiki/Google code wiki/Zread wiki documentation
5
+ License: MIT
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: httpx>=0.27.0
8
+ Requires-Dist: mcp<2.0.0,>=1.0.0
9
+ Requires-Dist: rich>=13.0.0
10
+ Requires-Dist: typer>=0.12.0
11
+ Requires-Dist: websockets>=13.0.0
12
+ Description-Content-Type: text/markdown
13
+
14
+ # repowiki-cli
15
+
16
+ Query [DeepWiki](https://deepwiki.com), [Google Code Wiki](https://codewiki.google),
17
+ and [zread.ai](https://zread.ai) documentation for any public GitHub repository
18
+ from your terminal.
19
+
20
+ > 中文文档见 [README.zh-CN.md](README.zh-CN.md) · Chinese docs:
21
+ > [README.zh-CN.md](README.zh-CN.md)
22
+
23
+ ## What it is
24
+
25
+ `repowiki-cli` is a Python/Typer CLI that reads AI-generated repository
26
+ documentation and answers questions about code, from the terminal. It speaks to
27
+ **three wiki services** behind a single uniform command surface, one namespace
28
+ per service:
29
+
30
+ | Service | Namespace | Transport | Auth |
31
+ |---------|-----------|-----------|------|
32
+ | **DeepWiki** | `deepwiki` | MCP (Streamable HTTP) + reverse REST/WebSocket | none |
33
+ | **Google Code Wiki** | `codewiki` | Google `batchexecute` RPC | none |
34
+ | **Zread** | `zread` | JSON REST + SSE | `ask` / `submit` need a token |
35
+
36
+ DeepWiki is served by two interchangeable backends:
37
+
38
+ | Backend | Transport | Commands | Richness |
39
+ |---------|-----------|----------|----------|
40
+ | **MCP** (official) | Streamable HTTP | `structure`, `contents`, `ask`, `cp` | body only |
41
+ | **Reverse** (`api.devin.ai`) | REST + WebSocket | `ask` (with flags) + `list` / `status` / `warm` / `get` / `stat` | body, summary, references, sources, stats |
42
+
43
+ The MCP backend is the official, documented DeepWiki server and is free for
44
+ public repos with no auth. The reverse backend is the underlying engine
45
+ `api.devin.ai` (same as the DeepWiki web app) — it is *not* a documented public
46
+ API, but it exposes engine selection (`fast`/`deep`/`codemap`), streaming,
47
+ conversation threading, and index-management endpoints that MCP does not.
48
+
49
+ ## Install
50
+
51
+ ```bash
52
+ uvx repowiki-cli --help
53
+ ```
54
+
55
+ From source:
56
+
57
+ ```bash
58
+ git clone <this-repo> && cd <this-repo>
59
+ uv sync
60
+ uv run repowiki-cli --help
61
+ ```
62
+
63
+ ## Quick start
64
+
65
+ ```bash
66
+ repowiki-cli deepwiki structure facebook/react # table of contents
67
+ repowiki-cli deepwiki contents vercel/next.js # full documentation
68
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?"
69
+ repowiki-cli codewiki ask facebook/react "What is Fiber?"
70
+ repowiki-cli zread contents vercel/next.js # overview page
71
+ ```
72
+
73
+ ## Command overview
74
+
75
+ | Command | Purpose | Service |
76
+ |---------|---------|---------|
77
+ | `structure REPO` | Print the documentation table of contents | DeepWiki (MCP) |
78
+ | `contents REPO` | Print the full documentation | DeepWiki (MCP) |
79
+ | `ask REPO [QUESTION]` | Answer a question (single-shot or interactive) | DeepWiki (MCP / reverse) |
80
+ | `list SEARCH` | Search indexed public repos | DeepWiki (reverse) |
81
+ | `status REPO` | Report a repo's indexing status | DeepWiki (reverse) |
82
+ | `warm REPO` | Pre-warm a repo's docs cache | DeepWiki (reverse) |
83
+ | `get QUERY_ID` | Replay a past answer by query id | DeepWiki (reverse) |
84
+ | `stat REPO` | Report a repo's index metadata | DeepWiki (reverse) |
85
+ | `cp REPO [OUTPUT_DIR]` | Export the whole wiki as Markdown + `llms.txt`/`README.md` | DeepWiki (MCP) |
86
+ | `structure REPO` | Print the documentation table of contents | CodeWiki |
87
+ | `contents REPO` | Print the full documentation | CodeWiki |
88
+ | `ask REPO [QUESTION]` | Answer a question (single-shot or interactive) | CodeWiki |
89
+ | `stat REPO` | Show the commit the wiki was generated from | CodeWiki |
90
+ | `cp REPO [OUTPUT_DIR]` | Export the whole wiki as Markdown + `llms.txt`/`README.md` | CodeWiki |
91
+ | `structure REPO` | Print the documentation table of contents | Zread |
92
+ | `contents REPO [SLUG]` | Print a page of documentation (default: overview) | Zread |
93
+ | `ask REPO [QUESTION]` | Answer a question (single-shot or interactive, needs token) | Zread |
94
+ | `find QUERY` | Search repositories | Zread |
95
+ | `stat REPO` | Report a repo's info and index status | Zread |
96
+ | `top [WEEKS]` | Show the trending list | Zread |
97
+ | `rand [TOPIC]` | Get a random repository recommendation | Zread |
98
+ | `cp REPO [OUTPUT_DIR]` | Export the whole wiki as Markdown + `llms.txt`/`README.md` | Zread |
99
+ | `submit REPO` | Submit a repo for indexing (needs token) | Zread |
100
+
101
+ Each service is documented in its own section below: [DeepWiki](#deepwiki),
102
+ [CodeWiki](#codewiki), [Zread](#zread).
103
+
104
+ ## Repo formats
105
+
106
+ `REPO` accepts any of:
107
+
108
+ - `owner/repo`
109
+ - `github.com/owner/repo`
110
+ - `www.github.com/owner/repo`
111
+ - `https://github.com/owner/repo` (optionally with `/tree/main` or `.git`)
112
+
113
+ Everything is normalized to `owner/repo`.
114
+
115
+ ## JSON output
116
+
117
+ Main commands emit an envelope with `repo` and `command`:
118
+
119
+ ```json
120
+ {
121
+ "repo": "facebook/react",
122
+ "command": "ask",
123
+ "question": "What is Fiber?",
124
+ "answer": "..."
125
+ }
126
+ ```
127
+
128
+ DeepWiki `ask` additionally includes `summary`, `references`, `sources`, `stats`,
129
+ and `query_id` when the reverse backend provides them. Management commands
130
+ (`list` / `status` / `warm` / `get` / `stat`) omit `repo` and use `command` +
131
+ fields only. Errors go to stderr as `{"error": ..., "kind": ...}`.
132
+
133
+ ## Saving (`--save`)
134
+
135
+ `--save` writes answers to a Markdown file:
136
+
137
+ - `--save PATH` writes to (and appends to) the given path, creating parent
138
+ directories. CodeWiki and Zread `ask` take a required path.
139
+ - DeepWiki `ask` also accepts a bare `--save`, which auto-names the file
140
+ `repowiki-<owner>-<repo>_<timestamp>.md` in the current directory.
141
+ - In interactive mode all answers in the session append to one file; single-shot
142
+ answers append when the file already exists.
143
+ - Combine with `--json` to keep stdout as JSON while writing Markdown to the file.
144
+
145
+ ## Environment variables
146
+
147
+ | Variable | Purpose | Default |
148
+ |----------|---------|---------|
149
+ | `DEEPWIKI_MCP_URL` | DeepWiki MCP endpoint | `https://mcp.deepwiki.com/mcp` |
150
+ | `DEEPWIKI_API_URL` | DeepWiki reverse backend endpoint | `https://api.devin.ai` |
151
+ | `DEEPWIKI_REPL_RETRIES` | DeepWiki reverse REPL retry attempts | `4` |
152
+ | `DEEPWIKI_TIMEOUT` | DeepWiki reverse answer timeout in seconds | `120` (`300` for `--mode deep`) |
153
+ | `CODEWIKI_CACHE_DIR` | CodeWiki bootstrap cache directory | `$XDG_CACHE_HOME` or `~/.cache` |
154
+ | `ZREAD_TOKEN` | Zread auth token for `ask` / `submit` | — |
155
+ | `ZREAD_LANG` | Zread default language | `en` |
156
+ | `ZREAD_MODEL` | Zread `ask` model | `glm-5.1` |
157
+ | `REPOWIKI_MOCK_TEXT` | mock MCP result (tests) | — |
158
+ | `REPOWIKI_DEVIN_MOCK` | mock reverse answer (tests) | — |
159
+ | `REPOWIKI_CODEWIKI_MOCK` | mock CodeWiki result (tests) | — |
160
+ | `REPOWIKI_ZREAD_MOCK` | mock Zread result (tests) | — |
161
+
162
+ ## DeepWiki
163
+
164
+ [DeepWiki](https://deepwiki.com) is the primary service, exposed under the
165
+ `deepwiki` namespace. It reads **public repositories** with **no auth**.
166
+
167
+ ### `deepwiki structure`
168
+
169
+ ```bash
170
+ repowiki-cli deepwiki structure REPO [--json]
171
+ ```
172
+
173
+ Prints the documentation table of contents (MCP `read_wiki_structure`).
174
+
175
+ ### `deepwiki contents`
176
+
177
+ ```bash
178
+ repowiki-cli deepwiki contents REPO [--page TITLE] [--rich] [--json]
179
+ ```
180
+
181
+ Prints the full documentation (MCP `read_wiki_contents`), which can be large.
182
+
183
+ - `--page TITLE` — print only the page whose title matches (case-insensitive
184
+ exact match). The `# Page:` delimiter is dropped, so the selected page shows a
185
+ single heading. If no page matches, the available titles are listed (to
186
+ stderr) and the command exits with error kind `page_not_found`.
187
+ - `--rich` — render Markdown with color/formatting via `rich`.
188
+ - `--json` — emit a JSON envelope instead of Markdown.
189
+
190
+ ### `deepwiki ask`
191
+
192
+ ```bash
193
+ repowiki-cli deepwiki ask REPO [QUESTION] \
194
+ [--rich] [--json] [--save [PATH]] \
195
+ [--mode fast|deep|codemap] [--id QUERY_ID] \
196
+ [--sources] [--no-summary] [--context TEXT] [--repo REPO]... \
197
+ [--mermaid] [--stream] [--timeout SECONDS]
198
+ ```
199
+
200
+ With a `QUESTION`, it answers once and exits. Without one, it enters an
201
+ interactive REPL (type `/exit` to quit).
202
+
203
+ **Backend routing.** `ask` uses the MCP backend unless at least one reverse flag
204
+ is present. Any of `--mode`, `--id`, `--sources`, `--repo`, `--context`,
205
+ `--no-summary`, or `--stream` switches it to the reverse backend. `--mermaid`
206
+ alone does **not** switch backends — pair it with `--mode codemap`.
207
+
208
+ - `--mode fast|deep|codemap` — engine selection. Mapping to the underlying
209
+ engine id: `fast` → `multihop_faster`, `deep` → `agent`, `codemap` → `codemap`.
210
+ - `--id QUERY_ID` — reuse a previous query id to continue the same conversation
211
+ thread.
212
+ - `--sources` — append line-numbered source-code slices for each citation.
213
+ - `--context TEXT` — pass additional context alongside the question.
214
+ - `--no-summary` — skip summary generation.
215
+ - `--repo REPO` — repeatable; ask one question against multiple repos at once
216
+ (the positional `repo` plus every `--repo`).
217
+ - `--mermaid` — render a `codemap` answer as a Mermaid `flowchart TB`. If the
218
+ answer is not a codemap, it warns and falls back to plain text. Paste the
219
+ output into mermaid.live, GitHub, or VS Code to view it.
220
+ - `--stream` — stream answer text chunk-by-chunk over a WebSocket instead of
221
+ waiting for the full answer, then append the summary and sources. Output is
222
+ plain text, so `--rich` has no effect. A mid-answer drop falls back to
223
+ polling. No effect with `--json`.
224
+ - `--timeout SECONDS` — answer timeout for the reverse backend. Defaults to
225
+ `120`, or `300` for `--mode deep`. Overrides `DEEPWIKI_TIMEOUT`.
226
+ - `--save [PATH]` — save each answer to a Markdown file (see *Saving*).
227
+ - `--rich` — render the answer's Markdown with `rich`. No effect with
228
+ `--stream`.
229
+ - `--json` — emit a JSON envelope. Ignored in interactive mode.
230
+
231
+ ### `deepwiki list`
232
+
233
+ ```bash
234
+ repowiki-cli deepwiki list SEARCH [--json]
235
+ ```
236
+
237
+ Searches DeepWiki's public index (reverse `list_public_indexes`).
238
+
239
+ ### `deepwiki status`
240
+
241
+ ```bash
242
+ repowiki-cli deepwiki status REPO [--json]
243
+ ```
244
+
245
+ Reports a repo's indexing state (reverse `public_repo_indexing_status`).
246
+ `unknown` is a normal result for an unindexed repo and exits `0`.
247
+
248
+ ### `deepwiki warm`
249
+
250
+ ```bash
251
+ repowiki-cli deepwiki warm REPO [--json]
252
+ ```
253
+
254
+ Pre-warms a repo's docs cache (reverse `warm_public_repo`).
255
+
256
+ ### `deepwiki get`
257
+
258
+ ```bash
259
+ repowiki-cli deepwiki get QUERY_ID [--rich] [--sources] [--json] [--mermaid]
260
+ ```
261
+
262
+ Replays a past answer by query id (reverse `get_query`).
263
+
264
+ ### `deepwiki stat`
265
+
266
+ ```bash
267
+ repowiki-cli deepwiki stat REPO [--human] [--stale] [--json]
268
+ ```
269
+
270
+ Shows a repo's index metadata from the reverse `list_public_indexes` — the
271
+ short commit sha (last segment of the index `id`) and `last_modified` (the
272
+ "Last indexed" timestamp shown on deepwiki.com).
273
+
274
+ - `--human` — render `last_modified` as a local, space-separated time.
275
+ - `--stale` — compare the indexed short sha against GitHub HEAD (via
276
+ `api.github.com/.../commits/HEAD`) and print `最新`/`过期`. Note: a refresh
277
+ (re-index) has no public endpoint — `index_public_repo` is reCAPTCHA-gated —
278
+ so `stat` can only *detect* staleness, not fix it.
279
+ - `--json` — emit a JSON envelope (with `stale` when `--stale` is set).
280
+
281
+ ### `deepwiki cp`
282
+
283
+ ```bash
284
+ repowiki-cli deepwiki cp REPO [OUTPUT_DIR]
285
+ ```
286
+
287
+ Exports the full wiki (MCP `read_wiki_contents`) as one Markdown file per
288
+ `# Page:` section, plus `llms.txt` / `README.md` (index) and `llms-full.txt`
289
+ (concatenated). `OUTPUT_DIR` defaults to `owner_repo`.
290
+
291
+ **Implementation:** the raw Markdown is split on `# Page:` delimiters by
292
+ `shared/output.py::split_pages` (a payload with no delimiters becomes a single
293
+ `Overview` page). Files are written by the shared `shared/export.py::export_pages`
294
+ helper, which names each page `NN-slug.md` and also emits `llms.txt` (index of
295
+ `- [title](NN-slug.md)` links), a `README.md` with the same index for GitHub
296
+ auto-rendering, and `llms-full.txt` (the whole concatenated text).
297
+
298
+ ### DeepWiki design
299
+
300
+ The whole CLI shares one result type, `Answer`, so both backends feed the same
301
+ formatting layer:
302
+
303
+ ```python
304
+ @dataclass
305
+ class Answer:
306
+ body: str # main answer text
307
+ summary: str | None = None # reverse backend only
308
+ references: list[Reference] = [] # {file_path, range_start, range_end}
309
+ sources: list[SourceFile] = [] # {repo, path, content}
310
+ stats: dict[str, float] = {} # reverse backend only
311
+ query_id: str | None = None # reverse backend only
312
+ ```
313
+
314
+ The MCP backend produces a bare `Answer(body=...)`. The reverse backend fills in
315
+ summary, references, sources, stats, and query_id — all carried by `--json`.
316
+
317
+ ### DeepWiki backends in detail
318
+
319
+ **MCP backend (`services/deepwiki/client.py`)**
320
+
321
+ - Endpoint: `DEEPWIKI_MCP_URL`, default `https://mcp.deepwiki.com/mcp`.
322
+ - Speaks **Streamable HTTP** (the SSE endpoint is deprecated).
323
+ - Tools: `read_wiki_structure`, `read_wiki_contents`, `ask_question`.
324
+ - Tool arguments use camelCase: `repoName` (and `question` for `ask_question`).
325
+ - Connection lifecycle:
326
+ - One-shot commands open/close a session per call.
327
+ - The interactive REPL opens **one** session and reuses it across questions.
328
+ - The initial connect is retried once on failure; a mid-session drop is
329
+ recovered by reopening once.
330
+
331
+ **Reverse backend (`services/deepwiki/devin.py`)**
332
+
333
+ - Endpoint: `DEEPWIKI_API_URL`, default `https://api.devin.ai`.
334
+ - Answer flow (`ask`):
335
+ 1. `POST /ada/query` with the payload below, then either stream or poll.
336
+ 2. **Streaming** — open `wss://…/ada/ws/query/{query_id}` and assemble the
337
+ answer from events.
338
+ 3. **Polling** — `GET /ada/query/{query_id}` on an interval until `state` is
339
+ `done` or `error`.
340
+
341
+ Request payload (`POST /ada/query`):
342
+
343
+ ```json
344
+ {
345
+ "engine_id": "agent",
346
+ "user_query": "...",
347
+ "keywords": [],
348
+ "repo_names": ["owner/repo"],
349
+ "additional_context": "",
350
+ "query_id": "<uuid>",
351
+ "use_notes": false,
352
+ "attached_context": [],
353
+ "generate_summary": true
354
+ }
355
+ ```
356
+
357
+ Engine mapping: `fast` → `multihop_faster`, `deep` → `agent`, `codemap` → `codemap`.
358
+
359
+ WebSocket event types observed on the stream: `snapshot`, `file_contents`,
360
+ `stats`, `chunk`, `reference`, `summary_chunk`, `summary_done`, `done`. The
361
+ stream carries the complete answer, so no follow-up `GET` is needed after
362
+ streaming — `parse_response` assembles the `Answer` directly from the events.
363
+
364
+ Management endpoints:
365
+
366
+ | Method | Path | Used by |
367
+ |--------|------|---------|
368
+ | `GET` | `/ada/list_public_indexes?search_repo=` | `list` |
369
+ | `GET` | `/ada/public_repo_indexing_status?repo_name=` | `status` |
370
+ | `POST` | `/ada/warm_public_repo?repo_name=` | `warm` |
371
+ | `GET` | `/ada/query/{query_id}` | `get` |
372
+
373
+ ### DeepWiki error handling and exit codes
374
+
375
+ Exceptions are classified into a small taxonomy and mapped to an exit code:
376
+
377
+ | Error kind | Meaning | Exit code |
378
+ |-----------|---------|-----------|
379
+ | success | — | `0` |
380
+ | `not_indexed` | repo is not indexed on DeepWiki | `2` |
381
+ | `connection` | could not connect to the server | `3` |
382
+ | `tool` / `error` / `invalid_repo` / `invalid_input` / `page_not_found` / `unexpected` | anything else | `1` |
383
+
384
+ `ConnectionError` (transport-level failure) and `ToolError` (a `{"detail": …}`
385
+ or tool error surfaced from the server) are the two core exception types. HTTP
386
+ error bodies are surfaced via FastAPI's `detail` field so the CLI can classify
387
+ "not indexed" vs. a generic tool error.
388
+
389
+ With `--json`, errors go to **stderr** as a single line:
390
+
391
+ ```json
392
+ {"error": "Could not connect to DeepWiki server...", "kind": "connection"}
393
+ ```
394
+
395
+ ### DeepWiki streaming, retry, and citations
396
+
397
+ This applies to the **reverse** backend only.
398
+
399
+ **Single-shot `--stream`** streams chunks over the WebSocket to stdout, then
400
+ prints the summary/sources tail. Inline `[i]` citation markers are emitted the
401
+ moment each `reference` event arrives, so the streamed body shows citations that
402
+ line up with the `## Sources` list printed at the end.
403
+
404
+ **Interactive reverse REPL** polls for each answer and renders the complete
405
+ result, so inline `[i]` citations, the summary, and sources all line up. Each
406
+ follow-up question reuses the previous `query_id`, keeping one conversation
407
+ thread (`/new` starts a fresh thread).
408
+
409
+ **Retry.** Both single-shot `ask` and the interactive REPL retry transient
410
+ failures — `ConnectionError` or a `ToolError` containing `HTTP 5` — with
411
+ **jittered exponential backoff**: delay = `1.0s × 2^attempt + random(0 … 0.5s)`.
412
+ The default is **4 attempts**, overridable with `DEEPWIKI_REPL_RETRIES`. Retries
413
+ happen only while **nothing has streamed yet**. If a single-shot `--stream`
414
+ drops **mid-answer**, the CLI falls back to polling the same `query_id` and
415
+ re-prints the complete answer (body, citations, summary, sources); the part
416
+ already streamed appears twice, but the answer is never lost.
417
+
418
+ Why retry matters: the reverse endpoint is unofficial and occasionally refuses
419
+ the WebSocket handshake (a millisecond-fast connection reset, not a slow
420
+ timeout). Retry with backoff absorbs one-off blips.
421
+
422
+ **Citation line numbers.** The `range_start`/`range_end` attached to each
423
+ citation are model-estimated, so treat them as approximate rather than exact:
424
+
425
+ 1. **Precision** — the range points at the *region* the model associated with a
426
+ claim, not necessarily the exact lines that back it; it can be off.
427
+ 2. **Version drift** — the numbers reflect whatever snapshot DeepWiki indexed,
428
+ which may not match your local checkout.
429
+
430
+ The CLI passes these numbers through unchanged; it does not offset or
431
+ re-interpret them.
432
+
433
+ ### DeepWiki Mermaid
434
+
435
+ `--mode codemap` returns a codemap (a `{"traces": [...]}` JSON blob). `--mermaid`
436
+ renders it as a `flowchart TB` with per-trace subgraphs and color styling. Paste
437
+ the output into mermaid.live, GitHub, or VS Code to view it. If the answer is
438
+ not a codemap, `--mermaid` warns and prints the plain text.
439
+
440
+ ### DeepWiki usage recipes
441
+
442
+ The combinations below are grouped by intent. All assume `facebook/react` as the
443
+ repo unless noted.
444
+
445
+ **Read documentation (MCP)**
446
+
447
+ ```bash
448
+ repowiki-cli deepwiki structure facebook/react
449
+ repowiki-cli deepwiki contents vercel/next.js
450
+ repowiki-cli deepwiki contents vercel/next.js --page "Getting Started" # one page only
451
+ repowiki-cli deepwiki contents vercel/next.js --rich # rendered
452
+ ```
453
+
454
+ **Ask questions (MCP)**
455
+
456
+ ```bash
457
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?"
458
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --rich
459
+ repowiki-cli deepwiki ask facebook/react # interactive
460
+ ```
461
+
462
+ **Machine-readable output**
463
+
464
+ ```bash
465
+ repowiki-cli deepwiki structure facebook/react --json
466
+ repowiki-cli deepwiki contents vercel/next.js --json
467
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --json
468
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --json --save out.md # JSON + Markdown file
469
+ ```
470
+
471
+ **Save answers to files**
472
+
473
+ ```bash
474
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --save # auto-named
475
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --save notes/answers.md
476
+ ```
477
+
478
+ **Reverse backend — engine and depth**
479
+
480
+ ```bash
481
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --mode deep
482
+ repowiki-cli deepwiki ask facebook/react "Quick facts?" --mode fast
483
+ repowiki-cli deepwiki ask facebook/react "Show the data flow" --mode codemap --mermaid
484
+ ```
485
+
486
+ **Reverse backend — sources and summary**
487
+
488
+ ```bash
489
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --mode deep --sources
490
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --mode deep --no-summary
491
+ ```
492
+
493
+ **Reverse backend — streaming and context**
494
+
495
+ ```bash
496
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --mode deep --stream
497
+ repowiki-cli deepwiki ask facebook/react "What is Fiber?" --mode deep --context "answer in Chinese"
498
+ ```
499
+
500
+ **Reverse backend — timeout**
501
+
502
+ ```bash
503
+ repowiki-cli deepwiki ask facebook/react "Deep dive?" --mode deep --timeout 600 # allow 10 min for deep answers
504
+ repowiki-cli deepwiki ask facebook/react "Quick facts?" --mode fast --timeout 30
505
+ DEEPWIKI_TIMEOUT=600 repowiki-cli deepwiki ask facebook/react "Deep dive?" --mode deep # or via env var
506
+ ```
507
+
508
+ **Reverse backend — threads and multi-repo**
509
+
510
+ ```bash
511
+ repowiki-cli deepwiki ask facebook/react "Follow-up?" --id <query-id> # continue a thread
512
+ repowiki-cli deepwiki ask facebook/react "diff?" --repo remix-run/react-router --repo TanStack/router
513
+ repowiki-cli deepwiki ask facebook/react --mode deep # interactive, auto-threads
514
+ ```
515
+
516
+ **Management**
517
+
518
+ ```bash
519
+ repowiki-cli deepwiki list react
520
+ repowiki-cli deepwiki status facebook/react
521
+ repowiki-cli deepwiki warm facebook/react
522
+ repowiki-cli deepwiki get <query-id>
523
+ repowiki-cli deepwiki get <query-id> --sources
524
+ repowiki-cli deepwiki get <query-id> --mermaid
525
+ repowiki-cli deepwiki stat Junjie-Zhu/IDPFold2 --human --stale
526
+ repowiki-cli deepwiki stat facebook/react --stale
527
+ ```
528
+
529
+ **Scripting with exit codes**
530
+
531
+ ```bash
532
+ repowiki-cli deepwiki ask some/repo "q?" --json > out.json
533
+ case $? in
534
+ 0) ;; # success
535
+ 2) echo "not indexed" ;;
536
+ 3) echo "connection error" ;;
537
+ *) echo "other error" ;;
538
+ esac
539
+ ```
540
+
541
+ ### DeepWiki MCP server
542
+
543
+ The official [DeepWiki MCP server](https://docs.devin.ai/work-with-devin/deepwiki-mcp)
544
+ is free and requires no auth for public repos. It exposes two wire protocols:
545
+ Streamable HTTP (`/mcp`, recommended) and SSE (`/sse`, deprecated). `repowiki-cli`
546
+ speaks Streamable HTTP.
547
+
548
+ To add it to Claude Code:
549
+
550
+ ```bash
551
+ claude mcp add -s user -t http deepwiki https://mcp.deepwiki.com/mcp
552
+ ```
553
+
554
+ Private repositories are out of scope for `repowiki-cli`; use the
555
+ [Devin MCP server](https://docs.devin.ai/work-with-devin/devin-mcp) with a Devin
556
+ API key. The full documentation index lives at
557
+ <https://docs.devin.ai/llms.txt>.
558
+
559
+ ### DeepWiki related tools
560
+
561
+ These are reference/alternative CLIs for the same space — worth consulting
562
+ before re-implementing anything:
563
+
564
+ - [Zread CLI](https://github.com/ZreadAI/zread_cli) — generates wiki docs
565
+ locally from your repo via an LLM (config `~/.zread/config.yaml`).
566
+ - [readmeX CLI](https://github.com/aibox22/readmeX) — official CLI.
567
+ - [deepwiki-open](https://github.com/AsyncFuncAI/deepwiki-open) — open-source
568
+ DeepWiki CLI.
569
+
570
+ If the goal is *generating* a wiki from your own API rather than querying the
571
+ public DeepWiki index, the official CLIs above already solve it — don't
572
+ reinvent the wheel.
573
+
574
+ ## CodeWiki
575
+
576
+ [Google Code Wiki](https://codewiki.google) is a second wiki service, exposed
577
+ under the `codewiki` namespace. CodeWiki reads **public repositories only** and
578
+ requires **no auth** — it does not support private repos.
579
+
580
+ ```bash
581
+ repowiki-cli codewiki structure REPO [--json]
582
+ repowiki-cli codewiki contents REPO [--page TITLE] [--rich] [--json]
583
+ repowiki-cli codewiki ask REPO [QUESTION] [--rich] [--json] [--save PATH]
584
+ repowiki-cli codewiki stat REPO [--stale] [--json]
585
+ repowiki-cli codewiki cp REPO [OUTPUT_DIR]
586
+ ```
587
+
588
+ Quick start:
589
+
590
+ ```bash
591
+ repowiki-cli codewiki structure facebook/react # table of contents
592
+ repowiki-cli codewiki contents vercel/next.js # full documentation
593
+ repowiki-cli codewiki ask facebook/react "What is Fiber?"
594
+ ```
595
+
596
+ ### `codewiki structure`
597
+
598
+ Prints the CodeWiki table of contents for a repository.
599
+
600
+ - `--json` — emit a JSON envelope instead of text.
601
+
602
+ ### `codewiki contents`
603
+
604
+ Prints the full CodeWiki documentation for a repository, which can be large.
605
+
606
+ - `--page TITLE` — print only the page whose title matches (case-insensitive
607
+ exact match). If no page matches, the available titles are listed (to stderr)
608
+ and the command exits with error kind `page_not_found`.
609
+ - `--rich` — render Markdown with color/formatting via `rich`.
610
+ - `--json` — emit a JSON envelope instead of Markdown.
611
+
612
+ ### `codewiki ask`
613
+
614
+ ```bash
615
+ repowiki-cli codewiki ask REPO [QUESTION] [--rich] [--json] [--save PATH]
616
+ ```
617
+
618
+ With `QUESTION`, `ask` answers once and exits. Without it, `ask` starts an
619
+ interactive REPL — type one question per line and `/exit` (or `/quit`/`/q`) to
620
+ quit. CodeWiki's `ask` is stateless, so each question is independent (no thread
621
+ continuation).
622
+
623
+ - `--rich` — render the answer's Markdown with `rich`.
624
+ - `--json` — emit a JSON envelope. Ignored in interactive mode.
625
+ - `--save PATH` — save the answer to a Markdown file (see *Saving*). A path is
626
+ required (CodeWiki's `ask` does not auto-name on a bare `--save`).
627
+
628
+ ### `codewiki stat`
629
+
630
+ ```bash
631
+ repowiki-cli codewiki stat REPO [--stale] [--json]
632
+ ```
633
+
634
+ Shows the commit sha the CodeWiki documentation was generated from (parsed from
635
+ the wiki payload header by `codewiki/wiki.py::parse`).
636
+
637
+ - `--stale` — compare the wiki commit against GitHub HEAD (via
638
+ `api.github.com/.../commits/HEAD`) and print `最新`/`过期`. CodeWiki has no
639
+ timestamp, so there is no `--human`; the wiki sha is a prefix of the full
640
+ GitHub sha when the wiki is current.
641
+ - `--json` — emit a JSON envelope (with `stale` when `--stale` is set).
642
+
643
+ **Implementation:** staleness is checked by `CodeWikiClient.github_head()`, which
644
+ calls `GET https://api.github.com/repos/{owner}/{name}/commits/HEAD` (with
645
+ `follow_redirects=True` to survive renamed-repo 301s) and returns the full
646
+ 40-char `sha` plus `commit.committer.date`. A wiki is current when the GitHub
647
+ sha `startswith` the wiki's (possibly short) sha.
648
+
649
+ ### `codewiki cp`
650
+
651
+ ```bash
652
+ repowiki-cli codewiki cp REPO [OUTPUT_DIR]
653
+ ```
654
+
655
+ Exports the full wiki as one Markdown file per section, plus `llms.txt` /
656
+ `README.md` (index) and `llms-full.txt` (concatenated). `OUTPUT_DIR` defaults to
657
+ `owner_repo`.
658
+
659
+ **Implementation:** each `Section` is rendered via
660
+ `codewiki/wiki.py::render_section` (heading + body + `dot` diagrams) and the full
661
+ text via `render_markdown`; both feed the shared `shared/export.py::export_pages`
662
+ helper (see `deepwiki cp`).
663
+
664
+ ## Zread
665
+
666
+ [zread.ai](https://zread.ai) is a third wiki service, exposed under the `zread`
667
+ namespace. Zread serves pre-generated docs for **public repositories**, and all
668
+ read commands need **no auth**. The commands `ask` and `submit` require a token
669
+ (see below).
670
+
671
+ > **Implementation note:** `structure`/`contents` fetch the wiki outline and page
672
+ > Markdown from zread's JSON REST API (`GET /api/v1/wiki/{id}` and
673
+ > `/api/v1/wiki/{id}/page/{slug}`), not by scraping the Next.js RSC flight
674
+ > payload. REST is more stable and faster than parsing `self.__next_f.push`. If
675
+ > those endpoints ever change, the previous RSC-scraping implementation is
676
+ > preserved in git history (`git log`) rather than kept as a fragile in-code
677
+ > fallback.
678
+
679
+ ```bash
680
+ repowiki-cli zread structure REPO [--lang zh|en] [--json]
681
+ repowiki-cli zread contents REPO [SLUG] [--file PATH] [--start N] [--end M] [--lang zh|en] [--rich] [--json]
682
+ repowiki-cli zread ask REPO [QUESTION] [--model MODEL] [--lang zh|en] [--rich] [--json] [--save PATH]
683
+ repowiki-cli zread find QUERY [--limit N] [--lang zh|en] [--json]
684
+ repowiki-cli zread stat REPO [--lang zh|en] [--human] [--stale] [--json]
685
+ repowiki-cli zread search REPO QUERY [--lang zh|en] [--json]
686
+ repowiki-cli zread top [WEEKS] [--lang zh|en] [--json]
687
+ repowiki-cli zread rand [TOPIC] [--lang zh|en] [--json]
688
+ repowiki-cli zread cp REPO [OUTPUT_DIR] [--concurrency N] [--lang zh|en]
689
+ repowiki-cli zread submit REPO [--json]
690
+ repowiki-cli zread refresh REPO [--json]
691
+ ```
692
+
693
+ Quick start:
694
+
695
+ ```bash
696
+ repowiki-cli zread structure facebook/react # table of contents
697
+ repowiki-cli zread contents vercel/next.js # overview page
698
+ repowiki-cli zread find react # search repositories
699
+ ```
700
+
701
+ The `--lang zh|en` flag selects the documentation language (default `en`, or the
702
+ `ZREAD_LANG` environment variable).
703
+
704
+ ### `zread structure`
705
+
706
+ Prints the zread.ai table of contents for a repository.
707
+
708
+ - `--lang zh|en` — language.
709
+ - `--json` — emit a JSON envelope instead of text.
710
+
711
+ ### `zread contents`
712
+
713
+ Prints a single page of Markdown documentation. With no `SLUG`, it prints the
714
+ overview (first) page.
715
+
716
+ The `REPO` argument also accepts a GitHub blob URL with an optional line
717
+ fragment, which reads that source file instead of a wiki page:
718
+
719
+ ```bash
720
+ repowiki-cli zread contents https://github.com/o/r/blob/main/src/a.py#L10-L20
721
+ ```
722
+
723
+ - `--file PATH` — read a source file from the repository instead of a wiki page
724
+ (mutually exclusive with `SLUG`).
725
+ - `--start N` / `--end M` — with `--file`, restrict to a line range.
726
+ - `--lang zh|en` — language.
727
+ - `--rich` — render Markdown with `rich`.
728
+ - `--json` — emit a JSON envelope instead of Markdown.
729
+
730
+ ### `zread ask`
731
+
732
+ ```bash
733
+ repowiki-cli zread ask REPO [QUESTION] [--model MODEL] [--rich] [--json] [--save PATH]
734
+ ```
735
+
736
+ With `QUESTION`, `ask` answers once and exits. Without it, `ask` starts an
737
+ interactive REPL — type one question per line and `/exit` (or `/quit`/`/q`) to
738
+ quit.
739
+
740
+ Unlike the other commands, `ask` requires an auth token (a JWT). Log in to
741
+ zread.ai, open the browser DevTools console, and run
742
+ `JSON.parse(localStorage.getItem("CGX_AUTH_STORAGE")).state.token` — this returns
743
+ the token. Set it as the `ZREAD_TOKEN` environment variable.
744
+
745
+ - `--model MODEL` — model (default `glm-5.1`, or the `ZREAD_MODEL` environment
746
+ variable). This maps to the web UI's `CGX_CHAT_MODEL` (e.g. `glm-5.1`,
747
+ `claude-sonnet-4.6`).
748
+ - `--lang zh|en` — language.
749
+ - `--rich` — render the answer's Markdown with `rich`.
750
+ - `--json` — emit a JSON envelope. Ignored in interactive mode.
751
+ - `--save PATH` — save the answer to a Markdown file (see *Saving*).
752
+
753
+ ### `zread find`
754
+
755
+ Searches zread.ai for repositories.
756
+
757
+ - `--limit N` — cap the number of results.
758
+ - `--lang zh|en` — language.
759
+ - `--json` — emit a JSON envelope.
760
+
761
+ ### `zread stat`
762
+
763
+ Prints repository info and index status on zread.ai.
764
+
765
+ - `--lang zh|en` — language.
766
+ - `--human` — render the timestamps (`created_at`, `updated_at`,
767
+ `last_commit.when`) as human-readable local times.
768
+ - `--stale` — fetch GitHub HEAD and compare its commit sha against
769
+ `last_commit.hash`, printing an up-to-date / stale verdict.
770
+ - `--json` — emit a JSON envelope.
771
+
772
+ ```bash
773
+ ❯ repowiki-cli zread stat google-deepmind/alphafold3 --human
774
+ ## Zread: google-deepmind/alphafold3 (stat)
775
+
776
+ - repo_id: 5fa748a6-6785-11f0-817c-3a18d81350c2
777
+ - owner: google-deepmind
778
+ - name: alphafold3
779
+ - url: https://github.com/google-deepmind/alphafold3
780
+ - description: AlphaFold 3 inference pipeline.
781
+ - description_zh: AlphaFold 3 推理管线实现
782
+ - star_count: 8570
783
+ - language: python
784
+ - topics: []
785
+ - wiki_id: 89e1aa24-7878-494b-95a1-7de0c860b94e
786
+ - status: success
787
+ - visibility: public
788
+ - created_at: 1753248298 (2025-07-23 13:24:58 CST)
789
+ - updated_at: 1789875263 (2026-09-20 11:34:23 CST)
790
+ - last_commit: {'hash': 'c0f97eda2f1f482fd94d3a38bece18c7069b4a5c', 'when': 1787154197 (2026-08-19 23:43:17 CST)}
791
+
792
+ ❯ repowiki-cli zread stat google-deepmind/alphafold3 --stale
793
+ ## Zread: google-deepmind/alphafold3 (stat)
794
+
795
+ - repo_id: 5fa748a6-6785-11f0-817c-3a18d81350c2
796
+ - owner: google-deepmind
797
+ - name: alphafold3
798
+ - url: https://github.com/google-deepmind/alphafold3
799
+ - description: AlphaFold 3 inference pipeline.
800
+ - description_zh: AlphaFold 3 推理管线实现
801
+ - star_count: 8570
802
+ - language: python
803
+ - topics: []
804
+ - wiki_id: 89e1aa24-7878-494b-95a1-7de0c860b94e
805
+ - status: success
806
+ - visibility: public
807
+ - created_at: 1753248298
808
+ - updated_at: 1789875263
809
+ - last_commit: {'hash': 'c0f97eda2f1f482fd94d3a38bece18c7069b4a5c', 'when': 1787154197}
810
+
811
+ 最新 (up-to-date): c0f97eda2f1f482fd94d3a38bece18c7069b4a5c
812
+ ```
813
+
814
+ ### `zread search`
815
+
816
+ Searches within a repository's wiki documentation for matching text, returning
817
+ the page title and highlighted matches.
818
+
819
+ ```bash
820
+ repowiki-cli zread search REPO QUERY [--lang zh|en] [--json]
821
+ ```
822
+
823
+ - `--lang zh|en` — language.
824
+ - `--json` — emit a JSON envelope.
825
+
826
+ ### `zread top`
827
+
828
+ Prints the zread.ai trending list. `WEEKS` limits the number of week-groups shown.
829
+
830
+ - `--lang zh|en` — language.
831
+ - `--json` — emit a JSON envelope.
832
+
833
+ ### `zread rand`
834
+
835
+ Prints a random repository recommendation, optionally filtered by `TOPIC`.
836
+
837
+ - `--lang zh|en` — language.
838
+ - `--json` — emit a JSON envelope.
839
+
840
+ ### `zread cp`
841
+
842
+ Exports the whole wiki as Markdown (`NN-slug.md` files) plus `llms.txt`,
843
+ `README.md`, and `llms-full.txt` into `OUTPUT_DIR` (defaults to the repository
844
+ name).
845
+
846
+ - `--concurrency N` — parallel page fetches (default `5`).
847
+ - `--lang zh|en` — language.
848
+
849
+ ### `zread submit`
850
+
851
+ Submits a repository for indexing on zread.ai. Requires a token (a JWT): log in
852
+ to zread.ai, run
853
+ `JSON.parse(localStorage.getItem("CGX_AUTH_STORAGE")).state.token` in the DevTools
854
+ console, and set the result as `ZREAD_TOKEN`. Without it, `submit` prints a
855
+ warning and skips. On success it also reports the indexing queue wait
856
+ (`backlog` repos ahead, `estimate_minutes` ETA).
857
+
858
+ - `--json` — emit a JSON envelope (includes an `eta` field).
859
+
860
+ ### `zread refresh`
861
+
862
+ Requests a re-index (refresh) of a repository's wiki. No auth required.
863
+
864
+ ```bash
865
+ repowiki-cli zread refresh REPO [--json]
866
+ ```
867
+
868
+ - `--json` — emit a JSON envelope.
869
+
870
+ ## Development
871
+
872
+ ```bash
873
+ uv sync
874
+ uv run pytest
875
+ ```