sourcecode 0.20.0__tar.gz → 0.21.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.
Files changed (110) hide show
  1. {sourcecode-0.20.0 → sourcecode-0.21.0}/PKG-INFO +70 -1
  2. {sourcecode-0.20.0 → sourcecode-0.21.0}/README.md +69 -0
  3. {sourcecode-0.20.0 → sourcecode-0.21.0}/docs/schema.md +2 -2
  4. {sourcecode-0.20.0 → sourcecode-0.21.0}/pyproject.toml +1 -1
  5. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/cli.py +93 -17
  7. sourcecode-0.21.0/src/sourcecode/prepare_context.py +486 -0
  8. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/semantic_analyzer.py +2 -0
  9. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_dependency_analyzer_node_python.py +2 -2
  10. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration_dependencies.py +1 -1
  11. sourcecode-0.20.0/src/sourcecode/prepare_context.py +0 -197
  12. {sourcecode-0.20.0 → sourcecode-0.21.0}/.gitignore +0 -0
  13. {sourcecode-0.20.0 → sourcecode-0.21.0}/.ruff.toml +0 -0
  14. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/architecture_analyzer.py +0 -0
  15. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/architecture_summary.py +0 -0
  16. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/classifier.py +0 -0
  17. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  18. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/coverage_parser.py +0 -0
  19. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/dependency_analyzer.py +0 -0
  20. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/__init__.py +0 -0
  21. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/base.py +0 -0
  22. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/dart.py +0 -0
  23. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/dotnet.py +0 -0
  24. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/elixir.py +0 -0
  25. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/go.py +0 -0
  26. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/heuristic.py +0 -0
  27. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/java.py +0 -0
  28. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  29. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/nodejs.py +0 -0
  30. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/parsers.py +0 -0
  31. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/php.py +0 -0
  32. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/project.py +0 -0
  33. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/python.py +0 -0
  34. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/ruby.py +0 -0
  35. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/rust.py +0 -0
  36. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/systems.py +0 -0
  37. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/terraform.py +0 -0
  38. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/detectors/tooling.py +0 -0
  39. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/doc_analyzer.py +0 -0
  40. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/env_analyzer.py +0 -0
  41. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/git_analyzer.py +0 -0
  42. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/graph_analyzer.py +0 -0
  43. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/metrics_analyzer.py +0 -0
  44. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/redactor.py +0 -0
  45. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/scanner.py +0 -0
  46. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/schema.py +0 -0
  47. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/serializer.py +0 -0
  48. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/summarizer.py +0 -0
  49. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/tree_utils.py +0 -0
  50. {sourcecode-0.20.0 → sourcecode-0.21.0}/src/sourcecode/workspace.py +0 -0
  51. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/__init__.py +0 -0
  52. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/conftest.py +0 -0
  53. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/coverage.xml +0 -0
  54. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  55. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
  56. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  57. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/go_service/go.mod +0 -0
  58. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/jacoco.xml +0 -0
  59. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/lcov.info +0 -0
  60. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  61. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/nextjs_app/package.json +0 -0
  62. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  63. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  64. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  65. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  66. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  67. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  68. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_architecture_analyzer.py +0 -0
  69. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_architecture_summary.py +0 -0
  70. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_classifier.py +0 -0
  71. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_cli.py +0 -0
  72. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_code_notes_analyzer.py +0 -0
  73. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_coverage_parser.py +0 -0
  74. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_cross_consistency.py +0 -0
  75. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
  76. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_dependency_schema.py +0 -0
  77. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_detector_go_rust_java.py +0 -0
  78. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_detector_nodejs.py +0 -0
  79. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_detector_php_ruby_dart.py +0 -0
  80. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_detector_python.py +0 -0
  81. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_detector_universal_managed.py +0 -0
  82. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_detector_universal_systems.py +0 -0
  83. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_detectors_base.py +0 -0
  84. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_doc_analyzer_jsdom.py +0 -0
  85. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_doc_analyzer_python.py +0 -0
  86. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_graph_analyzer_polyglot.py +0 -0
  87. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_graph_analyzer_python_node.py +0 -0
  88. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_graph_schema.py +0 -0
  89. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration.py +0 -0
  90. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration_detection.py +0 -0
  91. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration_docs.py +0 -0
  92. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration_graph_modules.py +0 -0
  93. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration_lqn.py +0 -0
  94. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration_metrics.py +0 -0
  95. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration_multistack.py +0 -0
  96. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration_semantics.py +0 -0
  97. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_integration_universal.py +0 -0
  98. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_metrics_analyzer.py +0 -0
  99. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_packaging.py +0 -0
  100. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_real_projects.py +0 -0
  101. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_redactor.py +0 -0
  102. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_scanner.py +0 -0
  103. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_schema.py +0 -0
  104. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_schema_normalization.py +0 -0
  105. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_semantic_analyzer_node.py +0 -0
  106. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_semantic_analyzer_python.py +0 -0
  107. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_semantic_import_resolution.py +0 -0
  108. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_semantic_schema.py +0 -0
  109. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_summarizer.py +0 -0
  110. {sourcecode-0.20.0 → sourcecode-0.21.0}/tests/test_workspace_analyzer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 0.20.0
