Add agent workflows & stuff
Build and Push Next App / quality (push) Failing after 48s
Build and Push Next App / build-next (push) Has been skipped

This commit is contained in:
Gabriel Brown
2026-06-21 21:15:15 -05:00
parent cf7ff2ee4e
commit 2dfa97ee4f
102 changed files with 8488 additions and 161 deletions
+356
View File
@@ -104,6 +104,30 @@ const applicationTables = {
lastCheckedAt: v.optional(v.number()),
lastUpstreamCommit: v.optional(v.string()),
lastForkCommit: v.optional(v.string()),
connectionId: v.optional(v.id('gitConnections')),
githubInstallationId: v.optional(v.string()),
githubRepositoryId: v.optional(v.number()),
upstreamRepositoryId: v.optional(v.number()),
syncStatus: v.optional(
v.union(
v.literal('unknown'),
v.literal('up_to_date'),
v.literal('behind'),
v.literal('ahead'),
v.literal('diverged'),
v.literal('checking'),
v.literal('conflict'),
v.literal('error'),
),
),
upstreamAheadBy: v.optional(v.number()),
forkAheadBy: v.optional(v.number()),
lastMergeBaseCommit: v.optional(v.string()),
lastSyncRunId: v.optional(v.id('syncRuns')),
lastAiReviewId: v.optional(v.id('aiReviews')),
lastGithubRefreshAt: v.optional(v.number()),
lastSuccessfulRefreshAt: v.optional(v.number()),
lastError: v.optional(v.string()),
createdAt: v.number(),
updatedAt: v.number(),
})
@@ -111,6 +135,87 @@ const applicationTables = {
.index('by_owner_status', ['ownerId', 'status'])
.index('by_owner_provider', ['ownerId', 'provider'])
.index('by_upstream', ['provider', 'upstreamOwner', 'upstreamRepo']),
spoonRepositoryStates: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
upstreamFullName: v.string(),
forkFullName: v.string(),
upstreamDefaultBranch: v.string(),
forkDefaultBranch: v.string(),
upstreamHeadSha: v.optional(v.string()),
forkHeadSha: v.optional(v.string()),
mergeBaseSha: v.optional(v.string()),
upstreamAheadBy: v.number(),
forkAheadBy: v.number(),
status: v.union(
v.literal('up_to_date'),
v.literal('behind'),
v.literal('ahead'),
v.literal('diverged'),
v.literal('unknown'),
),
openForkPullRequestCount: v.number(),
openUpstreamPullRequestCount: v.number(),
lastCommitAt: v.optional(v.number()),
rawCompareUrl: v.optional(v.string()),
refreshedAt: v.number(),
createdAt: v.number(),
updatedAt: v.number(),
})
.index('by_spoon', ['spoonId'])
.index('by_owner', ['ownerId'])
.index('by_status', ['ownerId', 'status']),
spoonCommits: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
sha: v.string(),
side: v.union(v.literal('upstream'), v.literal('fork')),
message: v.string(),
authorName: v.optional(v.string()),
authorEmail: v.optional(v.string()),
authorLogin: v.optional(v.string()),
committedAt: v.optional(v.number()),
htmlUrl: v.optional(v.string()),
filesChanged: v.optional(v.number()),
additions: v.optional(v.number()),
deletions: v.optional(v.number()),
createdAt: v.number(),
updatedAt: v.number(),
})
.index('by_spoon_side', ['spoonId', 'side'])
.index('by_owner', ['ownerId'])
.index('by_sha', ['spoonId', 'sha'])
.index('by_committed', ['spoonId', 'committedAt']),
spoonPullRequests: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
githubId: v.number(),
number: v.number(),
repoFullName: v.string(),
scope: v.union(
v.literal('fork'),
v.literal('upstream'),
v.literal('from_fork_to_upstream'),
),
title: v.string(),
state: v.union(v.literal('open'), v.literal('closed'), v.literal('merged')),
draft: v.boolean(),
authorLogin: v.optional(v.string()),
baseRef: v.string(),
headRef: v.string(),
headRepoFullName: v.optional(v.string()),
htmlUrl: v.string(),
createdAtGithub: v.optional(v.number()),
updatedAtGithub: v.optional(v.number()),
mergedAtGithub: v.optional(v.number()),
createdAt: v.number(),
updatedAt: v.number(),
})
.index('by_spoon', ['spoonId'])
.index('by_spoon_scope', ['spoonId', 'scope'])
.index('by_owner', ['ownerId'])
.index('by_github_id', ['githubId'])
.index('by_state', ['spoonId', 'state']),
syncRuns: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
@@ -143,10 +248,113 @@ const applicationTables = {
.index('by_spoon', ['spoonId'])
.index('by_owner_status', ['ownerId', 'status'])
.index('by_created', ['createdAt']),
aiReviews: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
syncRunId: v.optional(v.id('syncRuns')),
model: v.string(),
status: v.union(
v.literal('queued'),
v.literal('running'),
v.literal('completed'),
v.literal('failed'),
),
reviewType: v.union(
v.literal('upstream_update'),
v.literal('manual_prompt'),
v.literal('merge_safety'),
),
inputSummary: v.string(),
outputSummary: v.optional(v.string()),
risk: v.union(
v.literal('unknown'),
v.literal('low'),
v.literal('medium'),
v.literal('high'),
),
compatible: v.boolean(),
requiresHumanReview: v.boolean(),
recommendedAction: v.union(
v.literal('sync'),
v.literal('open_review_pr'),
v.literal('manual_review'),
v.literal('do_not_sync'),
v.literal('unknown'),
),
potentialConflicts: v.optional(v.array(v.string())),
importantFiles: v.optional(v.array(v.string())),
reasoningSummary: v.optional(v.string()),
error: v.optional(v.string()),
createdAt: v.number(),
updatedAt: v.number(),
completedAt: v.optional(v.number()),
})
.index('by_spoon', ['spoonId'])
.index('by_owner', ['ownerId'])
.index('by_status', ['ownerId', 'status'])
.index('by_sync_run', ['syncRunId'])
.index('by_created', ['createdAt']),
spoonSettings: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
autoRefreshEnabled: v.boolean(),
autoReviewEnabled: v.boolean(),
autoSyncEnabled: v.boolean(),
requireAiLowRiskForSync: v.boolean(),
requireCleanCompareForSync: v.boolean(),
ignoredFilePatterns: v.optional(v.array(v.string())),
importantFilePatterns: v.optional(v.array(v.string())),
createdAt: v.number(),
updatedAt: v.number(),
})
.index('by_spoon', ['spoonId'])
.index('by_owner', ['ownerId']),
spoonRemotes: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
label: v.string(),
url: v.string(),
remoteName: v.optional(v.string()),
createdAt: v.number(),
updatedAt: v.number(),
})
.index('by_spoon', ['spoonId'])
.index('by_owner', ['ownerId']),
userAiSettings: defineTable({
userId: v.id('users'),
provider: v.literal('openai'),
encryptedApiKey: v.optional(v.string()),
apiKeyPreview: v.optional(v.string()),
model: v.string(),
reasoningEffort: v.union(
v.literal('none'),
v.literal('minimal'),
v.literal('low'),
v.literal('medium'),
v.literal('high'),
v.literal('xhigh'),
),
createdAt: v.number(),
updatedAt: v.number(),
})
.index('by_user', ['userId'])
.index('by_user_provider', ['userId', 'provider']),
agentRequests: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
agentJobId: v.optional(v.id('agentJobs')),
prompt: v.string(),
requestType: v.optional(
v.union(
v.literal('manual_prompt'),
v.literal('upstream_review'),
v.literal('future_code_change'),
),
),
priority: v.optional(
v.union(v.literal('low'), v.literal('normal'), v.literal('high')),
),
source: v.optional(v.union(v.literal('user'), v.literal('system'))),
status: v.union(
v.literal('draft'),
v.literal('queued'),
@@ -157,6 +365,9 @@ const applicationTables = {
v.literal('cancelled'),
),
targetBranch: v.optional(v.string()),
selectedSecretIds: v.optional(v.array(v.id('spoonSecrets'))),
baseBranch: v.optional(v.string()),
requestedBranchName: v.optional(v.string()),
mergeRequestUrl: v.optional(v.string()),
summary: v.optional(v.string()),
error: v.optional(v.string()),
@@ -167,6 +378,151 @@ const applicationTables = {
.index('by_spoon', ['spoonId'])
.index('by_owner_status', ['ownerId', 'status'])
.index('by_created', ['createdAt']),
spoonSecrets: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
name: v.string(),
encryptedValue: v.string(),
valuePreview: v.optional(v.string()),
description: v.optional(v.string()),
createdAt: v.number(),
updatedAt: v.number(),
})
.index('by_spoon', ['spoonId'])
.index('by_owner', ['ownerId'])
.index('by_name', ['spoonId', 'name']),
spoonAgentSettings: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
enabled: v.boolean(),
defaultBaseBranch: v.optional(v.string()),
branchPrefix: v.string(),
installCommand: v.optional(v.string()),
checkCommand: v.optional(v.string()),
testCommand: v.optional(v.string()),
agentModel: v.string(),
reasoningEffort: v.union(
v.literal('none'),
v.literal('minimal'),
v.literal('low'),
v.literal('medium'),
v.literal('high'),
v.literal('xhigh'),
),
maxJobDurationMs: v.number(),
maxOutputBytes: v.number(),
createdAt: v.number(),
updatedAt: v.number(),
})
.index('by_spoon', ['spoonId'])
.index('by_owner', ['ownerId']),
agentJobs: defineTable({
spoonId: v.id('spoons'),
ownerId: v.id('users'),
agentRequestId: v.id('agentRequests'),
status: v.union(
v.literal('queued'),
v.literal('claimed'),
v.literal('preparing'),
v.literal('running'),
v.literal('checks_running'),
v.literal('changes_ready'),
v.literal('draft_pr_opened'),
v.literal('failed'),
v.literal('cancelled'),
v.literal('timed_out'),
),
prompt: v.string(),
baseBranch: v.string(),
workBranch: v.string(),
githubInstallationId: v.optional(v.string()),
forkOwner: v.string(),
forkRepo: v.string(),
forkUrl: v.string(),
upstreamOwner: v.string(),
upstreamRepo: v.string(),
selectedSecretIds: v.array(v.id('spoonSecrets')),
model: v.string(),
reasoningEffort: v.union(
v.literal('none'),
v.literal('minimal'),
v.literal('low'),
v.literal('medium'),
v.literal('high'),
v.literal('xhigh'),
),
commitSha: v.optional(v.string()),
pullRequestUrl: v.optional(v.string()),
pullRequestNumber: v.optional(v.number()),
summary: v.optional(v.string()),
error: v.optional(v.string()),
claimedBy: v.optional(v.string()),
claimedAt: v.optional(v.number()),
startedAt: v.optional(v.number()),
completedAt: v.optional(v.number()),
createdAt: v.number(),
updatedAt: v.number(),
})
.index('by_owner', ['ownerId'])
.index('by_spoon', ['spoonId'])
.index('by_request', ['agentRequestId'])
.index('by_status', ['status'])
.index('by_claim', ['status', 'createdAt']),
agentJobEvents: defineTable({
jobId: v.id('agentJobs'),
spoonId: v.id('spoons'),
ownerId: v.id('users'),
level: v.union(
v.literal('debug'),
v.literal('info'),
v.literal('warn'),
v.literal('error'),
),
phase: v.union(
v.literal('queued'),
v.literal('clone'),
v.literal('plan'),
v.literal('edit'),
v.literal('install'),
v.literal('check'),
v.literal('test'),
v.literal('commit'),
v.literal('push'),
v.literal('pr'),
v.literal('cleanup'),
),
message: v.string(),
metadata: v.optional(v.string()),
createdAt: v.number(),
})
.index('by_job', ['jobId'])
.index('by_spoon', ['spoonId'])
.index('by_owner', ['ownerId']),
agentJobArtifacts: defineTable({
jobId: v.id('agentJobs'),
spoonId: v.id('spoons'),
ownerId: v.id('users'),
kind: v.union(
v.literal('plan'),
v.literal('diff'),
v.literal('test_output'),
v.literal('summary'),
v.literal('error'),
v.literal('pr_body'),
),
title: v.string(),
content: v.string(),
contentType: v.union(
v.literal('text/markdown'),
v.literal('text/plain'),
v.literal('application/json'),
v.literal('text/x-diff'),
),
createdAt: v.number(),
})
.index('by_job', ['jobId'])
.index('by_spoon', ['spoonId'])
.index('by_owner', ['ownerId']),
};
export default defineSchema({