forgeoptimizer 1.0.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 (191) hide show
  1. forgeoptimizer-1.0.0/.github/workflows/ci.yml +197 -0
  2. forgeoptimizer-1.0.0/.gitignore +51 -0
  3. forgeoptimizer-1.0.0/Forge.toml +17 -0
  4. forgeoptimizer-1.0.0/LICENSE +21 -0
  5. forgeoptimizer-1.0.0/PKG-INFO +169 -0
  6. forgeoptimizer-1.0.0/README.md +100 -0
  7. forgeoptimizer-1.0.0/forgecli/__init__.py +4 -0
  8. forgeoptimizer-1.0.0/forgecli/build/__init__.py +135 -0
  9. forgeoptimizer-1.0.0/forgecli/build/apply.py +218 -0
  10. forgeoptimizer-1.0.0/forgecli/build/caveman_optimize.py +37 -0
  11. forgeoptimizer-1.0.0/forgecli/build/diff_extract.py +218 -0
  12. forgeoptimizer-1.0.0/forgecli/build/llm.py +167 -0
  13. forgeoptimizer-1.0.0/forgecli/build/optimize.py +37 -0
  14. forgeoptimizer-1.0.0/forgecli/build/pipeline.py +76 -0
  15. forgeoptimizer-1.0.0/forgecli/build/retrieval.py +157 -0
  16. forgeoptimizer-1.0.0/forgecli/build/summarize.py +76 -0
  17. forgeoptimizer-1.0.0/forgecli/build/test_run.py +75 -0
  18. forgeoptimizer-1.0.0/forgecli/builder/__init__.py +11 -0
  19. forgeoptimizer-1.0.0/forgecli/builder/builder.py +53 -0
  20. forgeoptimizer-1.0.0/forgecli/builder/editor.py +36 -0
  21. forgeoptimizer-1.0.0/forgecli/builder/formatter.py +31 -0
  22. forgeoptimizer-1.0.0/forgecli/cli/__init__.py +5 -0
  23. forgeoptimizer-1.0.0/forgecli/cli/bootstrap.py +281 -0
  24. forgeoptimizer-1.0.0/forgecli/cli/commands_graph.py +137 -0
  25. forgeoptimizer-1.0.0/forgecli/cli/commands_wrappers.py +63 -0
  26. forgeoptimizer-1.0.0/forgecli/cli/main.py +122 -0
  27. forgeoptimizer-1.0.0/forgecli/cli/ui.py +56 -0
  28. forgeoptimizer-1.0.0/forgecli/config/__init__.py +28 -0
  29. forgeoptimizer-1.0.0/forgecli/config/loader.py +85 -0
  30. forgeoptimizer-1.0.0/forgecli/config/settings.py +204 -0
  31. forgeoptimizer-1.0.0/forgecli/config/writer.py +90 -0
  32. forgeoptimizer-1.0.0/forgecli/core/__init__.py +35 -0
  33. forgeoptimizer-1.0.0/forgecli/core/container.py +68 -0
  34. forgeoptimizer-1.0.0/forgecli/core/context.py +54 -0
  35. forgeoptimizer-1.0.0/forgecli/core/credentials.py +114 -0
  36. forgeoptimizer-1.0.0/forgecli/core/errors.py +27 -0
  37. forgeoptimizer-1.0.0/forgecli/core/events.py +67 -0
  38. forgeoptimizer-1.0.0/forgecli/core/logging.py +47 -0
  39. forgeoptimizer-1.0.0/forgecli/core/models.py +159 -0
  40. forgeoptimizer-1.0.0/forgecli/core/plugins.py +56 -0
  41. forgeoptimizer-1.0.0/forgecli/core/service.py +22 -0
  42. forgeoptimizer-1.0.0/forgecli/docs/__init__.py +5 -0
  43. forgeoptimizer-1.0.0/forgecli/docs/generator.py +119 -0
  44. forgeoptimizer-1.0.0/forgecli/engine/__init__.py +105 -0
  45. forgeoptimizer-1.0.0/forgecli/engine/context.py +171 -0
  46. forgeoptimizer-1.0.0/forgecli/engine/defaults.py +89 -0
  47. forgeoptimizer-1.0.0/forgecli/engine/events.py +185 -0
  48. forgeoptimizer-1.0.0/forgecli/engine/execution.py +526 -0
  49. forgeoptimizer-1.0.0/forgecli/engine/plugins.py +146 -0
  50. forgeoptimizer-1.0.0/forgecli/engine/runner.py +155 -0
  51. forgeoptimizer-1.0.0/forgecli/engine/stages/__init__.py +33 -0
  52. forgeoptimizer-1.0.0/forgecli/engine/stages/caveman_optimizer.py +47 -0
  53. forgeoptimizer-1.0.0/forgecli/engine/stages/context_optimizer.py +44 -0
  54. forgeoptimizer-1.0.0/forgecli/engine/stages/execution_engine_stage.py +108 -0
  55. forgeoptimizer-1.0.0/forgecli/engine/stages/git_engine.py +30 -0
  56. forgeoptimizer-1.0.0/forgecli/engine/stages/intent_analyzer.py +38 -0
  57. forgeoptimizer-1.0.0/forgecli/engine/stages/model_router.py +66 -0
  58. forgeoptimizer-1.0.0/forgecli/engine/stages/planning_engine.py +45 -0
  59. forgeoptimizer-1.0.0/forgecli/engine/stages/repository_analyzer.py +54 -0
  60. forgeoptimizer-1.0.0/forgecli/engine/stages/validation_engine.py +89 -0
  61. forgeoptimizer-1.0.0/forgecli/git/__init__.py +9 -0
  62. forgeoptimizer-1.0.0/forgecli/git/repo.py +55 -0
  63. forgeoptimizer-1.0.0/forgecli/git/service.py +45 -0
  64. forgeoptimizer-1.0.0/forgecli/graph/__init__.py +56 -0
  65. forgeoptimizer-1.0.0/forgecli/graph/backend_graphify.py +453 -0
  66. forgeoptimizer-1.0.0/forgecli/graph/edge.py +19 -0
  67. forgeoptimizer-1.0.0/forgecli/graph/graph.py +85 -0
  68. forgeoptimizer-1.0.0/forgecli/graph/graphify.py +412 -0
  69. forgeoptimizer-1.0.0/forgecli/graph/indexer.py +82 -0
  70. forgeoptimizer-1.0.0/forgecli/graph/node.py +47 -0
  71. forgeoptimizer-1.0.0/forgecli/graph/repository.py +164 -0
  72. forgeoptimizer-1.0.0/forgecli/memory/__init__.py +12 -0
  73. forgeoptimizer-1.0.0/forgecli/memory/cache.py +61 -0
  74. forgeoptimizer-1.0.0/forgecli/memory/history.py +138 -0
  75. forgeoptimizer-1.0.0/forgecli/memory/store.py +87 -0
  76. forgeoptimizer-1.0.0/forgecli/optimizer/__init__.py +14 -0
  77. forgeoptimizer-1.0.0/forgecli/optimizer/caveman/__init__.py +173 -0
  78. forgeoptimizer-1.0.0/forgecli/optimizer/caveman/cli.py +64 -0
  79. forgeoptimizer-1.0.0/forgecli/optimizer/caveman/decorator.py +67 -0
  80. forgeoptimizer-1.0.0/forgecli/optimizer/caveman/factory.py +51 -0
  81. forgeoptimizer-1.0.0/forgecli/optimizer/caveman/ruleset.py +156 -0
  82. forgeoptimizer-1.0.0/forgecli/optimizer/caveman/state.py +52 -0
  83. forgeoptimizer-1.0.0/forgecli/optimizer/chunker.py +85 -0
  84. forgeoptimizer-1.0.0/forgecli/optimizer/optimizer.py +81 -0
  85. forgeoptimizer-1.0.0/forgecli/optimizer/ponytail/__init__.py +183 -0
  86. forgeoptimizer-1.0.0/forgecli/optimizer/ponytail/cli.py +168 -0
  87. forgeoptimizer-1.0.0/forgecli/optimizer/ponytail/decorator.py +70 -0
  88. forgeoptimizer-1.0.0/forgecli/optimizer/ponytail/factory.py +51 -0
  89. forgeoptimizer-1.0.0/forgecli/optimizer/ponytail/ruleset.py +168 -0
  90. forgeoptimizer-1.0.0/forgecli/optimizer/ponytail/state.py +53 -0
  91. forgeoptimizer-1.0.0/forgecli/optimizer/ranker.py +37 -0
  92. forgeoptimizer-1.0.0/forgecli/optimizer/summarizer.py +44 -0
  93. forgeoptimizer-1.0.0/forgecli/orchestrator/__init__.py +707 -0
  94. forgeoptimizer-1.0.0/forgecli/planner/__init__.py +56 -0
  95. forgeoptimizer-1.0.0/forgecli/planner/agent.py +61 -0
  96. forgeoptimizer-1.0.0/forgecli/planner/plan.py +65 -0
  97. forgeoptimizer-1.0.0/forgecli/planner/planner.py +17 -0
  98. forgeoptimizer-1.0.0/forgecli/planner/render.py +271 -0
  99. forgeoptimizer-1.0.0/forgecli/planner/serialize.py +106 -0
  100. forgeoptimizer-1.0.0/forgecli/planner/software.py +834 -0
  101. forgeoptimizer-1.0.0/forgecli/platform/__init__.py +91 -0
  102. forgeoptimizer-1.0.0/forgecli/platform/core.py +201 -0
  103. forgeoptimizer-1.0.0/forgecli/platform/deps.py +354 -0
  104. forgeoptimizer-1.0.0/forgecli/platform/paths.py +236 -0
  105. forgeoptimizer-1.0.0/forgecli/platform/shell.py +176 -0
  106. forgeoptimizer-1.0.0/forgecli/platform/update.py +252 -0
  107. forgeoptimizer-1.0.0/forgecli/plugins/__init__.py +251 -0
  108. forgeoptimizer-1.0.0/forgecli/prompts/__init__.py +11 -0
  109. forgeoptimizer-1.0.0/forgecli/prompts/loader.py +28 -0
  110. forgeoptimizer-1.0.0/forgecli/prompts/registry.py +32 -0
  111. forgeoptimizer-1.0.0/forgecli/prompts/renderer.py +23 -0
  112. forgeoptimizer-1.0.0/forgecli/providers/__init__.py +39 -0
  113. forgeoptimizer-1.0.0/forgecli/providers/anthropic.py +206 -0
  114. forgeoptimizer-1.0.0/forgecli/providers/base.py +206 -0
  115. forgeoptimizer-1.0.0/forgecli/providers/builtin.py +26 -0
  116. forgeoptimizer-1.0.0/forgecli/providers/conversation.py +78 -0
  117. forgeoptimizer-1.0.0/forgecli/providers/google.py +295 -0
  118. forgeoptimizer-1.0.0/forgecli/providers/http_base.py +211 -0
  119. forgeoptimizer-1.0.0/forgecli/providers/mock.py +113 -0
  120. forgeoptimizer-1.0.0/forgecli/providers/openai.py +202 -0
  121. forgeoptimizer-1.0.0/forgecli/providers/openai_compatible.py +728 -0
  122. forgeoptimizer-1.0.0/forgecli/providers/router.py +345 -0
  123. forgeoptimizer-1.0.0/forgecli/providers/router_state.py +89 -0
  124. forgeoptimizer-1.0.0/forgecli/review/__init__.py +45 -0
  125. forgeoptimizer-1.0.0/forgecli/review/analyzer.py +124 -0
  126. forgeoptimizer-1.0.0/forgecli/review/analyzers/__init__.py +1 -0
  127. forgeoptimizer-1.0.0/forgecli/review/analyzers/architecture.py +258 -0
  128. forgeoptimizer-1.0.0/forgecli/review/analyzers/complexity.py +167 -0
  129. forgeoptimizer-1.0.0/forgecli/review/analyzers/dead_code.py +262 -0
  130. forgeoptimizer-1.0.0/forgecli/review/analyzers/duplicates.py +163 -0
  131. forgeoptimizer-1.0.0/forgecli/review/analyzers/performance.py +165 -0
  132. forgeoptimizer-1.0.0/forgecli/review/analyzers/security.py +251 -0
  133. forgeoptimizer-1.0.0/forgecli/review/finding.py +68 -0
  134. forgeoptimizer-1.0.0/forgecli/review/report.py +311 -0
  135. forgeoptimizer-1.0.0/forgecli/review/repository.py +131 -0
  136. forgeoptimizer-1.0.0/forgecli/review/suggestions.py +98 -0
  137. forgeoptimizer-1.0.0/forgecli/runtime/__init__.py +6 -0
  138. forgeoptimizer-1.0.0/forgecli/runtime/cache_store.py +77 -0
  139. forgeoptimizer-1.0.0/forgecli/runtime/prepare.py +199 -0
  140. forgeoptimizer-1.0.0/forgecli/runtime/wrappers.py +152 -0
  141. forgeoptimizer-1.0.0/forgecli/sdk/__init__.py +132 -0
  142. forgeoptimizer-1.0.0/forgecli/sdk/events.py +206 -0
  143. forgeoptimizer-1.0.0/forgecli/sdk/interfaces.py +282 -0
  144. forgeoptimizer-1.0.0/forgecli/sdk/loader.py +243 -0
  145. forgeoptimizer-1.0.0/forgecli/sdk/manager.py +693 -0
  146. forgeoptimizer-1.0.0/forgecli/sdk/manifest.py +397 -0
  147. forgeoptimizer-1.0.0/forgecli/sdk/sandbox.py +197 -0
  148. forgeoptimizer-1.0.0/forgecli/sdk/version.py +316 -0
  149. forgeoptimizer-1.0.0/forgecli/templates/__init__.py +9 -0
  150. forgeoptimizer-1.0.0/forgecli/templates/engine.py +37 -0
  151. forgeoptimizer-1.0.0/forgecli/templates/registry.py +32 -0
  152. forgeoptimizer-1.0.0/forgecli/utils/__init__.py +19 -0
  153. forgeoptimizer-1.0.0/forgecli/utils/fs.py +91 -0
  154. forgeoptimizer-1.0.0/forgecli/utils/ids.py +11 -0
  155. forgeoptimizer-1.0.0/forgecli/utils/io.py +27 -0
  156. forgeoptimizer-1.0.0/forgecli/utils/paths.py +70 -0
  157. forgeoptimizer-1.0.0/forgecli/utils/timing.py +25 -0
  158. forgeoptimizer-1.0.0/forgecli.toml +1 -0
  159. forgeoptimizer-1.0.0/packaging/scoop/forgecli.json +18 -0
  160. forgeoptimizer-1.0.0/packaging/winget/forgecli.ForgeCli.yaml +56 -0
  161. forgeoptimizer-1.0.0/pyproject.toml +104 -0
  162. forgeoptimizer-1.0.0/tests/__init__.py +1 -0
  163. forgeoptimizer-1.0.0/tests/conftest.py +56 -0
  164. forgeoptimizer-1.0.0/tests/test_build_pipeline.py +462 -0
  165. forgeoptimizer-1.0.0/tests/test_caveman_cli.py +117 -0
  166. forgeoptimizer-1.0.0/tests/test_caveman_ruleset.py +201 -0
  167. forgeoptimizer-1.0.0/tests/test_cli.py +127 -0
  168. forgeoptimizer-1.0.0/tests/test_config.py +36 -0
  169. forgeoptimizer-1.0.0/tests/test_container.py +55 -0
  170. forgeoptimizer-1.0.0/tests/test_engine.py +443 -0
  171. forgeoptimizer-1.0.0/tests/test_graph.py +41 -0
  172. forgeoptimizer-1.0.0/tests/test_graphify_client.py +173 -0
  173. forgeoptimizer-1.0.0/tests/test_memory.py +45 -0
  174. forgeoptimizer-1.0.0/tests/test_optimizer.py +40 -0
  175. forgeoptimizer-1.0.0/tests/test_orchestrator.py +313 -0
  176. forgeoptimizer-1.0.0/tests/test_planner.py +50 -0
  177. forgeoptimizer-1.0.0/tests/test_planner_render.py +120 -0
  178. forgeoptimizer-1.0.0/tests/test_platform.py +371 -0
  179. forgeoptimizer-1.0.0/tests/test_ponytail_cli.py +196 -0
  180. forgeoptimizer-1.0.0/tests/test_ponytail_ruleset.py +191 -0
  181. forgeoptimizer-1.0.0/tests/test_prompts.py +18 -0
  182. forgeoptimizer-1.0.0/tests/test_providers.py +98 -0
  183. forgeoptimizer-1.0.0/tests/test_providers_http.py +278 -0
  184. forgeoptimizer-1.0.0/tests/test_repository_graph.py +244 -0
  185. forgeoptimizer-1.0.0/tests/test_review.py +442 -0
  186. forgeoptimizer-1.0.0/tests/test_router.py +163 -0
  187. forgeoptimizer-1.0.0/tests/test_runtime.py +58 -0
  188. forgeoptimizer-1.0.0/tests/test_sdk.py +581 -0
  189. forgeoptimizer-1.0.0/tests/test_software_planner.py +196 -0
  190. forgeoptimizer-1.0.0/tests/test_utils.py +66 -0
  191. forgeoptimizer-1.0.0/uv.lock +1086 -0