3
+ Version: 0.21.0
4
4
  Summary: Genera un mapa de contexto estructurado de proyectos de software para agentes IA
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -636,6 +636,75 @@ Combine flags for a comprehensive project handoff:
636
636
  sourcecode --compact --env-map --code-notes --git-context .
637
637
  ```
638
638
 
639
+ ## `prepare-context` — Task-aware context for LLMs
640
+
641
+ `prepare-context` is a subcommand that builds a focused, task-specific context optimized for LLM reasoning. Instead of a full project dump, it returns only the data an LLM needs for a specific goal.
642
+
643
+ > **Note:** Because `sourcecode` has a positional `PATH` argument, you must provide it explicitly before the subcommand:
644
+ > ```bash
645
+ > sourcecode . prepare-context <task> # current directory
646
+ > sourcecode /my/project prepare-context <task>
647
+ > ```
648
+
649
+ ### Available tasks
650
+
651
+ | Task | Goal | Output |
652
+ |------|------|--------|
653
+ | `explain` | Onboard an LLM to the project | `project_summary`, `architecture_summary`, `relevant_files`, `key_dependencies` |
654
+ | `fix-bug` | Identify likely bug locations | `relevant_files` (ranked by risk), `suspected_areas`, `code_notes_summary` |
655
+ | `refactor` | Surface improvement opportunities | `relevant_files`, `improvement_opportunities`, `architecture_summary` |
656
+ | `generate-tests` | Find untested areas | `test_gaps`, `relevant_files` (source without tests), `key_dependencies` |
657
+
658
+ ### Usage
659
+
660
+ ```bash
661
+ # List tasks with descriptions
662
+ sourcecode . prepare-context --task-help
663
+
664
+ # Explain the project
665
+ sourcecode . prepare-context explain
666
+
667
+ # Find bug areas, with a ready-to-paste LLM prompt
668
+ sourcecode . prepare-context fix-bug --llm-prompt
669
+
670
+ # Find untested files in a specific project
671
+ sourcecode . prepare-context generate-tests --path /my/project
672
+
673
+ # Preview what will be analyzed (no analysis run)
674
+ sourcecode . prepare-context refactor --dry-run
675
+ ```
676
+
677
+ ### Output format
678
+
679
+ ```json
680
+ {
681
+ "task": "fix-bug",
682
+ "goal": "Identify the most likely files and areas where a bug may be located.",
683
+ "project_summary": "CLI en Python (Typer). Entry points: src/cli.py. 4 dependencias.",
684
+ "architecture_summary": null,
685
+ "relevant_files": [
686
+ { "path": "src/handler.py", "role": "source", "score": 2.0, "reason": "matches 'handler'" },
687
+ { "path": "src/cli.py", "role": "entrypoint", "score": 3.0, "reason": "entry point" }
688
+ ],
689
+ "suspected_areas": ["src/handler.py (2 annotations)", "src/parser.py (1 annotation)"],
690
+ "code_notes_summary": { "total": 5, "by_kind": { "FIXME": 3, "BUG": 2 }, "top_files": ["src/handler.py"] }
691
+ }
692
+ ```
693
+
694
+ ### `--llm-prompt`
695
+
696
+ Add `--llm-prompt` to include a ready-to-use prompt that you can paste directly into any LLM:
697
+
698
+ ```bash
699
+ sourcecode . prepare-context explain --llm-prompt | jq -r '.llm_prompt'
700
+ ```
701
+
702
+ The prompt is task-specific and includes the project context, relevant files, and concrete instructions for the LLM.
703
+
704
+ ### Task auto-selection with `--agent`
705
+
706
+ For zero-config usage, `--agent` on the main command automatically selects the right flags for the project type. For task-aware context, use `prepare-context` explicitly with the task that matches your goal.
707
+
639
708
  ## Development
640
709
 
641
710
  Editable install with development dependencies:
@@ -620,6 +620,75 @@ Combine flags for a comprehensive project handoff:
620
620
  sourcecode --compact --env-map --code-notes --git-context .
621
621
  ```
