deepdoc 2.3.2__tar.gz → 2.3.4__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.2 → deepdoc-2.3.4}/PKG-INFO +5 -5
- {deepdoc-2.3.2 → deepdoc-2.3.4}/README.md +4 -4
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/__init__.py +1 -1
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/generator/generation.py +12 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/generator/post_processors.py +132 -2
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/llm/client.py +7 -4
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/site/builder/scaffold_files.py +2 -15
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc.egg-info/PKG-INFO +5 -5
- {deepdoc-2.3.2 → deepdoc-2.3.4}/pyproject.toml +1 -4
- {deepdoc-2.3.2 → deepdoc-2.3.4}/LICENSE +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/__main__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/benchmark_v2.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/call_graph.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/changelog_writer.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/answer_mixin.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/chunker.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/constants.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/deep_research.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/docs_summary.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/embeddings.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/indexer.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/linking.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/live_fallback_mixin.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/persistence.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/providers.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/retrieval_mixin.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/routes.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/scaffold.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/service.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/settings.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/source_archive.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/symbol_index.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/chatbot/types.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/cli.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/config.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/generator/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/generator/evidence.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/generator/validation.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/llm/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/llm/json_utils.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/llm/litellm_compat.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/manifest.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/openapi.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/api_detector.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/base.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/go_parser.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/js_ts_parser.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/php_parser.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/python_parser.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/registry.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/base.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/common.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/detector.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/django.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/express.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/falcon.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/fastify.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/go.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/js_shared.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/laravel.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/nestjs.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/python_shared.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/registry.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/routes/repo_resolver.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/parser/vue_parser.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/persistence_v2.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/pipeline_v2.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/bucket_injection.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/bucket_refinement.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/common.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/endpoint_refs.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/engine.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/flow_candidates.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/heuristics.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/nav_shaping.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/specializations.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/topology.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/planner/utils.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/prompts/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/prompts/bucket_types.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/prompts/page_types.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/prompts/selectors.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/prompts/system.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/prompts/update.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/py.typed +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/scanner/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/scanner/artifacts.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/scanner/clustering.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/scanner/common.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/scanner/database.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/scanner/endpoints.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/scanner/integrations.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/scanner/runtime.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/scanner/utils.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/site/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/site/builder/__init__.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/site/builder/chatbot_components.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/site/builder/common.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/site/builder/engine.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/site/builder/mdx_utils.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/site/builder/templates.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/smart_update_v2.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/source_metadata.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/updater_v2.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc/v2_models.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc.egg-info/SOURCES.txt +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc.egg-info/dependency_links.txt +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc.egg-info/entry_points.txt +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc.egg-info/requires.txt +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/deepdoc.egg-info/top_level.txt +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/setup.cfg +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_benchmark_scorecard.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_call_graph.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_changelog.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_config.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_embeddings.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_eval.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_index.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_persistence.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_providers.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_query.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_relationship.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_scaffold.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_chatbot_source_archive.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_classify.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_cli_generate.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_cli_serve.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_cli_update.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_flow_candidates.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_framework_fixtures.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_framework_support.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_fumadocs_builder.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_generation_evidence.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_internal_docs_metadata.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_litellm_compat.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_llm_json_utils.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_parallel_pipeline.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_parser_ranges.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_planner_consolidation.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_planner_granularity.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_route_registry.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_runtime_scan.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_smart_update.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/tests/test_stale.py +0 -0
- {deepdoc-2.3.2 → deepdoc-2.3.4}/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.4
|
|
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,10 @@ 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)
|
|
616
|
+
content = fix_bare_mermaid_fences(content)
|
|
617
|
+
content = fix_leaf_card_directives(content)
|
|
614
618
|
content = escape_mdx_angle_hazards(content)
|
|
615
619
|
content = repair_internal_doc_links(
|
|
616
620
|
content,
|
|
@@ -650,6 +654,10 @@ class BucketGenerationEngine:
|
|
|
650
654
|
content = repair_unbalanced_code_fences(content)
|
|
651
655
|
content = normalize_explanatory_lines_outside_fences(content)
|
|
652
656
|
content = repair_dangling_plain_fences(content)
|
|
657
|
+
content = normalize_fumadocs_directives(content)
|
|
658
|
+
content = fix_frontmatter_description(content)
|
|
659
|
+
content = fix_bare_mermaid_fences(content)
|
|
660
|
+
content = fix_leaf_card_directives(content)
|
|
653
661
|
content = escape_mdx_angle_hazards(content)
|
|
654
662
|
content = repair_internal_doc_links(
|
|
655
663
|
content,
|
|
@@ -692,6 +700,10 @@ class BucketGenerationEngine:
|
|
|
692
700
|
content = repair_unbalanced_code_fences(content)
|
|
693
701
|
content = normalize_explanatory_lines_outside_fences(content)
|
|
694
702
|
content = repair_dangling_plain_fences(content)
|
|
703
|
+
content = normalize_fumadocs_directives(content)
|
|
704
|
+
content = fix_frontmatter_description(content)
|
|
705
|
+
content = fix_bare_mermaid_fences(content)
|
|
706
|
+
content = fix_leaf_card_directives(content)
|
|
695
707
|
content = escape_mdx_angle_hazards(content)
|
|
696
708
|
content = repair_internal_doc_links(
|
|
697
709
|
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,132 @@ 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 fix_bare_mermaid_fences(content: str) -> str:
|
|
855
|
+
"""Repair mermaid diagrams where the LLM omitted the opening code fence.
|
|
856
|
+
|
|
857
|
+
The LLM sometimes writes just the word 'mermaid' on its own line followed
|
|
858
|
+
by diagram content and a closing ``` — instead of the correct ```mermaid
|
|
859
|
+
opening fence. This produces a bare 'mermaid' paragraph in MDX and leaves
|
|
860
|
+
the diagram body (including {node} labels) unescaped, causing acorn parse
|
|
861
|
+
errors.
|
|
862
|
+
|
|
863
|
+
Pattern matched:
|
|
864
|
+
<text ending in : or .\n>
|
|
865
|
+
mermaid\n
|
|
866
|
+
<diagram type line, e.g. sequenceDiagram>\n
|
|
867
|
+
...diagram body...
|
|
868
|
+
```
|
|
869
|
+
"""
|
|
870
|
+
return re.sub(
|
|
871
|
+
r'(?m)^mermaid\n(?=(sequenceDiagram|flowchart|graph|classDiagram|stateDiagram|erDiagram|gantt|pie|gitGraph|mindmap|timeline|journey|quadrantChart|xychart|block|packet|kanban|architecture))',
|
|
872
|
+
'```mermaid\n',
|
|
873
|
+
content,
|
|
874
|
+
)
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
def fix_leaf_card_directives(content: str) -> str:
|
|
878
|
+
"""Convert LLM-invented ::card{...}\\nCONTENT\\n:: to :::card{...}\\nCONTENT\\n:::.
|
|
879
|
+
|
|
880
|
+
The fumadocs remark-directive plugin expects 'card' to be a *container*
|
|
881
|
+
directive (:::card ... :::) so it can carry child content. The LLM
|
|
882
|
+
frequently uses the *leaf* directive form (::card) with a standalone ::
|
|
883
|
+
close marker — which remark-directive does not recognise, rendering both
|
|
884
|
+
the content and the :: as raw text.
|
|
885
|
+
"""
|
|
886
|
+
def fix_cards_block(m: re.Match) -> str:
|
|
887
|
+
inner = m.group(1)
|
|
888
|
+
# ::card{...}\nCONTENT\n:: → :::card{...}\nCONTENT\n:::
|
|
889
|
+
inner = re.sub(
|
|
890
|
+
r'^::card(\{[^}]*\})\n(.*?)\n^::$',
|
|
891
|
+
r':::card\1\n\2\n:::',
|
|
892
|
+
inner,
|
|
893
|
+
flags=re.MULTILINE | re.DOTALL,
|
|
894
|
+
)
|
|
895
|
+
return f':::cards\n{inner}\n:::'
|
|
896
|
+
|
|
897
|
+
return re.sub(
|
|
898
|
+
r':::cards\n(.*?)\n:::',
|
|
899
|
+
fix_cards_block,
|
|
900
|
+
content,
|
|
901
|
+
flags=re.DOTALL,
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
def unwrap_markdown_trapped_in_code_fences(content: str) -> str:
|
|
906
|
+
"""Detect code fences that contain markdown content and unwrap them.
|
|
907
|
+
|
|
908
|
+
The LLM sometimes forgets to close a code fence, leaving section headers
|
|
909
|
+
(## ...), callout directives (:::), and horizontal rules (---) trapped
|
|
910
|
+
inside a code block. These render as literal text instead of MDX.
|
|
911
|
+
"""
|
|
912
|
+
# Pattern: a fenced block that contains markdown indicators
|
|
913
|
+
MD_INDICATORS = re.compile(
|
|
914
|
+
r"^(?:#{1,6}\s|:::|\-\-\-\s*$|^\*\*\*\s*$)",
|
|
915
|
+
re.MULTILINE,
|
|
916
|
+
)
|
|
917
|
+
|
|
918
|
+
def maybe_unwrap(m: re.Match) -> str:
|
|
919
|
+
lang = m.group(1) # may be empty for plain ```
|
|
920
|
+
body = m.group(2)
|
|
921
|
+
# If body contains markdown indicators, unwrap it
|
|
922
|
+
if MD_INDICATORS.search(body):
|
|
923
|
+
return body
|
|
924
|
+
return m.group(0) # leave intact
|
|
925
|
+
|
|
926
|
+
return re.sub(
|
|
927
|
+
r"```([A-Za-z0-9_+-]*)\n([\s\S]*?)\n```",
|
|
928
|
+
maybe_unwrap,
|
|
929
|
+
content,
|
|
930
|
+
)
|
|
931
|
+
|
|
932
|
+
|
|
803
933
|
def extract_glossary_terms(glossary_content: str) -> list[tuple[str, str]]:
|
|
804
934
|
"""Parse `### TermName` (h3) headings from glossary MDX → [(term, anchor-slug)].
|
|
805
935
|
|
|
@@ -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)")
|
|
@@ -1670,21 +1670,8 @@ def _mermaid_component_tsx() -> str:
|
|
|
1670
1670
|
}
|
|
1671
1671
|
render() {
|
|
1672
1672
|
if (this.state.error) {
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
style={{
|
|
1676
|
-
padding: '0.75rem 1rem',
|
|
1677
|
-
background: 'var(--color-fd-muted)',
|
|
1678
|
-
borderRadius: '6px',
|
|
1679
|
-
fontSize: '0.75rem',
|
|
1680
|
-
color: 'var(--color-fd-muted-foreground)',
|
|
1681
|
-
whiteSpace: 'pre-wrap',
|
|
1682
|
-
wordBreak: 'break-word',
|
|
1683
|
-
}}
|
|
1684
|
-
>
|
|
1685
|
-
{'[diagram parse error] ' + this.state.error}
|
|
1686
|
-
</pre>
|
|
1687
|
-
);
|
|
1673
|
+
// Silently hide diagrams that fail to parse — noise-free fallback
|
|
1674
|
+
return null;
|
|
1688
1675
|
}
|
|
1689
1676
|
return this.props.children;
|
|
1690
1677
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepdoc
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
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.4"
|
|
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
|