eo-processor 0.4.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.

Potentially problematic release.


This version of eo-processor might be problematic. Click here for more details.

Files changed (48) hide show
  1. eo_processor-0.4.0/.github/FUNDING.yml +15 -0
  2. eo_processor-0.4.0/.github/copilot-instructions.md +322 -0
  3. eo_processor-0.4.0/.github/workflows/ci.yml +98 -0
  4. eo_processor-0.4.0/.github/workflows/jules-autofix.yml +130 -0
  5. eo_processor-0.4.0/.github/workflows/release.yml +238 -0
  6. eo_processor-0.4.0/.gitignore +73 -0
  7. eo_processor-0.4.0/AGENTS.md +444 -0
  8. eo_processor-0.4.0/CHANGELOG +122 -0
  9. eo_processor-0.4.0/CONTRIBUTING.md +220 -0
  10. eo_processor-0.4.0/Cargo.lock +387 -0
  11. eo_processor-0.4.0/Cargo.toml +26 -0
  12. eo_processor-0.4.0/LICENSE +21 -0
  13. eo_processor-0.4.0/Makefile +77 -0
  14. eo_processor-0.4.0/PKG-INFO +542 -0
  15. eo_processor-0.4.0/QUICKSTART.md +245 -0
  16. eo_processor-0.4.0/README.md +512 -0
  17. eo_processor-0.4.0/SECURITY.md +69 -0
  18. eo_processor-0.4.0/architecture/ADR-template.md +0 -0
  19. eo_processor-0.4.0/coverage-badge.svg +21 -0
  20. eo_processor-0.4.0/coverage.xml +64 -0
  21. eo_processor-0.4.0/examples/README.md +90 -0
  22. eo_processor-0.4.0/examples/basic_usage.py +133 -0
  23. eo_processor-0.4.0/examples/map_blocks.py +207 -0
  24. eo_processor-0.4.0/examples/spatial_distances.py +227 -0
  25. eo_processor-0.4.0/examples/spectral_indices_extended.py +300 -0
  26. eo_processor-0.4.0/examples/temporal_operations.py +90 -0
  27. eo_processor-0.4.0/examples/xarray_dask_usage.py +261 -0
  28. eo_processor-0.4.0/pyproject.toml +60 -0
  29. eo_processor-0.4.0/pytest.ini +6 -0
  30. eo_processor-0.4.0/python/eo_processor/__init__.py +379 -0
  31. eo_processor-0.4.0/python/eo_processor/__init__.pyi +60 -0
  32. eo_processor-0.4.0/scripts/benchmark.py +666 -0
  33. eo_processor-0.4.0/scripts/eo_cli.py +450 -0
  34. eo_processor-0.4.0/scripts/generate_coverage_badge.py +154 -0
  35. eo_processor-0.4.0/scripts/jules_session_manager.py +89 -0
  36. eo_processor-0.4.0/scripts/version.py +199 -0
  37. eo_processor-0.4.0/src/indices.rs +1008 -0
  38. eo_processor-0.4.0/src/lib.rs +40 -0
  39. eo_processor-0.4.0/src/spatial.rs +452 -0
  40. eo_processor-0.4.0/src/temporal.rs +235 -0
  41. eo_processor-0.4.0/src/tests.rs +48 -0
  42. eo_processor-0.4.0/tests/__init__.py +0 -0
  43. eo_processor-0.4.0/tests/test_indices.py +341 -0
  44. eo_processor-0.4.0/tests/test_spatial.py +67 -0
  45. eo_processor-0.4.0/tests/test_spatial_distances.py +179 -0
  46. eo_processor-0.4.0/tests/test_temporal.py +46 -0
  47. eo_processor-0.4.0/tox.ini +74 -0
  48. eo_processor-0.4.0/uv.lock +1595 -0