622
622
 
623
+ ## `prepare-context` — Task-aware context for LLMs
624
+
625
+ `prepare-context` is a subcommand that builds a focused, task-specific context optimized for LLM reasoning. Instead of a full project dump, it returns only the data an LLM needs for a specific goal.
626
+
627
+ > **Note:** Because `sourcecode` has a positional `PATH` argument, you must provide it explicitly before the subcommand:
628
+ > ```bash
629
+ > sourcecode . prepare-context <task> # current directory
630
+ > sourcecode /my/project prepare-context <task>
631
+ > ```
632
+
633
+ ### Available tasks
634
+
635
+ | Task | Goal | Output |
636
+ |------|------|--------|
637
+ | `explain` | Onboard an LLM to the project | `project_summary`, `architecture_summary`, `relevant_files`, `key_dependencies` |
638
+ | `fix-bug` | Identify likely bug locations | `relevant_files` (ranked by risk), `suspected_areas`, `code_notes_summary` |
639
+ | `refactor` | Surface improvement opportunities | `relevant_files`, `improvement_opportunities`, `architecture_summary` |
640
+ | `generate-tests` | Find untested areas | `test_gaps`, `relevant_files` (source without tests), `key_dependencies` |
641
+
642
+ ### Usage
643
+
644
+ ```bash
645
+ # List tasks with descriptions
646
+ sourcecode . prepare-context --task-help
647
+
648
+ # Explain the project
649
+ sourcecode . prepare-context explain
650
+
651
+ # Find bug areas, with a ready-to-paste LLM prompt
652
+ sourcecode . prepare-context fix-bug --llm-prompt
653
+
654
+ # Find untested files in a specific project
655
+ sourcecode . prepare-context generate-tests --path /my/project
656
+
657
+ # Preview what will be analyzed (no analysis run)
658
+ sourcecode . prepare-context refactor --dry-run
659
+ ```
660
+
661
+ ### Output format
662
+
663
+ ```json
664
+ {
665
+ "task": "fix-bug",
666
+ "goal": "Identify the most likely files and areas where a bug may be located.",
667
+ "project_summary": "CLI en Python (Typer). Entry points: src/cli.py. 4 dependencias.",
668
+ "architecture_summary": null,
669
+ "relevant_files": [
670
+ { "path": "src/handler.py", "role": "source", "score": 2.0, "reason": "matches 'handler'" },
671
+ { "path": "src/cli.py", "role": "entrypoint", "score": 3.0, "reason": "entry point" }
672
+ ],
673
+ "suspected_areas": ["src/handler.py (2 annotations)", "src/parser.py (1 annotation)"],
674
+ "code_notes_summary": { "total": 5, "by_kind": { "FIXME": 3, "BUG": 2 }, "top_files": ["src/handler.py"] }
675
+ }
676
+ ```
677
+
678
+ ### `--llm-prompt`
679
+
680
+ Add `--llm-prompt` to include a ready-to-use prompt that you can paste directly into any LLM:
681
+
682
+ ```bash
683
+ sourcecode . prepare-context explain --llm-prompt | jq -r '.llm_prompt'
684
+ ```
685
+
686
+ The prompt is task-specific and includes the project context, relevant files, and concrete instructions for the LLM.
687
+
688
+ ### Task auto-selection with `--agent`
689
+
690
+ For zero-config usage, `--agent` on the main command automatically selects the right flags for the project type. For task-aware context, use `prepare-context` explicitly with the task that matches your goal.
691
+
623
692
  ## Development
