deepdoc 2.3.1__tar.gz → 2.3.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.
- {deepdoc-2.3.1 → deepdoc-2.3.3}/PKG-INFO +5 -5
- {deepdoc-2.3.1 → deepdoc-2.3.3}/README.md +4 -4
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/__init__.py +1 -1
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/generator/generation.py +2 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/generator/post_processors.py +81 -2
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/llm/client.py +7 -4
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/site/builder/scaffold_files.py +33 -3
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc.egg-info/PKG-INFO +5 -5
- {deepdoc-2.3.1 → deepdoc-2.3.3}/pyproject.toml +1 -4
- {deepdoc-2.3.1 → deepdoc-2.3.3}/LICENSE +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/__main__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/benchmark_v2.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/call_graph.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/changelog_writer.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/answer_mixin.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/chunker.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/constants.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/deep_research.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/docs_summary.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/embeddings.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/indexer.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/linking.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/live_fallback_mixin.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/persistence.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/providers.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/retrieval_mixin.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/routes.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/scaffold.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/service.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/settings.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/source_archive.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/symbol_index.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/chatbot/types.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/cli.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/config.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/generator/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/generator/evidence.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/generator/validation.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/llm/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/llm/json_utils.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/llm/litellm_compat.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/manifest.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/openapi.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/api_detector.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/base.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/go_parser.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/js_ts_parser.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/php_parser.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/python_parser.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/registry.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/base.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/common.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/detector.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/django.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/express.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/falcon.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/fastify.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/go.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/js_shared.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/laravel.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/nestjs.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/python_shared.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/registry.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/routes/repo_resolver.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/parser/vue_parser.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/persistence_v2.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/pipeline_v2.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/bucket_injection.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/bucket_refinement.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/common.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/endpoint_refs.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/engine.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/flow_candidates.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/heuristics.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/nav_shaping.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/specializations.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/topology.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/planner/utils.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/prompts/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/prompts/bucket_types.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/prompts/page_types.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/prompts/selectors.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/prompts/system.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/prompts/update.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/py.typed +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/scanner/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/scanner/artifacts.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/scanner/clustering.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/scanner/common.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/scanner/database.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/scanner/endpoints.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/scanner/integrations.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/scanner/runtime.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/scanner/utils.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/site/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/site/builder/__init__.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/site/builder/chatbot_components.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/site/builder/common.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/site/builder/engine.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/site/builder/mdx_utils.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/site/builder/templates.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/smart_update_v2.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/source_metadata.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/updater_v2.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc/v2_models.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc.egg-info/SOURCES.txt +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc.egg-info/dependency_links.txt +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc.egg-info/entry_points.txt +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc.egg-info/requires.txt +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/deepdoc.egg-info/top_level.txt +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/setup.cfg +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_benchmark_scorecard.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_call_graph.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_changelog.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_config.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_embeddings.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_eval.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_index.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_persistence.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_providers.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_query.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_relationship.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_scaffold.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_chatbot_source_archive.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_classify.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_cli_generate.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_cli_serve.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_cli_update.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_flow_candidates.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_framework_fixtures.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_framework_support.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_fumadocs_builder.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_generation_evidence.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_internal_docs_metadata.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_litellm_compat.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_llm_json_utils.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_parallel_pipeline.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_parser_ranges.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_planner_consolidation.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_planner_granularity.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_route_registry.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_runtime_scan.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_smart_update.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_stale.py +0 -0
- {deepdoc-2.3.1 → deepdoc-2.3.3}/tests/test_state.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepdoc
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.3
|
|
4
4
|
Summary: Auto-generate beautiful docs from any codebase
|
|
5
5
|
Author: Pranav Kumar
|
|
6
6
|
License: MIT
|
|
@@ -82,7 +82,7 @@ DeepDoc scans your repo, builds a bucket-based documentation plan, generates ric
|
|
|
82
82
|
- **Bucket-based documentation architecture** — system, feature, endpoint, integration, and database buckets instead of one-file-per-page noise.
|
|
83
83
|
- **Multi-step AI planner** — classifies the repo, proposes buckets, then assigns files, symbols, artifacts, and dependencies into a final reader-first plan.
|
|
84
84
|
- **Giant-file handling** — large files are decomposed into feature-aligned clusters so a single controller can feed multiple doc pages.
|
|
85
|
-
- **MDX
|
|
85
|
+
- **MDX-safe generation** — generated pages are repaired and validated in Python before being written; deploy-time quality gates block failed, invalid, or stub pages before the Fumadocs build.
|
|
86
86
|
- **Evidence-first chatbot answers** — final code proof is hydrated from archived source snippets with exact file paths and line ranges, not just retrieval guesses.
|
|
87
87
|
- **Incremental updates** — `deepdoc update` regenerates only stale or structurally affected docs against the last synced commit.
|
|
88
88
|
- **OpenAPI-aware API docs** — auto-detects OpenAPI/Swagger specs and stages interactive `/api/*` pages in the generated site.
|
|
@@ -129,7 +129,7 @@ pip install click litellm gitpython rich pyyaml jinja2
|
|
|
129
129
|
pip install -e . --no-deps
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
You will also need **Node 18+** on `PATH
|
|
132
|
+
You will also need **Node 18+** on `PATH` when you run `deepdoc serve` or `deepdoc deploy`. DeepDoc generation itself uses Python-side repair and validation; Node is only needed for the generated Fumadocs site.
|
|
133
133
|
|
|
134
134
|
### Verify installation
|
|
135
135
|
|
|
@@ -346,7 +346,7 @@ deepdoc generate --exclude "tests/**"
|
|
|
346
346
|
|
|
347
347
|
1. **Phase 1: Scan** — Walk the repo, parse supported languages, detect endpoints, config/setup artifacts, runtime surfaces, integration signals, and OpenAPI specs.
|
|
348
348
|
2. **Phase 2: Plan** — Run the multi-step bucket planner. It classifies the repo, proposes bucket candidates, and assigns files/symbols/artifacts to the final doc structure.
|
|
349
|
-
3. **Phase 3: Generate** — Generate bucket pages in batches with parallel workers. High-level buckets are AI-planned; scanned endpoints enrich grouped API-reference pages instead of creating one page per route. Each page passes through
|
|
349
|
+
3. **Phase 3: Generate** — Generate bucket pages in batches with parallel workers. High-level buckets are AI-planned; scanned endpoints enrich grouped API-reference pages instead of creating one page per route. Each page passes through Python-side MDX repair, grounding validation, and bounded quality retries before being written to disk.
|
|
350
350
|
4. **Phase 4: API Ref** — Stage OpenAPI assets for the generated Fumadocs `/api/*` pages when a spec exists.
|
|
351
351
|
5. **Phase 5: Build** — Write the generated `site/` Fumadocs scaffold, page tree, search route, and static assets from the generated plan.
|
|
352
352
|
|
|
@@ -1562,7 +1562,7 @@ deepdoc generate --force # Full regen with new model
|
|
|
1562
1562
|
## Requirements
|
|
1563
1563
|
|
|
1564
1564
|
- Python 3.10+
|
|
1565
|
-
- **Node 18+** on `PATH` — used
|
|
1565
|
+
- **Node 18+** on `PATH` — used by `deepdoc serve` and `deepdoc deploy` for the generated Fumadocs site
|
|
1566
1566
|
- Git (for `deepdoc update` and `deepdoc deploy`)
|
|
1567
1567
|
- An LLM API key (or Ollama running locally)
|
|
1568
1568
|
|
|
@@ -43,7 +43,7 @@ DeepDoc scans your repo, builds a bucket-based documentation plan, generates ric
|
|
|
43
43
|
- **Bucket-based documentation architecture** — system, feature, endpoint, integration, and database buckets instead of one-file-per-page noise.
|
|
44
44
|
- **Multi-step AI planner** — classifies the repo, proposes buckets, then assigns files, symbols, artifacts, and dependencies into a final reader-first plan.
|
|
45
45
|
- **Giant-file handling** — large files are decomposed into feature-aligned clusters so a single controller can feed multiple doc pages.
|
|
46
|
-
- **MDX
|
|
46
|
+
- **MDX-safe generation** — generated pages are repaired and validated in Python before being written; deploy-time quality gates block failed, invalid, or stub pages before the Fumadocs build.
|
|
47
47
|
- **Evidence-first chatbot answers** — final code proof is hydrated from archived source snippets with exact file paths and line ranges, not just retrieval guesses.
|
|
48
48
|
- **Incremental updates** — `deepdoc update` regenerates only stale or structurally affected docs against the last synced commit.
|
|
49
49
|
- **OpenAPI-aware API docs** — auto-detects OpenAPI/Swagger specs and stages interactive `/api/*` pages in the generated site.
|
|
@@ -90,7 +90,7 @@ pip install click litellm gitpython rich pyyaml jinja2
|
|
|
90
90
|
pip install -e . --no-deps
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
You will also need **Node 18+** on `PATH
|
|
93
|
+
You will also need **Node 18+** on `PATH` when you run `deepdoc serve` or `deepdoc deploy`. DeepDoc generation itself uses Python-side repair and validation; Node is only needed for the generated Fumadocs site.
|
|
94
94
|
|
|
95
95
|
### Verify installation
|
|
96
96
|
|
|
@@ -307,7 +307,7 @@ deepdoc generate --exclude "tests/**"
|
|
|
307
307
|
|
|
308
308
|
1. **Phase 1: Scan** — Walk the repo, parse supported languages, detect endpoints, config/setup artifacts, runtime surfaces, integration signals, and OpenAPI specs.
|
|
309
309
|
2. **Phase 2: Plan** — Run the multi-step bucket planner. It classifies the repo, proposes bucket candidates, and assigns files/symbols/artifacts to the final doc structure.
|
|
310
|
-
3. **Phase 3: Generate** — Generate bucket pages in batches with parallel workers. High-level buckets are AI-planned; scanned endpoints enrich grouped API-reference pages instead of creating one page per route. Each page passes through
|
|
310
|
+
3. **Phase 3: Generate** — Generate bucket pages in batches with parallel workers. High-level buckets are AI-planned; scanned endpoints enrich grouped API-reference pages instead of creating one page per route. Each page passes through Python-side MDX repair, grounding validation, and bounded quality retries before being written to disk.
|
|
311
311
|
4. **Phase 4: API Ref** — Stage OpenAPI assets for the generated Fumadocs `/api/*` pages when a spec exists.
|
|
312
312
|
5. **Phase 5: Build** — Write the generated `site/` Fumadocs scaffold, page tree, search route, and static assets from the generated plan.
|
|
313
313
|
|
|
@@ -1523,7 +1523,7 @@ deepdoc generate --force # Full regen with new model
|
|
|
1523
1523
|
## Requirements
|
|
1524
1524
|
|
|
1525
1525
|
- Python 3.10+
|
|
1526
|
-
- **Node 18+** on `PATH` — used
|
|
1526
|
+
- **Node 18+** on `PATH` — used by `deepdoc serve` and `deepdoc deploy` for the generated Fumadocs site
|
|
1527
1527
|
- Git (for `deepdoc update` and `deepdoc deploy`)
|
|
1528
1528
|
- An LLM API key (or Ollama running locally)
|
|
1529
1529
|
|
|
@@ -611,6 +611,8 @@ class BucketGenerationEngine:
|
|
|
611
611
|
content = repair_unbalanced_code_fences(content)
|
|
612
612
|
content = normalize_explanatory_lines_outside_fences(content)
|
|
613
613
|
content = repair_dangling_plain_fences(content)
|
|
614
|
+
content = normalize_fumadocs_directives(content)
|
|
615
|
+
content = fix_frontmatter_description(content)
|
|
614
616
|
content = escape_mdx_angle_hazards(content)
|
|
615
617
|
content = repair_internal_doc_links(
|
|
616
618
|
content,
|
|
@@ -207,9 +207,13 @@ def _fix_mermaid_diagram(diagram: str) -> str:
|
|
|
207
207
|
dupes.append(nid)
|
|
208
208
|
seen.add(nid)
|
|
209
209
|
if dupes:
|
|
210
|
+
# Insert comment AFTER the diagram type declaration line, not before it
|
|
211
|
+
# (Mermaid requires diagram type as the very first line)
|
|
212
|
+
first_nl = result.index("\n") if "\n" in result else len(result)
|
|
210
213
|
result = (
|
|
211
|
-
|
|
212
|
-
+
|
|
214
|
+
result[: first_nl + 1]
|
|
215
|
+
+ f"%% Note: possible duplicate node IDs: {', '.join(set(dupes))}\n"
|
|
216
|
+
+ result[first_nl + 1 :]
|
|
213
217
|
)
|
|
214
218
|
|
|
215
219
|
return result
|
|
@@ -800,6 +804,81 @@ def inject_source_files_disclosure(content: str, evidence_files: list[str]) -> s
|
|
|
800
804
|
return patched if count else content
|
|
801
805
|
|
|
802
806
|
|
|
807
|
+
def normalize_fumadocs_directives(content: str) -> str:
|
|
808
|
+
"""Normalize fumadocs callout directive names to the supported set.
|
|
809
|
+
|
|
810
|
+
Valid fumadocs directive types: note, tip, info, warning, danger, caution.
|
|
811
|
+
The LLM frequently uses shorthands like :::warn, :::error, :::success.
|
|
812
|
+
"""
|
|
813
|
+
_alias: dict[str, str] = {
|
|
814
|
+
"warn": "warning",
|
|
815
|
+
"caution": "warning",
|
|
816
|
+
"alert": "warning",
|
|
817
|
+
"error": "danger",
|
|
818
|
+
"success": "tip",
|
|
819
|
+
"check": "tip",
|
|
820
|
+
"hint": "tip",
|
|
821
|
+
"important": "note",
|
|
822
|
+
"notice": "note",
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
def replace_directive(m: re.Match) -> str:
|
|
826
|
+
name = m.group(1).strip().lower()
|
|
827
|
+
canonical = _alias.get(name, name)
|
|
828
|
+
return f":::{canonical}"
|
|
829
|
+
|
|
830
|
+
# Only replace opening directives (:::name), not closing :::
|
|
831
|
+
return re.sub(r":::([a-z]+)", replace_directive, content)
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
def fix_frontmatter_description(content: str) -> str:
|
|
835
|
+
"""Strip directive artefacts (trailing ::, :::) from frontmatter description field.
|
|
836
|
+
|
|
837
|
+
The LLM sometimes writes description values that end with :: or ::: which
|
|
838
|
+
the remark-directive plugin then partially parses, corrupting the nav sidebar.
|
|
839
|
+
"""
|
|
840
|
+
def clean_description(m: re.Match) -> str:
|
|
841
|
+
prefix = m.group(1) # "description: "
|
|
842
|
+
value = m.group(2) # the value only
|
|
843
|
+
value = re.sub(r'\s*:{2,3}\s*$', '', value.rstrip())
|
|
844
|
+
return f'{prefix}{value}'
|
|
845
|
+
|
|
846
|
+
return re.sub(
|
|
847
|
+
r'^(description:\s*)(["\']?.*?["\']?)\s*$',
|
|
848
|
+
clean_description,
|
|
849
|
+
content,
|
|
850
|
+
flags=re.MULTILINE,
|
|
851
|
+
)
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
def unwrap_markdown_trapped_in_code_fences(content: str) -> str:
|
|
855
|
+
"""Detect code fences that contain markdown content and unwrap them.
|
|
856
|
+
|
|
857
|
+
The LLM sometimes forgets to close a code fence, leaving section headers
|
|
858
|
+
(## ...), callout directives (:::), and horizontal rules (---) trapped
|
|
859
|
+
inside a code block. These render as literal text instead of MDX.
|
|
860
|
+
"""
|
|
861
|
+
# Pattern: a fenced block that contains markdown indicators
|
|
862
|
+
MD_INDICATORS = re.compile(
|
|
863
|
+
r"^(?:#{1,6}\s|:::|\-\-\-\s*$|^\*\*\*\s*$)",
|
|
864
|
+
re.MULTILINE,
|
|
865
|
+
)
|
|
866
|
+
|
|
867
|
+
def maybe_unwrap(m: re.Match) -> str:
|
|
868
|
+
lang = m.group(1) # may be empty for plain ```
|
|
869
|
+
body = m.group(2)
|
|
870
|
+
# If body contains markdown indicators, unwrap it
|
|
871
|
+
if MD_INDICATORS.search(body):
|
|
872
|
+
return body
|
|
873
|
+
return m.group(0) # leave intact
|
|
874
|
+
|
|
875
|
+
return re.sub(
|
|
876
|
+
r"```([A-Za-z0-9_+-]*)\n([\s\S]*?)\n```",
|
|
877
|
+
maybe_unwrap,
|
|
878
|
+
content,
|
|
879
|
+
)
|
|
880
|
+
|
|
881
|
+
|
|
803
882
|
def extract_glossary_terms(glossary_content: str) -> list[tuple[str, str]]:
|
|
804
883
|
"""Parse `### TermName` (h3) headings from glossary MDX → [(term, anchor-slug)].
|
|
805
884
|
|
|
@@ -19,8 +19,10 @@ class LLMClient:
|
|
|
19
19
|
# max_tokens=None means don't cap — let the model use its full output capacity
|
|
20
20
|
self.max_tokens = llm_cfg.get("max_tokens", None)
|
|
21
21
|
self.temperature = llm_cfg.get("temperature", 0.2)
|
|
22
|
-
self.base_url = llm_cfg.get("base_url")
|
|
23
|
-
|
|
22
|
+
self.base_url = str(llm_cfg.get("base_url") or "") or None
|
|
23
|
+
# YAML parses bare dates like 2024-12-01 as datetime.date — coerce to str
|
|
24
|
+
_api_version = llm_cfg.get("api_version")
|
|
25
|
+
self.api_version = str(_api_version).strip() if _api_version is not None else None
|
|
24
26
|
self.usage: dict[str, int] = {
|
|
25
27
|
"calls": 0,
|
|
26
28
|
"prompt_chars": 0,
|
|
@@ -65,8 +67,9 @@ class LLMClient:
|
|
|
65
67
|
|
|
66
68
|
is_azure = provider.lower() == "azure" or model.lower().startswith("azure/")
|
|
67
69
|
if is_azure:
|
|
68
|
-
base_url = (llm_cfg.get("base_url") or "").strip()
|
|
69
|
-
|
|
70
|
+
base_url = str(llm_cfg.get("base_url") or "").strip()
|
|
71
|
+
# YAML parses bare dates like 2025-07-01 as datetime.date — coerce to str
|
|
72
|
+
api_version = str(llm_cfg.get("api_version") or "").strip()
|
|
70
73
|
missing = []
|
|
71
74
|
if not base_url:
|
|
72
75
|
missing.append("llm.base_url (your Azure OpenAI endpoint URL)")
|
|
@@ -1652,9 +1652,31 @@ def _mermaid_component_tsx() -> str:
|
|
|
1652
1652
|
"""\
|
|
1653
1653
|
'use client';
|
|
1654
1654
|
|
|
1655
|
-
import { use, useEffect, useId, useState } from 'react';
|
|
1655
|
+
import { Component, use, useEffect, useId, useState } from 'react';
|
|
1656
|
+
import type { ReactNode } from 'react';
|
|
1656
1657
|
import { useTheme } from 'next-themes';
|
|
1657
1658
|
|
|
1659
|
+
// Error boundary so a bad diagram never crashes the whole page
|
|
1660
|
+
class MermaidErrorBoundary extends Component<
|
|
1661
|
+
{ children: ReactNode },
|
|
1662
|
+
{ error: string | null }
|
|
1663
|
+
> {
|
|
1664
|
+
constructor(props: { children: ReactNode }) {
|
|
1665
|
+
super(props);
|
|
1666
|
+
this.state = { error: null };
|
|
1667
|
+
}
|
|
1668
|
+
static getDerivedStateFromError(err: unknown) {
|
|
1669
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
1670
|
+
}
|
|
1671
|
+
render() {
|
|
1672
|
+
if (this.state.error) {
|
|
1673
|
+
// Silently hide diagrams that fail to parse — noise-free fallback
|
|
1674
|
+
return null;
|
|
1675
|
+
}
|
|
1676
|
+
return this.props.children;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1658
1680
|
export function Mermaid({ chart }: { chart: string }) {
|
|
1659
1681
|
const [mounted, setMounted] = useState(false);
|
|
1660
1682
|
|
|
@@ -1663,7 +1685,11 @@ def _mermaid_component_tsx() -> str:
|
|
|
1663
1685
|
}, []);
|
|
1664
1686
|
|
|
1665
1687
|
if (!mounted) return null;
|
|
1666
|
-
return
|
|
1688
|
+
return (
|
|
1689
|
+
<MermaidErrorBoundary>
|
|
1690
|
+
<MermaidContent chart={chart} />
|
|
1691
|
+
</MermaidErrorBoundary>
|
|
1692
|
+
);
|
|
1667
1693
|
}
|
|
1668
1694
|
|
|
1669
1695
|
const cache = new Map<string, Promise<unknown>>();
|
|
@@ -1672,7 +1698,11 @@ def _mermaid_component_tsx() -> str:
|
|
|
1672
1698
|
const cached = cache.get(key);
|
|
1673
1699
|
if (cached) return cached as Promise<T>;
|
|
1674
1700
|
|
|
1675
|
-
const promise = setPromise()
|
|
1701
|
+
const promise = setPromise().catch((err) => {
|
|
1702
|
+
// Remove from cache so a retry is possible, then re-throw for boundary
|
|
1703
|
+
cache.delete(key);
|
|
1704
|
+
throw err;
|
|
1705
|
+
}) as Promise<T>;
|
|
1676
1706
|
cache.set(key, promise);
|
|
1677
1707
|
return promise;
|
|
1678
1708
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepdoc
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.3
|
|
4
4
|
Summary: Auto-generate beautiful docs from any codebase
|
|
5
5
|
Author: Pranav Kumar
|
|
6
6
|
License: MIT
|
|
@@ -82,7 +82,7 @@ DeepDoc scans your repo, builds a bucket-based documentation plan, generates ric
|
|
|
82
82
|
- **Bucket-based documentation architecture** — system, feature, endpoint, integration, and database buckets instead of one-file-per-page noise.
|
|
83
83
|
- **Multi-step AI planner** — classifies the repo, proposes buckets, then assigns files, symbols, artifacts, and dependencies into a final reader-first plan.
|
|
84
84
|
- **Giant-file handling** — large files are decomposed into feature-aligned clusters so a single controller can feed multiple doc pages.
|
|
85
|
-
- **MDX
|
|
85
|
+
- **MDX-safe generation** — generated pages are repaired and validated in Python before being written; deploy-time quality gates block failed, invalid, or stub pages before the Fumadocs build.
|
|
86
86
|
- **Evidence-first chatbot answers** — final code proof is hydrated from archived source snippets with exact file paths and line ranges, not just retrieval guesses.
|
|
87
87
|
- **Incremental updates** — `deepdoc update` regenerates only stale or structurally affected docs against the last synced commit.
|
|
88
88
|
- **OpenAPI-aware API docs** — auto-detects OpenAPI/Swagger specs and stages interactive `/api/*` pages in the generated site.
|
|
@@ -129,7 +129,7 @@ pip install click litellm gitpython rich pyyaml jinja2
|
|
|
129
129
|
pip install -e . --no-deps
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
You will also need **Node 18+** on `PATH
|
|
132
|
+
You will also need **Node 18+** on `PATH` when you run `deepdoc serve` or `deepdoc deploy`. DeepDoc generation itself uses Python-side repair and validation; Node is only needed for the generated Fumadocs site.
|
|
133
133
|
|
|
134
134
|
### Verify installation
|
|
135
135
|
|
|
@@ -346,7 +346,7 @@ deepdoc generate --exclude "tests/**"
|
|
|
346
346
|
|
|
347
347
|
1. **Phase 1: Scan** — Walk the repo, parse supported languages, detect endpoints, config/setup artifacts, runtime surfaces, integration signals, and OpenAPI specs.
|
|
348
348
|
2. **Phase 2: Plan** — Run the multi-step bucket planner. It classifies the repo, proposes bucket candidates, and assigns files/symbols/artifacts to the final doc structure.
|
|
349
|
-
3. **Phase 3: Generate** — Generate bucket pages in batches with parallel workers. High-level buckets are AI-planned; scanned endpoints enrich grouped API-reference pages instead of creating one page per route. Each page passes through
|
|
349
|
+
3. **Phase 3: Generate** — Generate bucket pages in batches with parallel workers. High-level buckets are AI-planned; scanned endpoints enrich grouped API-reference pages instead of creating one page per route. Each page passes through Python-side MDX repair, grounding validation, and bounded quality retries before being written to disk.
|
|
350
350
|
4. **Phase 4: API Ref** — Stage OpenAPI assets for the generated Fumadocs `/api/*` pages when a spec exists.
|
|
351
351
|
5. **Phase 5: Build** — Write the generated `site/` Fumadocs scaffold, page tree, search route, and static assets from the generated plan.
|
|
352
352
|
|
|
@@ -1562,7 +1562,7 @@ deepdoc generate --force # Full regen with new model
|
|
|
1562
1562
|
## Requirements
|
|
1563
1563
|
|
|
1564
1564
|
- Python 3.10+
|
|
1565
|
-
- **Node 18+** on `PATH` — used
|
|
1565
|
+
- **Node 18+** on `PATH` — used by `deepdoc serve` and `deepdoc deploy` for the generated Fumadocs site
|
|
1566
1566
|
- Git (for `deepdoc update` and `deepdoc deploy`)
|
|
1567
1567
|
- An LLM API key (or Ollama running locally)
|
|
1568
1568
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deepdoc"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.3"
|
|
8
8
|
description = "Auto-generate beautiful docs from any codebase"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -57,9 +57,6 @@ Issues = "https://github.com/tss-pranavkumar/deepdoc/issues"
|
|
|
57
57
|
where = ["."]
|
|
58
58
|
include = ["deepdoc*"]
|
|
59
59
|
|
|
60
|
-
[tool.setuptools.package-data]
|
|
61
|
-
"deepdoc.generator.mdx_validator" = ["validate.mjs", "package.json"]
|
|
62
|
-
|
|
63
60
|
[tool.pytest.ini_options]
|
|
64
61
|
testpaths = ["tests"]
|
|
65
62
|
python_files = ["test_*.py"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|