Skip to content

Commit 3de3a5d

Browse files
authored
feat: implemented dashboard v2 and assistant (#7)
* feat: implemented dashboard v2 * fix: handle optional github installation * fix: gracefully fallback without git key path * fix: added missing color-scheme tag * feat: persist agent events and added chat history * test: added chat history coverage * feat: adjusted chat interface * refactor: persist agent events and database * feat: added model selector in chat interface * fix: split persisted state at entry boundaries * feat: auto-title chat session with auxiliary * feat: re-aligned colour scheme with hermes * feat: standardised app header sizing
1 parent 4e4c256 commit 3de3a5d

61 files changed

Lines changed: 3367 additions & 369 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,14 @@ GIT_AUTHOR_NAME=Hermes Agent
115115
GIT_AUTHOR_EMAIL=hermes@users.noreply.github.com
116116
# Branch name template; {issue} is replaced with the issue number.
117117
BRANCH_PREFIX=hermes/issue-
118+
# Optional dedicated SSH deploy key for cloning/pushing DASHBOARD-origin jobs (created from
119+
# the UI) against an SSH remote. Leave UNSET to use the host's own SSH setup (ssh-agent,
120+
# ~/.ssh/config, default keys) exactly as a normal `git clone git@…` would — this is the
121+
# usual case when the orchestrator runs on a host that already has repo access. Set it only
122+
# to force an isolated key (it then ignores the host agent via IdentitiesOnly). Powerful — it
123+
# can push to any repo it's authorised for; mount it read-only and never expose it to the
124+
# agent container (git runs on the orchestrator host, not the agent sandbox).
125+
#GIT_SSH_KEY_PATH=/home/youruser/.ssh/olympian_deploy_key
118126

119127
# ── Sandbox ──────────────────────────────────────────────────────────────────
120128
# none = run hermes as a local subprocess using the system Hermes binary.

api/.hermes/config.base.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ delegation:
4040
# Per delegate_task subagent wall-clock cap. Hermes' default is 600s (10 min) — too short for the
4141
# substantial subtasks our agents delegate (e.g. "fix all build errors") on slow local inference,
4242
# where a child steadily making progress (~30s/API call) gets killed mid-work.
43-
child_timeout_seconds: 3600
43+
child_timeout_seconds: 7200
4444

4545
agent:
4646
max_turns: 1000 # default is 90; complex IMPLEMENT/REVISE jobs need far more — HERMES_TIMEOUT_MS is the real backstop

api/.hermes/plugins/persist_state/__init__.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
_FINDINGS_HEADER = "## Findings"
3434
_FINDINGS_BUDGET = 50_000 # max chars kept in Findings (drop oldest beyond this)
3535
_ENTRY_CAP = 12_000 # max chars of any single subagent report (holds a thorough survey whole)
36+
_TRIM_MARKER = "_…older findings trimmed…_"
37+
# Matches the start of each Findings entry ("### 12. …") so trimming drops whole entries.
38+
_ENTRY_START_RE = _re.compile(r"(?m)^### \d+\.")
3639

3740
_LOCK = threading.Lock()
3841
_STATE: dict[str, Any] = {
@@ -86,10 +89,35 @@ def _split(text: str) -> tuple[str, str]:
8689
return checklist, findings
8790

8891

89-
def _write(checklist: str, findings: str) -> None:
92+
def _trim_findings(findings: str) -> str:
93+
"""Cap Findings at _FINDINGS_BUDGET by dropping the OLDEST WHOLE entries (### N. blocks),
94+
never slicing mid-entry — a half-cut code block fed back to the agent is worse than missing
95+
history. Keeps as many newest entries as fit, with a marker noting older ones were dropped."""
9096
findings = findings.strip()
91-
if len(findings) > _FINDINGS_BUDGET:
92-
findings = "_…older findings trimmed…_\n\n" + findings[-_FINDINGS_BUDGET:].lstrip()
97+
if len(findings) <= _FINDINGS_BUDGET:
98+
return findings
99+
100+
marker = f"{_TRIM_MARKER}\n\n"
101+
budget = _FINDINGS_BUDGET - len(marker)
102+
starts = [m.start() for m in _ENTRY_START_RE.finditer(findings)]
103+
104+
# No recognisable entry boundaries — fall back to a hard tail slice (best effort).
105+
if not starts:
106+
return marker + findings[-budget:].lstrip()
107+
108+
# Earliest entry whose tail fits the budget; always keep at least the last entry
109+
# (each is capped at ~_ENTRY_CAP, so the newest entry alone comfortably fits).
110+
kept = starts[-1]
111+
for s in starts:
112+
if len(findings) - s <= budget:
113+
kept = s
114+
break
115+
116+
return marker + findings[kept:].lstrip()
117+
118+
119+
def _write(checklist: str, findings: str) -> None:
120+
findings = _trim_findings(findings)
93121
body = (
94122
f"{_CHECKLIST_HEADER}\n{checklist or '_(no checklist yet)_'}\n\n"
95123
f"{_FINDINGS_HEADER}\n{findings or '_(none yet)_'}\n"
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
-- CreateTable
2+
CREATE TABLE "ChatSession" (
3+
"id" TEXT NOT NULL PRIMARY KEY,
4+
"title" TEXT NOT NULL,
5+
"repoUrl" TEXT,
6+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
7+
"updatedAt" DATETIME NOT NULL
8+
);
9+
10+
-- CreateTable
11+
CREATE TABLE "ChatMessage" (
12+
"id" TEXT NOT NULL PRIMARY KEY,
13+
"sessionId" TEXT NOT NULL,
14+
"role" TEXT NOT NULL,
15+
"content" TEXT NOT NULL,
16+
"agentRunId" TEXT,
17+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
18+
CONSTRAINT "ChatMessage_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "ChatSession" ("id") ON DELETE CASCADE ON UPDATE CASCADE
19+
);
20+
21+
-- RedefineTables
22+
PRAGMA defer_foreign_keys=ON;
23+
PRAGMA foreign_keys=OFF;
24+
CREATE TABLE "new_AgentRun" (
25+
"id" TEXT NOT NULL PRIMARY KEY,
26+
"jobId" TEXT,
27+
"sessionId" TEXT,
28+
"phase" TEXT NOT NULL,
29+
"command" TEXT NOT NULL,
30+
"cwd" TEXT NOT NULL,
31+
"model" TEXT,
32+
"status" TEXT NOT NULL DEFAULT 'RUNNING',
33+
"exitCode" INTEGER,
34+
"stdout" TEXT,
35+
"stderr" TEXT,
36+
"durationMs" INTEGER,
37+
"judgePassed" BOOLEAN,
38+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
39+
CONSTRAINT "AgentRun_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "Job" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
40+
CONSTRAINT "AgentRun_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "ChatSession" ("id") ON DELETE CASCADE ON UPDATE CASCADE
41+
);
42+
INSERT INTO "new_AgentRun" ("command", "createdAt", "cwd", "durationMs", "exitCode", "id", "jobId", "judgePassed", "model", "phase", "status", "stderr", "stdout") SELECT "command", "createdAt", "cwd", "durationMs", "exitCode", "id", "jobId", "judgePassed", "model", "phase", "status", "stderr", "stdout" FROM "AgentRun";
43+
DROP TABLE "AgentRun";
44+
ALTER TABLE "new_AgentRun" RENAME TO "AgentRun";
45+
CREATE INDEX "AgentRun_jobId_idx" ON "AgentRun"("jobId");
46+
CREATE INDEX "AgentRun_sessionId_idx" ON "AgentRun"("sessionId");
47+
CREATE TABLE "new_Job" (
48+
"id" TEXT NOT NULL PRIMARY KEY,
49+
"installationId" TEXT,
50+
"repoOwner" TEXT,
51+
"repoName" TEXT,
52+
"repoFullName" TEXT,
53+
"issueNumber" INTEGER,
54+
"issueTitle" TEXT NOT NULL,
55+
"issueBody" TEXT NOT NULL,
56+
"triggerLabel" TEXT,
57+
"origin" TEXT NOT NULL DEFAULT 'GITHUB',
58+
"repoUrl" TEXT,
59+
"state" TEXT NOT NULL DEFAULT 'TRIAGED',
60+
"branchName" TEXT,
61+
"prNumber" INTEGER,
62+
"headSha" TEXT,
63+
"confidence" INTEGER,
64+
"verifyCommand" TEXT,
65+
"reviewCycle" INTEGER NOT NULL DEFAULT 0,
66+
"attempts" INTEGER NOT NULL DEFAULT 0,
67+
"error" TEXT,
68+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
69+
"updatedAt" DATETIME NOT NULL,
70+
CONSTRAINT "Job_installationId_fkey" FOREIGN KEY ("installationId") REFERENCES "RepoInstallation" ("id") ON DELETE SET NULL ON UPDATE CASCADE
71+
);
72+
INSERT INTO "new_Job" ("attempts", "branchName", "confidence", "createdAt", "error", "headSha", "id", "installationId", "issueBody", "issueNumber", "issueTitle", "prNumber", "repoFullName", "repoName", "repoOwner", "reviewCycle", "state", "triggerLabel", "updatedAt", "verifyCommand") SELECT "attempts", "branchName", "confidence", "createdAt", "error", "headSha", "id", "installationId", "issueBody", "issueNumber", "issueTitle", "prNumber", "repoFullName", "repoName", "repoOwner", "reviewCycle", "state", "triggerLabel", "updatedAt", "verifyCommand" FROM "Job";
73+
DROP TABLE "Job";
74+
ALTER TABLE "new_Job" RENAME TO "Job";
75+
CREATE INDEX "Job_state_idx" ON "Job"("state");
76+
CREATE INDEX "Job_repoFullName_state_idx" ON "Job"("repoFullName", "state");
77+
CREATE UNIQUE INDEX "Job_repoFullName_issueNumber_key" ON "Job"("repoFullName", "issueNumber");
78+
PRAGMA foreign_keys=ON;
79+
PRAGMA defer_foreign_keys=OFF;
80+
81+
-- CreateIndex
82+
CREATE INDEX "ChatMessage_sessionId_idx" ON "ChatMessage"("sessionId");
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-- CreateTable
2+
CREATE TABLE "AgentEvent" (
3+
"id" TEXT NOT NULL PRIMARY KEY,
4+
"runId" TEXT NOT NULL,
5+
"seq" INTEGER NOT NULL,
6+
"type" TEXT NOT NULL,
7+
"timestamp" TEXT NOT NULL,
8+
"body" TEXT NOT NULL,
9+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
10+
CONSTRAINT "AgentEvent_runId_fkey" FOREIGN KEY ("runId") REFERENCES "AgentRun" ("id") ON DELETE CASCADE ON UPDATE CASCADE
11+
);
12+
13+
-- CreateIndex
14+
CREATE INDEX "AgentEvent_runId_idx" ON "AgentEvent"("runId");
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the `Job` table. If the table is not empty, all the data it contains will be lost.
5+
- You are about to drop the `PullRequestRef` table. If the table is not empty, all the data it contains will be lost.
6+
7+
*/
8+
-- DropIndex
9+
DROP INDEX "Job_repoFullName_issueNumber_key";
10+
11+
-- DropIndex
12+
DROP INDEX "Job_repoFullName_state_idx";
13+
14+
-- DropIndex
15+
DROP INDEX "Job_state_idx";
16+
17+
-- DropIndex
18+
DROP INDEX "PullRequestRef_jobId_key";
19+
20+
-- DropTable
21+
PRAGMA foreign_keys=off;
22+
DROP TABLE "Job";
23+
PRAGMA foreign_keys=on;
24+
25+
-- DropTable
26+
PRAGMA foreign_keys=off;
27+
DROP TABLE "PullRequestRef";
28+
PRAGMA foreign_keys=on;
29+
30+
-- CreateTable
31+
CREATE TABLE "JobRecords" (
32+
"id" TEXT NOT NULL PRIMARY KEY,
33+
"installationId" TEXT,
34+
"repoOwner" TEXT,
35+
"repoName" TEXT,
36+
"repoFullName" TEXT,
37+
"issueNumber" INTEGER,
38+
"issueTitle" TEXT NOT NULL,
39+
"issueBody" TEXT NOT NULL,
40+
"triggerLabel" TEXT,
41+
"origin" TEXT NOT NULL DEFAULT 'GITHUB',
42+
"repoUrl" TEXT,
43+
"state" TEXT NOT NULL DEFAULT 'TRIAGED',
44+
"branchName" TEXT,
45+
"prNumber" INTEGER,
46+
"headSha" TEXT,
47+
"confidence" INTEGER,
48+
"verifyCommand" TEXT,
49+
"reviewCycle" INTEGER NOT NULL DEFAULT 0,
50+
"attempts" INTEGER NOT NULL DEFAULT 0,
51+
"error" TEXT,
52+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
53+
"updatedAt" DATETIME NOT NULL,
54+
CONSTRAINT "JobRecords_installationId_fkey" FOREIGN KEY ("installationId") REFERENCES "RepoInstallation" ("id") ON DELETE SET NULL ON UPDATE CASCADE
55+
);
56+
57+
-- CreateTable
58+
CREATE TABLE "PullRequest" (
59+
"id" TEXT NOT NULL PRIMARY KEY,
60+
"jobId" TEXT NOT NULL,
61+
"prNumber" INTEGER NOT NULL,
62+
"url" TEXT NOT NULL,
63+
"state" TEXT NOT NULL,
64+
"isDraft" BOOLEAN NOT NULL DEFAULT true,
65+
"headSha" TEXT,
66+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
67+
"updatedAt" DATETIME NOT NULL,
68+
CONSTRAINT "PullRequest_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "JobRecords" ("id") ON DELETE CASCADE ON UPDATE CASCADE
69+
);
70+
71+
-- RedefineTables
72+
PRAGMA defer_foreign_keys=ON;
73+
PRAGMA foreign_keys=OFF;
74+
CREATE TABLE "new_AgentRun" (
75+
"id" TEXT NOT NULL PRIMARY KEY,
76+
"jobId" TEXT,
77+
"sessionId" TEXT,
78+
"phase" TEXT NOT NULL,
79+
"command" TEXT NOT NULL,
80+
"cwd" TEXT NOT NULL,
81+
"model" TEXT,
82+
"status" TEXT NOT NULL DEFAULT 'RUNNING',
83+
"exitCode" INTEGER,
84+
"stdout" TEXT,
85+
"stderr" TEXT,
86+
"durationMs" INTEGER,
87+
"judgePassed" BOOLEAN,
88+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
89+
CONSTRAINT "AgentRun_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "JobRecords" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
90+
CONSTRAINT "AgentRun_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "ChatSession" ("id") ON DELETE CASCADE ON UPDATE CASCADE
91+
);
92+
INSERT INTO "new_AgentRun" ("command", "createdAt", "cwd", "durationMs", "exitCode", "id", "jobId", "judgePassed", "model", "phase", "sessionId", "status", "stderr", "stdout") SELECT "command", "createdAt", "cwd", "durationMs", "exitCode", "id", "jobId", "judgePassed", "model", "phase", "sessionId", "status", "stderr", "stdout" FROM "AgentRun";
93+
DROP TABLE "AgentRun";
94+
ALTER TABLE "new_AgentRun" RENAME TO "AgentRun";
95+
CREATE INDEX "AgentRun_jobId_idx" ON "AgentRun"("jobId");
96+
CREATE INDEX "AgentRun_sessionId_idx" ON "AgentRun"("sessionId");
97+
CREATE TABLE "new_JobStateTransition" (
98+
"id" TEXT NOT NULL PRIMARY KEY,
99+
"jobId" TEXT NOT NULL,
100+
"fromState" TEXT,
101+
"toState" TEXT NOT NULL,
102+
"reason" TEXT,
103+
"actor" TEXT NOT NULL DEFAULT 'SYSTEM',
104+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
105+
CONSTRAINT "JobStateTransition_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "JobRecords" ("id") ON DELETE CASCADE ON UPDATE CASCADE
106+
);
107+
INSERT INTO "new_JobStateTransition" ("actor", "createdAt", "fromState", "id", "jobId", "reason", "toState") SELECT "actor", "createdAt", "fromState", "id", "jobId", "reason", "toState" FROM "JobStateTransition";
108+
DROP TABLE "JobStateTransition";
109+
ALTER TABLE "new_JobStateTransition" RENAME TO "JobStateTransition";
110+
CREATE INDEX "JobStateTransition_jobId_idx" ON "JobStateTransition"("jobId");
111+
CREATE TABLE "new_PlanFeedback" (
112+
"id" TEXT NOT NULL PRIMARY KEY,
113+
"jobId" TEXT NOT NULL,
114+
"author" TEXT NOT NULL,
115+
"body" TEXT NOT NULL,
116+
"githubCommentId" BIGINT,
117+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
118+
CONSTRAINT "PlanFeedback_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "JobRecords" ("id") ON DELETE CASCADE ON UPDATE CASCADE
119+
);
120+
INSERT INTO "new_PlanFeedback" ("author", "body", "createdAt", "githubCommentId", "id", "jobId") SELECT "author", "body", "createdAt", "githubCommentId", "id", "jobId" FROM "PlanFeedback";
121+
DROP TABLE "PlanFeedback";
122+
ALTER TABLE "new_PlanFeedback" RENAME TO "PlanFeedback";
123+
CREATE INDEX "PlanFeedback_jobId_idx" ON "PlanFeedback"("jobId");
124+
CREATE TABLE "new_PlanRevision" (
125+
"id" TEXT NOT NULL PRIMARY KEY,
126+
"jobId" TEXT NOT NULL,
127+
"revision" INTEGER NOT NULL,
128+
"content" TEXT NOT NULL,
129+
"status" TEXT NOT NULL DEFAULT 'PROPOSED',
130+
"githubCommentId" BIGINT,
131+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
132+
CONSTRAINT "PlanRevision_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "JobRecords" ("id") ON DELETE CASCADE ON UPDATE CASCADE
133+
);
134+
INSERT INTO "new_PlanRevision" ("content", "createdAt", "githubCommentId", "id", "jobId", "revision", "status") SELECT "content", "createdAt", "githubCommentId", "id", "jobId", "revision", "status" FROM "PlanRevision";
135+
DROP TABLE "PlanRevision";
136+
ALTER TABLE "new_PlanRevision" RENAME TO "PlanRevision";
137+
CREATE INDEX "PlanRevision_jobId_idx" ON "PlanRevision"("jobId");
138+
CREATE UNIQUE INDEX "PlanRevision_jobId_revision_key" ON "PlanRevision"("jobId", "revision");
139+
CREATE TABLE "new_PrRevisionFeedback" (
140+
"id" TEXT NOT NULL PRIMARY KEY,
141+
"jobId" TEXT NOT NULL,
142+
"author" TEXT NOT NULL,
143+
"body" TEXT NOT NULL,
144+
"path" TEXT,
145+
"line" INTEGER,
146+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
147+
CONSTRAINT "PrRevisionFeedback_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "JobRecords" ("id") ON DELETE CASCADE ON UPDATE CASCADE
148+
);
149+
INSERT INTO "new_PrRevisionFeedback" ("author", "body", "createdAt", "id", "jobId", "line", "path") SELECT "author", "body", "createdAt", "id", "jobId", "line", "path" FROM "PrRevisionFeedback";
150+
DROP TABLE "PrRevisionFeedback";
151+
ALTER TABLE "new_PrRevisionFeedback" RENAME TO "PrRevisionFeedback";
152+
CREATE INDEX "PrRevisionFeedback_jobId_idx" ON "PrRevisionFeedback"("jobId");
153+
CREATE TABLE "new_QueueTask" (
154+
"id" TEXT NOT NULL PRIMARY KEY,
155+
"jobId" TEXT NOT NULL,
156+
"kind" TEXT NOT NULL,
157+
"status" TEXT NOT NULL DEFAULT 'PENDING',
158+
"priority" INTEGER NOT NULL DEFAULT 0,
159+
"runAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
160+
"attempts" INTEGER NOT NULL DEFAULT 0,
161+
"maxAttempts" INTEGER NOT NULL DEFAULT 3,
162+
"lockedAt" DATETIME,
163+
"lockedBy" TEXT,
164+
"lastError" TEXT,
165+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
166+
"updatedAt" DATETIME NOT NULL,
167+
CONSTRAINT "QueueTask_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "JobRecords" ("id") ON DELETE CASCADE ON UPDATE CASCADE
168+
);
169+
INSERT INTO "new_QueueTask" ("attempts", "createdAt", "id", "jobId", "kind", "lastError", "lockedAt", "lockedBy", "maxAttempts", "priority", "runAt", "status", "updatedAt") SELECT "attempts", "createdAt", "id", "jobId", "kind", "lastError", "lockedAt", "lockedBy", "maxAttempts", "priority", "runAt", "status", "updatedAt" FROM "QueueTask";
170+
DROP TABLE "QueueTask";
171+
ALTER TABLE "new_QueueTask" RENAME TO "QueueTask";
172+
CREATE INDEX "QueueTask_status_runAt_idx" ON "QueueTask"("status", "runAt");
173+
CREATE INDEX "QueueTask_jobId_idx" ON "QueueTask"("jobId");
174+
CREATE TABLE "new_ReviewPass" (
175+
"id" TEXT NOT NULL PRIMARY KEY,
176+
"jobId" TEXT NOT NULL,
177+
"cycle" INTEGER NOT NULL DEFAULT 1,
178+
"passNumber" INTEGER NOT NULL,
179+
"confidence" INTEGER NOT NULL,
180+
"verdict" TEXT NOT NULL,
181+
"dimensions" TEXT,
182+
"verifyOk" BOOLEAN,
183+
"issues" TEXT NOT NULL,
184+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
185+
CONSTRAINT "ReviewPass_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "JobRecords" ("id") ON DELETE CASCADE ON UPDATE CASCADE
186+
);
187+
INSERT INTO "new_ReviewPass" ("confidence", "createdAt", "cycle", "dimensions", "id", "issues", "jobId", "passNumber", "verdict", "verifyOk") SELECT "confidence", "createdAt", "cycle", "dimensions", "id", "issues", "jobId", "passNumber", "verdict", "verifyOk" FROM "ReviewPass";
188+
DROP TABLE "ReviewPass";
189+
ALTER TABLE "new_ReviewPass" RENAME TO "ReviewPass";
190+
CREATE INDEX "ReviewPass_jobId_idx" ON "ReviewPass"("jobId");
191+
CREATE UNIQUE INDEX "ReviewPass_jobId_cycle_passNumber_key" ON "ReviewPass"("jobId", "cycle", "passNumber");
192+
CREATE TABLE "new_VerifyRun" (
193+
"id" TEXT NOT NULL PRIMARY KEY,
194+
"jobId" TEXT NOT NULL,
195+
"cycle" INTEGER NOT NULL,
196+
"attempt" INTEGER NOT NULL,
197+
"command" TEXT NOT NULL,
198+
"ok" BOOLEAN NOT NULL,
199+
"output" TEXT NOT NULL,
200+
"durationMs" INTEGER NOT NULL,
201+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
202+
CONSTRAINT "VerifyRun_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "JobRecords" ("id") ON DELETE CASCADE ON UPDATE CASCADE
203+
);
204+
INSERT INTO "new_VerifyRun" ("attempt", "command", "createdAt", "cycle", "durationMs", "id", "jobId", "ok", "output") SELECT "attempt", "command", "createdAt", "cycle", "durationMs", "id", "jobId", "ok", "output" FROM "VerifyRun";
205+
DROP TABLE "VerifyRun";
206+
ALTER TABLE "new_VerifyRun" RENAME TO "VerifyRun";
207+
CREATE INDEX "VerifyRun_jobId_idx" ON "VerifyRun"("jobId");
208+
PRAGMA foreign_keys=ON;
209+
PRAGMA defer_foreign_keys=OFF;
210+
211+
-- CreateIndex
212+
CREATE INDEX "JobRecords_state_idx" ON "JobRecords"("state");
213+
214+
-- CreateIndex
215+
CREATE INDEX "JobRecords_repoFullName_state_idx" ON "JobRecords"("repoFullName", "state");
216+
217+
-- CreateIndex
218+
CREATE UNIQUE INDEX "JobRecords_repoFullName_issueNumber_key" ON "JobRecords"("repoFullName", "issueNumber");
219+
220+
-- CreateIndex
221+
CREATE UNIQUE INDEX "PullRequest_jobId_key" ON "PullRequest"("jobId");

0 commit comments

Comments
 (0)