forgeoptimizer 1.0.0__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.
- forgecli/__init__.py +4 -0
- forgecli/build/__init__.py +135 -0
- forgecli/build/apply.py +218 -0
- forgecli/build/caveman_optimize.py +37 -0
- forgecli/build/diff_extract.py +218 -0
- forgecli/build/llm.py +167 -0
- forgecli/build/optimize.py +37 -0
- forgecli/build/pipeline.py +76 -0
- forgecli/build/retrieval.py +157 -0
- forgecli/build/summarize.py +76 -0
- forgecli/build/test_run.py +75 -0
- forgecli/builder/__init__.py +11 -0
- forgecli/builder/builder.py +53 -0
- forgecli/builder/editor.py +36 -0
- forgecli/builder/formatter.py +31 -0
- forgecli/cli/__init__.py +5 -0
- forgecli/cli/bootstrap.py +281 -0
- forgecli/cli/commands_graph.py +137 -0
- forgecli/cli/commands_wrappers.py +63 -0
- forgecli/cli/main.py +122 -0
- forgecli/cli/ui.py +56 -0
- forgecli/config/__init__.py +28 -0
- forgecli/config/loader.py +85 -0
- forgecli/config/settings.py +204 -0
- forgecli/config/writer.py +90 -0
- forgecli/core/__init__.py +35 -0
- forgecli/core/container.py +68 -0
- forgecli/core/context.py +54 -0
- forgecli/core/credentials.py +114 -0
- forgecli/core/errors.py +27 -0
- forgecli/core/events.py +67 -0
- forgecli/core/logging.py +47 -0
- forgecli/core/models.py +159 -0
- forgecli/core/plugins.py +56 -0
- forgecli/core/service.py +22 -0
- forgecli/docs/__init__.py +5 -0
- forgecli/docs/generator.py +119 -0
- forgecli/engine/__init__.py +105 -0
- forgecli/engine/context.py +171 -0
- forgecli/engine/defaults.py +89 -0
- forgecli/engine/events.py +185 -0
- forgecli/engine/execution.py +526 -0
- forgecli/engine/plugins.py +146 -0
- forgecli/engine/runner.py +155 -0
- forgecli/engine/stages/__init__.py +33 -0
- forgecli/engine/stages/caveman_optimizer.py +47 -0
- forgecli/engine/stages/context_optimizer.py +44 -0
- forgecli/engine/stages/execution_engine_stage.py +108 -0
- forgecli/engine/stages/git_engine.py +30 -0
- forgecli/engine/stages/intent_analyzer.py +38 -0
- forgecli/engine/stages/model_router.py +66 -0
- forgecli/engine/stages/planning_engine.py +45 -0
- forgecli/engine/stages/repository_analyzer.py +54 -0
- forgecli/engine/stages/validation_engine.py +89 -0
- forgecli/git/__init__.py +9 -0
- forgecli/git/repo.py +55 -0
- forgecli/git/service.py +45 -0
- forgecli/graph/__init__.py +56 -0
- forgecli/graph/backend_graphify.py +453 -0
- forgecli/graph/edge.py +19 -0
- forgecli/graph/graph.py +85 -0
- forgecli/graph/graphify.py +412 -0
- forgecli/graph/indexer.py +82 -0
- forgecli/graph/node.py +47 -0
- forgecli/graph/repository.py +164 -0
- forgecli/memory/__init__.py +12 -0
- forgecli/memory/cache.py +61 -0
- forgecli/memory/history.py +138 -0
- forgecli/memory/store.py +87 -0
- forgecli/optimizer/__init__.py +14 -0
- forgecli/optimizer/caveman/__init__.py +173 -0
- forgecli/optimizer/caveman/cli.py +64 -0
- forgecli/optimizer/caveman/decorator.py +67 -0
- forgecli/optimizer/caveman/factory.py +51 -0
- forgecli/optimizer/caveman/ruleset.py +156 -0
- forgecli/optimizer/caveman/state.py +52 -0
- forgecli/optimizer/chunker.py +85 -0
- forgecli/optimizer/optimizer.py +81 -0
- forgecli/optimizer/ponytail/__init__.py +183 -0
- forgecli/optimizer/ponytail/cli.py +168 -0
- forgecli/optimizer/ponytail/decorator.py +70 -0
- forgecli/optimizer/ponytail/factory.py +51 -0
- forgecli/optimizer/ponytail/ruleset.py +168 -0
- forgecli/optimizer/ponytail/state.py +53 -0
- forgecli/optimizer/ranker.py +37 -0
- forgecli/optimizer/summarizer.py +44 -0
- forgecli/orchestrator/__init__.py +707 -0
- forgecli/planner/__init__.py +56 -0
- forgecli/planner/agent.py +61 -0
- forgecli/planner/plan.py +65 -0
- forgecli/planner/planner.py +17 -0
- forgecli/planner/render.py +271 -0
- forgecli/planner/serialize.py +106 -0
- forgecli/planner/software.py +834 -0
- forgecli/platform/__init__.py +91 -0
- forgecli/platform/core.py +201 -0
- forgecli/platform/deps.py +354 -0
- forgecli/platform/paths.py +236 -0
- forgecli/platform/shell.py +176 -0
- forgecli/platform/update.py +252 -0
- forgecli/plugins/__init__.py +251 -0
- forgecli/prompts/__init__.py +11 -0
- forgecli/prompts/loader.py +28 -0
- forgecli/prompts/registry.py +32 -0
- forgecli/prompts/renderer.py +23 -0
- forgecli/providers/__init__.py +39 -0
- forgecli/providers/anthropic.py +206 -0
- forgecli/providers/base.py +206 -0
- forgecli/providers/builtin.py +26 -0
- forgecli/providers/conversation.py +78 -0
- forgecli/providers/google.py +295 -0
- forgecli/providers/http_base.py +211 -0
- forgecli/providers/mock.py +113 -0
- forgecli/providers/openai.py +202 -0
- forgecli/providers/openai_compatible.py +728 -0
- forgecli/providers/router.py +345 -0
- forgecli/providers/router_state.py +89 -0
- forgecli/review/__init__.py +45 -0
- forgecli/review/analyzer.py +124 -0
- forgecli/review/analyzers/__init__.py +1 -0
- forgecli/review/analyzers/architecture.py +258 -0
- forgecli/review/analyzers/complexity.py +167 -0
- forgecli/review/analyzers/dead_code.py +262 -0
- forgecli/review/analyzers/duplicates.py +163 -0
- forgecli/review/analyzers/performance.py +165 -0
- forgecli/review/analyzers/security.py +251 -0
- forgecli/review/finding.py +68 -0
- forgecli/review/report.py +311 -0
- forgecli/review/repository.py +131 -0
- forgecli/review/suggestions.py +98 -0
- forgecli/runtime/__init__.py +6 -0
- forgecli/runtime/cache_store.py +77 -0
- forgecli/runtime/prepare.py +199 -0
- forgecli/runtime/wrappers.py +152 -0
- forgecli/sdk/__init__.py +132 -0
- forgecli/sdk/events.py +206 -0
- forgecli/sdk/interfaces.py +282 -0
- forgecli/sdk/loader.py +243 -0
- forgecli/sdk/manager.py +693 -0
- forgecli/sdk/manifest.py +397 -0
- forgecli/sdk/sandbox.py +197 -0
- forgecli/sdk/version.py +316 -0
- forgecli/templates/__init__.py +9 -0
- forgecli/templates/engine.py +37 -0
- forgecli/templates/registry.py +32 -0
- forgecli/utils/__init__.py +19 -0
- forgecli/utils/fs.py +91 -0
- forgecli/utils/ids.py +11 -0
- forgecli/utils/io.py +27 -0
- forgecli/utils/paths.py +70 -0
- forgecli/utils/timing.py +25 -0
- forgeoptimizer-1.0.0.dist-info/METADATA +169 -0
- forgeoptimizer-1.0.0.dist-info/RECORD +156 -0
- forgeoptimizer-1.0.0.dist-info/WHEEL +4 -0
- forgeoptimizer-1.0.0.dist-info/entry_points.txt +2 -0
- forgeoptimizer-1.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Stage 7 — Validation Engine.
|
|
2
|
+
|
|
3
|
+
Applies the extracted diff to disk, runs tests, and produces a
|
|
4
|
+
summary of the results. Combines :func:`forgecli.build.apply.apply_diff`,
|
|
5
|
+
:func:`forgecli.build.test_run.run_tests`, and
|
|
6
|
+
:func:`forgecli.build.summarize.summarize` into a single stage.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from forgecli.build import BuildContext
|
|
14
|
+
from forgecli.build.apply import apply_diff
|
|
15
|
+
from forgecli.build.summarize import summarize
|
|
16
|
+
from forgecli.build.test_run import run_tests
|
|
17
|
+
from forgecli.engine.execution import StageContext, StageResult, StageStatus
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ValidationEngineStage:
|
|
21
|
+
"""Apply the diff, run tests, and produce a summary."""
|
|
22
|
+
|
|
23
|
+
name = "validation-engine"
|
|
24
|
+
|
|
25
|
+
def __init__(self, test_command: str | None = None) -> None:
|
|
26
|
+
self._test_command = test_command
|
|
27
|
+
|
|
28
|
+
async def __call__(self, context: StageContext) -> StageResult:
|
|
29
|
+
decision = context.engine.extras.get("decision")
|
|
30
|
+
build_ctx = BuildContext(
|
|
31
|
+
prompt=context.engine.prompt,
|
|
32
|
+
root=Path(context.engine.cwd),
|
|
33
|
+
decision=decision,
|
|
34
|
+
)
|
|
35
|
+
build_ctx.diff_text = context.engine.diff_text
|
|
36
|
+
if context.engine.retrieval is not None:
|
|
37
|
+
build_ctx.retrieval = context.engine.retrieval.context_text
|
|
38
|
+
|
|
39
|
+
test_command = (
|
|
40
|
+
self._test_command or context.engine.extras.get("test_command")
|
|
41
|
+
)
|
|
42
|
+
if test_command:
|
|
43
|
+
build_ctx.extras["test_command"] = test_command
|
|
44
|
+
test_timeout = context.engine.extras.get("test_timeout")
|
|
45
|
+
if test_timeout:
|
|
46
|
+
build_ctx.extras["test_timeout"] = test_timeout
|
|
47
|
+
|
|
48
|
+
build_ctx = await apply_diff(build_ctx)
|
|
49
|
+
build_ctx = await run_tests(build_ctx)
|
|
50
|
+
build_ctx = await summarize(build_ctx)
|
|
51
|
+
|
|
52
|
+
context.engine.applied_files = build_ctx.applied_files
|
|
53
|
+
context.engine.diff_text = build_ctx.diff_text
|
|
54
|
+
context.engine.test_stdout = build_ctx.test_stdout
|
|
55
|
+
context.engine.test_stderr = build_ctx.test_stderr
|
|
56
|
+
context.engine.test_returncode = build_ctx.test_returncode
|
|
57
|
+
context.engine.extras["summary"] = build_ctx.summary
|
|
58
|
+
|
|
59
|
+
notes: list[str] = []
|
|
60
|
+
if build_ctx.applied_files:
|
|
61
|
+
notes.append(f"applied {len(build_ctx.applied_files)} files")
|
|
62
|
+
else:
|
|
63
|
+
notes.append("no files applied")
|
|
64
|
+
|
|
65
|
+
if build_ctx.test_returncode is None:
|
|
66
|
+
notes.append("tests skipped")
|
|
67
|
+
elif build_ctx.test_returncode == 0:
|
|
68
|
+
notes.append("tests passed")
|
|
69
|
+
else:
|
|
70
|
+
notes.append(f"tests FAILED (exit {build_ctx.test_returncode})")
|
|
71
|
+
return StageResult(
|
|
72
|
+
status=StageStatus.FAILED,
|
|
73
|
+
data={
|
|
74
|
+
"applied_files": [str(p) for p in build_ctx.applied_files],
|
|
75
|
+
"test_returncode": build_ctx.test_returncode,
|
|
76
|
+
"test_stderr": build_ctx.test_stderr[-500:],
|
|
77
|
+
},
|
|
78
|
+
notes=tuple(notes),
|
|
79
|
+
error=f"tests failed with exit code {build_ctx.test_returncode}",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return StageResult(
|
|
83
|
+
status=StageStatus.SUCCEEDED,
|
|
84
|
+
data={
|
|
85
|
+
"applied_files": [str(p) for p in build_ctx.applied_files],
|
|
86
|
+
"test_returncode": build_ctx.test_returncode,
|
|
87
|
+
},
|
|
88
|
+
notes=tuple(notes),
|
|
89
|
+
)
|
forgecli/git/__init__.py
ADDED
forgecli/git/repo.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Thin wrapper around GitPython's :class:`Repo`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from git import Repo as _PyRepo
|
|
9
|
+
from git.exc import GitError as _PyGitError
|
|
10
|
+
|
|
11
|
+
from forgecli.core.errors import GitError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GitRepo:
|
|
15
|
+
"""Wrapper around GitPython's :class:`Repo` with typed errors."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, path: str | Path) -> None:
|
|
18
|
+
self._path = Path(path)
|
|
19
|
+
try:
|
|
20
|
+
self._repo = _PyRepo(str(self._path))
|
|
21
|
+
except _PyGitError as exc:
|
|
22
|
+
raise GitError(f"Not a git repository: {self._path}") from exc
|
|
23
|
+
except Exception as exc:
|
|
24
|
+
raise GitError(f"Failed to open repository at {self._path}: {exc}") from exc
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def path(self) -> Path:
|
|
28
|
+
return self._path
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def raw(self) -> _PyRepo:
|
|
32
|
+
return self._repo
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def head(self) -> str:
|
|
36
|
+
try:
|
|
37
|
+
return str(self._repo.head.commit)
|
|
38
|
+
except _PyGitError as exc:
|
|
39
|
+
raise GitError(f"Unable to read HEAD: {exc}") from exc
|
|
40
|
+
|
|
41
|
+
def is_clean(self) -> bool:
|
|
42
|
+
return not self._repo.is_dirty(untracked_files=True)
|
|
43
|
+
|
|
44
|
+
def status(self) -> dict[str, Any]:
|
|
45
|
+
"""Return a small status summary; placeholder for richer UX."""
|
|
46
|
+
return {
|
|
47
|
+
"branch": self._safe_branch(),
|
|
48
|
+
"clean": self.is_clean(),
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
def _safe_branch(self) -> str:
|
|
52
|
+
try:
|
|
53
|
+
return self._repo.active_branch.name
|
|
54
|
+
except Exception:
|
|
55
|
+
return "detached"
|
forgecli/git/service.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""High-level git operations: stage, branch, push, diff."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from forgecli.core.errors import GitError
|
|
10
|
+
from forgecli.core.service import Service
|
|
11
|
+
from forgecli.git.repo import GitRepo
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GitService(Service):
|
|
15
|
+
"""Convenience operations built on top of :class:`GitRepo`."""
|
|
16
|
+
|
|
17
|
+
name = "git.service"
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
repo: GitRepo,
|
|
22
|
+
*,
|
|
23
|
+
default_branch: str = "main",
|
|
24
|
+
) -> None:
|
|
25
|
+
super().__init__()
|
|
26
|
+
self._repo = repo
|
|
27
|
+
self._default_branch = default_branch
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def repo(self) -> GitRepo:
|
|
31
|
+
return self._repo
|
|
32
|
+
|
|
33
|
+
def stage(self, paths: Iterable[str | Path]) -> None:
|
|
34
|
+
"""Add ``paths`` to the index."""
|
|
35
|
+
try:
|
|
36
|
+
self._repo.raw.index.add([str(p) for p in paths])
|
|
37
|
+
except Exception as exc:
|
|
38
|
+
raise GitError(f"Failed to stage files: {exc}") from exc
|
|
39
|
+
|
|
40
|
+
def current_branch(self) -> str:
|
|
41
|
+
return self._repo._safe_branch()
|
|
42
|
+
|
|
43
|
+
def diff(self, *args: Any) -> str:
|
|
44
|
+
"""Return ``git diff`` output; placeholder."""
|
|
45
|
+
raise NotImplementedError("GitService.diff() is a scaffold placeholder")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Repository graph: indexing, parsing, code intelligence.
|
|
2
|
+
|
|
3
|
+
The package exposes two layers:
|
|
4
|
+
|
|
5
|
+
* A small in-memory graph (:class:`CodeGraph`, :class:`Node`, :class:`Edge`)
|
|
6
|
+
used by lightweight callers and tests.
|
|
7
|
+
* A back-end abstraction (:class:`RepositoryGraph`) implemented by
|
|
8
|
+
:class:`GraphifyRepositoryGraph`, which delegates to the external
|
|
9
|
+
Graphify CLI.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from forgecli.graph.backend_graphify import GraphifyRepositoryGraph
|
|
13
|
+
from forgecli.graph.edge import Edge, EdgeKind
|
|
14
|
+
from forgecli.graph.graph import CodeGraph
|
|
15
|
+
from forgecli.graph.graphify import (
|
|
16
|
+
GraphifyArtifacts,
|
|
17
|
+
GraphifyBuildOutcome,
|
|
18
|
+
GraphifyClient,
|
|
19
|
+
GraphifyInvocationError,
|
|
20
|
+
GraphifyNotFoundError,
|
|
21
|
+
)
|
|
22
|
+
from forgecli.graph.indexer import Indexer
|
|
23
|
+
from forgecli.graph.node import Node, NodeKind
|
|
24
|
+
from forgecli.graph.repository import (
|
|
25
|
+
BuildResult,
|
|
26
|
+
ExplainResult,
|
|
27
|
+
GraphCommunity,
|
|
28
|
+
GraphEdge,
|
|
29
|
+
GraphNode,
|
|
30
|
+
GraphSnapshot,
|
|
31
|
+
QueryResult,
|
|
32
|
+
RepositoryGraph,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"BuildResult",
|
|
37
|
+
"CodeGraph",
|
|
38
|
+
"Edge",
|
|
39
|
+
"EdgeKind",
|
|
40
|
+
"ExplainResult",
|
|
41
|
+
"GraphCommunity",
|
|
42
|
+
"GraphEdge",
|
|
43
|
+
"GraphNode",
|
|
44
|
+
"GraphSnapshot",
|
|
45
|
+
"GraphifyArtifacts",
|
|
46
|
+
"GraphifyBuildOutcome",
|
|
47
|
+
"GraphifyClient",
|
|
48
|
+
"GraphifyInvocationError",
|
|
49
|
+
"GraphifyNotFoundError",
|
|
50
|
+
"GraphifyRepositoryGraph",
|
|
51
|
+
"Indexer",
|
|
52
|
+
"Node",
|
|
53
|
+
"NodeKind",
|
|
54
|
+
"QueryResult",
|
|
55
|
+
"RepositoryGraph",
|
|
56
|
+
]
|