@@ -0,0 +1,197 @@
1
+ name: ci
2
+ env:
3
+ PYTHONUTF8: "1"
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ tags:
8
+ - "v*"
9
+ pull_request:
10
+ branches: [main]
11
+ workflow_dispatch:
12
+
13
+ jobs:
14
+ test:
15
+ name: test (${{ matrix.os }} / py${{ matrix.python-version }})
16
+ runs-on: ${{ matrix.os }}
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ os: [ubuntu-latest, macos-latest, windows-latest]
21
+ python-version: ["3.12"]
22
+
23
+ steps:
24
+ - name: Check out
25
+ uses: actions/checkout@v4
26
+
27
+ - name: Set up Python ${{ matrix.python-version }}
28
+ uses: actions/setup-python@v5
29
+ with:
30
+ python-version: ${{ matrix.python-version }}
31
+ cache: pip
32
+
33
+ - name: Install
34
+ run: |
35
+ python -m pip install --upgrade pip
36
+ python -m pip install -e ".[dev]"
37
+
38
+ - name: Smoke test CLI
39
+ run: |
40
+ forge --version
41
+ forge --help
42
+ forge graph --help
43
+
44
+ - name: Lint
45
+ run: python -m ruff check forgecli tests
46
+
47
+ - name: Tests
48
+ run: python -m pytest -q
49
+
50
+ - name: Cross-platform shell smoke
51
+ if: runner.os != 'Windows'
52
+ shell: bash
53
+ run: |
54
+ python -c "from forgecli.platform import run; r = run(['echo', 'cross-platform']); print('OK' if r.ok else 'FAIL')"
55
+
56
+ - name: Cross-platform shell smoke (Windows)
57
+ if: runner.os == 'Windows'
58
+ shell: pwsh
59
+ run: |
60
+ python -c "from forgecli.platform import run; r = run(['cmd.exe', '/c', 'echo cross-platform']); print('OK' if r.ok else 'FAIL')"
61
+
62
+ build:
63
+ name: build sdist + wheel
64
+ runs-on: ubuntu-latest
65
+ steps:
66
+ - uses: actions/checkout@v4
67
+ - uses: actions/setup-python@v5
68
+ with:
69
+ python-version: "3.12"
70
+ - name: Install build
71
+ run: python -m pip install --upgrade build twine
72
+ - name: Build
73
+ run: python -m build
74
+ - name: Verify package metadata
75
+ run: |
76
+ twine check dist/*
77
+ python - <<'PY'
78
+ import zipfile
79
+ from pathlib import Path
80
+ wheel = next(Path("dist").glob("*.whl"))
81
+ with zipfile.ZipFile(wheel) as zf:
82
+ names = zf.namelist()
83
+ assert any(n.startswith("forgecli/") for n in names), "missing forgecli package"
84
+ print(f"OK: {wheel.name}")
85
+ PY
86
+ - name: Upload artifacts
87
+ uses: actions/upload-artifact@v4
88
+ with:
89
+ name: dist
90
+ path: dist/
91
+
92
+ uv-install:
93
+ name: uv tool install (${{ matrix.os }})
94
+ needs: build
95
+ runs-on: ${{ matrix.os }}
96
+ strategy:
97
+ fail-fast: false
98
+ matrix:
99
+ os: [ubuntu-latest, macos-latest, windows-latest]
100
+ steps:
101
+ - name: Check out
102
+ uses: actions/checkout@v4
103
+
104
+ - name: Set up Python
105
+ uses: actions/setup-python@v5
106
+ with:
107
+ python-version: "3.12"
108
+
109
+ - name: Install uv
110
+ uses: astral-sh/setup-uv@v6
111
+
112
+ - uses: actions/download-artifact@v4
113
+ with:
114
+ name: dist
115
+ path: dist/
116
+
117
+ - name: Install forgectx via uv tool
118
+ shell: bash
119
+ run: |
120
+ uv tool install dist/*.whl
121
+
122
+ - name: Verify forge --help
123
+ run: forge --help
124
+
125
+ - name: Verify wrapper commands are registered
126
+ run: |
127
+ forge claude --help
128
+ forge codex --help
129
+ forge cursor --help
130
+ forge opencode --help
131
+ forge commandcode --help
132
+
133
+
134
+ publish-testpypi:
135
+ name: publish to TestPyPI (on tag or manual)
136
+ if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
137
+ needs: [test, build, uv-install]
138
+ runs-on: ubuntu-latest
139
+ environment: testpypi
140
+ permissions:
141
+ id-token: write
142
+ contents: read
143
+ steps:
144
+ - uses: actions/checkout@v4
145
+ - uses: actions/setup-python@v5
146
+ with:
147
+ python-version: "3.12"
148
+ - name: Rename package to match TestPyPI Trusted Publisher
149
+ run: |
150
+ python -c "
151
+ p = 'pyproject.toml'
152
+ content = open(p).read()
153
+ content = content.replace('name = \"forgectx\"', 'name = \"forgekit\"')
154
+ open(p, 'w').write(content)
155
+ "
156
+ - name: Build sdist and wheel
157
+ run: |
158
+ pip install --upgrade build
159
+ python -m build
160
+ - name: Publish
161
+ uses: pypa/gh-action-pypi-publish@release/v1
162
+ with:
163
+ repository-url: https://test.pypi.org/legacy/
164
+ skip-existing: true
165
+
166
+ publish-pypi:
167
+ name: publish to PyPI (on tag or manual)
168
+ if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
169
+ needs: [test, build, uv-install]
170
+ runs-on: ubuntu-latest
171
+ environment: pypi
172
+ permissions:
173
+ id-token: write
174
+ contents: read
175
+ steps:
176
+ - uses: actions/checkout@v4
177
+ - uses: actions/setup-python@v5
178
+ with:
179
+ python-version: "3.12"
180
+ - name: Rename package to match PyPI Trusted Publisher
181
+ run: |
182
+ python -c "
183
+ p = 'pyproject.toml'
184
+ content = open(p).read()
185
+ content = content.replace('name = \"forgectx\"', 'name = \"forgeoptimizer\"')
186
+ open(p, 'w').write(content)
187
+ "
188
+ - name: Build sdist and wheel
189
+ run: |
190
+ pip install --upgrade build
191
+ python -m build
192
+ - name: Publish
193
+ uses: pypa/gh-action-pypi-publish@release/v1
194
+ with:
195
+ skip-existing: true
196
+
197
+
@@ -0,0 +1,51 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ .commandcode/
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ build/
11
+ graphify-out/
12
+ dist/
13
+ *.egg-info/
14
+ *.egg
15
+
16
+ # But the in-tree `forgecli/build/` package is part of our source.
17
+ !forgecli/build/
18
+
19
+ # Virtual environments
20
+ .venv/
21
+ venv/
22
+ env/
23
+ .env
24
+
25
+ # Test / coverage
26
+ .pytest_cache/
27
+ .coverage
28
+ htmlcov/
29
+ .mypy_cache/
30
+ .ruff_cache/
31
+
32
+ # Editor
33
+ .idea/
34
+ .vscode/
35
+ *.swp
36
+ .DS_Store
37
+
38
+ # Local config / secrets
39
+ .env
40
+ .env.*
41
+ !.env.example
42
+ *.local.toml
43
+
44
+ # Local data
45
+ *.db
46
+ *.sqlite
47
+ *.sqlite3
48
+
49
+ # Test artifacts (prevent CI failures)
50
+ foo.py
51
+ main.go
@@ -0,0 +1,17 @@
1
+ [app]
2
+ log_level = "INFO"
3
+
4
+ [git]
5
+ default_branch = "main"
6
+
7
+ [graph]
8
+ enabled = true
9
+ languages = ["python", "typescript"]
10
+
11
+ [prompt_optimizer]
12
+ backend = "ruleset"
13
+ enabled = true
14
+ intensity = "lite"
15
+
16
+ [providers]
17
+ allowed = ["mock"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Forge Authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,169 @@
1
+ Metadata-Version: 2.4
2
+ Name: forgeoptimizer
3
+ Version: 1.0.0
4
+ Summary: Forge — AI optimization runtime. Fast prompt and token optimization for Claude Code, Codex, Cursor, OpenCode, and CommandCode CLI.
5
+ Project-URL: Homepage, https://github.com/mdshzb04/ForgeCli
6
+ Project-URL: Repository, https://github.com/mdshzb04/ForgeCli
7
+ Project-URL: Documentation, https://github.com/mdshzb04/ForgeCli#readme
8
+ Project-URL: Issues, https://github.com/mdshzb04/ForgeCli/issues
9
+ Author: Forge Authors
10
+ License: MIT License
11
+
12
+ Copyright (c) 2025 Forge Authors
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: ai,claude,cli,codex,cursor,developer-tools
33
+ Classifier: Development Status :: 5 - Production/Stable
34
+ Classifier: Environment :: Console
35
+ Classifier: Intended Audience :: Developers
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Programming Language :: Python :: 3.13
41
+ Classifier: Topic :: Software Development
42
+ Requires-Python: >=3.12
43
+ Requires-Dist: aiofiles>=23.2.1
44
+ Requires-Dist: click>=8.1.7
45
+ Requires-Dist: cryptography>=42.0.5
46
+ Requires-Dist: gitpython>=3.1.42
47
+ Requires-Dist: httpx>=0.27.0
48
+ Requires-Dist: keyring>=25.2.0
49
+ Requires-Dist: platformdirs>=4.2.0
50
+ Requires-Dist: pydantic-settings>=2.2.0
51
+ Requires-Dist: pydantic>=2.6.0
52
+ Requires-Dist: pyyaml>=6.0
53
+ Requires-Dist: rich>=13.7.0
54
+ Requires-Dist: tree-sitter-languages>=1.10.0
55
+ Requires-Dist: tree-sitter>=0.21.0
56
+ Requires-Dist: typer>=0.12.0
57
+ Provides-Extra: dev
58
+ Requires-Dist: build>=1.0.0; extra == 'dev'
59
+ Requires-Dist: mypy>=1.10.0; extra == 'dev'
60
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
61
+ Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
62
+ Requires-Dist: pytest-timeout>=2.3.0; extra == 'dev'
63
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
64
+ Requires-Dist: respx>=0.21.0; extra == 'dev'
65
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
66
+ Requires-Dist: twine>=5.0.0; extra == 'dev'
67
+ Requires-Dist: types-pyyaml; extra == 'dev'
68
+ Description-Content-Type: text/markdown
69
+
70
+ # Forge
71
+
72
+ Forge is an AI optimization runtime. It prepares your repository context at light speed — prompt optimization and token compression — then launches the AI CLI you already use.
73
+
74
+ Install:
75
+
76
+ ```bash
77
+ uv tool install forgectx
78
+ ```
79
+
80
+ The command is `forge`.
81
+
82
+ ## What it does
83
+
84
+ When you run `forge claude`, `forge codex`, `forge cursor`, `forge opencode`, or `forge commandcode`, Forge:
85
+
86
+ 1. Detects your git repository (or current directory)
87
+ 2. Builds a **shallow** repo snapshot — it does **not** index your whole codebase
88
+ 3. Runs prompt optimization (Ponytail ruleset) and token compression
89
+ 4. Reuses cached results when nothing important changed
90
+ 5. Launches the selected CLI with `FORGE_CONTEXT` and `FORGE_CONTEXT_FILE` set
91
+
92
+ Wrappers feel instant because Forge skips full graph builds during normal use.
93
+
94
+ ## Commands
95
+
96
+ | Command | Description |
97
+ | -------- | ------------ |
98
+ | `forge claude` | Launch Claude Code with optimized context |
99
+ | `forge codex` | Launch Codex CLI with optimized context |
100
+ | `forge cursor` | Launch Cursor CLI with optimized context |
101
+ | `forge opencode` | Launch OpenCode CLI with optimized context |
102
+ | `forge commandcode` | Launch CommandCode CLI with optimized context |
103
+ | `forge graph build` | Optionally build a full knowledge graph via Graphify |
104
+ | `forge --version` | Show version |
105
+
106
+ Pass through any flags your CLI supports:
107
+
108
+ ```bash
109
+ forge claude -- "fix the failing test in tests/test_foo.py"
110
+ forge codex --help
111
+ forge cursor --refresh
112
+ ```
113
+
114
+ Use `--refresh` to bypass Forge's context cache.
115
+
116
+ ## Optional: knowledge graph
117
+
118
+ If you want a full codebase knowledge graph (separate from the fast wrapper path):
119
+
120
+ ```bash
121
+ uv tool install graphifyy
122
+ forge graph build
123
+ ```
124
+
125
+ Graphify runs only when you ask for it — not on every `forge claude` / `codex` / `cursor` invocation.
126
+
127
+ ## Environment variables
128
+
129
+ Wrappers export:
130
+
131
+ | Variable | Purpose |
132
+ | -------- | -------- |
133
+ | `FORGE_CONTEXT` | Optimized text context |
134
+ | `FORGE_CONTEXT_FILE` | Path to the optimized context file |
135
+ | `FORGE_REPO_ROOT` | Detected repository root |
136
+
137
+ ## Development
138
+
139
+ ```bash
140
+ git clone https://github.com/mdshzb04/ForgeCli
141
+ cd ForgeCli
142
+ python -m venv .venv && source .venv/bin/activate
143
+ pip install -e ".[dev]"
144
+ pytest
145
+ ruff check forgecli tests
146
+ ```
147
+
148
+ ## Release
149
+
150
+ Push a version tag to publish to TestPyPI and PyPI:
151
+
152
+ ```bash
153
+ git tag v1.0.0
154
+ git push origin v1.0.0
155
+ ```
156
+
157
+ Publish jobs run **only on `v*` tags**. On regular pushes to `main`, those jobs show as **Skipped** — that is expected, not a failure.
158
+
159
+ Configure GitHub environments `testpypi` and `pypi` with PyPI trusted publishing for package name `forgectx`.
160
+
161
+ ---
162
+
163
+ <img width="1854" height="1005" alt="image" src="https://github.com/user-attachments/assets/03f3c2e2-424c-4784-8a59-b2b0f4b99447" />
164
+
165
+ <img width="1854" height="1005" alt="image" src="https://github.com/user-attachments/assets/6eb06d10-6f1f-4648-b679-028368362c24" />
166
+
167
+ ## License
168
+
169
+ [MIT](LICENSE)
@@ -0,0 +1,100 @@
1
+ # Forge
2
+
3
+ Forge is an AI optimization runtime. It prepares your repository context at light speed — prompt optimization and token compression — then launches the AI CLI you already use.
4
+
5
+ Install:
6
+
7
+ ```bash
8
+ uv tool install forgectx
9
+ ```
10
+
11
+ The command is `forge`.
12
+
13
+ ## What it does
14
+
15
+ When you run `forge claude`, `forge codex`, `forge cursor`, `forge opencode`, or `forge commandcode`, Forge:
16
+
17
+ 1. Detects your git repository (or current directory)
18
+ 2. Builds a **shallow** repo snapshot — it does **not** index your whole codebase
19
+ 3. Runs prompt optimization (Ponytail ruleset) and token compression
20
+ 4. Reuses cached results when nothing important changed
21
+ 5. Launches the selected CLI with `FORGE_CONTEXT` and `FORGE_CONTEXT_FILE` set
22
+
23
+ Wrappers feel instant because Forge skips full graph builds during normal use.
24
+
25
+ ## Commands
26
+
27
+ | Command | Description |
28
+ | -------- | ------------ |
29
+ | `forge claude` | Launch Claude Code with optimized context |
30
+ | `forge codex` | Launch Codex CLI with optimized context |
31
+ | `forge cursor` | Launch Cursor CLI with optimized context |
32
+ | `forge opencode` | Launch OpenCode CLI with optimized context |
33
+ | `forge commandcode` | Launch CommandCode CLI with optimized context |
34
+ | `forge graph build` | Optionally build a full knowledge graph via Graphify |
35
+ | `forge --version` | Show version |
36
+
37
+ Pass through any flags your CLI supports:
38
+
39
+ ```bash
40
+ forge claude -- "fix the failing test in tests/test_foo.py"
41
+ forge codex --help
42
+ forge cursor --refresh
43
+ ```
44
+
45
+ Use `--refresh` to bypass Forge's context cache.
46
+
47
+ ## Optional: knowledge graph
48
+
49
+ If you want a full codebase knowledge graph (separate from the fast wrapper path):
50
+
51
+ ```bash
52
+ uv tool install graphifyy
53
+ forge graph build
54
+ ```
55
+
56
+ Graphify runs only when you ask for it — not on every `forge claude` / `codex` / `cursor` invocation.
57
+
58
+ ## Environment variables
59
+
60
+ Wrappers export:
61
+
62
+ | Variable | Purpose |
63
+ | -------- | -------- |
64
+ | `FORGE_CONTEXT` | Optimized text context |
65
+ | `FORGE_CONTEXT_FILE` | Path to the optimized context file |
66
+ | `FORGE_REPO_ROOT` | Detected repository root |
67
+
68
+ ## Development
69
+
70
+ ```bash
71
+ git clone https://github.com/mdshzb04/ForgeCli
72
+ cd ForgeCli
73
+ python -m venv .venv && source .venv/bin/activate
74
+ pip install -e ".[dev]"
75
+ pytest
76
+ ruff check forgecli tests
77
+ ```
78
+
79
+ ## Release
80
+
81
+ Push a version tag to publish to TestPyPI and PyPI:
82
+
83
+ ```bash
84
+ git tag v1.0.0
85
+ git push origin v1.0.0
86
+ ```
87
+
88
+ Publish jobs run **only on `v*` tags**. On regular pushes to `main`, those jobs show as **Skipped** — that is expected, not a failure.
89
+
90
+ Configure GitHub environments `testpypi` and `pypi` with PyPI trusted publishing for package name `forgectx`.
91
+
92
+ ---
93
+
94
+ <img width="1854" height="1005" alt="image" src="https://github.com/user-attachments/assets/03f3c2e2-424c-4784-8a59-b2b0f4b99447" />
95
+
96
+ <img width="1854" height="1005" alt="image" src="https://github.com/user-attachments/assets/6eb06d10-6f1f-4648-b679-028368362c24" />
97
+
98
+ ## License
99
+
100
+ [MIT](LICENSE)
@@ -0,0 +1,4 @@
1
+ """Forge — AI optimization runtime."""
2
+
3
+ __version__ = "1.0.0"
4
+ __app_name__ = "Forge"
@@ -0,0 +1,135 @@
1
+ """Build pipeline: Graphify retrieval -> Ponytail -> LLM -> diff -> apply -> test -> summary.
2
+
3
+ Each stage is a small async function that takes a :class:`BuildContext` and
4
+ mutates it, returning the same context. The :class:`BuildPipeline` runs the
5
+ stages in order and records per-stage status; on failure it short-circuits
6
+ unless ``continue_on_error`` is set.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from collections.abc import Awaitable, Callable
12
+ from dataclasses import dataclass, field
13
+ from enum import Enum
14
+ from pathlib import Path
15
+ from typing import Any
16
+
17
+ from forgecli.providers.base import ChatResponse
18
+ from forgecli.providers.router import RouteDecision
19
+
20
+
21
+ class StageStatus(str, Enum):
22
+ """Lifecycle status of a single pipeline stage."""
23
+
24
+ PENDING = "pending"
25
+ RUNNING = "running"
26
+ SUCCEEDED = "succeeded"
27
+ FAILED = "failed"
28
+ SKIPPED = "skipped"
29
+
30
+
31
+ @dataclass
32
+ class StageRecord:
33
+ """One row in the pipeline's per-stage log."""
34
+
35
+ name: str
36
+ status: StageStatus = StageStatus.PENDING
37
+ started_at: float | None = None
38
+ finished_at: float | None = None
39
+ notes: tuple[str, ...] = ()
40
+ error: str | None = None
41
+
42
+ @property
43
+ def duration_seconds(self) -> float | None:
44
+ if self.started_at is None or self.finished_at is None:
45
+ return None
46
+ return self.finished_at - self.started_at
47
+
48
+
49
+ @dataclass
50
+ class BuildContext:
51
+ """Mutable state shared by every pipeline stage."""
52
+
53
+ prompt: str
54
+ root: Path
55
+ decision: RouteDecision | None = None
56
+ retrieval: str = "" # graph-derived context
57
+ caveman_optimized_request: Any = None
58
+ caveman_optimized_notes: tuple[str, ...] = ()
59
+ optimized_request: Any = None
60
+ optimized_notes: tuple[str, ...] = ()
61
+ response: ChatResponse | None = None
62
+ diff_text: str = ""
63
+ applied_files: list[Path] = field(default_factory=list)
64
+ test_stdout: str = ""
65
+ test_stderr: str = ""
66
+ test_returncode: int | None = None
67
+ summary: str = ""
68
+ extras: dict[str, Any] = field(default_factory=dict)
69
+ stages: list[StageRecord] = field(default_factory=list)
70
+
71
+
72
+ PipelineStage = Callable[[BuildContext], Awaitable[BuildContext]]
73
+
74
+
75
+ @dataclass
76
+ class BuildResult:
77
+ """The output of :meth:`BuildPipeline.run`."""
78
+
79
+ success: bool
80
+ context: BuildContext
81
+ failure_stage: str | None = None
82
+
83
+
84
+ class BuildPipeline:
85
+ """A composable async pipeline of named stages."""
86
+
87
+ def __init__(
88
+ self,
89
+ stages: list[tuple[str, PipelineStage]],
90
+ *,
91
+ continue_on_error: bool = False,
92
+ ) -> None:
93
+ self._stages = list(stages)
94
+ self._continue_on_error = continue_on_error
95
+
96
+ @property
97
+ def stage_names(self) -> list[str]:
98
+ return [name for name, _ in self._stages]
99
+
100
+ async def run(self, context: BuildContext) -> BuildResult:
101
+ context.stages = [
102
+ StageRecord(name=name) for name, _ in self._stages
103
+ ]
104
+ for index, (name, stage) in enumerate(self._stages):
105
+ record = context.stages[index]
106
+ record.status = StageStatus.RUNNING
107
+ import time
108
+
109
+ record.started_at = time.perf_counter()
110
+ try:
111
+ context = await stage(context)
112
+ record.status = StageStatus.SUCCEEDED
113
+ except Exception as exc: # noqa: BLE001 - we want to capture everything
114
+ record.status = StageStatus.FAILED
115
+ record.error = repr(exc)
116
+ record.finished_at = time.perf_counter()
117
+ if not self._continue_on_error:
118
+ return BuildResult(
119
+ success=False,
120
+ context=context,
121
+ failure_stage=name,
122
+ )
123
+ else:
124
+ record.finished_at = time.perf_counter()
125
+ return BuildResult(success=True, context=context)
126
+
127
+
128
+ __all__ = [
129
+ "BuildContext",
130
+ "BuildPipeline",
131
+ "BuildResult",
132
+ "PipelineStage",
133
+ "StageRecord",
134
+ "StageStatus",
135
+ ]