624
693
 
625
694
  Editable install with development dependencies:
@@ -81,7 +81,7 @@ Campos:
81
81
  {
82
82
  "schema_version": "1.0",
83
83
  "generated_at": "2026-04-07T19:41:05.686277+00:00",
84
- "sourcecode_version": "0.20.0",
84
+ "sourcecode_version": "0.21.0",
85
85
  "analyzed_path": "/abs/path/to/project"
86
86
  }
87
87
  ```
@@ -645,7 +645,7 @@ Ejemplo de salida para un monorepo con web Node.js y API Python con `--dependenc
645
645
  "metadata": {
646
646
  "schema_version": "1.0",
647
647
  "generated_at": "2026-04-07T19:41:05.686277+00:00",
648
- "sourcecode_version": "0.20.0",
648
+ "sourcecode_version": "0.21.0",
649
649
  "analyzed_path": "/abs/path/to/project"
650
650
  },
651
651
  "file_tree": {
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "0.20.0"
7
+ version = "0.21.0"
8
8
  description = "Genera un mapa de contexto estructurado de proyectos de software para agentes IA"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Genera mapas de contexto estructurado para agentes IA."""
2
2
 
3
- __version__ = "0.20.0"
3
+ __version__ = "0.21.0"
@@ -163,6 +163,10 @@ def main(
163
163
  ),
164
164
  ) -> None:
165
165
  """Genera un mapa de contexto estructurado del proyecto en formato JSON o YAML."""
166
+ # When a subcommand (e.g. prepare-context) is invoked, skip the main analysis.
167
+ if ctx.invoked_subcommand is not None:
168
+ return
169
+
166
170
  # Validar formato
167
171
  if format not in FORMAT_CHOICES:
168
172
  typer.echo(
@@ -654,31 +658,103 @@ def main(
654
658
 
655
659
  @app.command("prepare-context")
656
660
  def prepare_context_cmd(
657
- task: str = typer.Argument(..., help="Descripción de la tarea"),
658
- path: Path = typer.Option(".", "--path", "-p", help="Directorio del proyecto"),
661
+ task: Optional[str] = typer.Argument(
662
+ None,
663
+ help="Task: explain | fix-bug | refactor | generate-tests",
664
+ ),
665
+ path: Path = typer.Option(
666
+ Path("."),
667
+ "--path", "-p",
668
+ help="Project directory to analyze (default: current directory)",
669
+ ),
670
+ llm_prompt: bool = typer.Option(
671
+ False,
672
+ "--llm-prompt",
673
+ help="Append a ready-to-use LLM prompt to the output",
674
+ ),
675
+ task_help: bool = typer.Option(
676
+ False,
677
+ "--task-help",
678
+ help="List available tasks with descriptions and exit",
679
+ ),
680
+ dry_run: bool = typer.Option(
681
+ False,
682
+ "--dry-run",
683
+ help="Show what would be analyzed without running it",
684
+ ),
659
685
  ) -> None:
660
- """Prepara contexto mínimo optimizado para que un LLM modifique el código."""
661
- from dataclasses import asdict
686
+ """Prepare task-aware context optimized for LLM reasoning.
687
+
688
+ \b
689
+ Note: PATH must be provided before the subcommand (default: '.'):
690
+ sourcecode . prepare-context explain
691
+ sourcecode . prepare-context fix-bug --path /my/project
692
+ sourcecode . prepare-context generate-tests --llm-prompt
693
+ sourcecode . prepare-context --task-help
694
+ """
695
+ from sourcecode.prepare_context import TASKS, TaskContextBuilder
696
+
697
+ if task_help:
698
+ typer.echo("Available tasks:\n")
699
+ for name, spec in TASKS.items():
700
+ typer.echo(f" {name:<20} {spec.description}")
701
+ typer.echo(f" {'':20} Output: {spec.output_hint}\n")
702
+ raise typer.Exit()
662
703
 
663
- from sourcecode.prepare_context import ContextBuilder
704
+ if task is None:
705
+ typer.echo(
706
+ f"Error: task is required. Available: {', '.join(TASKS)}\n"
707
+ "Use --task-help for descriptions.",
708
+ err=True,
709
+ )
710
+ raise typer.Exit(code=1)
664
711
 
665
- target = path.resolve()
712
+ if task not in TASKS:
713
+ typer.echo(
714
+ f"Error: unknown task '{task}'. Available: {', '.join(TASKS)}",
715
+ err=True,
716
+ )
717
+ raise typer.Exit(code=1)
666
718
 
719
+ target = path.resolve()
667
720
  if not target.exists() or not target.is_dir():
668
721
  typer.echo(f"Error: '{target}' no es un directorio válido.", err=True)
669
722
  raise typer.Exit(code=1)
670
723
 
671
- builder = ContextBuilder(target)
672
- result = builder.prepare(task)
673
-
674
- out = {
675
- "task": result.task,
676
- "entry_points": result.entry_points,
677
- "relevant_files": [asdict(f) for f in result.relevant_files],
678
- "call_flow": result.call_flow,
679
- "snippets": [asdict(s) for s in result.snippets],
680
- "tests": result.tests,
681
- "notes": result.notes,
724
+ if dry_run:
725
+ spec = TASKS[task]
726
+ typer.echo(f"task: {task}")
727
+ typer.echo(f"goal: {spec.goal}")
728
+ typer.echo(f"path: {target}")
729
+ typer.echo(f"analyzers: dependencies={'yes' if spec.enable_dependencies else 'no'}"
730
+ f", code_notes={'yes' if spec.enable_code_notes else 'no'}")
731
+ typer.echo(f"output: {spec.output_hint}")
732
+ raise typer.Exit()
733
+
734
+ from dataclasses import asdict
735
+
736
+ builder = TaskContextBuilder(target)
737
+ output = builder.build(task)
738
+
739
+ out: dict[str, Any] = {
740
+ "task": output.task,
741
+ "goal": output.goal,
742
+ "project_summary": output.project_summary,
743
+ "architecture_summary": output.architecture_summary,
744
+ "relevant_files": [asdict(f) for f in output.relevant_files],
745
+ "key_dependencies": output.key_dependencies,
682
746
  }
747
+ if output.suspected_areas:
748
+ out["suspected_areas"] = output.suspected_areas
749
+ if output.improvement_opportunities:
750
+ out["improvement_opportunities"] = output.improvement_opportunities
751
+ if output.test_gaps:
752
+ out["test_gaps"] = output.test_gaps
753
+ if output.code_notes_summary:
754
+ out["code_notes_summary"] = output.code_notes_summary
755
+ if output.limitations:
756
+ out["limitations"] = output.limitations
757
+ if llm_prompt:
758
+ out["llm_prompt"] = builder.render_prompt(output)
683
759
 
684
760
  typer.echo(json.dumps(out, indent=2, ensure_ascii=False))