Initial commit: SDLC Orchestrator replacing n8n

Lightweight Hono webhook router that receives Gitea events and creates
Coder workspaces for each SDLC stage (analyse, architect, develop,
review, test, rework, release, maintenance). Includes k8s manifests
for deployment and the Coder workspace template moved from babble.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Daniel Samson
2026-04-12 12:44:28 +01:00
co-authored by Claude Opus 4.6
commit 55dee1f2bd
22 changed files with 3521 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
import type { Context } from "hono";
import type { IssueCommentEvent, TaskRequest } from "../types.js";
import type { CoderClient } from "../services/coder.js";
import type { Config } from "../config.js";
/**
* Issue comment created → re-trigger analyst if still in analysis.
*
* Replaces: issue-comment-reply.json
*/
export function issueComment(config: Config, coder: CoderClient) {
return async (c: Context) => {
const event = await c.req.json<IssueCommentEvent>();
if (event.action !== "created") {
return c.text("ignored: not a created event", 200);
}
const commenter = event.comment.user.login;
const botUsernames = [config.botDevUsername, config.botReviewUsername];
if (botUsernames.includes(commenter)) {
return c.text("ignored: bot comment", 200);
}
const labels = event.issue.labels.map((l) => l.name);
const pastAnalysis =
labels.includes("ready-for-architecture") ||
labels.includes("ready-for-development");
if (pastAnalysis) {
return c.text("ignored: issue past analysis stage", 200);
}
const [org, repo] = event.repository.full_name.split("/");
const task: TaskRequest = {
taskType: "analyse",
issueNumber: event.issue.number,
giteaOrg: org,
giteaRepo: repo,
repoCloneUrl: event.repository.clone_url,
giteaToken: config.giteaDevToken,
};
console.log(`[issue-comment] #${task.issueNumber} → re-trigger analyst`);
const workspace = await coder.createWorkspace(task);
console.log(`[issue-comment] workspace created: ${workspace.name}`);
return c.json({ ok: true, workspace: workspace.name });
};
}