jules-orchestrator-kit 0.26.2 β 0.27.1
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.
- package/README.md +172 -108
- package/bin/agentctl.mjs +29 -2
- package/package.json +1 -1
- package/src/dashboard.mjs +136 -0
- package/src/git.mjs +1 -24
- package/src/provider.mjs +42 -2
- package/src/review-repair.mjs +53 -0
- package/src/process-group.mjs +0 -80
package/README.md
CHANGED
|
@@ -4,76 +4,115 @@
|
|
|
4
4
|
|
|
5
5
|
### Universal Autonomous AI Agent Orchestration Kernel for Google Jules
|
|
6
6
|
|
|
7
|
+
<br/>
|
|
8
|
+
|
|
7
9
|
[](https://github.com/FullThrottle83/jules-orchestrator-kit/actions/workflows/jules-audit.yml)
|
|
8
10
|
[](https://www.npmjs.com/package/jules-orchestrator-kit)
|
|
9
11
|
[](https://opensource.org/licenses/MIT)
|
|
10
12
|
[](https://nodejs.org)
|
|
11
13
|
[](https://nodejs.org)
|
|
12
|
-
|
|
14
|
+
|
|
15
|
+
<br/>
|
|
13
16
|
|
|
14
17
|
<p align="center">
|
|
15
|
-
<b>The zero-dependency safety gatekeeper and self-healing engineering kernel for autonomous coding agent swarms.</b
|
|
18
|
+
<b>The zero-dependency safety gatekeeper and self-healing engineering kernel for autonomous coding agent swarms.</b>
|
|
16
19
|
Transforms single-turn AI chat assistants into production-grade engineering swarms running 300+ daily sessions across any language or monorepo.
|
|
17
20
|
</p>
|
|
18
21
|
|
|
22
|
+
<br/>
|
|
23
|
+
|
|
19
24
|
<p align="center">
|
|
20
|
-
<a href="
|
|
21
|
-
<a href="
|
|
22
|
-
<a href="
|
|
23
|
-
<a href="
|
|
24
|
-
<
|
|
25
|
-
<a href="
|
|
26
|
-
<a href="
|
|
25
|
+
<a href="#what-is-kit">π‘ What is Kit?</a> β’
|
|
26
|
+
<a href="#quickstart">β‘ Quickstart</a> β’
|
|
27
|
+
<a href="#triage-guidelines">π― Triage Guidelines</a> β’
|
|
28
|
+
<a href="#matrix">π Matrix</a>
|
|
29
|
+
<br/>
|
|
30
|
+
<a href="#architecture">ποΈ Architecture</a> β’
|
|
31
|
+
<a href="#cli-docs">π οΈ CLI Docs</a> β’
|
|
32
|
+
<a href="#roadmap">πΊοΈ Roadmap</a>
|
|
27
33
|
</p>
|
|
28
34
|
|
|
29
35
|
</div>
|
|
30
36
|
|
|
37
|
+
<br/>
|
|
38
|
+
|
|
31
39
|
---
|
|
32
40
|
|
|
41
|
+
<br/>
|
|
42
|
+
|
|
43
|
+
<a id="what-is-kit"></a>
|
|
33
44
|
## π‘ 2-Sentence Mental Model
|
|
34
45
|
|
|
46
|
+
> [!TIP]
|
|
35
47
|
> **Think of `jules-orchestrator-kit` as an automated Engineering Manager for AI coding agents.**
|
|
36
|
-
>
|
|
48
|
+
> It hands out clear tasks, runs your tests in an isolated sandbox, fixes broken code automatically, and only opens a Pull Request when 100% of your tests pass.
|
|
49
|
+
|
|
50
|
+
<br/>
|
|
37
51
|
|
|
38
52
|
---
|
|
39
53
|
|
|
54
|
+
<br/>
|
|
55
|
+
|
|
40
56
|
## π― Why `jules-orchestrator-kit`?
|
|
41
57
|
|
|
42
58
|
Autonomous coding agents can write software at 100Γ human speedβbut unconstrained agents introduce silent regressions, leak API keys, hallucinate test assertions, and thrash shared monorepos.
|
|
43
59
|
|
|
44
60
|
`jules-orchestrator-kit` provides the missing **Safety, Orchestration, and Verification Kernel** for high-reliability AI agent deployments:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
|
|
62
|
+
* **π Zero Runtime Dependencies:** Built exclusively on Node.js 20+ built-ins (`node:fs`, `node:child_process`, `node:crypto`, `node:path`, `node:http`, `node:test`). Zero third-party npm packages mean zero supply-chain CVE risk.
|
|
63
|
+
|
|
64
|
+
* **π‘οΈ Fail-Closed Security Gatekeeper:** Unconditionally evaluates explicit Deny rules *before* Allow rules, redacts high-entropy secrets and PII from dry-runs and git diffs, and rejects PRs exceeding the 75 KB Diff Payload governor.
|
|
65
|
+
|
|
66
|
+
* **π Autonomous OODA Self-Healing:** Captures test stderr/stdout, normalizes failure fingerprints, and feeds structured error contexts back into repair iterations (up to 3 automatic attempts) before human escalation.
|
|
67
|
+
|
|
68
|
+
* **π Universal Polyglot Spine:** Natively auto-detects 24+ tech stacks (PHP/Laravel/WordPress, .NET/C#, Python, Go, Rust, C/C++, Flutter/Swift, Node/Deno/Bun) and transparently wraps verification suites in Docker Compose or Devcontainer sandboxes.
|
|
69
|
+
|
|
70
|
+
* **π Scoped Monorepo Boundary Resolver:** Statically maps changed files up directory ancestry to invoke isolated subshell test suites (`(cd backend && pytest) && (cd cli && cargo test)`), eliminating global test thrashing.
|
|
71
|
+
|
|
72
|
+
* **π Zero-Test Bootstrapping (`agentctl bootstrap`):** Synthesizes deterministic syntax-check and smoke-test verification oracles for untested legacy repositories so agents always operate against a falsifiable feedback loop.
|
|
73
|
+
|
|
74
|
+
* **π Proven Scale & Reliability:** Empirically tested with **224 unit tests across 55 suites passing in < 1.2s**, supporting 300+ daily agent sessions per repository.
|
|
75
|
+
|
|
76
|
+
<br/>
|
|
52
77
|
|
|
53
78
|
---
|
|
54
79
|
|
|
80
|
+
<br/>
|
|
81
|
+
|
|
82
|
+
<a id="triage-guidelines"></a>
|
|
55
83
|
## π― Triage Guidelines: When to Use vs. When NOT to Use
|
|
56
84
|
|
|
57
85
|
To ensure maximum merge success, dispatch tasks according to our deterministic triage boundaries:
|
|
58
86
|
|
|
87
|
+
<br/>
|
|
88
|
+
|
|
59
89
|
### π’ Ideal Tasks for Autonomous Swarms
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
90
|
+
|
|
91
|
+
* β
**Scoped Code Changes & Bug Fixes:** Well-defined objectives mechanically verifiable via unit tests (`npm test`, `pytest`, `cargo test`, `dotnet test`).
|
|
92
|
+
* β
**Type & Linter Migrations:** TypeScript strict mode fixes, PHP 8.3 type hint additions, or Python MyPy type annotation passes.
|
|
93
|
+
* β
**Dependency Bumps & Security Audits:** Remediating CVEs in lockfiles (`package.json`, `Cargo.toml`, `composer.json`) with hermetic test verification.
|
|
94
|
+
* β
**Refactoring Legacy Codebases:** Modularizing backend routes, API controllers, or database query layers.
|
|
95
|
+
* β
**Visual & E2E Testing (via Playwright):** UI changes paired with automated headless Playwright snapshot tests (`npx playwright test`).
|
|
96
|
+
|
|
97
|
+
<br/>
|
|
65
98
|
|
|
66
99
|
### π΄ When NOT to Use (Out of Scope)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
100
|
+
|
|
101
|
+
* β **Unverifiable Visual UI Tweaks:** Pixel-perfect CSS/Tailwind adjustments lacking automated visual regression tests (agents cannot "see" raw browser output without Playwright).
|
|
102
|
+
* β **Closed Proprietary Platforms Without CLI:** Systems lacking local CLI tools or git repositories (e.g., Salesforce, Webflow, closed SAP backends).
|
|
103
|
+
* β **Unmocked Live Cloud Systems:** Code requiring live connections to 10+ external cloud APIs without local emulators or mocks.
|
|
104
|
+
* β **Protected Infrastructure Paths:** Direct edits to `.github/workflows/`, production deployment keys, or agent security gate rules (enforced fail-closed by `Agent Scope Guard`).
|
|
105
|
+
|
|
106
|
+
<br/>
|
|
71
107
|
|
|
72
108
|
---
|
|
73
109
|
|
|
110
|
+
<br/>
|
|
111
|
+
|
|
112
|
+
<a id="matrix"></a>
|
|
74
113
|
## π Feature Comparison Matrix
|
|
75
114
|
|
|
76
|
-
| Dimension | Raw Agent Execution (No Orchestrator) | Standard CI/CD Pipelines | `jules-orchestrator-kit` (v0.
|
|
115
|
+
| Dimension | Raw Agent Execution (No Orchestrator) | Standard CI/CD Pipelines | `jules-orchestrator-kit` (v0.27+) |
|
|
77
116
|
| :--- | :--- | :--- | :--- |
|
|
78
117
|
| **Self-Healing Loop** | β None (Crashes on test error) | β None (Fails build; notifies human) | β
**Autonomous OODA Loop** (Max 3 repair turns with error fingerprinting) |
|
|
79
118
|
| **Scope Isolation** | β None (Can modify CI files or lockfiles) | π‘ Post-commit branch rules only | β
**Fail-Closed Scope Guard** (Deny-first evaluation; blocks protected paths) |
|
|
@@ -84,12 +123,19 @@ To ensure maximum merge success, dispatch tasks according to our deterministic t
|
|
|
84
123
|
| **Secret Leak Prevention**| β Prone to leaking tokens in diffs | π‘ Post-push secret scanning alerts | β
**Pre-Dispatch & Pre-Commit Diff Scanner** (Blocks CVEs/keys before PR creation) |
|
|
85
124
|
| **Dependency Footprint** | β Requires heavy SDKs & parsers | π‘ Many external actions & plugins | β
**0 Native Dependencies** (100% Node.js 20+ ESM built-ins) |
|
|
86
125
|
|
|
126
|
+
<br/>
|
|
127
|
+
|
|
87
128
|
---
|
|
88
129
|
|
|
130
|
+
<br/>
|
|
131
|
+
|
|
132
|
+
<a id="quickstart"></a>
|
|
89
133
|
## β‘ Universal 30-Second Quickstart (Zero to Verified PR)
|
|
90
134
|
|
|
91
135
|
Get from zero to an autonomously verified GitHub Pull Request across any software ecosystem in 30 seconds.
|
|
92
136
|
|
|
137
|
+
<br/>
|
|
138
|
+
|
|
93
139
|
### 1οΈβ£ Node.js / TypeScript (npm, pnpm, yarn, bun, deno)
|
|
94
140
|
```bash
|
|
95
141
|
# Dispatch a scoped task; auto-detects package.json / tsconfig.json and runs type-checked tests
|
|
@@ -97,6 +143,8 @@ npx jules-orchestrator-kit dispatch --title "Add rate limiting to API router" \
|
|
|
97
143
|
--prompt "Implement IP-based token-bucket rate limiting in src/router.ts with unit tests."
|
|
98
144
|
```
|
|
99
145
|
|
|
146
|
+
<br/>
|
|
147
|
+
|
|
100
148
|
### 2οΈβ£ Python / FastAPI / Django (pytest, pyproject.toml)
|
|
101
149
|
```bash
|
|
102
150
|
# Bootstrap zero-test or legacy Python repo, then dispatch task
|
|
@@ -105,6 +153,8 @@ npx jules-orchestrator-kit dispatch --title "Add OAuth2 JWT validation" \
|
|
|
105
153
|
--prompt "Add JWT bearer authentication middleware to backend/api/auth.py and verify via pytest."
|
|
106
154
|
```
|
|
107
155
|
|
|
156
|
+
<br/>
|
|
157
|
+
|
|
108
158
|
### 3οΈβ£ PHP / Laravel / WordPress (Docker Compose + PHPUnit/Pest)
|
|
109
159
|
```bash
|
|
110
160
|
# Auto-detects docker-compose.yml and wraps test commands in `docker compose exec -T app ...`
|
|
@@ -112,6 +162,8 @@ npx jules-orchestrator-kit dispatch --title "Upgrade PHP 8.3 type annotations" \
|
|
|
112
162
|
--prompt "Add strict type hints to all repository classes in app/Repositories/."
|
|
113
163
|
```
|
|
114
164
|
|
|
165
|
+
<br/>
|
|
166
|
+
|
|
115
167
|
### 4οΈβ£ .NET / C# Enterprise (*.sln, *.csproj)
|
|
116
168
|
```bash
|
|
117
169
|
# Auto-detects .sln / .csproj and runs `dotnet test --no-restore --nologo`
|
|
@@ -119,6 +171,8 @@ npx jules-orchestrator-kit dispatch --title "Implement OrderService caching" \
|
|
|
119
171
|
--prompt "Add IMemoryCache caching to OrderService.cs with xUnit coverage."
|
|
120
172
|
```
|
|
121
173
|
|
|
174
|
+
<br/>
|
|
175
|
+
|
|
122
176
|
### 5οΈβ£ UI / Frontend E2E (Playwright)
|
|
123
177
|
```bash
|
|
124
178
|
# Dispatch frontend task verified via headless Playwright E2E tests
|
|
@@ -126,88 +180,109 @@ npx jules-orchestrator-kit dispatch --title "Add Dark Mode Toggle Component" \
|
|
|
126
180
|
--prompt "Create ThemeToggle component in src/components/ThemeToggle.tsx and verify via npx playwright test."
|
|
127
181
|
```
|
|
128
182
|
|
|
183
|
+
<br/>
|
|
184
|
+
|
|
129
185
|
### 6οΈβ£ Polyglot Monorepo (FastAPI + React + Rust CLI)
|
|
130
186
|
```bash
|
|
131
187
|
# Run a parallel worktree swarm; changed files automatically route to scoped subproject tests
|
|
132
188
|
npx jules-orchestrator-kit swarm
|
|
133
189
|
```
|
|
134
190
|
|
|
191
|
+
<br/>
|
|
192
|
+
|
|
193
|
+
<details>
|
|
194
|
+
<summary><b>π View All 24+ Supported Ecosystems & Stack Triggers</b></summary>
|
|
195
|
+
|
|
196
|
+
<br/>
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
Ecosystems Natively Supported by src/stack-detector.mjs:
|
|
200
|
+
βββ PHP / Laravel / WordPress (composer.json, phpunit.xml, pest.php, artisan, wp-cli.yml)
|
|
201
|
+
βββ .NET / C# / F# (*.sln, *.csproj, *.fsproj, global.json)
|
|
202
|
+
βββ Mobile / Dart / Flutter (pubspec.yaml)
|
|
203
|
+
βββ Mobile / Swift / Xcode (Package.swift)
|
|
204
|
+
βββ Mobile / React Native (app.json, react-native.config.js)
|
|
205
|
+
βββ Systems / CMake (CMakeLists.txt)
|
|
206
|
+
βββ Systems / Rust Cargo (Cargo.toml)
|
|
207
|
+
βββ Systems / Go (go.mod)
|
|
208
|
+
βββ Systems / Make (Makefile)
|
|
209
|
+
βββ Python / FastAPI / Django (pyproject.toml, requirements.txt, setup.py)
|
|
210
|
+
βββ Elixir / Phoenix (mix.exs)
|
|
211
|
+
βββ Ruby / Rails (Gemfile)
|
|
212
|
+
βββ Java / Maven (pom.xml)
|
|
213
|
+
βββ Java / Gradle (build.gradle, build.gradle.kts)
|
|
214
|
+
βββ JS / TS Workspaces (turbo.json, pnpm-workspace.yaml, nx.json)
|
|
215
|
+
βββ JS / TS Runtimes (bunfig.toml, deno.json, package.json)
|
|
216
|
+
βββ Devcontainers & Docker Compose (.devcontainer/devcontainer.json, docker-compose.yml, Dockerfile)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
</details>
|
|
220
|
+
|
|
221
|
+
<br/>
|
|
222
|
+
|
|
135
223
|
---
|
|
136
224
|
|
|
225
|
+
<br/>
|
|
226
|
+
|
|
227
|
+
<a id="architecture"></a>
|
|
137
228
|
## ποΈ System Architecture & Visual Diagrams
|
|
138
229
|
|
|
230
|
+
<br/>
|
|
231
|
+
|
|
139
232
|
### 1. The Autonomous OODA Verification Loop
|
|
140
233
|
Every task dispatched to `jules-orchestrator-kit` executes within an immutable, fail-closed verification loop:
|
|
141
234
|
|
|
235
|
+
```mermaid
|
|
236
|
+
flowchart TD
|
|
237
|
+
A["π© Task Envelope"] --> B["1. Validate Scope & Base Freshness"]
|
|
238
|
+
B --> C["2. Create Isolated Git Worktree & VFS Lock"]
|
|
239
|
+
C --> D["3. Dispatch Task to Google Jules / LLM"]
|
|
240
|
+
D --> E["4. Execute Scoped Verification Gate<br/><code>detectPolyglotStack().testCmd</code>"]
|
|
241
|
+
|
|
242
|
+
E -->|PASS| F["5. Security Audit<br/><i>Redact Secrets, Diff < 75KB</i>"]
|
|
243
|
+
F --> G["7. Rebase & Open PR<br/><code>git rebase main && gh pr create</code>"]
|
|
244
|
+
|
|
245
|
+
E -->|FAIL| H["6. Fingerprint Stderr & Flaky Verdict"]
|
|
246
|
+
H -->|Oscillation >= 0.40| I["π¨ Quarantined Test<br/><i>Exit Code 8</i>"]
|
|
247
|
+
H -->|Normal Failure| J["π Attempt OODA Repair Turn<br/><i>Max 3 Retries; Exit 4 on Exhaust</i>"]
|
|
248
|
+
J --> D
|
|
142
249
|
```
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
| |
|
|
146
|
-
| [Task Envelope] --> (1. Validate Scope & Base Freshness) |
|
|
147
|
-
| | |
|
|
148
|
-
| v |
|
|
149
|
-
| (2. Create Isolated Git Worktree / VFS Lock) |
|
|
150
|
-
| | |
|
|
151
|
-
| v |
|
|
152
|
-
| (3. Dispatch AI Task to Google Jules / LLM) |
|
|
153
|
-
| | |
|
|
154
|
-
| v |
|
|
155
|
-
| (4. Execute Scoped Verification Gate) |
|
|
156
|
-
| -- detectPolyglotStack().testCmd |
|
|
157
|
-
| -- Docker Compose / Devcontainer wrapper |
|
|
158
|
-
| | |
|
|
159
|
-
| +---------+---------+ |
|
|
160
|
-
| | PASS | FAIL |
|
|
161
|
-
| v v |
|
|
162
|
-
| (5. Security Audit) (6. Fingerprint Stderr / Flaky Verdict) |
|
|
163
|
-
| - Redact Secrets | |
|
|
164
|
-
| - Check Diff < 75KB +---> Is test QUARANTINED? (Oscillation >= 0.40) |
|
|
165
|
-
| | | | |
|
|
166
|
-
| v YES NO |
|
|
167
|
-
| (7. Rebase & PR) | | |
|
|
168
|
-
| - git rebase main v v |
|
|
169
|
-
| - gh pr create [Log Quarantined Flake] [Attempt OODA Repair Turn] |
|
|
170
|
-
| (Exit Code 8) (Max 3 Retries; Exit 4 on Exhaust) |
|
|
171
|
-
+---------------------------------------------------------------------------------------------------+
|
|
172
|
-
```
|
|
250
|
+
|
|
251
|
+
<br/>
|
|
173
252
|
|
|
174
253
|
### 2. Polyglot Monorepo Scoped Execution Engine
|
|
175
254
|
In monorepos containing multiple languages, `resolveWorkspaceBoundary(changedFiles)` traverses directory ancestry to isolate verification to affected subprojects:
|
|
176
255
|
|
|
256
|
+
```mermaid
|
|
257
|
+
flowchart TD
|
|
258
|
+
A["π Changed Files<br/><code>['backend/api/main.py', 'cli/src/main.rs']</code>"] --> B{"Check Shared Triggers?<br/><i>docker-compose.yml, openapi.yaml</i>"}
|
|
259
|
+
B -->|None Changed| C["Traverse Directory Ancestry"]
|
|
260
|
+
C --> D1["<code>backend/api/main.py</code> β <code>backend/pyproject.toml</code><br/><i>(Python Stack)</i>"]
|
|
261
|
+
C --> D2["<code>cli/src/main.rs</code> β <code>cli/Cargo.toml</code><br/><i>(Rust Stack)</i>"]
|
|
262
|
+
D1 --> E["Synthesize POSIX Subshell Verification Plan<br/><code>(cd backend && pytest) && (cd cli && cargo test)</code>"]
|
|
263
|
+
D2 --> E
|
|
177
264
|
```
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
| |
|
|
181
|
-
| changedFiles: ["backend/api/main.py", "cli/src/main.rs", "docs/README.md"] |
|
|
182
|
-
| | |
|
|
183
|
-
| +---> 1. Check Root Shared Triggers (openapi.yaml, docker-compose.yml, Makefile) |
|
|
184
|
-
| | -> None changed. Continue subproject isolation. |
|
|
185
|
-
| | |
|
|
186
|
-
| +---> 2. Map Files to Subproject Roots by Trigger File Traversal: |
|
|
187
|
-
| | - "backend/api/main.py" -> backend/pyproject.toml (Python Stack) |
|
|
188
|
-
| | - "cli/src/main.rs" -> cli/Cargo.toml (Rust/Cargo Stack) |
|
|
189
|
-
| | - "docs/README.md" -> (Documentation; R0 Cosmetic Risk) |
|
|
190
|
-
| | |
|
|
191
|
-
| +---> 3. Synthesize Scoped POSIX Subshell Verification Plan: |
|
|
192
|
-
| testCmd: "(cd backend && pytest) && (cd cli && cargo test --workspace)" |
|
|
193
|
-
| buildCmd: "(cd cli && cargo build)" |
|
|
194
|
-
| |
|
|
195
|
-
| Result: 100% test isolation, 0 global test thrashing, 0 git index lock collisions. |
|
|
196
|
-
+---------------------------------------------------------------------------------------------------+
|
|
197
|
-
```
|
|
265
|
+
|
|
266
|
+
<br/>
|
|
198
267
|
|
|
199
268
|
---
|
|
200
269
|
|
|
270
|
+
<br/>
|
|
271
|
+
|
|
272
|
+
<a id="cli-docs"></a>
|
|
201
273
|
## π οΈ CLI Command Reference (`agentctl`)
|
|
202
274
|
|
|
203
275
|
`agentctl` is the unified command-line interface for `jules-orchestrator-kit`, available via `bin/agentctl.mjs` or `npx jules-orchestrator-kit <command>`.
|
|
204
276
|
|
|
277
|
+
<br/>
|
|
278
|
+
|
|
205
279
|
| Command | Usage | Description | Exit Codes |
|
|
206
280
|
| :--- | :--- | :--- | :--- |
|
|
207
281
|
| `dispatch` | `agentctl dispatch --title <t> --prompt <p>` | Dispatches a single task to an AI agent in an isolated worktree. | `0` (Success), `1` (Arg error), `2` (429 Rate limit), `3` (Scope deny), `4` (OODA exhausted), `5` (Diff > 75KB), `6` (Secret leak) |
|
|
282
|
+
| `review-repair`| `agentctl review-repair <pr-comments.json>`| Parses GitHub PR review comments and synthesizes actionable OODA repair tasks. | `0` (Parsed), `1` (Missing file) |
|
|
283
|
+
| `dashboard` | `agentctl dashboard [port]` | Starts zero-dependency local HTTP telemetry and audit visualizer dashboard. | `0` (Running) |
|
|
208
284
|
| `gate` / `audit`| `agentctl gate --base main --json` | Runs security, secret scanning, and verification gate against current branch. | `0` (Approved), `3` (Scope violation), `5` (Diff limit), `6` (Secret leak) |
|
|
209
285
|
| `bootstrap` | `agentctl bootstrap [--force] [--json]` | Inspects an untested repository and synthesizes `.agent/config.yml` with a zero-test verification oracle (`php -l`, `compileall`, `dotnet build`, `tsc`, `smoke`). | `0` (Bootstrapped / Existing) |
|
|
210
|
-
| `review-repair`| `agentctl review-repair <pr-comments.json>`| Parses GitHub PR review comments and synthesizes actionable OODA repair tasks. | `0` (Parsed), `1` (Missing file) |
|
|
211
286
|
| `queue` | `agentctl queue` | Consumes and executes pending markdown task envelopes in `.agent/queue/`. | `0` (Complete) |
|
|
212
287
|
| `swarm` | `agentctl swarm` | Runs parallel multi-agent swarm across queued tasks with token-bucket concurrency. | `0` (Complete) |
|
|
213
288
|
| `doctor` | `agentctl doctor` | Diagnostic inspect: displays detected stack, container wrapper, test command, and daily session budget. | `0` (Healthy) |
|
|
@@ -215,57 +290,46 @@ In monorepos containing multiple languages, `resolveWorkspaceBoundary(changedFil
|
|
|
215
290
|
| `clean` | `agentctl clean` | Prunes stale git worktrees, lockfiles, and temporary ledgers. | `0` (Clean) |
|
|
216
291
|
| `init` | `agentctl init` | Scaffolds `.agent/` directory structure and default `.agent/config.yml`. | `0` (Created) |
|
|
217
292
|
| `mcp` | `agentctl mcp` | Starts stdio Model Context Protocol (MCP) server for tool integration. | `0` / Stdio stream |
|
|
218
|
-
| `version` | `agentctl version` | Outputs orchestrator kit semantic version (`v0.
|
|
293
|
+
| `version` | `agentctl version` | Outputs orchestrator kit semantic version (`v0.27.0`). | `0` |
|
|
219
294
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
## π Universal Polyglot Support & Stack Detection
|
|
223
|
-
|
|
224
|
-
The table below illustrates the 24+ software ecosystems natively supported by `src/stack-detector.mjs`:
|
|
225
|
-
|
|
226
|
-
```
|
|
227
|
-
Ecosystems Supported:
|
|
228
|
-
βββ PHP / Laravel / WordPress (composer.json, phpunit.xml, pest.php, artisan, wp-cli.yml)
|
|
229
|
-
βββ .NET / C# / F# (*.sln, *.csproj, *.fsproj, global.json)
|
|
230
|
-
βββ Mobile / Dart / Flutter (pubspec.yaml)
|
|
231
|
-
βββ Mobile / Swift / Xcode (Package.swift)
|
|
232
|
-
βββ Mobile / React Native (app.json, react-native.config.js)
|
|
233
|
-
βββ Systems / CMake (CMakeLists.txt)
|
|
234
|
-
βββ Systems / Rust Cargo (Cargo.toml)
|
|
235
|
-
βββ Systems / Go (go.mod)
|
|
236
|
-
βββ Systems / Make (Makefile)
|
|
237
|
-
βββ Python / FastAPI / Django (pyproject.toml, requirements.txt, setup.py)
|
|
238
|
-
βββ Elixir / Phoenix (mix.exs)
|
|
239
|
-
βββ Ruby / Rails (Gemfile)
|
|
240
|
-
βββ Java / Maven (pom.xml)
|
|
241
|
-
βββ Java / Gradle (build.gradle, build.gradle.kts)
|
|
242
|
-
βββ JS / TS Workspaces (turbo.json, pnpm-workspace.yaml, nx.json)
|
|
243
|
-
βββ JS / TS Runtimes (bunfig.toml, deno.json, package.json)
|
|
244
|
-
βββ Devcontainers & Docker Compose (.devcontainer/devcontainer.json, docker-compose.yml, Dockerfile)
|
|
245
|
-
```
|
|
295
|
+
<br/>
|
|
246
296
|
|
|
247
297
|
---
|
|
248
298
|
|
|
299
|
+
<br/>
|
|
300
|
+
|
|
301
|
+
<a id="roadmap"></a>
|
|
249
302
|
## πΊοΈ v0.27+ Next-Gen Feature Roadmap
|
|
250
303
|
|
|
251
304
|
| Feature | Module / Command | Architectural Blueprint | Target Release |
|
|
252
305
|
| :--- | :--- | :--- | :---: |
|
|
253
|
-
| **PR Review Auto-Remediation Loop** | `agentctl review-repair` (`src/review-repair.mjs`) | Ingests GitHub PR review comments (`CHANGES_REQUESTED`), extracts line/file context, and dispatches automated OODA repair turns until reviewer comments are resolved. | **v0.27.0** *(
|
|
254
|
-
| **Multi-Provider Failover Router** | `createFailoverProvider` (`src/provider.mjs`) | Ordered router (`["jules", "claude-code", "local-mcp"]`) that seamlessly falls back to secondary LLMs on HTTP 429 rate limits or 5xx service unavailability. | **v0.27.0** *(
|
|
255
|
-
| **Telemetry & Audit Web Dashboard**| `agentctl dashboard` (`src/dashboard.mjs`) | Zero-dependency local HTTP server displaying real-time DAG execution graphs, Wilson-Score flaky test ledgers, and SHA-256 telemetry chains. | **v0.27.0** |
|
|
306
|
+
| **PR Review Auto-Remediation Loop** | `agentctl review-repair` (`src/review-repair.mjs`) | Ingests GitHub PR review comments (`CHANGES_REQUESTED`), extracts line/file context, and dispatches automated OODA repair turns until reviewer comments are resolved. | **v0.27.0** *(Shipped)* |
|
|
307
|
+
| **Multi-Provider Failover Router** | `createFailoverProvider` (`src/provider.mjs`) | Ordered router (`["jules", "claude-code", "local-mcp"]`) that seamlessly falls back to secondary LLMs on HTTP 429 rate limits or 5xx service unavailability. | **v0.27.0** *(Shipped)* |
|
|
308
|
+
| **Telemetry & Audit Web Dashboard**| `agentctl dashboard` (`src/dashboard.mjs`) | Zero-dependency local HTTP server displaying real-time DAG execution graphs, Wilson-Score flaky test ledgers, and SHA-256 telemetry chains. | **v0.27.0** *(Shipped)* |
|
|
256
309
|
| **Cross-Language Contract Guard** | `hashCrossLanguageInterface` (`src/merge-blocks.mjs`)| Canonical SHA-256 schema hashing for OpenAPI/Protobuf specs across polyglot task dependencies in `DagExecutor`. | **v0.26.0** *(Shipped)* |
|
|
257
310
|
|
|
311
|
+
<br/>
|
|
312
|
+
|
|
258
313
|
---
|
|
259
314
|
|
|
315
|
+
<br/>
|
|
316
|
+
|
|
260
317
|
## π Recipes, Documentation & Prior Art
|
|
261
318
|
|
|
319
|
+
- [**Google Jules Official Documentation**](https://jules.google) β Official platform overview and API specifications for Google Jules.
|
|
320
|
+
- [**Google Labs Code Repositories**](https://github.com/google-labs-code) β Official Google Labs public GitHub organization (jules-action, jules-sdk).
|
|
262
321
|
- [**Universal Polyglot Architecture & Zero-Test Specification**](./docs/UNIVERSAL_POLYGLOT_ARCHITECTURE.md) β Comprehensive technical report on boundary resolution, OODA math, and B2B workflows.
|
|
322
|
+
- [**v0.27.0 Architectural Audit & Platform Evolution**](./docs/V0.27_ARCHITECTURAL_AUDIT_AND_EVOLUTION.md) β PR review remediation, failover router, and local dashboard specs.
|
|
263
323
|
- [**Examples & Task Envelope Recipes**](./EXAMPLES.md) β Production YAML and Markdown task envelopes.
|
|
264
324
|
- [**Adversarial Security Audit Phase 4 Report**](./docs/AUDIT_REPORT.md) β CWE-77, CWE-1321, and CWE-183 security hardening analysis.
|
|
265
325
|
- [**Changelog**](./CHANGELOG.md) β Full release history and migration guides.
|
|
266
326
|
|
|
327
|
+
<br/>
|
|
328
|
+
|
|
267
329
|
---
|
|
268
330
|
|
|
331
|
+
<br/>
|
|
332
|
+
|
|
269
333
|
<div align="center">
|
|
270
334
|
<p><b>jules-orchestrator-kit</b> β’ Built with zero external dependencies for Google Jules and enterprise AI agent swarms.</p>
|
|
271
335
|
</div>
|
package/bin/agentctl.mjs
CHANGED
|
@@ -14,7 +14,7 @@ const command = args[0];
|
|
|
14
14
|
|
|
15
15
|
function printHelp() {
|
|
16
16
|
console.log(`
|
|
17
|
-
π agentctl v0.
|
|
17
|
+
π agentctl v0.27.1 β Universal Agent Orchestrator & Safety Gatekeeper
|
|
18
18
|
|
|
19
19
|
Usage: agentctl <command> [options]
|
|
20
20
|
|
|
@@ -28,6 +28,8 @@ Commands:
|
|
|
28
28
|
lock <action> Manage mutex locks (acquire | release | status | cleanup)
|
|
29
29
|
doctor Run system diagnostics and stack resolution checks
|
|
30
30
|
bootstrap Bootstrap zero-test repository with verification oracle
|
|
31
|
+
review-repair Parse PR review comments and synthesize OODA repair tasks
|
|
32
|
+
dashboard Start local HTTP telemetry and audit dashboard
|
|
31
33
|
init Scaffold .agent/ directory and config.yml
|
|
32
34
|
version Output agentctl version
|
|
33
35
|
|
|
@@ -45,7 +47,7 @@ async function main() {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
if (command === "version" || command === "--version" || command === "-v") {
|
|
48
|
-
console.log("agentctl v0.
|
|
50
|
+
console.log("agentctl v0.27.0");
|
|
49
51
|
process.exit(0);
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -263,6 +265,31 @@ async function main() {
|
|
|
263
265
|
break;
|
|
264
266
|
}
|
|
265
267
|
|
|
268
|
+
case "review-repair": {
|
|
269
|
+
const fileArg = args[1];
|
|
270
|
+
if (!fileArg || !existsSync(fileArg)) {
|
|
271
|
+
console.error("Error: Please provide a valid JSON file containing PR review comments.");
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
const { parseReviewComments, createReviewRepairTask } = await import("../src/review-repair.mjs");
|
|
275
|
+
const raw = readFileSync(fileArg, "utf-8");
|
|
276
|
+
const comments = parseReviewComments(raw);
|
|
277
|
+
console.log(`β
Parsed ${comments.length} actionable review comment(s).`);
|
|
278
|
+
for (const c of comments) {
|
|
279
|
+
const task = createReviewRepairTask(c);
|
|
280
|
+
console.log(` Task: ${task.title} (Author: @${c.author}, Line: ${c.line || "N/A"})`);
|
|
281
|
+
}
|
|
282
|
+
process.exit(0);
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
case "dashboard": {
|
|
287
|
+
const port = Number(args[1] || 4100);
|
|
288
|
+
const { startDashboardServer } = await import("../src/dashboard.mjs");
|
|
289
|
+
startDashboardServer(port, root);
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
|
|
266
293
|
case "init": {
|
|
267
294
|
const agentDir = join(root, ".agent");
|
|
268
295
|
ensureDir(agentDir);
|
package/package.json
CHANGED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-Dependency Local Telemetry & Audit HTTP Dashboard for jules-orchestrator-kit (v0.27.0).
|
|
3
|
+
* Uses node:http to serve real-time HTML/CSS dark mode visualizer and REST JSON endpoints.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import http from "node:http";
|
|
7
|
+
import { readTelemetry, verifyTelemetryIntegrity } from "./telemetry.mjs";
|
|
8
|
+
import { readVerifyRuns, flakyVerdict } from "./flaky-ledger.mjs";
|
|
9
|
+
import { lockStatus } from "./state.mjs";
|
|
10
|
+
|
|
11
|
+
export function getDashboardHtml(root = process.cwd()) {
|
|
12
|
+
return `<!DOCTYPE html>
|
|
13
|
+
<html lang="en">
|
|
14
|
+
<head>
|
|
15
|
+
<meta charset="UTF-8">
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17
|
+
<title>jules-orchestrator-kit Dashboard</title>
|
|
18
|
+
<style>
|
|
19
|
+
body { background-color: #0d1117; color: #c9d1d9; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; padding: 24px; }
|
|
20
|
+
h1 { color: #58a6ff; font-size: 24px; margin-bottom: 8px; }
|
|
21
|
+
.subtitle { color: #8b949e; font-size: 14px; margin-bottom: 24px; }
|
|
22
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; margin-bottom: 24px; }
|
|
23
|
+
.card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 16px; }
|
|
24
|
+
.card h2 { font-size: 16px; color: #f0f6fc; margin-top: 0; border-bottom: 1px solid #21262d; padding-bottom: 8px; }
|
|
25
|
+
table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
26
|
+
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #21262d; }
|
|
27
|
+
th { color: #8b949e; }
|
|
28
|
+
.badge { display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 12px; font-weight: 600; }
|
|
29
|
+
.badge-success { background: rgba(46, 160, 67, 0.15); color: #3fb950; border: 1px solid rgba(46, 160, 67, 0.4); }
|
|
30
|
+
.badge-warn { background: rgba(210, 153, 34, 0.15); color: #d29922; border: 1px solid rgba(210, 153, 34, 0.4); }
|
|
31
|
+
code { font-family: monospace; background: #21262d; padding: 2px 4px; border-radius: 4px; }
|
|
32
|
+
</style>
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
<h1>π jules-orchestrator-kit Dashboard (v0.27.0)</h1>
|
|
36
|
+
<div class="subtitle">Repository: <code>${root}</code></div>
|
|
37
|
+
|
|
38
|
+
<div class="grid">
|
|
39
|
+
<div class="card">
|
|
40
|
+
<h2>π‘οΈ SHA-256 Telemetry Integrity</h2>
|
|
41
|
+
<div id="telemetry-status">Loading...</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="card">
|
|
44
|
+
<h2>βοΈ Wilson-Score Flaky Ledger</h2>
|
|
45
|
+
<div id="flaky-status">Loading...</div>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="card">
|
|
48
|
+
<h2>π Active VFS Mutex Locks</h2>
|
|
49
|
+
<div id="locks-status">Loading...</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<script>
|
|
54
|
+
async function updateDashboard() {
|
|
55
|
+
try {
|
|
56
|
+
const [telRes, flakyRes, locksRes] = await Promise.all([
|
|
57
|
+
fetch('/api/telemetry?limit=10').then(r => r.json()),
|
|
58
|
+
fetch('/api/flaky').then(r => r.json()),
|
|
59
|
+
fetch('/api/locks').then(r => r.json())
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
document.getElementById('telemetry-status').innerHTML = telRes.integrity?.valid
|
|
63
|
+
? '<span class="badge badge-success">β SHA-256 Hash Chain Valid</span> <p>Events logged: ' + telRes.events.length + '</p>'
|
|
64
|
+
: '<span class="badge badge-warn">β Check Telemetry Logs</span>';
|
|
65
|
+
|
|
66
|
+
document.getElementById('flaky-status').innerHTML = '<p>Verdict: <code>' + (flakyRes.verdict?.action || 'CLEAN') + '</code></p><p>Tracked test runs: ' + flakyRes.count + '</p>';
|
|
67
|
+
document.getElementById('locks-status').innerHTML = '<p>Active VFS Locks: <code>' + locksRes.count + '</code></p>';
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error("Dashboard update failed:", err);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
updateDashboard();
|
|
73
|
+
setInterval(updateDashboard, 5000);
|
|
74
|
+
</script>
|
|
75
|
+
</body>
|
|
76
|
+
</html>`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function createDashboardServer({ root = process.cwd(), port: _port = 4100 } = {}) {
|
|
80
|
+
return http.createServer((req, res) => {
|
|
81
|
+
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
82
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
83
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
84
|
+
|
|
85
|
+
if (req.method === "OPTIONS") {
|
|
86
|
+
res.writeHead(204);
|
|
87
|
+
return res.end();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (url.pathname === "/" || url.pathname === "/index.html") {
|
|
91
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
92
|
+
return res.end(getDashboardHtml(root));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (url.pathname === "/api/status") {
|
|
96
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
97
|
+
return res.end(JSON.stringify({ ok: true, version: "0.27.0", root, ts: new Date().toISOString() }));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (url.pathname === "/api/telemetry") {
|
|
101
|
+
const limit = Number(url.searchParams.get("limit") || "50");
|
|
102
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
103
|
+
return res.end(
|
|
104
|
+
JSON.stringify({
|
|
105
|
+
ok: true,
|
|
106
|
+
count: limit,
|
|
107
|
+
integrity: verifyTelemetryIntegrity(root),
|
|
108
|
+
events: readTelemetry(root, limit),
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (url.pathname === "/api/flaky") {
|
|
114
|
+
const runs = readVerifyRuns(root);
|
|
115
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
116
|
+
return res.end(JSON.stringify({ ok: true, count: runs.length, verdict: flakyVerdict(runs), runs }));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (url.pathname === "/api/locks") {
|
|
120
|
+
const locks = lockStatus(root);
|
|
121
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
122
|
+
return res.end(JSON.stringify({ ok: true, count: locks.length, locks }));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
res.writeHead(404, { "Content-Type": "application/json; charset=utf-8" });
|
|
126
|
+
res.end(JSON.stringify({ ok: false, error: "Not Found", path: url.pathname }));
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function startDashboardServer(port = 4100, root = process.cwd()) {
|
|
131
|
+
const server = createDashboardServer({ root, port });
|
|
132
|
+
server.listen(port, "0.0.0.0", () => {
|
|
133
|
+
console.log(`π jules-orchestrator-kit Dashboard running at http://localhost:${port}`);
|
|
134
|
+
});
|
|
135
|
+
return server;
|
|
136
|
+
}
|
package/src/git.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { normalizePath } from "./config.mjs";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
|
|
5
5
|
export const NET_GUARD_PRELOAD_URL = new URL("./preload-net-guard.mjs", import.meta.url).href;
|
|
6
6
|
export const NET_GUARD_FLAG = `--import ${NET_GUARD_PRELOAD_URL}`;
|
|
@@ -173,29 +173,6 @@ export function showFromOrigin(root = process.cwd(), base = "main", filePath = "
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
export function createBranch(root = process.cwd(), branch = "") {
|
|
177
|
-
const opId = journalIntent(root, { type: "create_branch", branch, targetPath: "" });
|
|
178
|
-
try {
|
|
179
|
-
const res = git(["branch", branch], { cwd: root });
|
|
180
|
-
journalDone(root, opId);
|
|
181
|
-
return res;
|
|
182
|
-
} catch (err) {
|
|
183
|
-
journalDone(root, opId);
|
|
184
|
-
throw err;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export function worktreeAdd(root = process.cwd(), branch = "agent/task", targetDir = "") {
|
|
189
|
-
const opId = journalIntent(root, { type: "worktree_add", targetPath: targetDir, branch });
|
|
190
|
-
try {
|
|
191
|
-
const res = git(["worktree", "add", targetDir, "-b", branch], { cwd: root });
|
|
192
|
-
journalDone(root, opId);
|
|
193
|
-
return res;
|
|
194
|
-
} catch (err) {
|
|
195
|
-
journalDone(root, opId);
|
|
196
|
-
throw err;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
176
|
|
|
200
177
|
export function worktreeRemove(root = process.cwd(), targetDir = "") {
|
|
201
178
|
return git(["worktree", "remove", targetDir, "--force"], { cwd: root });
|
package/src/provider.mjs
CHANGED
|
@@ -218,7 +218,6 @@ export function createProvider(spec = "jules", config = {}) {
|
|
|
218
218
|
const rawArgs = providerSpec.args || (providerSpec.command ? providerSpec.command.split(" ").slice(1) : []);
|
|
219
219
|
const command = providerSpec.command ? providerSpec.command.split(" ")[0] : "claude";
|
|
220
220
|
|
|
221
|
-
// CRITICAL H-a FIX: Filter out '{prompt}' argument if prompt is passed via stdin
|
|
222
221
|
const filteredArgs = providerSpec.promptViaStdin
|
|
223
222
|
? rawArgs.filter((arg) => !arg.includes("{prompt}"))
|
|
224
223
|
: rawArgs;
|
|
@@ -228,7 +227,7 @@ export function createProvider(spec = "jules", config = {}) {
|
|
|
228
227
|
const res = spawnSync(command, processedArgs, {
|
|
229
228
|
cwd: config._root || process.cwd(),
|
|
230
229
|
encoding: "utf-8",
|
|
231
|
-
shell: false,
|
|
230
|
+
shell: false,
|
|
232
231
|
input: providerSpec.promptViaStdin ? data.prompt : undefined,
|
|
233
232
|
timeout: providerSpec.timeoutMs || 900000,
|
|
234
233
|
maxBuffer: 32 * 1024 * 1024,
|
|
@@ -259,3 +258,44 @@ export function createProvider(spec = "jules", config = {}) {
|
|
|
259
258
|
},
|
|
260
259
|
};
|
|
261
260
|
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Creates a failover provider router that attempts dispatches sequentially across an ordered array of providers.
|
|
264
|
+
* Intercepts rate limits (429) and 5xx unavailability, logging telemetry events before falling over.
|
|
265
|
+
*/
|
|
266
|
+
export function createFailoverProvider(providers = ["jules"], config = {}) {
|
|
267
|
+
const providerList = (Array.isArray(providers) && providers.length > 0 ? providers : ["jules"]).map((spec) =>
|
|
268
|
+
spec && typeof spec === "object" && typeof spec.dispatch === "function" ? spec : createProvider(spec, config)
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
name: `failover:${providerList.map((p) => p.name).join("->")}`,
|
|
273
|
+
|
|
274
|
+
async dispatch(task, ctx = {}) {
|
|
275
|
+
const errors = [];
|
|
276
|
+
for (let i = 0; i < providerList.length; i++) {
|
|
277
|
+
const provider = providerList[i];
|
|
278
|
+
try {
|
|
279
|
+
const res = await provider.dispatch(task, ctx);
|
|
280
|
+
return { ...res, _routedProvider: provider.name, _failoverAttempts: i };
|
|
281
|
+
} catch (err) {
|
|
282
|
+
errors.push({ provider: provider.name, error: err });
|
|
283
|
+
const isRecoverable =
|
|
284
|
+
err instanceof ProviderRateLimitError ||
|
|
285
|
+
err instanceof ProviderUnavailableError ||
|
|
286
|
+
(err.status && err.status >= 500 && err.status < 600) ||
|
|
287
|
+
err.status === 429;
|
|
288
|
+
|
|
289
|
+
if (i === providerList.length - 1 || !isRecoverable) {
|
|
290
|
+
err._failoverErrors = errors;
|
|
291
|
+
throw err;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
validate() {
|
|
298
|
+
return providerList.every((p) => p.validate());
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR Review Auto-Remediation Engine for jules-orchestrator-kit (v0.27.0).
|
|
3
|
+
* Parses GitHub PR review comments, filters conversational praise/noise,
|
|
4
|
+
* and synthesizes actionable OODA repair task envelopes.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export function parseReviewComments(input) {
|
|
8
|
+
let comments = typeof input === "string" ? (() => { try { return JSON.parse(input); } catch { return []; } })() : input;
|
|
9
|
+
comments = Array.isArray(comments) ? comments : comments?.comments || comments?.reviews || [comments];
|
|
10
|
+
|
|
11
|
+
const actionable = [];
|
|
12
|
+
let idx = 0;
|
|
13
|
+
for (const c of comments) {
|
|
14
|
+
if (!c || typeof c !== "object") continue;
|
|
15
|
+
|
|
16
|
+
const state = String(c.state || c.status || "").toUpperCase();
|
|
17
|
+
if (state === "APPROVED" || state === "DISMISSED" || c.isResolved === true || c.resolved === true) continue;
|
|
18
|
+
|
|
19
|
+
const body = String(c.body || c.comment || "").trim();
|
|
20
|
+
if (body.length < 5) continue;
|
|
21
|
+
|
|
22
|
+
const praiseRegex = /^(?:lgtm|looks good(?: to me)?|nice|awesome|thanks|thank you|great work|approved|ship it)[\s.!]*$/i;
|
|
23
|
+
if (praiseRegex.test(body)) continue;
|
|
24
|
+
|
|
25
|
+
idx++;
|
|
26
|
+
const path = c.path || c.file || null;
|
|
27
|
+
const line = c.line || c.original_line || null;
|
|
28
|
+
const author = c.user?.login || c.author || "reviewer";
|
|
29
|
+
|
|
30
|
+
actionable.push({
|
|
31
|
+
id: String(c.id || `review-${idx}`),
|
|
32
|
+
path,
|
|
33
|
+
line: line ? Number(line) : null,
|
|
34
|
+
author,
|
|
35
|
+
body,
|
|
36
|
+
actionable: true,
|
|
37
|
+
prompt: `Fix PR review comment by @${author} on ${path || "code"}${line ? ` line ${line}` : ""}:\n\n"${body}"\n\nEnsure all unit tests and safety gates pass cleanly after applying fix.`,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return actionable;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function createReviewRepairTask(comment, baseBranch = "main") {
|
|
45
|
+
return {
|
|
46
|
+
id: `repair-${comment.id}`,
|
|
47
|
+
title: `PR Review Repair: ${comment.path || "code"} (${comment.id})`,
|
|
48
|
+
prompt: comment.prompt || `Fix review feedback: ${comment.body}`,
|
|
49
|
+
baseBranch,
|
|
50
|
+
targetFiles: comment.path ? [comment.path] : [],
|
|
51
|
+
metadata: { source: "pr-review", commentId: comment.id, author: comment.author, line: comment.line },
|
|
52
|
+
};
|
|
53
|
+
}
|
package/src/process-group.mjs
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ProcessGroupManager manages child processes in isolated process groups
|
|
5
|
-
* and ensures 100% leak-free cleanup on process exit or termination signals.
|
|
6
|
-
*/
|
|
7
|
-
export class ProcessGroupManager {
|
|
8
|
-
constructor() {
|
|
9
|
-
this.activePgids = new Set();
|
|
10
|
-
this.activePids = new Set();
|
|
11
|
-
this.installed = false;
|
|
12
|
-
this.installSignalHandlers();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
installSignalHandlers() {
|
|
16
|
-
if (this.installed) return;
|
|
17
|
-
this.installed = true;
|
|
18
|
-
|
|
19
|
-
const cleanup = (signal) => {
|
|
20
|
-
this.killAll(signal || "SIGTERM");
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
process.once("SIGINT", () => {
|
|
24
|
-
cleanup("SIGINT");
|
|
25
|
-
process.exit(130);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
process.once("SIGTERM", () => {
|
|
29
|
-
cleanup("SIGTERM");
|
|
30
|
-
process.exit(143);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
process.once("exit", () => {
|
|
34
|
-
this.killAll("SIGKILL");
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
spawnProcess(command, args = [], options = {}) {
|
|
39
|
-
const opts = {
|
|
40
|
-
...options,
|
|
41
|
-
detached: true,
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const child = spawn(command, args, opts);
|
|
45
|
-
|
|
46
|
-
if (child.pid) {
|
|
47
|
-
const pgid = child.pid;
|
|
48
|
-
this.activePgids.add(pgid);
|
|
49
|
-
this.activePids.add(child.pid);
|
|
50
|
-
|
|
51
|
-
child.on("exit", () => {
|
|
52
|
-
this.activePgids.delete(pgid);
|
|
53
|
-
this.activePids.delete(child.pid);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
child.on("error", () => {
|
|
57
|
-
this.activePgids.delete(pgid);
|
|
58
|
-
this.activePids.delete(child.pid);
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return child;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
killAll(signal = "SIGTERM") {
|
|
66
|
-
for (const pgid of this.activePgids) {
|
|
67
|
-
try {
|
|
68
|
-
process.kill(-pgid, signal);
|
|
69
|
-
} catch (_) {
|
|
70
|
-
try {
|
|
71
|
-
process.kill(pgid, signal);
|
|
72
|
-
} catch (_) {}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
this.activePgids.clear();
|
|
76
|
-
this.activePids.clear();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export const processGroupManager = new ProcessGroupManager();
|