jules-orchestrator-kit 0.26.1 β 0.27.0
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 +30 -4
- package/bin/agentctl.mjs +29 -2
- package/package.json +1 -1
- package/src/dashboard.mjs +136 -0
- package/src/provider.mjs +42 -2
- package/src/review-repair.mjs +53 -0
package/README.md
CHANGED
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
<p align="center">
|
|
20
20
|
<a href="#-2-sentence-mental-model">π‘ What is Kit?</a> β’
|
|
21
21
|
<a href="#-universal-30-second-quickstart-zero-to-verified-pr">β‘ 30s Quickstart</a> β’
|
|
22
|
+
<a href="#-triage-guidelines-when-to-use-vs-when-not-to-use">π― Triage Guidelines</a> β’
|
|
22
23
|
<a href="#-feature-comparison-matrix">π Comparison Matrix</a> β’
|
|
23
24
|
<a href="#-system-architecture--visual-diagrams">ποΈ Architecture</a> β’
|
|
24
25
|
<a href="#-cli-command-reference-agentctl">π οΈ CLI Reference</a> β’
|
|
25
|
-
<a href="#-v027-next-gen-feature-roadmap">πΊοΈ Roadmap</a>
|
|
26
|
-
<a href="./docs/UNIVERSAL_POLYGLOT_ARCHITECTURE.md">π Polyglot Spec</a>
|
|
26
|
+
<a href="#-v027-next-gen-feature-roadmap">πΊοΈ Roadmap</a>
|
|
27
27
|
</p>
|
|
28
28
|
|
|
29
29
|
</div>
|
|
@@ -52,6 +52,25 @@ Autonomous coding agents can write software at 100Γ human speedβbut unconstra
|
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
|
55
|
+
## π― Triage Guidelines: When to Use vs. When NOT to Use
|
|
56
|
+
|
|
57
|
+
To ensure maximum merge success, dispatch tasks according to our deterministic triage boundaries:
|
|
58
|
+
|
|
59
|
+
### π’ Ideal Tasks for Autonomous Swarms
|
|
60
|
+
- β
**Scoped Code Changes & Bug Fixes:** Well-defined objectives mechanically verifiable via unit tests (`npm test`, `pytest`, `cargo test`, `dotnet test`).
|
|
61
|
+
- β
**Type & Linter Migrations:** TypeScript strict mode fixes, PHP 8.3 type hint additions, or Python MyPy type annotation passes.
|
|
62
|
+
- β
**Dependency Bumps & Security Audits:** Remediating CVEs in lockfiles (`package.json`, `Cargo.toml`, `composer.json`) with hermetic test verification.
|
|
63
|
+
- β
**Refactoring Legacy Codebases:** Modularizing backend routes, API controllers, or database query layers.
|
|
64
|
+
- β
**Visual & E2E Testing (via Playwright):** UI changes paired with automated headless Playwright snapshot tests (`npx playwright test`).
|
|
65
|
+
|
|
66
|
+
### π΄ When NOT to Use (Out of Scope)
|
|
67
|
+
- β **Unverifiable Visual UI Tweaks:** Pixel-perfect CSS/Tailwind adjustments lacking automated visual regression tests (agents cannot "see" raw browser output without Playwright).
|
|
68
|
+
- β **Closed Proprietary Platforms Without CLI:** Systems lacking local CLI tools or git repositories (e.g., Salesforce, Webflow, closed SAP backends).
|
|
69
|
+
- β **Unmocked Live Cloud Systems:** Code requiring live connections to 10+ external cloud APIs without local emulators or mocks.
|
|
70
|
+
- β **Protected Infrastructure Paths:** Direct edits to `.github/workflows/`, production deployment keys, or agent security gate rules (enforced fail-closed by `Agent Scope Guard`).
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
55
74
|
## π Feature Comparison Matrix
|
|
56
75
|
|
|
57
76
|
| Dimension | Raw Agent Execution (No Orchestrator) | Standard CI/CD Pipelines | `jules-orchestrator-kit` (v0.26+) |
|
|
@@ -100,7 +119,14 @@ npx jules-orchestrator-kit dispatch --title "Implement OrderService caching" \
|
|
|
100
119
|
--prompt "Add IMemoryCache caching to OrderService.cs with xUnit coverage."
|
|
101
120
|
```
|
|
102
121
|
|
|
103
|
-
### 5οΈβ£
|
|
122
|
+
### 5οΈβ£ UI / Frontend E2E (Playwright)
|
|
123
|
+
```bash
|
|
124
|
+
# Dispatch frontend task verified via headless Playwright E2E tests
|
|
125
|
+
npx jules-orchestrator-kit dispatch --title "Add Dark Mode Toggle Component" \
|
|
126
|
+
--prompt "Create ThemeToggle component in src/components/ThemeToggle.tsx and verify via npx playwright test."
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 6οΈβ£ Polyglot Monorepo (FastAPI + React + Rust CLI)
|
|
104
130
|
```bash
|
|
105
131
|
# Run a parallel worktree swarm; changed files automatically route to scoped subproject tests
|
|
106
132
|
npx jules-orchestrator-kit swarm
|
|
@@ -189,7 +215,7 @@ In monorepos containing multiple languages, `resolveWorkspaceBoundary(changedFil
|
|
|
189
215
|
| `clean` | `agentctl clean` | Prunes stale git worktrees, lockfiles, and temporary ledgers. | `0` (Clean) |
|
|
190
216
|
| `init` | `agentctl init` | Scaffolds `.agent/` directory structure and default `.agent/config.yml`. | `0` (Created) |
|
|
191
217
|
| `mcp` | `agentctl mcp` | Starts stdio Model Context Protocol (MCP) server for tool integration. | `0` / Stdio stream |
|
|
192
|
-
| `version` | `agentctl version` | Outputs orchestrator kit semantic version (`v0.26.
|
|
218
|
+
| `version` | `agentctl version` | Outputs orchestrator kit semantic version (`v0.26.1`). | `0` |
|
|
193
219
|
|
|
194
220
|
---
|
|
195
221
|
|
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.0 β 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/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
|
+
}
|