hexicodes 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. hexicodes-0.1.0/LICENSE +21 -0
  2. hexicodes-0.1.0/PKG-INFO +232 -0
  3. hexicodes-0.1.0/README.md +184 -0
  4. hexicodes-0.1.0/pyproject.toml +81 -0
  5. hexicodes-0.1.0/setup.cfg +4 -0
  6. hexicodes-0.1.0/src/hexi/__init__.py +2 -0
  7. hexicodes-0.1.0/src/hexi/adapters/__init__.py +21 -0
  8. hexicodes-0.1.0/src/hexi/adapters/event_log_jsonl.py +17 -0
  9. hexicodes-0.1.0/src/hexi/adapters/events_console.py +37 -0
  10. hexicodes-0.1.0/src/hexi/adapters/exec_local.py +16 -0
  11. hexicodes-0.1.0/src/hexi/adapters/memory_file.py +224 -0
  12. hexicodes-0.1.0/src/hexi/adapters/model_anthropic_compat.py +35 -0
  13. hexicodes-0.1.0/src/hexi/adapters/model_http_common.py +19 -0
  14. hexicodes-0.1.0/src/hexi/adapters/model_openai_compat.py +23 -0
  15. hexicodes-0.1.0/src/hexi/adapters/model_openrouter_http.py +135 -0
  16. hexicodes-0.1.0/src/hexi/adapters/model_openrouter_sdk.py +36 -0
  17. hexicodes-0.1.0/src/hexi/adapters/workspace_local_git.py +72 -0
  18. hexicodes-0.1.0/src/hexi/cli.py +739 -0
  19. hexicodes-0.1.0/src/hexi/core/__init__.py +11 -0
  20. hexicodes-0.1.0/src/hexi/core/domain.py +41 -0
  21. hexicodes-0.1.0/src/hexi/core/policy.py +30 -0
  22. hexicodes-0.1.0/src/hexi/core/ports.py +52 -0
  23. hexicodes-0.1.0/src/hexi/core/schemas.py +122 -0
  24. hexicodes-0.1.0/src/hexi/core/service.py +181 -0
  25. hexicodes-0.1.0/src/hexicodes.egg-info/PKG-INFO +232 -0
  26. hexicodes-0.1.0/src/hexicodes.egg-info/SOURCES.txt +39 -0
  27. hexicodes-0.1.0/src/hexicodes.egg-info/dependency_links.txt +1 -0
  28. hexicodes-0.1.0/src/hexicodes.egg-info/entry_points.txt +2 -0
  29. hexicodes-0.1.0/src/hexicodes.egg-info/requires.txt +27 -0
  30. hexicodes-0.1.0/src/hexicodes.egg-info/top_level.txt +1 -0
  31. hexicodes-0.1.0/tests/test_actionplan_parser.py +22 -0
  32. hexicodes-0.1.0/tests/test_cli.py +136 -0
  33. hexicodes-0.1.0/tests/test_event_log_jsonl.py +20 -0
  34. hexicodes-0.1.0/tests/test_exec_local.py +43 -0
  35. hexicodes-0.1.0/tests/test_memory_file.py +94 -0
  36. hexicodes-0.1.0/tests/test_models.py +64 -0
  37. hexicodes-0.1.0/tests/test_openrouter_models.py +157 -0
  38. hexicodes-0.1.0/tests/test_policy.py +17 -0
  39. hexicodes-0.1.0/tests/test_service.py +156 -0
  40. hexicodes-0.1.0/tests/test_workspace.py +15 -0
  41. hexicodes-0.1.0/tests/test_workspace_local_git.py +42 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Antonio Ognio
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,232 @@
1
+ Metadata-Version: 2.4
2
+ Name: hexicodes
3
+ Version: 0.1.0
4
+ Summary: Minimal contract-driven coding-agent runtime + CLI
5
+ Author: Antonio Ognio
6
+ Maintainer: Antonio Ognio
7
+ License: MIT
8
+ Project-URL: Homepage, https://hexi.readthedocs.io
9
+ Project-URL: Documentation, https://hexi.readthedocs.io
10
+ Project-URL: Source, https://github.com/antonioognio/hexi
11
+ Project-URL: Issues, https://github.com/antonioognio/hexi/issues
12
+ Keywords: ai,agent,coding-agent,cli,developer-tools,hexagonal-architecture,openrouter,typer
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Build Tools
22
+ Classifier: Topic :: Software Development :: Libraries
23
+ Classifier: Topic :: Software Development :: Testing
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: typer<1,>=0.12
28
+ Requires-Dist: httpx<1,>=0.27
29
+ Requires-Dist: rich<15,>=13.7
30
+ Requires-Dist: tomli>=2.0.1; python_version < "3.11"
31
+ Provides-Extra: openrouter-http
32
+ Requires-Dist: requests<3,>=2.31; extra == "openrouter-http"
33
+ Provides-Extra: openrouter-sdk
34
+ Requires-Dist: openrouter<1,>=0.6.0; extra == "openrouter-sdk"
35
+ Provides-Extra: openrouter
36
+ Requires-Dist: requests<3,>=2.31; extra == "openrouter"
37
+ Requires-Dist: openrouter<1,>=0.6.0; extra == "openrouter"
38
+ Provides-Extra: docs
39
+ Requires-Dist: mkdocs<2,>=1.6; extra == "docs"
40
+ Requires-Dist: mkdocs-material<10,>=9.5; extra == "docs"
41
+ Provides-Extra: dev
42
+ Requires-Dist: pytest<9,>=8.2; extra == "dev"
43
+ Requires-Dist: pytest-asyncio<1,>=0.23; extra == "dev"
44
+ Requires-Dist: requests<3,>=2.31; extra == "dev"
45
+ Requires-Dist: responses<1,>=0.25; extra == "dev"
46
+ Requires-Dist: respx<1,>=0.21; extra == "dev"
47
+ Dynamic: license-file
48
+
49
+ # Hexi v0.1.0
50
+
51
+ Hexi is a minimal, contract-driven (hexagonal) coding-agent runtime and CLI.
52
+ It runs exactly one agent step per invocation against a local git repository.
53
+
54
+ ## Test Drive (5 Minutes)
55
+ Run this in any local git repo you can safely modify.
56
+
57
+ 1. Install Hexi:
58
+ ```bash
59
+ pip install -e .
60
+ ```
61
+ Optional OpenRouter support:
62
+ ```bash
63
+ pip install -e ".[openrouter]"
64
+ ```
65
+
66
+ 2. Initialize Hexi files:
67
+ ```bash
68
+ hexi init
69
+ ```
70
+
71
+ 3. Onboard provider/model and key:
72
+ ```bash
73
+ hexi onboard
74
+ ```
75
+ When prompted, pick any provider. For OpenRouter providers, install the optional extra and provide `OPENROUTER_API_KEY`.
76
+
77
+ 4. Verify setup:
78
+ ```bash
79
+ hexi doctor
80
+ ```
81
+ Expected: provider/model printed and `Doctor check passed`.
82
+
83
+ 5. Run one agent step:
84
+ ```bash
85
+ hexi run "Add one tiny test for an existing function and run pytest"
86
+ ```
87
+
88
+ 6. Inspect what changed:
89
+ ```bash
90
+ hexi diff
91
+ tail -n 20 .hexi/runlog.jsonl
92
+ ```
93
+
94
+ 7. If you want to switch providers later:
95
+ ```bash
96
+ hexi onboard
97
+ ```
98
+ Re-run onboarding to update `.hexi/local.toml`.
99
+
100
+ ## What it is
101
+ - Python package (PyPI distribution): `hexicodes`
102
+ - Core contracts in `hexi.core`
103
+ - Side-effect adapters in `hexi.adapters`
104
+ - One-step execution with structured event logging to `.hexi/runlog.jsonl`
105
+
106
+ ## What it is not
107
+ - No daemon, no background workers, no web UI
108
+ - No MCP server and no SQLite in v0.1.0
109
+ - No multi-agent orchestration
110
+
111
+
112
+ ## Install
113
+ ```bash
114
+ pip install -e .
115
+ ```
116
+
117
+ ### OpenRouter support (optional)
118
+ - HTTP adapter only (`openrouter_http` provider):
119
+ ```bash
120
+ pip install -e ".[openrouter-http]"
121
+ ```
122
+ - SDK adapter only (`openrouter_sdk` provider):
123
+ ```bash
124
+ pip install -e ".[openrouter-sdk]"
125
+ ```
126
+ - Both OpenRouter adapters:
127
+ ```bash
128
+ pip install -e ".[openrouter]"
129
+ ```
130
+
131
+ Dev/test dependencies:
132
+ ```bash
133
+ pip install -e ".[dev]"
134
+ ```
135
+
136
+ ## CLI
137
+ - `hexi --help` or `hexi help` : show command help
138
+ - `hexi --version` or `hexi version` : print installed version
139
+ - `hexi init` : create `.hexi/config.toml`, `.hexi/local.toml`, `.hexi/runlog.jsonl`
140
+ - `hexi onboard` : interactive setup for provider/model and optional local key paste
141
+ - `hexi new` : scaffold a project from built-in Hexi templates (non-interactive by default)
142
+ - `hexi demo` : fancy interactive flow with random/model-generated ideas and template scaffolding
143
+ - `hexi run "<task>"` : execute one agent step and emit structured events
144
+ - `hexi diff` : show current git diff
145
+ - `hexi doctor` : verbose diagnostics; use `--probe-model` for live “What model are you?” check
146
+ - `hexi plan-check --file plan.json` : validate/troubleshoot ActionPlan JSON directly
147
+
148
+ ## Documentation (MkDocs + Read the Docs)
149
+ Build docs locally:
150
+ ```bash
151
+ pip install -e ".[docs]"
152
+ mkdocs serve
153
+ ```
154
+
155
+ Read the Docs config is in `.readthedocs.yml`.
156
+
157
+ ## Configuration design choices
158
+ Hexi uses layered TOML configuration:
159
+ 1. `.hexi/config.toml` (repo defaults)
160
+ 2. `.hexi/local.toml` (local machine overrides)
161
+ 3. Environment variables (recommended for secrets)
162
+
163
+ For secrets, env vars are preferred. `hexi onboard` can write keys to `.hexi/local.toml` for local/testing convenience.
164
+
165
+ ## Config shape (`.hexi/config.toml`)
166
+ ```toml
167
+ [model]
168
+ provider = "openai_compat" # openrouter_http | openrouter_sdk | openai_compat | anthropic_compat
169
+ model = "gpt-4o-mini"
170
+
171
+ [providers.openrouter_http]
172
+ base_url = "https://openrouter.ai/api/v1"
173
+ api_style = "openai" # openai | anthropic
174
+
175
+ [providers.openrouter_sdk]
176
+ base_url = "https://openrouter.ai/api/v1"
177
+
178
+ [providers.openai_compat]
179
+ base_url = "https://api.openai.com/v1"
180
+
181
+ [providers.anthropic_compat]
182
+ base_url = "https://api.anthropic.com"
183
+
184
+ [policy]
185
+ allow_commands = ["git status", "git diff", "pytest", "python -m pytest"]
186
+ max_diff_chars = 4000
187
+ max_file_read_chars = 4000
188
+ ```
189
+
190
+ ## Local override example (`.hexi/local.toml`)
191
+ ```toml
192
+ [model]
193
+ provider = "openrouter_http"
194
+ model = "anthropic/claude-sonnet-4-6"
195
+
196
+ [providers.openrouter_http]
197
+ api_style = "anthropic"
198
+
199
+ [secrets]
200
+ openrouter_api_key = "..."
201
+ ```
202
+
203
+ ## Env vars
204
+ - `OPENROUTER_API_KEY` for `openrouter_http` and `openrouter_sdk`
205
+ - `OPENAI_API_KEY` for `openai_compat`
206
+ - `ANTHROPIC_API_KEY` for `anthropic_compat`
207
+
208
+ ## Packaging
209
+ - Distribution name: `hexicodes`
210
+ - Console script: `hexi`
211
+ - Optional extras:
212
+ - `openrouter-http`
213
+ - `openrouter-sdk`
214
+ - `openrouter`
215
+ - `docs`
216
+ - `dev`
217
+
218
+ ## Included example projects
219
+ - `examples/todo_refiner` : minimal CLI-wrapper agent integration
220
+ - `examples/embedded_step` : direct embedded `RunStepService` usage
221
+ - `examples/policy_loop` : multi-step user-gated loop using repeated `hexi run`
222
+
223
+ ## Included Hexi-native templates
224
+ - `templates/hexi-python-lib` : tested library starter with Hexi wiring
225
+ - `templates/hexi-fastapi-service` : FastAPI service starter with Hexi wiring
226
+ - `templates/hexi-typer-cli` : Typer CLI starter with Hexi wiring
227
+ - `templates/hexi-data-job` : data job starter with dry-run and Hexi wiring
228
+ - `templates/hexi-agent-worker` : embedded Hexi runtime starter
229
+
230
+ ## Provenance
231
+
232
+ Made with ❤️ from 🇵🇪. El Perú es clave 🔑.
@@ -0,0 +1,184 @@
1
+ # Hexi v0.1.0
2
+
3
+ Hexi is a minimal, contract-driven (hexagonal) coding-agent runtime and CLI.
4
+ It runs exactly one agent step per invocation against a local git repository.
5
+
6
+ ## Test Drive (5 Minutes)
7
+ Run this in any local git repo you can safely modify.
8
+
9
+ 1. Install Hexi:
10
+ ```bash
11
+ pip install -e .
12
+ ```
13
+ Optional OpenRouter support:
14
+ ```bash
15
+ pip install -e ".[openrouter]"
16
+ ```
17
+
18
+ 2. Initialize Hexi files:
19
+ ```bash
20
+ hexi init
21
+ ```
22
+
23
+ 3. Onboard provider/model and key:
24
+ ```bash
25
+ hexi onboard
26
+ ```
27
+ When prompted, pick any provider. For OpenRouter providers, install the optional extra and provide `OPENROUTER_API_KEY`.
28
+
29
+ 4. Verify setup:
30
+ ```bash
31
+ hexi doctor
32
+ ```
33
+ Expected: provider/model printed and `Doctor check passed`.
34
+
35
+ 5. Run one agent step:
36
+ ```bash
37
+ hexi run "Add one tiny test for an existing function and run pytest"
38
+ ```
39
+
40
+ 6. Inspect what changed:
41
+ ```bash
42
+ hexi diff
43
+ tail -n 20 .hexi/runlog.jsonl
44
+ ```
45
+
46
+ 7. If you want to switch providers later:
47
+ ```bash
48
+ hexi onboard
49
+ ```
50
+ Re-run onboarding to update `.hexi/local.toml`.
51
+
52
+ ## What it is
53
+ - Python package (PyPI distribution): `hexicodes`
54
+ - Core contracts in `hexi.core`
55
+ - Side-effect adapters in `hexi.adapters`
56
+ - One-step execution with structured event logging to `.hexi/runlog.jsonl`
57
+
58
+ ## What it is not
59
+ - No daemon, no background workers, no web UI
60
+ - No MCP server and no SQLite in v0.1.0
61
+ - No multi-agent orchestration
62
+
63
+
64
+ ## Install
65
+ ```bash
66
+ pip install -e .
67
+ ```
68
+
69
+ ### OpenRouter support (optional)
70
+ - HTTP adapter only (`openrouter_http` provider):
71
+ ```bash
72
+ pip install -e ".[openrouter-http]"
73
+ ```
74
+ - SDK adapter only (`openrouter_sdk` provider):
75
+ ```bash
76
+ pip install -e ".[openrouter-sdk]"
77
+ ```
78
+ - Both OpenRouter adapters:
79
+ ```bash
80
+ pip install -e ".[openrouter]"
81
+ ```
82
+
83
+ Dev/test dependencies:
84
+ ```bash
85
+ pip install -e ".[dev]"
86
+ ```
87
+
88
+ ## CLI
89
+ - `hexi --help` or `hexi help` : show command help
90
+ - `hexi --version` or `hexi version` : print installed version
91
+ - `hexi init` : create `.hexi/config.toml`, `.hexi/local.toml`, `.hexi/runlog.jsonl`
92
+ - `hexi onboard` : interactive setup for provider/model and optional local key paste
93
+ - `hexi new` : scaffold a project from built-in Hexi templates (non-interactive by default)
94
+ - `hexi demo` : fancy interactive flow with random/model-generated ideas and template scaffolding
95
+ - `hexi run "<task>"` : execute one agent step and emit structured events
96
+ - `hexi diff` : show current git diff
97
+ - `hexi doctor` : verbose diagnostics; use `--probe-model` for live “What model are you?” check
98
+ - `hexi plan-check --file plan.json` : validate/troubleshoot ActionPlan JSON directly
99
+
100
+ ## Documentation (MkDocs + Read the Docs)
101
+ Build docs locally:
102
+ ```bash
103
+ pip install -e ".[docs]"
104
+ mkdocs serve
105
+ ```
106
+
107
+ Read the Docs config is in `.readthedocs.yml`.
108
+
109
+ ## Configuration design choices
110
+ Hexi uses layered TOML configuration:
111
+ 1. `.hexi/config.toml` (repo defaults)
112
+ 2. `.hexi/local.toml` (local machine overrides)
113
+ 3. Environment variables (recommended for secrets)
114
+
115
+ For secrets, env vars are preferred. `hexi onboard` can write keys to `.hexi/local.toml` for local/testing convenience.
116
+
117
+ ## Config shape (`.hexi/config.toml`)
118
+ ```toml
119
+ [model]
120
+ provider = "openai_compat" # openrouter_http | openrouter_sdk | openai_compat | anthropic_compat
121
+ model = "gpt-4o-mini"
122
+
123
+ [providers.openrouter_http]
124
+ base_url = "https://openrouter.ai/api/v1"
125
+ api_style = "openai" # openai | anthropic
126
+
127
+ [providers.openrouter_sdk]
128
+ base_url = "https://openrouter.ai/api/v1"
129
+
130
+ [providers.openai_compat]
131
+ base_url = "https://api.openai.com/v1"
132
+
133
+ [providers.anthropic_compat]
134
+ base_url = "https://api.anthropic.com"
135
+
136
+ [policy]
137
+ allow_commands = ["git status", "git diff", "pytest", "python -m pytest"]
138
+ max_diff_chars = 4000
139
+ max_file_read_chars = 4000
140
+ ```
141
+
142
+ ## Local override example (`.hexi/local.toml`)
143
+ ```toml
144
+ [model]
145
+ provider = "openrouter_http"
146
+ model = "anthropic/claude-sonnet-4-6"
147
+
148
+ [providers.openrouter_http]
149
+ api_style = "anthropic"
150
+
151
+ [secrets]
152
+ openrouter_api_key = "..."
153
+ ```
154
+
155
+ ## Env vars
156
+ - `OPENROUTER_API_KEY` for `openrouter_http` and `openrouter_sdk`
157
+ - `OPENAI_API_KEY` for `openai_compat`
158
+ - `ANTHROPIC_API_KEY` for `anthropic_compat`
159
+
160
+ ## Packaging
161
+ - Distribution name: `hexicodes`
162
+ - Console script: `hexi`
163
+ - Optional extras:
164
+ - `openrouter-http`
165
+ - `openrouter-sdk`
166
+ - `openrouter`
167
+ - `docs`
168
+ - `dev`
169
+
170
+ ## Included example projects
171
+ - `examples/todo_refiner` : minimal CLI-wrapper agent integration
172
+ - `examples/embedded_step` : direct embedded `RunStepService` usage
173
+ - `examples/policy_loop` : multi-step user-gated loop using repeated `hexi run`
174
+
175
+ ## Included Hexi-native templates
176
+ - `templates/hexi-python-lib` : tested library starter with Hexi wiring
177
+ - `templates/hexi-fastapi-service` : FastAPI service starter with Hexi wiring
178
+ - `templates/hexi-typer-cli` : Typer CLI starter with Hexi wiring
179
+ - `templates/hexi-data-job` : data job starter with dry-run and Hexi wiring
180
+ - `templates/hexi-agent-worker` : embedded Hexi runtime starter
181
+
182
+ ## Provenance
183
+
184
+ Made with ❤️ from 🇵🇪. El Perú es clave 🔑.
@@ -0,0 +1,81 @@
1
+ [build-system]
2
+ requires = ["setuptools>=69", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "hexicodes"
7
+ version = "0.1.0"
8
+ description = "Minimal contract-driven coding-agent runtime + CLI"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Antonio Ognio" }]
13
+ maintainers = [{ name = "Antonio Ognio" }]
14
+ keywords = [
15
+ "ai",
16
+ "agent",
17
+ "coding-agent",
18
+ "cli",
19
+ "developer-tools",
20
+ "hexagonal-architecture",
21
+ "openrouter",
22
+ "typer"
23
+ ]
24
+ classifiers = [
25
+ "Development Status :: 3 - Alpha",
26
+ "Intended Audience :: Developers",
27
+ "License :: OSI Approved :: MIT License",
28
+ "Programming Language :: Python :: 3",
29
+ "Programming Language :: Python :: 3.10",
30
+ "Programming Language :: Python :: 3.11",
31
+ "Programming Language :: Python :: 3.12",
32
+ "Programming Language :: Python :: 3.13",
33
+ "Topic :: Software Development :: Build Tools",
34
+ "Topic :: Software Development :: Libraries",
35
+ "Topic :: Software Development :: Testing"
36
+ ]
37
+ dependencies = [
38
+ "typer>=0.12,<1",
39
+ "httpx>=0.27,<1",
40
+ "rich>=13.7,<15",
41
+ "tomli>=2.0.1; python_version < '3.11'"
42
+ ]
43
+
44
+ [project.optional-dependencies]
45
+ openrouter-http = ["requests>=2.31,<3"]
46
+ openrouter-sdk = ["openrouter>=0.6.0,<1"]
47
+ openrouter = [
48
+ "requests>=2.31,<3",
49
+ "openrouter>=0.6.0,<1"
50
+ ]
51
+ docs = [
52
+ "mkdocs>=1.6,<2",
53
+ "mkdocs-material>=9.5,<10"
54
+ ]
55
+ dev = [
56
+ "pytest>=8.2,<9",
57
+ "pytest-asyncio>=0.23,<1",
58
+ "requests>=2.31,<3",
59
+ "responses>=0.25,<1",
60
+ "respx>=0.21,<1"
61
+ ]
62
+
63
+ [project.urls]
64
+ Homepage = "https://hexi.readthedocs.io"
65
+ Documentation = "https://hexi.readthedocs.io"
66
+ Source = "https://github.com/antonioognio/hexi"
67
+ Issues = "https://github.com/antonioognio/hexi/issues"
68
+
69
+ [project.scripts]
70
+ hexi = "hexi.cli:app"
71
+
72
+ [tool.setuptools]
73
+ package-dir = {"" = "src"}
74
+ license-files = ["LICENSE"]
75
+
76
+ [tool.setuptools.packages.find]
77
+ where = ["src"]
78
+
79
+ [tool.pytest.ini_options]
80
+ testpaths = ["tests"]
81
+ addopts = "-q"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,2 @@
1
+ __all__ = ["__version__"]
2
+ __version__ = "0.1.0"
@@ -0,0 +1,21 @@
1
+ from .event_log_jsonl import JsonlRunlogEventSink
2
+ from .events_console import ConsoleEventSink
3
+ from .exec_local import LocalExec
4
+ from .memory_file import FileMemory
5
+ from .model_anthropic_compat import AnthropicCompatModel
6
+ from .model_openai_compat import OpenAICompatModel
7
+ from .model_openrouter_http import OpenRouterHTTPModel
8
+ from .model_openrouter_sdk import OpenRouterSDKModel
9
+ from .workspace_local_git import LocalGitWorkspace
10
+
11
+ __all__ = [
12
+ "JsonlRunlogEventSink",
13
+ "ConsoleEventSink",
14
+ "LocalExec",
15
+ "FileMemory",
16
+ "AnthropicCompatModel",
17
+ "OpenAICompatModel",
18
+ "OpenRouterHTTPModel",
19
+ "OpenRouterSDKModel",
20
+ "LocalGitWorkspace",
21
+ ]
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+ from hexi.core.domain import Event
7
+ from hexi.core.schemas import event_to_dict
8
+
9
+
10
+ class JsonlRunlogEventSink:
11
+ def __init__(self, runlog_path: Path) -> None:
12
+ self.runlog_path = runlog_path
13
+
14
+ def emit(self, event: Event) -> None:
15
+ self.runlog_path.parent.mkdir(parents=True, exist_ok=True)
16
+ with self.runlog_path.open("a", encoding="utf-8") as f:
17
+ f.write(json.dumps(event_to_dict(event), ensure_ascii=True) + "\n")
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+ from rich.console import Console, Group
6
+ from rich.panel import Panel
7
+ from rich.syntax import Syntax
8
+ from rich.text import Text
9
+
10
+ from hexi.core.domain import Event
11
+
12
+ _EVENT_STYLES: dict[str, tuple[str, str]] = {
13
+ "progress": ("cyan", "⏳"),
14
+ "question": ("yellow", "❓"),
15
+ "review": ("magenta", "🔎"),
16
+ "artifact": ("green", "📦"),
17
+ "error": ("red", "✖"),
18
+ "done": ("bright_blue", "✔"),
19
+ }
20
+
21
+
22
+ class ConsoleEventSink:
23
+ def __init__(self) -> None:
24
+ self.console = Console()
25
+
26
+ def emit(self, event: Event) -> None:
27
+ color, icon = _EVENT_STYLES.get(event.type, ("white", "•"))
28
+ title = Text(f"{icon} {event.type.upper()}", style=f"bold {color}")
29
+ subtitle = "blocking" if event.blocking else "non-blocking"
30
+
31
+ lines = [Text(event.one_line_summary, style="bold")]
32
+ if event.payload:
33
+ payload_str = json.dumps(event.payload, ensure_ascii=True, indent=2)
34
+ lines.append(Text(""))
35
+ lines.append(Syntax(payload_str, "json", word_wrap=True))
36
+
37
+ self.console.print(Panel.fit(Group(*lines), title=title, subtitle=subtitle, border_style=color))
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+
3
+ import shlex
4
+ import subprocess
5
+
6
+ from hexi.core.domain import Policy
7
+ from hexi.core.policy import command_allowed
8
+
9
+
10
+ class LocalExec:
11
+ def run(self, command: str, policy: Policy) -> tuple[int, str, str]:
12
+ if not command_allowed(command, policy):
13
+ raise PermissionError(f"command is not allowlisted: {command}")
14
+ args = shlex.split(command)
15
+ proc = subprocess.run(args, capture_output=True, text=True, check=False)
16
+ return proc.returncode, proc.stdout[-8000:], proc.stderr[-8000:]