feat: branch protection + deps caching

This commit is contained in:
2026-05-31 02:44:12 -05:00
parent d5d2e5b58e
commit 19671c6299
6 changed files with 40 additions and 23 deletions
+19
View File
@@ -11,12 +11,31 @@ const dir = dirname(fileURLToPath(import.meta.url));
if (!existsSync(`${dir}/node_modules`)) { if (!existsSync(`${dir}/node_modules`)) {
console.error("» installing dependencies..."); console.error("» installing dependencies...");
// Try to activate pnpm via corepack (Node 24 ships corepack).
// If that works, use pnpm with the lockfile for a fast, reproducible install.
// Otherwise fall back to plain npm install.
let installed = false;
try {
execSync("corepack enable pnpm", { stdio: "pipe" });
execSync("pnpm install --frozen-lockfile", {
cwd: dir,
stdio: "inherit",
timeout: 120_000,
});
installed = true;
} catch {
// corepack or pnpm not available
}
if (!installed) {
execSync("npm install --no-fund --no-audit", { execSync("npm install --no-fund --no-audit", {
cwd: dir, cwd: dir,
stdio: "inherit", stdio: "inherit",
timeout: 120_000, timeout: 120_000,
}); });
} }
}
const [{ main }, core] = await Promise.all([ const [{ main }, core] = await Promise.all([
import(`${dir}/main.ts`), import(`${dir}/main.ts`),
+11 -13
View File
@@ -169,9 +169,18 @@ export async function main(): Promise<MainResult> {
const modes = computeModes(agentId); const modes = computeModes(agentId);
const outputSchema = resolveOutputSchema(); const outputSchema = resolveOutputSchema();
let defaultBranch = "main";
try {
const repoData = await gitea.request(
"GET /repos/{owner}/{repo}",
{ owner: repoContext.owner, repo: repoContext.name }
);
defaultBranch = (repoData.data as { default_branch?: string }).default_branch ?? "main";
} catch { /* keep "main" fallback */ }
toolContext = { toolContext = {
agentId, agentId,
repo: repoContext, repo: { ...repoContext, defaultBranch },
payload, payload,
gitea, gitea,
gitToken: botToken, gitToken: botToken,
@@ -185,17 +194,6 @@ export async function main(): Promise<MainResult> {
tmpdir, tmpdir,
}; };
let defaultBranch: string | undefined;
try {
const repoData = await gitea.request(
"GET /repos/{owner}/{repo}",
{ owner: repoContext.owner, repo: repoContext.name }
);
defaultBranch = (repoData.data as { default_branch?: string }).default_branch;
} catch {
defaultBranch = "main";
}
await using mcpHttpServer = await startMcpHttpServer(toolContext, { outputSchema }); await using mcpHttpServer = await startMcpHttpServer(toolContext, { outputSchema });
toolContext.mcpServerUrl = mcpHttpServer.url; toolContext.mcpServerUrl = mcpHttpServer.url;
log.info(`» MCP server started at ${mcpHttpServer.url}`); log.info(`» MCP server started at ${mcpHttpServer.url}`);
@@ -205,7 +203,7 @@ export async function main(): Promise<MainResult> {
const instructions = resolveInstructions({ const instructions = resolveInstructions({
payload, payload,
repo: { owner: repoContext.owner, name: repoContext.name, ...(defaultBranch ? { defaultBranch } : {}) }, repo: { owner: repoContext.owner, name: repoContext.name, defaultBranch },
modes, modes,
agentId, agentId,
outputSchema, outputSchema,
+2 -2
View File
@@ -217,7 +217,7 @@ export function classifyPushError(msg: string): PushErrorKind {
const TRANSIENT_RETRY_DELAYS_MS = [2000, 5000]; const TRANSIENT_RETRY_DELAYS_MS = [2000, 5000];
export function PushBranchTool(ctx: ToolContext) { export function PushBranchTool(ctx: ToolContext) {
const defaultBranch = process.env.DEFAULT_BRANCH || "main"; const defaultBranch = ctx.repo.defaultBranch;
const pushPermission = ctx.payload.push; const pushPermission = ctx.payload.push;
return tool({ return tool({
@@ -643,7 +643,7 @@ const DeleteBranch = type({
export function DeleteBranchTool(ctx: ToolContext) { export function DeleteBranchTool(ctx: ToolContext) {
const pushPermission = ctx.payload.push; const pushPermission = ctx.payload.push;
const defaultBranch = process.env.DEFAULT_BRANCH || "main"; const defaultBranch = ctx.repo.defaultBranch;
return tool({ return tool({
name: "delete_branch", name: "delete_branch",
+1 -1
View File
@@ -42,7 +42,7 @@ import { UploadFileTool } from "./upload.ts";
export interface ToolContext { export interface ToolContext {
agentId: "ollama"; agentId: "ollama";
repo: { owner: string; name: string }; repo: { owner: string; name: string; defaultBranch: string };
payload: ResolvedPayload; payload: ResolvedPayload;
gitea: Gitea; gitea: Gitea;
gitToken: string; gitToken: string;
+1 -1
View File
@@ -4,7 +4,7 @@ export function buildShockbotFooter(params?: {
model?: string | undefined; model?: string | undefined;
}): string { }): string {
const modelPart = params?.model ? ` · \`${params.model}\`` : ""; const modelPart = params?.model ? ` · \`${params.model}\`` : "";
return `\n\n<br>\n\n---\n${FOOTER_MARKER}\n*Reviewed by [shockbot](https://git.shockvpn.com)${modelPart}*`; return `\n\n<br>\n\n---\n${FOOTER_MARKER}\n*Reviewed by [shockbot](https://git.shockvpn.com/shockbot)${modelPart}*`;
} }
export function stripExistingFooter(body: string): string { export function stripExistingFooter(body: string): string {
+1 -1
View File
@@ -20,7 +20,7 @@ export function defaultRepoSettings(): RepoSettings {
prepushScript: null, prepushScript: null,
stopScript: null, stopScript: null,
push: "restricted", push: "restricted",
shell: "restricted", shell: "disabled",
prApproveEnabled: false, prApproveEnabled: false,
modeInstructions: {}, modeInstructions: {},
}; };