feat(lanes): add POST /:id/profile/init route (F5)

This commit is contained in:
2026-08-06 11:42:09 +07:00
parent 64c00dea85
commit 5dd4793b88
+29
View File
@@ -47,6 +47,7 @@ const {
removeLaneData,
} = require("../lib/lane-runtime");
const { reapOrphanMcp, capOversizedLogs } = require("../lib/lane-gc");
const { detectNode, scaffoldProfile } = require("../lib/lane-detect");
const router = Router();
const MAX_WORKTREE_DIRECTORY_ATTEMPTS = 50;
@@ -389,6 +390,34 @@ router.post("/:id/mcp/sync", sameOriginGuard, async (req, res) => {
}
});
/**
* Detect a Node.js project at this lane's OWN directory and scaffold
* .ccam/profile/ if one is found — the HTTP equivalent of
* `ccam lanes profile init`, always targeting lane.cwd (never an arbitrary
* path; the CLI's <repo> argument has no meaning here, this lane's own
* directory is the only sensible target). "No Node.js project detected" is
* a normal 200 outcome, not an error — most lanes won't be auto-detectable
* and that's fine, same as every other optional profile declaration.
*/
router.post("/:id/profile/init", sameOriginGuard, (req, res) => {
const lane = lanesLib.getLane(req.params.id);
if (!lane) return res.status(404).json({ error: { code: "ENOLANE", message: "lane not found" } });
const facts = detectNode(lane.cwd);
if (!facts) {
return res.json({ scaffolded: false, reason: "no detectable Node.js project" });
}
try {
const result = scaffoldProfile(lane.cwd, facts, { force: req.body?.force === true });
res.json({ scaffolded: true, written: result.written, todos: result.todos });
} catch (err) {
if (err.code === "EPROFILEEXISTS") {
return res.status(400).json({ error: { code: err.code, message: err.message } });
}
res.status(500).json({ error: { code: err.code || "ERUNTIME", message: err.message } });
}
});
/**
* Whether a named integration (tracker, dev_qc, ci_wait, ...) is turned on
* for this lane — reads .ccam/profile/integrations.env. Read-only, no