@@ -0,0 +1,15 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4
+ patreon: bnjam
5
+ open_collective: # Replace with a single Open Collective username
6
+ ko_fi: # Replace with a single Ko-fi username
7
+ tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8
+ community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9
+ liberapay: # Replace with a single Liberapay username
10
+ issuehunt: # Replace with a single IssueHunt username
11
+ lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12
+ polar: # Replace with a single Polar username
13
+ buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14
+ thanks_dev: # Replace with a single thanks.dev username
15
+ custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
@@ -0,0 +1,322 @@
1
+ # GitHub Copilot / AI Agent Instructions
2
+
3
+ This document defines how AI code assistants (e.g., GitHub Copilot, autonomous agents) should behave when generating, modifying, or proposing code in the `eo-processor` repository. It complements `AGENTS.md` and focuses on inline assistance, code completion, and automated changes.
4
+
5
+ ---
6
+
7
+ ## 1. Scope of Assistance
8
+
9
+ AI assistance MAY:
10
+ - Suggest Rust functions implementing EO spectral indices and numeric transforms
11
+ - Provide Python integration layers (imports, type stubs, tests)
12
+ - Improve performance in pure Rust (keeping safety)
13
+ - Add unit tests and benchmarks (lightweight)
14
+ - Refactor for clarity without breaking public APIs
15
+ - Maintain or regenerate `coverage-badge.svg` via existing script logic
16
+ - Propose documentation updates (README, QUICKSTART)
17
+ - Add missing type hints, docstrings, or comments
18
+
19
+ AI assistance MUST NOT:
20
+ - Introduce external services, network calls, or file I/O into the core computational path
21
+ - Add unchecked dependencies without justification
22
+ - Use `unsafe` Rust blocks (unless explicitly approved and documented)
23
+ - Commit partial implementations (functions without tests or exports)
24
+ - Generate large boilerplate unrelated to repository goals
25
+ - Fabricate data, benchmarks, or security claims
26
+
27
+ ---
28
+
29
+ ## 2. Repository Structure Awareness
30
+
31
+ Key areas for code suggestions:
32
+ - `src/` – Rust source (PyO3 module functions)
33
+ - `python/eo_processor/` – Python package exports and type stubs
34
+ - `tests/` – Python tests (add test_*.py files here)
35
+ - `scripts/` – Utility scripts (badge generation, etc.)
36
+ - `pyproject.toml` – Metadata, versioning, dependencies
37
+ - `tox.ini` – Test environments, coverage configuration
38
+
39
+ Do not invent directories. Use existing patterns (e.g., 1D, 2D variants where appropriate).
40
+
41
+ ---
42
+
43
+ ## 3. Coding Conventions
44
+
45
+ Rust:
46
+ - Format with `cargo fmt`
47
+ - Zero clippy warnings (`cargo clippy -- -D warnings`)
48
+ - Prefer slice/array operations over explicit loops where clear
49
+ - Avoid `unwrap()`—use explicit error handling or safe assumptions
50
+ - Enforce shape matching before arithmetic when combining arrays
51
+
52
+ Python:
53
+ - Export new functions in `__init__.py`
54
+ - Add type stubs in `__init__.pyi`
55
+ - Keep tests deterministic (no random seeds unless specified)
56
+ - Use NumPy array assertions (`np.allclose`, `np.isfinite`)
57
+ - Prefer descriptive test names (`test_<function>_<case>`)
58
+
59
+ Documentation:
60
+ - Add formulas for new spectral indices
61
+ - Include minimal runnable examples
62
+ - Maintain consistency with existing README function lists
63
+
64
+ ---
65
+
66
+ ## 4. Performance Guidance
67
+
68
+ When suggesting optimizations:
69
+ - Preserve numerical correctness (tolerance ≤ 1e-9)
70
+ - Prefer vectorized ndarray operations in Rust
71
+ - Avoid micro-optimizations that reduce readability unless >20% speed gain
72
+ - Suggest benchmarking snippets only if relevant
73
+
74
+ Benchmarks must be realistic (large arrays, e.g., 5000 x 5000).
75
+
76
+ ---
77
+
78
+ ## 5. Safe Rust Patterns
79
+
80
+ DO:
81
+ - Use `ndarray` arithmetic operations
82
+ - Validate shapes early
83
+ - Use small constants like `1e-10` for numeric stability
84
+
85
+ DON'T:
86
+ - Introduce `unsafe`
87
+ - Allocate excessively in tight loops
88
+ - Return inconsistent array dimensions
89
+ - Silently swallow errors
90
+
91
+ ---
92
+
93
+ ## 6. Adding New Functionality (Checklist)
94
+
95
+ For each new function:
96
+ 1. Implement in Rust (`src/lib.rs`)
97
+ 2. Register with `#[pyfunction]` and add to `#[pymodule]`
98
+ 3. Export in `python/eo_processor/__init__.py`
99
+ 4. Add type stub in `python/eo_processor/__init__.pyi`
100
+ 5. Create test file in `tests/`
101
+ 6. Update README function list and examples
102
+ 7. Run full pre-commit checklist (Section 8)
103
+ 8. Consider version bump (patch/minor/major)
104
+
105
+ ---
106
+
107
+ ## 7. Versioning Rules (SemVer)
108
+
109
+ - Patch: Bug fixes / internal refactors
110
+ - Minor: New functions (backward-compatible)
111
+ - Major: Breaking changes (signature changes, removals)
112
+
113
+ AI agents should tag suggestions that require version bumps.
114
+
115
+ ---
116
+
117
+ ## 8. Pre-Commit / Pre-Push Checklist (MANDATORY)
118
+
119
+ Before generating or validating a commit, ensure:
120
+ - [ ] Rust code formatted (`cargo fmt`)
121
+ - [ ] No clippy warnings
122
+ - [ ] `cargo check --lib` succeeds (or `cargo test` if tests exist)
123
+ - [ ] Python style/lint: ruff passes
124
+ - [ ] `mypy python/eo_processor` has no new errors
125
+ - [ ] Tests pass (`tox` or individual env)
126
+ - [ ] Coverage updated if logic changed (`tox -e coverage`)
127
+ - [ ] Badge regenerated if coverage changed:
128
+ `python scripts/generate_coverage_badge.py coverage.xml coverage-badge.svg`
129
+ - [ ] README / docs updated for public API changes
130
+ - [ ] Version updated if needed
131
+ - [ ] No secrets or unintended large binaries staged
132
+ - [ ] Commit message follows convention (Section 9)
133
+ - [ ] Performance impact evaluated (if relevant)
134
+
135
+ If any step fails, DO NOT propose commit.
136
+
137
+ ---
138
+
139
+ ## 9. Commit Message Pattern
140
+
141
+ Format:
142
+ ```
143
+ <type>(scope): concise summary
144
+
145
+ Optional body explaining rationale, benchmarks, or docs
146
+ Refs: issue numbers, benchmarks, links
147
+ ```
148
+
149
+ Types:
150
+ - feat
151
+ - fix
152
+ - perf
153
+ - docs
154
+ - test
155
+ - chore
156
+ - build
157
+ - ci
158
+
159
+ Example:
160
+ ```
161
+ feat(indices): add Enhanced Vegetation Index (EVI)
162
+
163
+ Implements EVI with 1D/2D variants. Adds tests and docs.
164
+ Benchmarked at 1.28x speed vs NumPy baseline.
165
+ Refs: #45
166
+ ```
167
+
168
+ ---
169
+
170
+ ## 10. When NOT to Suggest Code
171
+
172
+ AI agents should refrain if:
173
+ - Required context (file content) is missing
174
+ - Task involves strategic redesign (defer to human proposal)
175
+ - Operation would introduce external network access
176
+ - Performance trade-offs cannot be reasonably estimated
177
+ - Security posture could be affected (e.g., unsafe / dynamic execution)
178
+
179
+ Instead, propose clarification questions or planning steps.
180
+
181
+ ---
182
+
183
+ ## 11. Testing Guidance
184
+
185
+ Minimal test template:
186
+ ```python
187
+ def test_new_index_basic():
188
+ import numpy as np
189
+ from eo_processor import new_index
190
+ a = np.array([0.6, 0.7, 0.8])
191
+ b = np.array([0.2, 0.3, 0.4])
192
+ out = new_index(a, b)
193
+ assert out.shape == a.shape
194
+ assert np.isfinite(out).all()
195
+ ```
196
+
197
+ Edge case tests:
198
+ - Zeros / near-zero denominators
199
+ - Matching shape enforcement
200
+ - Large arrays performance (sanity only; avoid huge runtime)
201
+
202
+ ---
203
+
204
+ ## 12. Coverage Badge Regeneration
205
+
206
+ Trigger conditions:
207
+ - Python code modified
208
+ - Tests added/removed
209
+ - Coverage threshold changes
210
+
211
+ Sequence:
212
+ 1. `tox -e coverage`
213
+ 2. Confirm `coverage.xml` exists
214
+ 3. Run script
215
+ 4. Verify SVG text alignment locally
216
+ 5. Stage updated badge
217
+
218
+ ---
219
+
220
+ ## 13. Documentation Updates
221
+
222
+ For new features:
223
+ - Add function signature to README
224
+ - Add usage snippet
225
+ - Provide formula
226
+ - Mention typical EO use-case
227
+ - Optional: scientific reference (if standard index)
228
+
229
+ ---
230
+
231
+ ## 14. Performance Claim Template
232
+
233
+ If suggesting optimization:
234
+ ```
235
+ Benchmark:
236
+ Array size: 5000 x 5000
237
+ Old: 1.42s
238
+ New: 1.05s
239
+ Speedup: 1.35x
240
+
241
+ Methodology:
242
+ Single run, warm cache discarded
243
+ Python timing via time.time()
244
+ ```
245
+
246
+ ---
247
+
248
+ ## 15. Do / Don’t Summary
249
+
250
+ DO:
251
+ - Maintain parity between Rust and Python exports
252
+ - Use explicit naming (`index_1d`, `index_2d`)
253
+ - Keep code minimal and safe
254
+ - Suggest incremental changes
255
+
256
+ DON’T:
257
+ - Combine unrelated changes in one diff
258
+ - Introduce unstable dependencies
259
+ - Modify unrelated files casually
260
+ - Reduce test coverage
261
+
262
+ ---
263
+
264
+ ## 16. Rollback Strategy (If Committed Mistake Detected)
265
+
266
+ 1. Reset local changes: `git reset --hard HEAD~1` (if safe)
267
+ 2. Revert remote commit: create a `revert:` commit
268
+ 3. Re-run full checklist
269
+ 4. Open issue documenting root cause if systemic
270
+
271
+ ---
272
+
273
+ ## 17. Example Rust Function Pattern (Reusable)
274
+
275
+ ```rust
276
+ #[pyfunction]
277
+ fn example_index<'py>(
278
+ py: Python<'py>,
279
+ a: PyReadonlyArray2<f64>,
280
+ b: PyReadonlyArray2<f64>,
281
+ ) -> PyResult<&'py PyArray2<f64>> {
282
+ let a_arr = a.as_array();
283
+ let b_arr = b.as_array();
284
+ assert_eq!(a_arr.shape(), b_arr.shape(), "Input arrays must have matching shapes");
285
+ let numerator = &a_arr - &b_arr;
286
+ let denominator = &a_arr + &b_arr + 1e-10;
287
+ let out = numerator / denominator;
288
+ Ok(out.into_pyarray(py))
289
+ }
290
+ ```
291
+
292
+ ---
293
+
294
+ ## 18. Red Flags (Require Human Review)
295
+
296
+ - Proposal to add GPU or distributed code paths
297
+ - Changes to module initialization signature
298
+ - Introduction of concurrency primitives (threads / async)
299
+ - Large memory allocations (> several GB)
300
+ - Breaking API removals
301
+
302
+ ---
303
+
304
+ ## 19. Optional Extensions (Future Suggestions)
305
+
306
+ Agents may propose (but not implement without approval):
307
+ - Additional indices: EVI, SAVI, NBR, GCI
308
+ - Sliding window operations
309
+ - Batch spectral composite builder
310
+ - Multi-threaded internal tiling (must justify)
311
+
312
+ ---
313
+
314
+ ## 20. Final Rule
315
+
316
+ If uncertain about spec or impact → STOP and generate a structured clarification prompt rather than guessing.
317
+
318
+ Quality > speed. Safety > novelty.
319
+
320
+ ---
321
+
322
+ End of GitHub Copilot / AI Agent Instructions.
@@ -0,0 +1,98 @@
1
+ name: CI
2
+
3
+ # --- TRIGGER: Runs on Pull Requests ---
4
+ on:
5
+ pull_request:
6
+ types: [opened, synchronize, reopened, edited]
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ env:
13
+ CARGO_TERM_COLOR: always
14
+ RUN_BENCHMARKS: false
15
+
16
+ jobs:
17
+ test:
18
+ name: Tests via tox (Python ${{ matrix.python-version }})
19
+ runs-on: ubuntu-latest
20
+ permissions:
21
+ contents: write # Needed for coverage badge/artifacts
22
+ strategy:
23
+ matrix:
24
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
25
+ steps:
26
+ - name: Checkout repository
27
+ uses: actions/checkout@v4
28
+
29
+ # --- SETUP ---
30
+ - name: Install Rust toolchain
31
+ # Required for the 'clippy' environment and maturin builds
32
+ uses: dtolnay/rust-toolchain@stable
33
+
34
+ - name: Set up Python ${{ matrix.python-version }}
35
+ uses: actions/setup-python@v5
36
+ with:
37
+ python-version: ${{ matrix.python-version }}
38
+
39
+ - name: Install uv and tools
40
+ uses: astral-sh/setup-uv@v3
41
+
42
+ - name: Install tox and plugins
43
+ # Install tox and the tox-gh-actions plugin into the base environment
44
+ run: uv pip install --system tox tox-gh-actions
45
+
46
+ # --- LINT & CLIPPY STEPS (Run once on 3.11) ---
47
+ # Running static checks only on one version to save time
48
+ - name: 🔎 Run Lint (tox -e lint)
49
+ if: matrix.python-version == '3.11'
50
+ run: tox -e lint
51
+
52
+ - name: 🔎 Run Rust Checks (tox -e clippy)
53
+ if: matrix.python-version == '3.11'
54
+ run: tox -e clippy
55
+
56
+ # --- CORE TESTS STEP (Run on both 3.11 and 3.12) ---
57
+ - name: 🧪 Run Tests (tox -e py${{ matrix.python-version }})
58
+ id: tests_step
59
+ # Runs 'maturin develop' and 'pytest -q'
60
+ run: tox -e py${{ matrix.python-version }}
61
+
62
+ # --- COVERAGE & BADGE STEPS (Run once on 3.12) ---
63
+ - name: 📊 Run Coverage Threshold Check
64
+ if: matrix.python-version == '3.12'
65
+ id: coverage_step
66
+ # This assumes the tox 'coverage' environment produces a coverage.xml file in the repository root.
67
+ run: |
68
+ set -euo pipefail
69
+ tox -e coverage
70
+ python scripts/generate_coverage_badge.py coverage.xml coverage-badge.svg || echo "Badge generation skipped"
71
+
72
+ - name: 🚀 Run Example Scripts (Smoke Tests)
73
+ if: matrix.python-version == '3.12'
74
+ run: |
75
+ set -e
76
+ echo "Running smoke-test examples..."
77
+ uv run python examples/basic_usage.py
78
+ uv run python examples/temporal_operations.py
79
+ uv run python examples/spatial_distances.py
80
+ # Optional dependencies may not be installed in minimal CI; tolerate failure.
81
+ uv run python examples/xarray_dask_usage.py || echo "xarray/dask example skipped (optional deps missing)"
82
+ uv run python examples/map_blocks.py || echo "map_blocks example skipped (optional deps missing)"
83
+
84
+ - name: 🏁 Benchmark (Optional)
85
+ if: matrix.python-version == '3.12' && env.RUN_BENCHMARKS == 'true'
86
+ run: |
87
+ set -e
88
+ echo "Running benchmark suite (with NumPy baseline comparisons)..."
89
+ uv run python scripts/benchmark.py --group all --height 1024 --width 1024 --time 8 --points-a 500 --points-b 500 --point-dim 8 --loops 2 --warmups 1 --compare-numpy --json-out benchmark-results.json --quiet
90
+ echo "Benchmark JSON generated: benchmark-results.json"
91
+ - name: 📦 Upload Benchmark Artifact
92
+ if: matrix.python-version == '3.12' && env.RUN_BENCHMARKS == 'true'
93
+ uses: actions/upload-artifact@v4
94
+ with:
95
+ name: benchmark-results
96
+ path: benchmark-results.json
97
+ if-no-files-found: warn
98
+ retention-days: 7
@@ -0,0 +1,130 @@
1
+ name: 🤖 Jules Autofix
2
+
3
+ # This workflow runs only when the main CI workflow completes and fails on a pull_request
4
+ on:
5
+ workflow_run:
6
+ workflows: [CI]
7
+ types: [completed]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.event.workflow_run.head_sha }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ jules_autofix:
15
+ name: Run Jules Fix Session
16
+ # Use a faster, lighter runner since it's mostly Python scripting
17
+ runs-on: ubuntu-latest
18
+ permissions:
19
+ pull-requests: write # Needed to comment on the PR
20
+ contents: read # Needed to checkout code
21
+ actions: read # Needed to list/download artifacts
22
+
23
+ # Only run if the CI failed AND it was triggered by a pull request
24
+ if: |
25
+ github.event.workflow_run.conclusion == 'failure' &&
26
+ github.event.workflow_run.event == 'pull_request'
27
+
28
+ steps:
29
+ - name: Checkout repository
30
+ uses: actions/checkout@v4
31
+ with:
32
+ # Use the commit SHA from the failed run to ensure context is correct
33
+ ref: ${{ github.event.workflow_run.head_sha }}
34
+
35
+ - name: Get PR Number and Author
36
+ id: get_pr
37
+ uses: actions/github-script@v6
38
+ with:
39
+ script: |
40
+ // Find the PR associated with the commit SHA from the failed workflow run
41
+ const { data: pullRequest } = await github.rest.pulls.list({
42
+ owner: context.repo.owner,
43
+ repo: context.repo.repo,
44
+ head: context.repo.owner + ':' + context.event.workflow_run.head_branch,
45
+ });
46
+ if (pullRequest.length === 0) {
47
+ core.info('Could not find corresponding pull request. Skipping.');
48
+ return;
49
+ }
50
+ core.setOutput('pr_number', pullRequest[0].number);
51
+ core.setOutput('pr_author', pullRequest[0].user.login);
52
+ core.setOutput('pr_repo', pullRequest[0].base.repo.full_name);
53
+
54
+ - name: Check if Author is "bnjam" (or other approved user)
55
+ # This conditional check ensures the script only runs for approved users, matching the original logic
56
+ if: ${{ steps.get_pr.outputs.pr_author != 'bnjam' }}
57
+ run: |
58
+ echo "Skipping Jules session. PR author is not 'bnjam'."
59
+ exit 0
60
+
61
+ - name: Set up Python
62
+ uses: actions/setup-python@v5
63
+ with:
64
+ python-version: "3.12"
65
+
66
+ # --- Download Artifacts from failed run ---
67
+ - name: 📥 Find and Download Failure Context
68
+ uses: actions/github-script@v6
69
+ id: download_artifact
70
+ with:
71
+ script: |
72
+ const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
73
+ owner: context.repo.owner,
74
+ repo: context.repo.repo,
75
+ run_id: context.event.workflow_run.id,
76
+ });
77
+
78
+ // Find the artifact uploaded by the failing test job (e.g., failure-context-3.12)
79
+ const matchArtifact = artifacts.data.artifacts.find(artifact =>
80
+ artifact.name.startsWith('failure-context-')
81
+ );
82
+
83
+ if (matchArtifact) {
84
+ const download = await github.rest.actions.downloadArtifact({
85
+ owner: context.repo.owner,
86
+ repo: context.repo.repo,
87
+ artifact_id: matchArtifact.id,
88
+ archive_format: 'zip',
89
+ });
90
+
91
+ const fs = require('fs');
92
+ const unzip = require('unzip-stream');
93
+
94
+ // This downloads the zip, extracts it, and makes the error message available
95
+ fs.writeFileSync('failure-context.zip', Buffer.from(download.data));
96
+ fs.mkdirSync('failure-context');
97
+ const readStream = fs.createReadStream('failure-context.zip');
98
+ const extractStream = unzip.Extract({ path: 'failure-context' });
99
+
100
+ await new Promise((resolve, reject) => {
101
+ extractStream.on('close', resolve);
102
+ extractStream.on('error', reject);
103
+ readStream.pipe(extractStream);
104
+ });
105
+
106
+ console.log('Successfully downloaded and extracted failure context.');
107
+ } else {
108
+ core.setFailed('Could not find failure-context artifact. Aborting autofix attempt.');
109
+ }
110
+
111
+ - name: Install dependencies for API interaction
112
+ run: pip install requests # Need 'requests' to talk to the Jules API
113
+
114
+ - name: 💬 Run Jules Session Manager
115
+ env:
116
+ JULES_API_KEY: ${{ secrets.JULES_API_KEY }}
117
+ REPO_NAME: ${{ steps.get_pr.outputs.pr_repo }}
118
+ PR_NUMBER: ${{ steps.get_pr.outputs.pr_number }}
119
+ BRANCH_NAME: ${{ github.event.workflow_run.head_branch }}
120
+ ERROR_MESSAGE: ""
121
+ run: |
122
+ # Load the error message from the downloaded artifact
123
+ if [ -f failure-context/error_message.txt ]; then
124
+ export ERROR_MESSAGE=$(cat failure-context/error_message.txt)
125
+ else
126
+ export ERROR_MESSAGE="CI failed, but the specific error message artifact was missing."
127
+ fi
128
+
129
+ # Execute the Python script that interacts with the fixing system
130
+ python ./scripts/jules_session_manager.py