repowise 0.1.0__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.
- repowise-0.1.0/MANIFEST.in +2 -0
- repowise-0.1.0/PKG-INFO +150 -0
- repowise-0.1.0/README.md +74 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/__init__.py +9 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/__init__.py +1 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/claude_md_cmd.py +103 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/dead_code_cmd.py +143 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/decision_cmd.py +489 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/doctor_cmd.py +145 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/export_cmd.py +158 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/init_cmd.py +1012 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/mcp_cmd.py +59 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/reindex_cmd.py +183 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/search_cmd.py +167 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/serve_cmd.py +33 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/status_cmd.py +88 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/update_cmd.py +306 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/commands/watch_cmd.py +99 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/cost_estimator.py +282 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/helpers.py +258 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/main.py +41 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/mcp_config.py +66 -0
- repowise-0.1.0/packages/cli/src/repowise/cli/ui.py +540 -0
- repowise-0.1.0/packages/core/src/repowise/core/__init__.py +9 -0
- repowise-0.1.0/packages/core/src/repowise/core/analysis/__init__.py +1 -0
- repowise-0.1.0/packages/core/src/repowise/core/analysis/dead_code.py +554 -0
- repowise-0.1.0/packages/core/src/repowise/core/analysis/decision_extractor.py +783 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/__init__.py +90 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/context_assembler.py +823 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/editor_files/__init__.py +30 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/editor_files/base.py +130 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/editor_files/claude_md.py +25 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/editor_files/data.py +54 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/editor_files/fetcher.py +235 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/editor_files/tech_stack.py +203 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/job_system.py +253 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/models.py +357 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/page_generator.py +913 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/api_contract.j2 +30 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/architecture_diagram.j2 +31 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/claude_md.j2 +87 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/cross_package.j2 +18 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/diff_summary.j2 +46 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/file_page.j2 +129 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/infra_page.j2 +21 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/module_page.j2 +39 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/repo_overview.j2 +38 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/scc_page.j2 +30 -0
- repowise-0.1.0/packages/core/src/repowise/core/generation/templates/symbol_spotlight.j2 +41 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/__init__.py +55 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/change_detector.py +418 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/git_indexer.py +897 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/graph.py +420 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/models.py +214 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/parser.py +988 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/parsers/__init__.py +4 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/parsers/base.py +3 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/parsers/go.py +2 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/parsers/python.py +2 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/parsers/typescript.py +2 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/c.scm +35 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/cpp.scm +62 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/go.scm +36 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/java.scm +44 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/javascript.scm +45 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/kotlin.scm +25 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/python.scm +59 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/ruby.scm +30 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/rust.scm +56 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/queries/typescript.scm +78 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/special_handlers.py +290 -0
- repowise-0.1.0/packages/core/src/repowise/core/ingestion/traverser.py +525 -0
- repowise-0.1.0/packages/core/src/repowise/core/persistence/__init__.py +183 -0
- repowise-0.1.0/packages/core/src/repowise/core/persistence/crud.py +1299 -0
- repowise-0.1.0/packages/core/src/repowise/core/persistence/database.py +140 -0
- repowise-0.1.0/packages/core/src/repowise/core/persistence/models.py +458 -0
- repowise-0.1.0/packages/core/src/repowise/core/persistence/search.py +247 -0
- repowise-0.1.0/packages/core/src/repowise/core/persistence/vector_store.py +373 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/__init__.py +50 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/embedding/__init__.py +26 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/embedding/base.py +74 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/embedding/gemini.py +129 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/embedding/openai.py +107 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/embedding/registry.py +99 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/llm/__init__.py +42 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/llm/anthropic.py +306 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/llm/base.py +227 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/llm/gemini.py +383 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/llm/litellm.py +253 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/llm/mock.py +158 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/llm/ollama.py +240 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/llm/openai.py +254 -0
- repowise-0.1.0/packages/core/src/repowise/core/providers/llm/registry.py +154 -0
- repowise-0.1.0/packages/core/src/repowise/core/rate_limiter.py +132 -0
- repowise-0.1.0/packages/server/src/repowise/server/__init__.py +10 -0
- repowise-0.1.0/packages/server/src/repowise/server/app.py +166 -0
- repowise-0.1.0/packages/server/src/repowise/server/chat_tools.py +289 -0
- repowise-0.1.0/packages/server/src/repowise/server/deps.py +55 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/__init__.py +96 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/_helpers.py +275 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/_server.py +231 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/_state.py +17 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/tool_context.py +384 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/tool_dead_code.py +261 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/tool_dependency.py +253 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/tool_diagram.py +202 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/tool_overview.py +135 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/tool_risk.py +342 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/tool_search.py +138 -0
- repowise-0.1.0/packages/server/src/repowise/server/mcp_server/tool_why.py +481 -0
- repowise-0.1.0/packages/server/src/repowise/server/provider_config.py +199 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/__init__.py +1 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/chat.py +500 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/claude_md.py +84 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/dead_code.py +95 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/decisions.py +144 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/git.py +184 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/graph.py +692 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/health.py +82 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/jobs.py +103 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/pages.py +107 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/providers.py +53 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/repos.py +181 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/search.py +42 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/symbols.py +90 -0
- repowise-0.1.0/packages/server/src/repowise/server/routers/webhooks.py +169 -0
- repowise-0.1.0/packages/server/src/repowise/server/scheduler.py +117 -0
- repowise-0.1.0/packages/server/src/repowise/server/schemas.py +666 -0
- repowise-0.1.0/pyproject.toml +236 -0
- repowise-0.1.0/repowise.egg-info/PKG-INFO +150 -0
- repowise-0.1.0/repowise.egg-info/SOURCES.txt +134 -0
- repowise-0.1.0/repowise.egg-info/dependency_links.txt +1 -0
- repowise-0.1.0/repowise.egg-info/entry_points.txt +2 -0
- repowise-0.1.0/repowise.egg-info/requires.txt +60 -0
- repowise-0.1.0/repowise.egg-info/top_level.txt +1 -0
- repowise-0.1.0/setup.cfg +4 -0
repowise-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: repowise
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Codebase intelligence for developers and AI — generates and maintains a structured wiki for any codebase
|
|
5
|
+
License-Expression: AGPL-3.0-only
|
|
6
|
+
Project-URL: Homepage, https://repowise.dev
|
|
7
|
+
Project-URL: Repository, https://github.com/repowise-ai/repowise
|
|
8
|
+
Project-URL: Issues, https://github.com/repowise-ai/repowise/issues
|
|
9
|
+
Project-URL: Documentation, https://docs.repowise.dev
|
|
10
|
+
Keywords: documentation,codebase,wiki,llm,ai,mcp
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Environment :: Console
|
|
18
|
+
Classifier: Framework :: FastAPI
|
|
19
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: httpx<1,>=0.27
|
|
24
|
+
Requires-Dist: tree-sitter<1,>=0.23
|
|
25
|
+
Requires-Dist: tree-sitter-python<1,>=0.23
|
|
26
|
+
Requires-Dist: tree-sitter-typescript<1,>=0.23
|
|
27
|
+
Requires-Dist: tree-sitter-javascript<1,>=0.23
|
|
28
|
+
Requires-Dist: tree-sitter-go<1,>=0.23
|
|
29
|
+
Requires-Dist: tree-sitter-rust<1,>=0.23
|
|
30
|
+
Requires-Dist: tree-sitter-java<1,>=0.23
|
|
31
|
+
Requires-Dist: tree-sitter-cpp<1,>=0.23
|
|
32
|
+
Requires-Dist: networkx<4,>=3.3
|
|
33
|
+
Requires-Dist: scipy<2,>=1.11
|
|
34
|
+
Requires-Dist: jinja2<4,>=3.1
|
|
35
|
+
Requires-Dist: pathspec<1,>=0.12
|
|
36
|
+
Requires-Dist: structlog<25,>=24
|
|
37
|
+
Requires-Dist: sqlalchemy[asyncio]<3,>=2.0
|
|
38
|
+
Requires-Dist: aiosqlite<1,>=0.20
|
|
39
|
+
Requires-Dist: alembic<2,>=1.13
|
|
40
|
+
Requires-Dist: pydantic<3,>=2.8
|
|
41
|
+
Requires-Dist: tenacity<10,>=9
|
|
42
|
+
Requires-Dist: gitpython<4,>=3.1
|
|
43
|
+
Requires-Dist: pyyaml<7,>=6.0
|
|
44
|
+
Requires-Dist: lancedb<1,>=0.12
|
|
45
|
+
Requires-Dist: click<9,>=8.1
|
|
46
|
+
Requires-Dist: rich<14,>=13
|
|
47
|
+
Requires-Dist: watchdog<5,>=4
|
|
48
|
+
Requires-Dist: fastapi<1,>=0.115
|
|
49
|
+
Requires-Dist: uvicorn[standard]<1,>=0.32
|
|
50
|
+
Requires-Dist: mcp<2,>=1.0
|
|
51
|
+
Requires-Dist: apscheduler<4,>=3.10
|
|
52
|
+
Requires-Dist: cryptography<44,>=43
|
|
53
|
+
Provides-Extra: anthropic
|
|
54
|
+
Requires-Dist: anthropic<1,>=0.40; extra == "anthropic"
|
|
55
|
+
Provides-Extra: openai
|
|
56
|
+
Requires-Dist: openai<2,>=1.50; extra == "openai"
|
|
57
|
+
Provides-Extra: gemini
|
|
58
|
+
Requires-Dist: google-genai<2,>=1.0; extra == "gemini"
|
|
59
|
+
Provides-Extra: litellm
|
|
60
|
+
Requires-Dist: litellm<2,>=1.50; extra == "litellm"
|
|
61
|
+
Provides-Extra: postgres
|
|
62
|
+
Requires-Dist: pgvector<1,>=0.3; extra == "postgres"
|
|
63
|
+
Requires-Dist: asyncpg<1,>=0.29; extra == "postgres"
|
|
64
|
+
Provides-Extra: all
|
|
65
|
+
Requires-Dist: repowise[anthropic,gemini,litellm,openai,postgres]; extra == "all"
|
|
66
|
+
Provides-Extra: dev
|
|
67
|
+
Requires-Dist: pytest<9,>=8; extra == "dev"
|
|
68
|
+
Requires-Dist: pytest-asyncio<1,>=0.23; extra == "dev"
|
|
69
|
+
Requires-Dist: pytest-snapshot<1,>=0.9; extra == "dev"
|
|
70
|
+
Requires-Dist: respx<1,>=0.21; extra == "dev"
|
|
71
|
+
Requires-Dist: time-machine<3,>=2.14; extra == "dev"
|
|
72
|
+
Requires-Dist: ruff<1,>=0.6; extra == "dev"
|
|
73
|
+
Requires-Dist: mypy<2,>=1.11; extra == "dev"
|
|
74
|
+
Requires-Dist: types-networkx<4,>=3.3; extra == "dev"
|
|
75
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
76
|
+
|
|
77
|
+
# repowise
|
|
78
|
+
|
|
79
|
+
**Codebase intelligence for developers and AI.**
|
|
80
|
+
|
|
81
|
+
repowise generates and maintains a structured, hierarchical wiki for any codebase.
|
|
82
|
+
It keeps documentation accurate as code changes and exposes everything through an
|
|
83
|
+
MCP server so AI coding assistants can query it in real time.
|
|
84
|
+
|
|
85
|
+
## Features
|
|
86
|
+
|
|
87
|
+
- **Automatic documentation** — generates module, file, and symbol-level docs from source code
|
|
88
|
+
- **Git intelligence** — tracks churn hotspots, ownership, and change patterns
|
|
89
|
+
- **Dead code detection** — finds confirmed unused exports, functions, and types
|
|
90
|
+
- **Decision intelligence** — captures *why* code is structured the way it is
|
|
91
|
+
- **MCP server** — 8 tools for AI assistants (Claude Code, Cursor, Windsurf, etc.)
|
|
92
|
+
- **REST API + Web UI** — browse the wiki, search, and explore architecture diagrams
|
|
93
|
+
- **Multi-language** — Python, TypeScript, JavaScript, Go, Rust, Java, C/C++, Kotlin, Ruby
|
|
94
|
+
|
|
95
|
+
## Install
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install repowise
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
LLM providers are optional — install only the one you need:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pip install "repowise[anthropic]" # Claude models
|
|
105
|
+
pip install "repowise[openai]" # GPT models
|
|
106
|
+
pip install "repowise[gemini]" # Gemini models
|
|
107
|
+
pip install "repowise[litellm]" # 100+ providers via LiteLLM
|
|
108
|
+
pip install "repowise[all]" # Everything
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Quick Start
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Generate documentation for your codebase
|
|
115
|
+
repowise init --provider anthropic --model claude-sonnet-4-6
|
|
116
|
+
|
|
117
|
+
# Keep docs in sync after code changes
|
|
118
|
+
repowise update
|
|
119
|
+
|
|
120
|
+
# Start the MCP server for AI assistants
|
|
121
|
+
repowise mcp
|
|
122
|
+
|
|
123
|
+
# Launch the web UI
|
|
124
|
+
repowise serve
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## How It Works
|
|
128
|
+
|
|
129
|
+
1. **Ingestion** — parses every file using tree-sitter, extracts symbols, imports, and builds a dependency graph
|
|
130
|
+
2. **Analysis** — computes git signals (churn, ownership, recency), detects dead code, identifies architectural decisions
|
|
131
|
+
3. **Generation** — sends structured prompts to an LLM to produce wiki pages at every level of the hierarchy
|
|
132
|
+
4. **Persistence** — stores everything in SQLite (or PostgreSQL) with full-text and vector search
|
|
133
|
+
5. **Serving** — exposes the wiki through REST API, MCP server, and web UI
|
|
134
|
+
|
|
135
|
+
## Requirements
|
|
136
|
+
|
|
137
|
+
- Python 3.11+
|
|
138
|
+
- Git (for repository analysis)
|
|
139
|
+
- An LLM API key (for documentation generation — not needed for analysis-only mode)
|
|
140
|
+
|
|
141
|
+
## Documentation
|
|
142
|
+
|
|
143
|
+
- [Architecture Guide](docs/ARCHITECTURE.md)
|
|
144
|
+
- [CLI Reference](packages/cli/README.md)
|
|
145
|
+
- [Server & MCP Tools](packages/server/README.md)
|
|
146
|
+
- [Core Library](packages/core/README.md)
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
AGPL-3.0 — see [LICENSE](LICENSE) for details.
|
repowise-0.1.0/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# repowise
|
|
2
|
+
|
|
3
|
+
**Codebase intelligence for developers and AI.**
|
|
4
|
+
|
|
5
|
+
repowise generates and maintains a structured, hierarchical wiki for any codebase.
|
|
6
|
+
It keeps documentation accurate as code changes and exposes everything through an
|
|
7
|
+
MCP server so AI coding assistants can query it in real time.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Automatic documentation** — generates module, file, and symbol-level docs from source code
|
|
12
|
+
- **Git intelligence** — tracks churn hotspots, ownership, and change patterns
|
|
13
|
+
- **Dead code detection** — finds confirmed unused exports, functions, and types
|
|
14
|
+
- **Decision intelligence** — captures *why* code is structured the way it is
|
|
15
|
+
- **MCP server** — 8 tools for AI assistants (Claude Code, Cursor, Windsurf, etc.)
|
|
16
|
+
- **REST API + Web UI** — browse the wiki, search, and explore architecture diagrams
|
|
17
|
+
- **Multi-language** — Python, TypeScript, JavaScript, Go, Rust, Java, C/C++, Kotlin, Ruby
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install repowise
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
LLM providers are optional — install only the one you need:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install "repowise[anthropic]" # Claude models
|
|
29
|
+
pip install "repowise[openai]" # GPT models
|
|
30
|
+
pip install "repowise[gemini]" # Gemini models
|
|
31
|
+
pip install "repowise[litellm]" # 100+ providers via LiteLLM
|
|
32
|
+
pip install "repowise[all]" # Everything
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Generate documentation for your codebase
|
|
39
|
+
repowise init --provider anthropic --model claude-sonnet-4-6
|
|
40
|
+
|
|
41
|
+
# Keep docs in sync after code changes
|
|
42
|
+
repowise update
|
|
43
|
+
|
|
44
|
+
# Start the MCP server for AI assistants
|
|
45
|
+
repowise mcp
|
|
46
|
+
|
|
47
|
+
# Launch the web UI
|
|
48
|
+
repowise serve
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## How It Works
|
|
52
|
+
|
|
53
|
+
1. **Ingestion** — parses every file using tree-sitter, extracts symbols, imports, and builds a dependency graph
|
|
54
|
+
2. **Analysis** — computes git signals (churn, ownership, recency), detects dead code, identifies architectural decisions
|
|
55
|
+
3. **Generation** — sends structured prompts to an LLM to produce wiki pages at every level of the hierarchy
|
|
56
|
+
4. **Persistence** — stores everything in SQLite (or PostgreSQL) with full-text and vector search
|
|
57
|
+
5. **Serving** — exposes the wiki through REST API, MCP server, and web UI
|
|
58
|
+
|
|
59
|
+
## Requirements
|
|
60
|
+
|
|
61
|
+
- Python 3.11+
|
|
62
|
+
- Git (for repository analysis)
|
|
63
|
+
- An LLM API key (for documentation generation — not needed for analysis-only mode)
|
|
64
|
+
|
|
65
|
+
## Documentation
|
|
66
|
+
|
|
67
|
+
- [Architecture Guide](docs/ARCHITECTURE.md)
|
|
68
|
+
- [CLI Reference](packages/cli/README.md)
|
|
69
|
+
- [Server & MCP Tools](packages/server/README.md)
|
|
70
|
+
- [Core Library](packages/core/README.md)
|
|
71
|
+
|
|
72
|
+
## License
|
|
73
|
+
|
|
74
|
+
AGPL-3.0 — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""repowise CLI package.
|
|
2
|
+
|
|
3
|
+
Entry point: ``repowise`` command (defined in repowise.cli.main).
|
|
4
|
+
Codebase intelligence for developers and AI — dependency graphs,
|
|
5
|
+
git signals, dead code detection, architectural decisions, and
|
|
6
|
+
AI-generated documentation.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""CLI command modules."""
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""repowise generate-claude-md — generate/update CLAUDE.md for a repository."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
from repowise.cli.helpers import (
|
|
10
|
+
ensure_repowise_dir,
|
|
11
|
+
get_db_url_for_repo,
|
|
12
|
+
run_async,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.command("generate-claude-md")
|
|
17
|
+
@click.argument("path", required=False, default=None)
|
|
18
|
+
@click.option(
|
|
19
|
+
"--output",
|
|
20
|
+
"output_path",
|
|
21
|
+
default=None,
|
|
22
|
+
metavar="FILE",
|
|
23
|
+
help="Write to a custom path (default: CLAUDE.md in the repo root).",
|
|
24
|
+
)
|
|
25
|
+
@click.option(
|
|
26
|
+
"--stdout",
|
|
27
|
+
"to_stdout",
|
|
28
|
+
is_flag=True,
|
|
29
|
+
default=False,
|
|
30
|
+
help="Print generated content to stdout instead of writing a file.",
|
|
31
|
+
)
|
|
32
|
+
def claude_md_command(
|
|
33
|
+
path: str | None,
|
|
34
|
+
output_path: str | None,
|
|
35
|
+
to_stdout: bool,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Generate or update CLAUDE.md with codebase intelligence context.
|
|
38
|
+
|
|
39
|
+
PATH defaults to the current directory.
|
|
40
|
+
|
|
41
|
+
The file is split into two sections:
|
|
42
|
+
- Your custom instructions (above the REPOWISE markers) — never modified.
|
|
43
|
+
- Repowise-managed section (between markers) — auto-updated from the index.
|
|
44
|
+
|
|
45
|
+
Run 'repowise init' or 'repowise update' to keep it current automatically.
|
|
46
|
+
"""
|
|
47
|
+
repo_path = Path(path).resolve() if path else Path.cwd()
|
|
48
|
+
ensure_repowise_dir(repo_path)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
content = run_async(_generate(repo_path, output_path, to_stdout))
|
|
52
|
+
except Exception as exc: # noqa: BLE001
|
|
53
|
+
raise click.ClickException(str(exc)) from exc
|
|
54
|
+
|
|
55
|
+
if to_stdout:
|
|
56
|
+
click.echo(content, nl=False)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def _generate(
|
|
60
|
+
repo_path: Path,
|
|
61
|
+
output_path: str | None,
|
|
62
|
+
to_stdout: bool,
|
|
63
|
+
) -> str | None:
|
|
64
|
+
from repowise.core.generation.editor_files import ClaudeMdGenerator, EditorFileDataFetcher
|
|
65
|
+
from repowise.core.persistence import (
|
|
66
|
+
create_engine,
|
|
67
|
+
create_session_factory,
|
|
68
|
+
get_session,
|
|
69
|
+
init_db,
|
|
70
|
+
)
|
|
71
|
+
from repowise.core.persistence.crud import get_repository_by_path
|
|
72
|
+
|
|
73
|
+
url = get_db_url_for_repo(repo_path)
|
|
74
|
+
engine = create_engine(url)
|
|
75
|
+
await init_db(engine)
|
|
76
|
+
sf = create_session_factory(engine)
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
async with get_session(sf) as session:
|
|
80
|
+
repo = await get_repository_by_path(session, str(repo_path))
|
|
81
|
+
if repo is None:
|
|
82
|
+
raise click.ClickException(
|
|
83
|
+
f"Repository not found in index. Run 'repowise init' first."
|
|
84
|
+
)
|
|
85
|
+
fetcher = EditorFileDataFetcher(session, repo.id, repo_path)
|
|
86
|
+
data = await fetcher.fetch()
|
|
87
|
+
finally:
|
|
88
|
+
await engine.dispose()
|
|
89
|
+
|
|
90
|
+
gen = ClaudeMdGenerator()
|
|
91
|
+
|
|
92
|
+
if to_stdout:
|
|
93
|
+
return gen.render_full(repo_path, data)
|
|
94
|
+
|
|
95
|
+
dest = Path(output_path).resolve() if output_path else None
|
|
96
|
+
written = gen.write(dest.parent if dest else repo_path, data)
|
|
97
|
+
if dest and dest != written:
|
|
98
|
+
# Custom output path differs from default filename in same dir
|
|
99
|
+
written.rename(dest)
|
|
100
|
+
written = dest
|
|
101
|
+
|
|
102
|
+
click.echo(f"CLAUDE.md updated: {written}")
|
|
103
|
+
return None
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""``repowise dead-code`` — detect dead and unused code."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
from repowise.cli.helpers import (
|
|
11
|
+
console,
|
|
12
|
+
resolve_repo_path,
|
|
13
|
+
run_async,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.command("dead-code")
|
|
18
|
+
@click.argument("path", required=False, type=click.Path(exists=True))
|
|
19
|
+
@click.option("--min-confidence", default=0.4, type=float, help="Minimum confidence threshold.")
|
|
20
|
+
@click.option("--safe-only", is_flag=True, help="Only show safe_to_delete=True findings.")
|
|
21
|
+
@click.option(
|
|
22
|
+
"--kind",
|
|
23
|
+
type=click.Choice(["unreachable_file", "unused_export", "unused_internal", "zombie_package"]),
|
|
24
|
+
help="Filter by finding kind.",
|
|
25
|
+
)
|
|
26
|
+
@click.option(
|
|
27
|
+
"--format",
|
|
28
|
+
"fmt",
|
|
29
|
+
default="table",
|
|
30
|
+
type=click.Choice(["table", "json", "md"]),
|
|
31
|
+
help="Output format.",
|
|
32
|
+
)
|
|
33
|
+
def dead_code_command(
|
|
34
|
+
path: str | None,
|
|
35
|
+
min_confidence: float,
|
|
36
|
+
safe_only: bool,
|
|
37
|
+
kind: str | None,
|
|
38
|
+
fmt: str,
|
|
39
|
+
) -> None:
|
|
40
|
+
"""Detect dead and unused code."""
|
|
41
|
+
from pathlib import Path as PathlibPath
|
|
42
|
+
|
|
43
|
+
from repowise.core.analysis.dead_code import DeadCodeAnalyzer
|
|
44
|
+
from repowise.core.ingestion import ASTParser, FileTraverser, GraphBuilder
|
|
45
|
+
|
|
46
|
+
repo_path = resolve_repo_path(path)
|
|
47
|
+
|
|
48
|
+
console.print(f"[bold]repowise dead-code[/bold] — {repo_path}")
|
|
49
|
+
|
|
50
|
+
# Ingest
|
|
51
|
+
traverser = FileTraverser(repo_path)
|
|
52
|
+
file_infos = list(traverser.traverse())
|
|
53
|
+
parser = ASTParser()
|
|
54
|
+
graph_builder = GraphBuilder()
|
|
55
|
+
|
|
56
|
+
for fi in file_infos:
|
|
57
|
+
try:
|
|
58
|
+
source = PathlibPath(fi.abs_path).read_bytes()
|
|
59
|
+
parsed = parser.parse_file(fi, source)
|
|
60
|
+
graph_builder.add_file(parsed)
|
|
61
|
+
except Exception:
|
|
62
|
+
pass
|
|
63
|
+
graph_builder.build()
|
|
64
|
+
|
|
65
|
+
# Git metadata (best effort)
|
|
66
|
+
git_meta_map: dict = {}
|
|
67
|
+
try:
|
|
68
|
+
from repowise.core.ingestion.git_indexer import GitIndexer
|
|
69
|
+
|
|
70
|
+
git_indexer = GitIndexer(repo_path)
|
|
71
|
+
_, metadata_list = run_async(git_indexer.index_repo(""))
|
|
72
|
+
git_meta_map = {m["file_path"]: m for m in metadata_list}
|
|
73
|
+
except Exception:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
# Analyze
|
|
77
|
+
config = {"min_confidence": min_confidence}
|
|
78
|
+
if kind:
|
|
79
|
+
# Enable only the requested kind
|
|
80
|
+
config["detect_unreachable_files"] = kind == "unreachable_file"
|
|
81
|
+
config["detect_unused_exports"] = kind == "unused_export"
|
|
82
|
+
config["detect_unused_internals"] = kind == "unused_internal"
|
|
83
|
+
config["detect_zombie_packages"] = kind == "zombie_package"
|
|
84
|
+
|
|
85
|
+
analyzer = DeadCodeAnalyzer(graph_builder.graph(), git_meta_map)
|
|
86
|
+
report = analyzer.analyze(config)
|
|
87
|
+
|
|
88
|
+
findings = report.findings
|
|
89
|
+
if safe_only:
|
|
90
|
+
findings = [f for f in findings if f.safe_to_delete]
|
|
91
|
+
|
|
92
|
+
if fmt == "json":
|
|
93
|
+
output = []
|
|
94
|
+
for f in findings:
|
|
95
|
+
output.append({
|
|
96
|
+
"kind": f.kind.value,
|
|
97
|
+
"file_path": f.file_path,
|
|
98
|
+
"symbol_name": f.symbol_name,
|
|
99
|
+
"confidence": f.confidence,
|
|
100
|
+
"reason": f.reason,
|
|
101
|
+
"safe_to_delete": f.safe_to_delete,
|
|
102
|
+
"lines": f.lines,
|
|
103
|
+
"primary_owner": f.primary_owner,
|
|
104
|
+
})
|
|
105
|
+
click.echo(json.dumps(output, indent=2))
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
if fmt == "md":
|
|
109
|
+
click.echo(f"# Dead Code Report\n")
|
|
110
|
+
click.echo(f"**Total findings:** {len(findings)}")
|
|
111
|
+
click.echo(f"**Deletable lines:** {report.deletable_lines}\n")
|
|
112
|
+
for f in findings:
|
|
113
|
+
safe = " (safe to remove)" if f.safe_to_delete else ""
|
|
114
|
+
name = f"`{f.symbol_name}`" if f.symbol_name else f"`{f.file_path}`"
|
|
115
|
+
click.echo(f"- [{f.kind.value}] {name} — {f.reason} ({f.confidence:.0%}){safe}")
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
# Table format (default)
|
|
119
|
+
table = Table(title=f"Dead Code ({len(findings)} findings)")
|
|
120
|
+
table.add_column("Kind", style="cyan")
|
|
121
|
+
table.add_column("File / Symbol")
|
|
122
|
+
table.add_column("Confidence", justify="right")
|
|
123
|
+
table.add_column("Safe?", justify="center")
|
|
124
|
+
table.add_column("Lines", justify="right")
|
|
125
|
+
table.add_column("Reason")
|
|
126
|
+
|
|
127
|
+
for f in findings:
|
|
128
|
+
name = f.symbol_name or f.file_path
|
|
129
|
+
safe = "[green]✓[/green]" if f.safe_to_delete else "[red]✗[/red]"
|
|
130
|
+
table.add_row(
|
|
131
|
+
f.kind.value,
|
|
132
|
+
name,
|
|
133
|
+
f"{f.confidence:.0%}",
|
|
134
|
+
safe,
|
|
135
|
+
str(f.lines),
|
|
136
|
+
f.reason[:60],
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
console.print(table)
|
|
140
|
+
console.print(
|
|
141
|
+
f"\nDeletable lines: [bold]{report.deletable_lines:,}[/bold] "
|
|
142
|
+
f"(confidence: {report.confidence_summary})"
|
|
143
|
+
)
|