feat(lanes): add POST /api/lanes/gc route (F4)

This commit is contained in:
2026-08-06 09:31:42 +07:00
parent e7ef7bcef9
commit e32c684bf0
+18
View File
@@ -46,6 +46,7 @@ const {
resetLaneData, resetLaneData,
removeLaneData, removeLaneData,
} = require("../lib/lane-runtime"); } = require("../lib/lane-runtime");
const { reapOrphanMcp, capOversizedLogs } = require("../lib/lane-gc");
const router = Router(); const router = Router();
const MAX_WORKTREE_DIRECTORY_ATTEMPTS = 50; const MAX_WORKTREE_DIRECTORY_ATTEMPTS = 50;
@@ -174,6 +175,23 @@ router.post("/ensure", sameOriginGuard, (req, res) => {
} }
}); });
/**
* Machine-wide housekeeping — not scoped to one lane. Reaps orphaned
* Playwright MCP processes and caps oversized hook logs across every lane
* on this machine. See server/lib/lane-gc.js for what "orphaned" and
* "oversized" mean.
*/
router.post("/gc", sameOriginGuard, (req, res) => {
const dryRun = req.body?.dryRun === true;
try {
const reaped = reapOrphanMcp({ dryRun });
const capped = capOversizedLogs({ dryRun });
res.json({ reaped, capped });
} catch (err) {
res.status(500).json({ error: { code: err.code || "ERUNTIME", message: err.message } });
}
});
router.get("/:id", (req, res) => { router.get("/:id", (req, res) => {
const lane = lanesLib.getLane(req.params.id); const lane = lanesLib.getLane(req.params.id);
if (!lane) return res.status(404).json({ error: { code: "ENOLANE", message: "lane not found" } }); if (!lane) return res.status(404).json({ error: { code: "ENOLANE", message: "lane not found" } });