@arungeorgesaji/assembly 0.1.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.
@@ -0,0 +1,33 @@
1
+ import { validateAgentProfiles } from "./agent-profiles.js";
2
+ import { validateScope } from "./scope.js";
3
+
4
+ export function validatePlan(plan) {
5
+ const errors = [];
6
+ const taskIds = new Set(plan.tasks.map((task) => task.id));
7
+
8
+ if (plan.tasks.length === 0) {
9
+ errors.push("plan must include at least one task");
10
+ }
11
+
12
+ for (const task of plan.tasks) {
13
+ if (!task.id) {
14
+ errors.push("task id cannot be empty");
15
+ }
16
+ if (!task.owner) {
17
+ errors.push(`task ${task.id} must have an owner`);
18
+ }
19
+ if (task.acceptanceCriteria.length === 0) {
20
+ errors.push(`task ${task.id} must include acceptance criteria`);
21
+ }
22
+ errors.push(...validateScope(task.scope, task.id));
23
+ for (const dependency of task.dependencies) {
24
+ if (!taskIds.has(dependency)) {
25
+ errors.push(`task ${task.id} depends on unknown task ${dependency}`);
26
+ }
27
+ }
28
+ }
29
+
30
+ errors.push(...validateAgentProfiles(plan));
31
+
32
+ return errors;
33
+ }
@@ -0,0 +1,51 @@
1
+ import { spawn } from "node:child_process";
2
+
3
+ export async function runVerificationCommands(commands, rootDir = process.cwd()) {
4
+ const results = [];
5
+
6
+ for (const command of commands) {
7
+ const result = await runCommand(command, rootDir);
8
+ results.push(result);
9
+ if (result.exitCode !== 0) {
10
+ break;
11
+ }
12
+ }
13
+
14
+ return results;
15
+ }
16
+
17
+ function runCommand(command, rootDir) {
18
+ return new Promise((resolve) => {
19
+ const child = spawn(command, {
20
+ cwd: rootDir,
21
+ shell: true,
22
+ env: process.env,
23
+ });
24
+ let stdout = "";
25
+ let stderr = "";
26
+
27
+ child.stdout.on("data", (chunk) => {
28
+ stdout += chunk;
29
+ });
30
+ child.stderr.on("data", (chunk) => {
31
+ stderr += chunk;
32
+ });
33
+ child.on("error", (error) => {
34
+ resolve({
35
+ command,
36
+ exitCode: 1,
37
+ stdout,
38
+ stderr: error.message,
39
+ });
40
+ });
41
+ child.on("close", (exitCode) => {
42
+ resolve({
43
+ command,
44
+ exitCode,
45
+ stdout,
46
+ stderr,
47
+ });
48
+ });
49
+ });
50
+ }
51
+
@@ -0,0 +1,64 @@
1
+ import http from "node:http";
2
+
3
+ import { loadEnv } from "./config.js";
4
+ import { handleGitHubWebhook } from "./github-webhooks.js";
5
+ import { processJob } from "./job-worker.js";
6
+ import { handleSlackWebhook } from "./slack-webhooks.js";
7
+
8
+ export function startWebhookServer({ port = 3000, host = "127.0.0.1", rootDir = process.cwd(), processJobs = true } = {}) {
9
+ const server = http.createServer(async (request, response) => {
10
+ await loadEnv(rootDir);
11
+
12
+ if (request.method !== "POST" || !["/github/webhook", "/slack/events"].includes(request.url)) {
13
+ response.writeHead(404, { "Content-Type": "application/json" });
14
+ response.end(JSON.stringify({ error: "not found" }));
15
+ return;
16
+ }
17
+
18
+ const rawBody = await readRequestBody(request);
19
+ const result = await routeWebhook(request, rawBody, rootDir).catch((error) => {
20
+ console.error(`webhook error: ${error.stack ?? error.message}`);
21
+ return { status: 500, body: { error: error.message } };
22
+ });
23
+
24
+ response.writeHead(result.status, { "Content-Type": "application/json" });
25
+ response.end(JSON.stringify(result.body));
26
+
27
+ if (processJobs && result.body?.queued && result.body.jobId) {
28
+ setImmediate(() => {
29
+ processJob(result.body.jobId, { rootDir }).catch((error) => {
30
+ console.error(`job ${result.body.jobId} failed: ${error.stack ?? error.message}`);
31
+ });
32
+ });
33
+ }
34
+ });
35
+
36
+ server.listen(port, host);
37
+ return server;
38
+ }
39
+
40
+ function routeWebhook(request, rawBody, rootDir) {
41
+ if (request.url === "/github/webhook") {
42
+ return handleGitHubWebhook({
43
+ event: request.headers["x-github-event"],
44
+ delivery: request.headers["x-github-delivery"],
45
+ signature: request.headers["x-hub-signature-256"],
46
+ rawBody,
47
+ }, rootDir);
48
+ }
49
+
50
+ return handleSlackWebhook({
51
+ signature: request.headers["x-slack-signature"],
52
+ timestamp: request.headers["x-slack-request-timestamp"],
53
+ rawBody,
54
+ }, rootDir);
55
+ }
56
+
57
+ function readRequestBody(request) {
58
+ return new Promise((resolve, reject) => {
59
+ const chunks = [];
60
+ request.on("data", (chunk) => chunks.push(chunk));
61
+ request.on("error", reject);
62
+ request.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
63
+ });
64
+ }