Merge RepoSettings into Repo (#248)

* Merge RepoSettings into Repo

Inline all RepoSettings fields (triggers, tools, instructions, scripts,
defaultAgent) directly into the Repo model. Pivot Macro/Mode foreign keys
from repoSettingsId to repoId. Drop the repo_settings table entirely.

Migration backfills all existing data safely.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Remove dead null-coalescing and defaultSettings fallback

All settings fields are now NOT NULL on Repo, so ?? fallbacks in
run-context are unnecessary. initialSettings is non-nullable, so
the defaultSettings memo in RepoConsole was dead code.

Co-authored-by: Cursor <cursoragent@cursor.com>

* drop dead /workflows route, extract getAuthenticatedRepoContext helper

- delete /api/repo/[owner]/[repo]/workflows/ (duplicate of /modes/, no consumers)
- extract shared auth helper that returns { account, owner, repo, token, dbRepo, role }
- update settings, macros, modes routes to use the helper

Co-authored-by: Cursor <cursoragent@cursor.com>

* type-safe API route returns via inferred NextResponse generics

- add ApiResponse<T> utility type that extracts JSON body from route handlers
- remove explicit return type annotations and dead interfaces from 5 routes
- update 3 routes with existing type exports to use ApiResponse<typeof handler>
- narrow error union in ReposTable fetchRepos

Co-authored-by: Cursor <cursoragent@cursor.com>

* run tests on push in addition to pull_request

Co-authored-by: Cursor <cursoragent@cursor.com>

* add rule: no --trailer flags on git commits

Co-authored-by: Cursor <cursoragent@cursor.com>

* move git trailer rule into Rules section

Co-authored-by: Cursor <cursoragent@cursor.com>

* consolidate Learnings into Rules section

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Colin McDonnell
2026-02-09 20:46:34 +00:00
committed by pullfrog[bot]
parent 60da0e5749
commit 623e11c7ce
2 changed files with 32 additions and 18 deletions
+14 -7
View File
@@ -41449,28 +41449,35 @@ async function getIsCancelled(params) {
}
log.info("[post] no cancellation found, assuming failure");
} catch (error2) {
log.warning(`[post] failed to get job status: ${error2 instanceof Error ? error2.message : String(error2)}`);
log.warning(
`[post] failed to get job status: ${error2 instanceof Error ? error2.message : String(error2)}`
);
}
return false;
}
async function runPostCleanup() {
log.info("\xBB [post] starting post cleanup");
const runIdStr = process.env.GITHUB_RUN_ID;
if (!runIdStr)
return log.info("\xBB [post] no GITHUB_RUN_ID available, skipping cleanup");
if (!runIdStr) return log.info("\xBB [post] no GITHUB_RUN_ID available, skipping cleanup");
let promptInput = null;
try {
const resolved = resolvePromptInput();
if (typeof resolved !== "string") promptInput = resolved;
} catch (error2) {
log.warning(`[post] failed to resolve prompt input: ${error2 instanceof Error ? error2.message : String(error2)}`);
log.warning(
`[post] failed to resolve prompt input: ${error2 instanceof Error ? error2.message : String(error2)}`
);
}
const token = getJobToken();
const repoContext = parseRepoContext();
const octokit = createOctokit(token);
const commentId = await validateStuckProgressComment(promptInput, octokit, repoContext.owner, repoContext.name);
if (!commentId)
return log.info("\xBB [post] no stuck progress comment to update, skipping cleanup");
const commentId = await validateStuckProgressComment(
promptInput,
octokit,
repoContext.owner,
repoContext.name
);
if (!commentId) return log.info("\xBB [post] no stuck progress comment to update, skipping cleanup");
log.info(`\xBB [post] validated stuck comment: ${commentId}, updating with error message`);
try {
const body = buildErrorCommentBody({
+18 -11
View File
@@ -68,8 +68,8 @@ async function validateStuckProgressComment(
* While the job is still in_progress, the individual steps may have their conclusions set.
*/
async function getIsCancelled(params: {
repoContext: ReturnType<typeof parseRepoContext>,
octokit: ReturnType<typeof createOctokit>,
repoContext: ReturnType<typeof parseRepoContext>;
octokit: ReturnType<typeof createOctokit>;
runIdStr: string;
}): Promise<boolean> {
try {
@@ -85,7 +85,7 @@ async function getIsCancelled(params: {
// So we match jobs that START with the job ID
const currentJobName = process.env.GITHUB_JOB;
const currentJob = currentJobName
? jobs.jobs.find(j => j.name === currentJobName || j.name.startsWith(`${currentJobName} (`))
? jobs.jobs.find((j) => j.name === currentJobName || j.name.startsWith(`${currentJobName} (`))
: jobs.jobs[0]; // fallback to first job
if (!currentJob) {
@@ -97,14 +97,16 @@ async function getIsCancelled(params: {
if (currentJob.conclusion === "cancelled") return true; // whole job explicit cancellation
// but if it's still null, check steps for cancellation:
const cancelledStep = currentJob.steps?.find(step => step.conclusion === "cancelled");
const cancelledStep = currentJob.steps?.find((step) => step.conclusion === "cancelled");
if (cancelledStep) {
log.info(`[post] found cancelled step: ${cancelledStep.name}`);
return true;
}
log.info("[post] no cancellation found, assuming failure");
} catch (error) {
log.warning(`[post] failed to get job status: ${error instanceof Error ? error.message : String(error)}`);
log.warning(
`[post] failed to get job status: ${error instanceof Error ? error.message : String(error)}`
);
}
return false; // assuming failure
}
@@ -114,8 +116,7 @@ async function runPostCleanup(): Promise<void> {
const runIdStr = process.env.GITHUB_RUN_ID;
if (!runIdStr)
return log.info("» [post] no GITHUB_RUN_ID available, skipping cleanup");
if (!runIdStr) return log.info("» [post] no GITHUB_RUN_ID available, skipping cleanup");
// resolve prompt input once and use it for both issue number and comment ID extraction
// only use the object form (JSON payload), not plain string prompts
@@ -124,7 +125,9 @@ async function runPostCleanup(): Promise<void> {
const resolved = resolvePromptInput();
if (typeof resolved !== "string") promptInput = resolved;
} catch (error) {
log.warning(`[post] failed to resolve prompt input: ${error instanceof Error ? error.message : String(error)}`);
log.warning(
`[post] failed to resolve prompt input: ${error instanceof Error ? error.message : String(error)}`
);
}
// get job token for API calls
@@ -133,10 +136,14 @@ async function runPostCleanup(): Promise<void> {
const octokit = createOctokit(token);
// validate that progressCommentId from prompt input is stuck on "Leaping into action"
const commentId = await validateStuckProgressComment(promptInput, octokit, repoContext.owner, repoContext.name);
const commentId = await validateStuckProgressComment(
promptInput,
octokit,
repoContext.owner,
repoContext.name
);
if (!commentId)
return log.info("» [post] no stuck progress comment to update, skipping cleanup");
if (!commentId) return log.info("» [post] no stuck progress comment to update, skipping cleanup");
log.info(`» [post] validated stuck comment: ${commentId}, updating with error message`);