gwc-pybundle 2.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of gwc-pybundle might be problematic. Click here for more details.
- gwc_pybundle-2.1.2.dist-info/METADATA +903 -0
- gwc_pybundle-2.1.2.dist-info/RECORD +82 -0
- gwc_pybundle-2.1.2.dist-info/WHEEL +5 -0
- gwc_pybundle-2.1.2.dist-info/entry_points.txt +2 -0
- gwc_pybundle-2.1.2.dist-info/licenses/LICENSE.md +25 -0
- gwc_pybundle-2.1.2.dist-info/top_level.txt +1 -0
- pybundle/__init__.py +0 -0
- pybundle/__main__.py +4 -0
- pybundle/cli.py +546 -0
- pybundle/context.py +404 -0
- pybundle/doctor.py +148 -0
- pybundle/filters.py +228 -0
- pybundle/manifest.py +77 -0
- pybundle/packaging.py +45 -0
- pybundle/policy.py +132 -0
- pybundle/profiles.py +454 -0
- pybundle/roadmap_model.py +42 -0
- pybundle/roadmap_scan.py +328 -0
- pybundle/root_detect.py +14 -0
- pybundle/runner.py +180 -0
- pybundle/steps/__init__.py +26 -0
- pybundle/steps/ai_context.py +791 -0
- pybundle/steps/api_docs.py +219 -0
- pybundle/steps/asyncio_analysis.py +358 -0
- pybundle/steps/bandit.py +72 -0
- pybundle/steps/base.py +20 -0
- pybundle/steps/blocking_call_detection.py +291 -0
- pybundle/steps/call_graph.py +219 -0
- pybundle/steps/compileall.py +76 -0
- pybundle/steps/config_docs.py +319 -0
- pybundle/steps/config_validation.py +302 -0
- pybundle/steps/container_image.py +294 -0
- pybundle/steps/context_expand.py +272 -0
- pybundle/steps/copy_pack.py +293 -0
- pybundle/steps/coverage.py +101 -0
- pybundle/steps/cprofile_step.py +166 -0
- pybundle/steps/dependency_sizes.py +136 -0
- pybundle/steps/django_checks.py +214 -0
- pybundle/steps/dockerfile_lint.py +282 -0
- pybundle/steps/dockerignore.py +311 -0
- pybundle/steps/duplication.py +103 -0
- pybundle/steps/env_completeness.py +269 -0
- pybundle/steps/env_var_usage.py +253 -0
- pybundle/steps/error_refs.py +204 -0
- pybundle/steps/event_loop_patterns.py +280 -0
- pybundle/steps/exception_patterns.py +190 -0
- pybundle/steps/fastapi_integration.py +250 -0
- pybundle/steps/flask_debugging.py +312 -0
- pybundle/steps/git_analytics.py +315 -0
- pybundle/steps/handoff_md.py +176 -0
- pybundle/steps/import_time.py +175 -0
- pybundle/steps/interrogate.py +106 -0
- pybundle/steps/license_scan.py +96 -0
- pybundle/steps/line_profiler.py +117 -0
- pybundle/steps/link_validation.py +287 -0
- pybundle/steps/logging_analysis.py +233 -0
- pybundle/steps/memory_profile.py +176 -0
- pybundle/steps/migration_history.py +336 -0
- pybundle/steps/mutation_testing.py +141 -0
- pybundle/steps/mypy.py +103 -0
- pybundle/steps/orm_optimization.py +316 -0
- pybundle/steps/pip_audit.py +45 -0
- pybundle/steps/pipdeptree.py +62 -0
- pybundle/steps/pylance.py +562 -0
- pybundle/steps/pytest.py +66 -0
- pybundle/steps/query_pattern_analysis.py +334 -0
- pybundle/steps/radon.py +161 -0
- pybundle/steps/repro_md.py +161 -0
- pybundle/steps/rg_scans.py +78 -0
- pybundle/steps/roadmap.py +153 -0
- pybundle/steps/ruff.py +117 -0
- pybundle/steps/secrets_detection.py +235 -0
- pybundle/steps/security_headers.py +309 -0
- pybundle/steps/shell.py +74 -0
- pybundle/steps/slow_tests.py +178 -0
- pybundle/steps/sqlalchemy_validation.py +269 -0
- pybundle/steps/test_flakiness.py +184 -0
- pybundle/steps/tree.py +116 -0
- pybundle/steps/type_coverage.py +277 -0
- pybundle/steps/unused_deps.py +211 -0
- pybundle/steps/vulture.py +167 -0
- pybundle/tools.py +63 -0
pybundle/profiles.py
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
import dataclasses
|
|
5
|
+
from .context import RunOptions
|
|
6
|
+
from .steps.shell import ShellStep
|
|
7
|
+
from .steps.tree import TreeStep, LargestFilesStep
|
|
8
|
+
from .steps.compileall import CompileAllStep
|
|
9
|
+
from .steps.ruff import RuffCheckStep, RuffFormatCheckStep
|
|
10
|
+
from .steps.mypy import MypyStep
|
|
11
|
+
from .steps.pylance import PylanceStep
|
|
12
|
+
from .steps.pytest import PytestStep
|
|
13
|
+
from .steps.bandit import BanditStep
|
|
14
|
+
from .steps.pip_audit import PipAuditStep
|
|
15
|
+
from .steps.coverage import CoverageStep
|
|
16
|
+
from .steps.rg_scans import default_rg_steps
|
|
17
|
+
from .steps.error_refs import ErrorReferencedFilesStep
|
|
18
|
+
from .steps.context_expand import ErrorContextExpandStep
|
|
19
|
+
from .steps.copy_pack import CuratedCopyStep
|
|
20
|
+
from .steps.repro_md import ReproMarkdownStep
|
|
21
|
+
from .steps.handoff_md import HandoffMarkdownStep
|
|
22
|
+
from .steps.roadmap import RoadmapStep
|
|
23
|
+
|
|
24
|
+
# Code quality tools (v1.3.0)
|
|
25
|
+
from .steps.vulture import VultureStep
|
|
26
|
+
from .steps.radon import RadonStep
|
|
27
|
+
from .steps.interrogate import InterrogateStep
|
|
28
|
+
from .steps.duplication import DuplicationStep
|
|
29
|
+
|
|
30
|
+
# Dependency analysis tools (v1.3.1)
|
|
31
|
+
from .steps.pipdeptree import PipdeptreeStep
|
|
32
|
+
from .steps.unused_deps import UnusedDependenciesStep
|
|
33
|
+
from .steps.license_scan import LicenseScanStep
|
|
34
|
+
from .steps.dependency_sizes import DependencySizesStep
|
|
35
|
+
|
|
36
|
+
# Performance profiling tools (v1.4.0)
|
|
37
|
+
from .steps.cprofile_step import CProfileStep
|
|
38
|
+
from .steps.import_time import ImportTimeStep
|
|
39
|
+
from .steps.memory_profile import MemoryProfileStep
|
|
40
|
+
from .steps.line_profiler import LineProfilerStep
|
|
41
|
+
|
|
42
|
+
# Test quality & coverage tools (v1.4.1)
|
|
43
|
+
from .steps.test_flakiness import TestFlakinessStep
|
|
44
|
+
from .steps.slow_tests import SlowTestsStep
|
|
45
|
+
from .steps.mutation_testing import MutationTestingStep
|
|
46
|
+
|
|
47
|
+
# Documentation & type quality tools (v1.5.0)
|
|
48
|
+
from .steps.type_coverage import TypeCoverageStep
|
|
49
|
+
from .steps.link_validation import LinkValidationStep
|
|
50
|
+
from .steps.api_docs import ApiDocsStep
|
|
51
|
+
|
|
52
|
+
# AI context generation (v2.1.0)
|
|
53
|
+
from .steps.ai_context import AIContextStep
|
|
54
|
+
from .steps.config_docs import ConfigDocumentationStep
|
|
55
|
+
|
|
56
|
+
# Git analytics tools (v1.5.1)
|
|
57
|
+
from .steps.git_analytics import GitAnalyticsStep
|
|
58
|
+
|
|
59
|
+
# Runtime analysis tools (v1.5.2)
|
|
60
|
+
from .steps.exception_patterns import ExceptionPatternsStep
|
|
61
|
+
from .steps.logging_analysis import LoggingAnalysisStep
|
|
62
|
+
from .steps.call_graph import CallGraphStep
|
|
63
|
+
from .steps.env_var_usage import EnvVarUsageStep
|
|
64
|
+
|
|
65
|
+
# Container & deployment tools (v2.0.0)
|
|
66
|
+
from .steps.dockerfile_lint import DockerfileLintStep
|
|
67
|
+
from .steps.dockerignore import DockerigoreStep
|
|
68
|
+
from .steps.container_image import ContainerImageStep
|
|
69
|
+
|
|
70
|
+
# Configuration & security tools (v2.0.0)
|
|
71
|
+
from .steps.config_validation import ConfigValidationStep
|
|
72
|
+
from .steps.secrets_detection import SecretsDetectionStep
|
|
73
|
+
from .steps.env_completeness import EnvCompletenessStep
|
|
74
|
+
from .steps.security_headers import SecurityHeadersStep
|
|
75
|
+
|
|
76
|
+
# Async & modern Python tools (v2.0.0)
|
|
77
|
+
from .steps.asyncio_analysis import AsyncioAnalysisStep
|
|
78
|
+
from .steps.blocking_call_detection import BlockingCallDetectionStep
|
|
79
|
+
from .steps.event_loop_patterns import EventLoopPatternsStep
|
|
80
|
+
|
|
81
|
+
# Database & data layer tools (v2.0.0)
|
|
82
|
+
from .steps.migration_history import MigrationHistoryStep
|
|
83
|
+
from .steps.query_pattern_analysis import QueryPatternAnalysisStep
|
|
84
|
+
from .steps.orm_optimization import ORMOptimizationStep
|
|
85
|
+
|
|
86
|
+
# Framework-specific tools (v2.0.0)
|
|
87
|
+
from .steps.django_checks import DjangoSystemChecksStep
|
|
88
|
+
from .steps.fastapi_integration import FastAPIIntegrationStep
|
|
89
|
+
from .steps.flask_debugging import FlaskDebuggingStep
|
|
90
|
+
from .steps.sqlalchemy_validation import SQLAlchemyValidationStep
|
|
91
|
+
|
|
92
|
+
from .policy import AIContextPolicy
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass(frozen=True)
|
|
96
|
+
class Profile:
|
|
97
|
+
name: str
|
|
98
|
+
steps: list
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _dedupe_steps(steps: list) -> list:
|
|
102
|
+
seen = set()
|
|
103
|
+
out = []
|
|
104
|
+
for s in steps:
|
|
105
|
+
key = (
|
|
106
|
+
getattr(s, "out", None)
|
|
107
|
+
or getattr(s, "out_md", None)
|
|
108
|
+
or getattr(s, "name", None)
|
|
109
|
+
)
|
|
110
|
+
# fallback to class name if needed
|
|
111
|
+
key = key or s.__class__.__name__
|
|
112
|
+
if key in seen:
|
|
113
|
+
continue
|
|
114
|
+
seen.add(key)
|
|
115
|
+
out.append(s)
|
|
116
|
+
return out
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def resolve_defaults(profile: str, opts: RunOptions) -> RunOptions:
|
|
120
|
+
if profile == "ai":
|
|
121
|
+
return dataclasses.replace(
|
|
122
|
+
opts,
|
|
123
|
+
no_ruff=opts.no_ruff if opts.no_ruff is not None else True,
|
|
124
|
+
no_mypy=opts.no_mypy if opts.no_mypy is not None else True,
|
|
125
|
+
no_pytest=opts.no_pytest if opts.no_pytest is not None else True,
|
|
126
|
+
no_rg=opts.no_rg if opts.no_rg is not None else True,
|
|
127
|
+
no_error_refs=opts.no_error_refs
|
|
128
|
+
if opts.no_error_refs is not None
|
|
129
|
+
else True,
|
|
130
|
+
no_context=opts.no_context if opts.no_context is not None else True,
|
|
131
|
+
no_compileall=opts.no_compileall
|
|
132
|
+
if opts.no_compileall is not None
|
|
133
|
+
else True,
|
|
134
|
+
)
|
|
135
|
+
return opts
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _analysis_steps(options: RunOptions) -> list:
|
|
139
|
+
"""
|
|
140
|
+
Analysis profile: What the code IS
|
|
141
|
+
- Structure, metrics, dependencies
|
|
142
|
+
- Documentation and codebase understanding
|
|
143
|
+
- No error detection or linting
|
|
144
|
+
"""
|
|
145
|
+
policy = AIContextPolicy()
|
|
146
|
+
|
|
147
|
+
steps: list = [
|
|
148
|
+
# Environment & git status
|
|
149
|
+
ShellStep(
|
|
150
|
+
"git status", "meta/00_git_status.txt", ["git", "status"], require_cmd="git"
|
|
151
|
+
),
|
|
152
|
+
ShellStep(
|
|
153
|
+
"git diff", "meta/01_git_diff.txt", ["git", "diff"], require_cmd="git"
|
|
154
|
+
),
|
|
155
|
+
ShellStep(
|
|
156
|
+
"uname -a", "meta/21_uname.txt", ["uname", "-a"], require_cmd="uname"
|
|
157
|
+
),
|
|
158
|
+
ShellStep(
|
|
159
|
+
"python -V",
|
|
160
|
+
"meta/20_python_version.txt",
|
|
161
|
+
["python", "-V"],
|
|
162
|
+
require_cmd="python",
|
|
163
|
+
),
|
|
164
|
+
ShellStep(
|
|
165
|
+
"pip freeze",
|
|
166
|
+
"meta/22_pip_freeze.txt",
|
|
167
|
+
["python", "-m", "pip", "freeze"],
|
|
168
|
+
require_cmd="python",
|
|
169
|
+
),
|
|
170
|
+
# Code structure
|
|
171
|
+
TreeStep(max_depth=policy.tree_max_depth, policy=policy),
|
|
172
|
+
LargestFilesStep(limit=policy.largest_limit, policy=policy),
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
# Code quality metrics (what the code looks like)
|
|
176
|
+
if not options.no_radon:
|
|
177
|
+
steps += [RadonStep()]
|
|
178
|
+
|
|
179
|
+
if not options.no_interrogate:
|
|
180
|
+
steps += [InterrogateStep()]
|
|
181
|
+
|
|
182
|
+
if not options.no_duplication:
|
|
183
|
+
steps += [DuplicationStep()]
|
|
184
|
+
|
|
185
|
+
# Dependency analysis (what the project uses)
|
|
186
|
+
if not options.no_pipdeptree:
|
|
187
|
+
steps += [PipdeptreeStep()]
|
|
188
|
+
|
|
189
|
+
if not options.no_license_scan:
|
|
190
|
+
steps += [LicenseScanStep()]
|
|
191
|
+
|
|
192
|
+
if not options.no_dependency_sizes:
|
|
193
|
+
steps += [DependencySizesStep()]
|
|
194
|
+
|
|
195
|
+
# Performance profiling (what the code does)
|
|
196
|
+
if not options.no_profile:
|
|
197
|
+
steps += [CProfileStep()]
|
|
198
|
+
steps += [ImportTimeStep()]
|
|
199
|
+
|
|
200
|
+
if options.profile_memory:
|
|
201
|
+
steps += [MemoryProfileStep()]
|
|
202
|
+
|
|
203
|
+
if options.enable_line_profiler:
|
|
204
|
+
steps += [LineProfilerStep()]
|
|
205
|
+
|
|
206
|
+
# Documentation & type quality (what the code documents/types)
|
|
207
|
+
if not options.no_type_coverage:
|
|
208
|
+
steps += [TypeCoverageStep()]
|
|
209
|
+
|
|
210
|
+
if not options.no_link_check:
|
|
211
|
+
steps += [LinkValidationStep()]
|
|
212
|
+
|
|
213
|
+
if not options.no_api_docs:
|
|
214
|
+
steps += [ApiDocsStep()]
|
|
215
|
+
|
|
216
|
+
if not options.no_config_docs:
|
|
217
|
+
steps += [ConfigDocumentationStep()]
|
|
218
|
+
|
|
219
|
+
# Git analytics (v1.5.1)
|
|
220
|
+
if not options.no_git_analytics:
|
|
221
|
+
steps += [GitAnalyticsStep()]
|
|
222
|
+
|
|
223
|
+
# Runtime analysis (v1.5.2)
|
|
224
|
+
if not options.no_runtime_analysis:
|
|
225
|
+
steps += [
|
|
226
|
+
ExceptionPatternsStep(),
|
|
227
|
+
LoggingAnalysisStep(),
|
|
228
|
+
CallGraphStep(),
|
|
229
|
+
EnvVarUsageStep(),
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
# Container & deployment (v2.0.0)
|
|
233
|
+
if not options.no_container_analysis:
|
|
234
|
+
steps += [
|
|
235
|
+
DockerfileLintStep(),
|
|
236
|
+
DockerigoreStep(),
|
|
237
|
+
ContainerImageStep(),
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
# Configuration & security (v2.0.0)
|
|
241
|
+
if not options.no_config_security_analysis:
|
|
242
|
+
steps += [
|
|
243
|
+
ConfigValidationStep(),
|
|
244
|
+
SecretsDetectionStep(),
|
|
245
|
+
EnvCompletenessStep(),
|
|
246
|
+
SecurityHeadersStep(),
|
|
247
|
+
]
|
|
248
|
+
|
|
249
|
+
# Async & modern Python (v2.0.0)
|
|
250
|
+
if not options.no_async_analysis:
|
|
251
|
+
steps += [
|
|
252
|
+
AsyncioAnalysisStep(),
|
|
253
|
+
BlockingCallDetectionStep(),
|
|
254
|
+
EventLoopPatternsStep(),
|
|
255
|
+
]
|
|
256
|
+
|
|
257
|
+
# Database & data layer (v2.0.0)
|
|
258
|
+
if not options.no_db_analysis:
|
|
259
|
+
steps += [
|
|
260
|
+
MigrationHistoryStep(),
|
|
261
|
+
QueryPatternAnalysisStep(),
|
|
262
|
+
ORMOptimizationStep(),
|
|
263
|
+
]
|
|
264
|
+
|
|
265
|
+
# Framework-specific tools (v2.0.0)
|
|
266
|
+
if not options.no_framework_analysis:
|
|
267
|
+
steps += [
|
|
268
|
+
DjangoSystemChecksStep(),
|
|
269
|
+
FastAPIIntegrationStep(),
|
|
270
|
+
FlaskDebuggingStep(),
|
|
271
|
+
SQLAlchemyValidationStep(),
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
# Source snapshot and documentation
|
|
275
|
+
steps += [
|
|
276
|
+
CuratedCopyStep(policy=policy),
|
|
277
|
+
RoadmapStep(policy=policy),
|
|
278
|
+
HandoffMarkdownStep(),
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
return _dedupe_steps(steps)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _debug_steps(options: RunOptions) -> list:
|
|
285
|
+
"""
|
|
286
|
+
Debug profile: What's WRONG with the code
|
|
287
|
+
- Linting, type checking, testing
|
|
288
|
+
- Security vulnerabilities
|
|
289
|
+
- Code quality issues
|
|
290
|
+
- Error detection and context
|
|
291
|
+
"""
|
|
292
|
+
policy = AIContextPolicy()
|
|
293
|
+
|
|
294
|
+
steps: list = [
|
|
295
|
+
# Environment & git status
|
|
296
|
+
ShellStep(
|
|
297
|
+
"git status", "meta/00_git_status.txt", ["git", "status"], require_cmd="git"
|
|
298
|
+
),
|
|
299
|
+
ShellStep(
|
|
300
|
+
"git diff", "meta/01_git_diff.txt", ["git", "diff"], require_cmd="git"
|
|
301
|
+
),
|
|
302
|
+
ShellStep(
|
|
303
|
+
"uname -a", "meta/21_uname.txt", ["uname", "-a"], require_cmd="uname"
|
|
304
|
+
),
|
|
305
|
+
ShellStep(
|
|
306
|
+
"python -V",
|
|
307
|
+
"meta/20_python_version.txt",
|
|
308
|
+
["python", "-V"],
|
|
309
|
+
require_cmd="python",
|
|
310
|
+
),
|
|
311
|
+
ShellStep(
|
|
312
|
+
"pip freeze",
|
|
313
|
+
"meta/22_pip_freeze.txt",
|
|
314
|
+
["python", "-m", "pip", "freeze"],
|
|
315
|
+
require_cmd="python",
|
|
316
|
+
),
|
|
317
|
+
ShellStep(
|
|
318
|
+
"pip check",
|
|
319
|
+
"logs/25_pip_check.txt",
|
|
320
|
+
["python", "-m", "pip", "check"],
|
|
321
|
+
require_cmd="python",
|
|
322
|
+
),
|
|
323
|
+
# Code structure (for context)
|
|
324
|
+
TreeStep(max_depth=policy.tree_max_depth, policy=policy),
|
|
325
|
+
LargestFilesStep(limit=policy.largest_limit, policy=policy),
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
# Compilation errors
|
|
329
|
+
if not options.no_compileall:
|
|
330
|
+
steps.append(CompileAllStep())
|
|
331
|
+
|
|
332
|
+
# Linting & type checking (what's wrong with code style/types)
|
|
333
|
+
if not options.no_ruff:
|
|
334
|
+
steps += [
|
|
335
|
+
RuffCheckStep(target=options.ruff_target),
|
|
336
|
+
RuffFormatCheckStep(target=options.ruff_target),
|
|
337
|
+
]
|
|
338
|
+
|
|
339
|
+
if not options.no_mypy:
|
|
340
|
+
steps += [MypyStep(target=options.mypy_target)]
|
|
341
|
+
|
|
342
|
+
if not options.no_pylance:
|
|
343
|
+
steps += [PylanceStep()]
|
|
344
|
+
|
|
345
|
+
# Testing (what's broken in functionality)
|
|
346
|
+
if not options.no_pytest:
|
|
347
|
+
steps += [PytestStep(args=options.pytest_args or ["-q"])]
|
|
348
|
+
|
|
349
|
+
if not options.no_coverage:
|
|
350
|
+
steps += [CoverageStep()]
|
|
351
|
+
|
|
352
|
+
# Test quality issues
|
|
353
|
+
steps += [TestFlakinessStep()] # Non-deterministic tests
|
|
354
|
+
steps += [SlowTestsStep()] # Performance issues in tests
|
|
355
|
+
|
|
356
|
+
if options.enable_mutation_testing:
|
|
357
|
+
steps += [MutationTestingStep()] # Test effectiveness
|
|
358
|
+
|
|
359
|
+
# Security vulnerabilities
|
|
360
|
+
if not options.no_bandit:
|
|
361
|
+
steps += [BanditStep()]
|
|
362
|
+
|
|
363
|
+
if not options.no_pip_audit:
|
|
364
|
+
steps += [PipAuditStep()]
|
|
365
|
+
|
|
366
|
+
# Code quality issues (dead code, complexity)
|
|
367
|
+
if not options.no_vulture:
|
|
368
|
+
steps += [VultureStep()]
|
|
369
|
+
|
|
370
|
+
if not options.no_radon:
|
|
371
|
+
steps += [RadonStep()]
|
|
372
|
+
|
|
373
|
+
# Dependency issues
|
|
374
|
+
if not options.no_unused_deps:
|
|
375
|
+
steps += [UnusedDependenciesStep()]
|
|
376
|
+
|
|
377
|
+
if not options.no_pipdeptree:
|
|
378
|
+
steps += [PipdeptreeStep()] # For conflict detection
|
|
379
|
+
|
|
380
|
+
# Pattern scanning (anti-patterns, TODOs)
|
|
381
|
+
if not options.no_rg:
|
|
382
|
+
steps += list(default_rg_steps(target="."))
|
|
383
|
+
|
|
384
|
+
# Error context extraction
|
|
385
|
+
if not options.no_error_refs:
|
|
386
|
+
steps += [ErrorReferencedFilesStep(max_files=options.error_max_files)]
|
|
387
|
+
|
|
388
|
+
if not options.no_context:
|
|
389
|
+
steps += [
|
|
390
|
+
ErrorContextExpandStep(
|
|
391
|
+
depth=options.context_depth,
|
|
392
|
+
max_files=options.context_max_files,
|
|
393
|
+
)
|
|
394
|
+
]
|
|
395
|
+
|
|
396
|
+
# Source snapshot + repro documentation
|
|
397
|
+
steps += [
|
|
398
|
+
CuratedCopyStep(policy=policy),
|
|
399
|
+
ReproMarkdownStep(),
|
|
400
|
+
AIContextStep(), # Generate AI_CONTEXT.md for AI consumption
|
|
401
|
+
HandoffMarkdownStep(),
|
|
402
|
+
]
|
|
403
|
+
|
|
404
|
+
return _dedupe_steps(steps)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def get_profile(name: str, options: RunOptions) -> Profile:
|
|
408
|
+
if name == "analysis":
|
|
409
|
+
return Profile(name="analysis", steps=_analysis_steps(options))
|
|
410
|
+
|
|
411
|
+
if name == "debug":
|
|
412
|
+
return Profile(name="debug", steps=_debug_steps(options))
|
|
413
|
+
|
|
414
|
+
if name == "backup":
|
|
415
|
+
# Minimal backup: source + environment, no analysis
|
|
416
|
+
policy = AIContextPolicy()
|
|
417
|
+
return Profile(
|
|
418
|
+
name="backup",
|
|
419
|
+
steps=[
|
|
420
|
+
ShellStep(
|
|
421
|
+
"git status",
|
|
422
|
+
"meta/00_git_status.txt",
|
|
423
|
+
["git", "status"],
|
|
424
|
+
require_cmd="git",
|
|
425
|
+
),
|
|
426
|
+
ShellStep(
|
|
427
|
+
"git diff",
|
|
428
|
+
"meta/01_git_diff.txt",
|
|
429
|
+
["git", "diff"],
|
|
430
|
+
require_cmd="git",
|
|
431
|
+
),
|
|
432
|
+
ShellStep(
|
|
433
|
+
"python -V",
|
|
434
|
+
"meta/20_python_version.txt",
|
|
435
|
+
["python", "-V"],
|
|
436
|
+
require_cmd="python",
|
|
437
|
+
),
|
|
438
|
+
ShellStep(
|
|
439
|
+
"pip freeze",
|
|
440
|
+
"meta/22_pip_freeze.txt",
|
|
441
|
+
["python", "-m", "pip", "freeze"],
|
|
442
|
+
require_cmd="python",
|
|
443
|
+
),
|
|
444
|
+
CuratedCopyStep(policy=policy), # Copy source code
|
|
445
|
+
],
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
if name == "ai":
|
|
449
|
+
# AI profile: debug optimized for AI consumption
|
|
450
|
+
# Disables some noisy tools but keeps everything for problem understanding
|
|
451
|
+
opts = resolve_defaults("ai", options)
|
|
452
|
+
return Profile(name="ai", steps=_debug_steps(opts))
|
|
453
|
+
|
|
454
|
+
raise ValueError(f"unknown profile: {name}")
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import asdict, dataclass
|
|
4
|
+
from typing import Literal
|
|
5
|
+
|
|
6
|
+
Lang = Literal["python", "js", "ts", "rust", "html", "css", "config", "unknown"]
|
|
7
|
+
EdgeType = Literal["import", "require", "use", "mod", "include", "script", "entrypoint"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class Node:
|
|
12
|
+
id: str # stable id (usually path)
|
|
13
|
+
path: str # repo-relative
|
|
14
|
+
lang: Lang
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True)
|
|
18
|
+
class Edge:
|
|
19
|
+
src: str # node id
|
|
20
|
+
dst: str # node id (or synthetic id)
|
|
21
|
+
type: EdgeType
|
|
22
|
+
note: str = "" # e.g. "from X import Y", "package.json script: dev"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class EntryPoint:
|
|
27
|
+
node: str # node id
|
|
28
|
+
reason: str # why we think it's an entry
|
|
29
|
+
confidence: int = 2 # 1-3
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class RoadmapGraph:
|
|
34
|
+
version: int
|
|
35
|
+
root: str
|
|
36
|
+
nodes: list[Node]
|
|
37
|
+
edges: list[Edge]
|
|
38
|
+
entrypoints: list[EntryPoint]
|
|
39
|
+
stats: dict[str, int] # counts by lang/edge types/etc.
|
|
40
|
+
|
|
41
|
+
def to_dict(self) -> dict:
|
|
42
|
+
return asdict(self)
|