limn-review 0.1.126 → 0.1.128
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.
- package/dist/api/plugins/rate-limit.js +35 -23
- package/dist/app.js +5 -0
- package/dist/config.js +3 -0
- package/dist/db/erase-account.js +25 -0
- package/dist/db/export-account.js +17 -0
- package/dist/db/migrations/0084_auto_fix_off_by_default.sql +7 -0
- package/dist/db/migrations/0085_auto_review_daily_cap.sql +6 -0
- package/dist/db/migrations/0086_ticket_review_pr_cards.sql +24 -0
- package/dist/db/migrations/0087_auto_post.sql +21 -0
- package/dist/db/migrations/0088_issue_tracker.sql +109 -0
- package/dist/db/migrations/0089_github_issue_links.sql +18 -0
- package/dist/db/migrations/0090_linear_links.sql +22 -0
- package/dist/db/migrations/meta/_journal.json +49 -0
- package/dist/db/migrations-pg/0071_auto_fix_off_by_default.sql +5 -0
- package/dist/db/migrations-pg/0072_auto_review_daily_cap.sql +3 -0
- package/dist/db/migrations-pg/0073_ticket_review_pr_cards.sql +17 -0
- package/dist/db/migrations-pg/0074_auto_post.sql +14 -0
- package/dist/db/migrations-pg/0075_issue_tracker.sql +77 -0
- package/dist/db/migrations-pg/0076_github_issue_links.sql +6 -0
- package/dist/db/migrations-pg/0077_linear_links.sql +8 -0
- package/dist/db/migrations-pg/meta/_journal.json +49 -0
- package/dist/db/queries.js +16 -2
- package/dist/db/retention.js +3 -0
- package/dist/db/schema.pg.js +125 -1
- package/dist/db/schema.sqlite.js +226 -1
- package/dist/db/ticket-review-prune.js +4 -1
- package/dist/github/rate-budget.js +15 -0
- package/dist/index.js +7 -0
- package/dist/pr/detail-enricher.js +8 -18
- package/dist/pro/bind.js +3 -14
- package/dist/pro/contract.js +0 -1
- package/dist/review/claude-review/auto-post.js +405 -0
- package/dist/review/claude-review/auto-settings.js +175 -11
- package/dist/review/claude-review/auto.js +3 -3
- package/dist/review/claude-review/manager.js +7 -4
- package/dist/review/claude-review/persist.js +29 -5
- package/dist/review/claude-review/routes.js +9 -0
- package/dist/review/clone-manager.js +48 -0
- package/dist/review/path-guard.js +1 -1
- package/dist/review/post-review.js +6 -2
- package/dist/review/post-seam.js +22 -13
- package/dist/review/ticket-review/auto-post.js +291 -0
- package/dist/review/ticket-review/cards.js +271 -0
- package/dist/review/ticket-review/fingerprint.js +2 -0
- package/dist/review/ticket-review/manager.js +169 -28
- package/dist/review/ticket-review/persist.js +44 -2
- package/dist/review/ticket-review/post-item.js +187 -0
- package/dist/review/ticket-review/prepare.js +34 -50
- package/dist/review/ticket-review/prepass.js +259 -0
- package/dist/review/ticket-review/prompts.js +72 -11
- package/dist/review/ticket-review/routes.js +36 -156
- package/dist/review/ticket-review/schema.js +43 -0
- package/dist/review/ticket-review/sweep.js +12 -12
- package/dist/shared/claude-review.js +173 -7
- package/dist/shared/types.js +49 -8
- package/dist/sync/scheduler.js +15 -0
- package/dist/tracker/ac.js +172 -0
- package/dist/tracker/calls.js +59 -0
- package/dist/tracker/context.js +45 -0
- package/dist/tracker/detect.js +172 -0
- package/dist/tracker/enricher.js +147 -0
- package/dist/tracker/github/ac.js +8 -0
- package/dist/tracker/github/adapter.js +47 -0
- package/dist/tracker/github/links.js +115 -0
- package/dist/tracker/github/reader.js +166 -0
- package/dist/tracker/index.js +39 -0
- package/dist/tracker/jira/adapter.js +23 -0
- package/dist/tracker/jira/candidates.js +122 -0
- package/dist/tracker/jira/client.js +158 -0
- package/dist/tracker/jira/fetch.js +238 -0
- package/dist/tracker/jira/text.js +329 -0
- package/dist/tracker/legacy-import.js +140 -0
- package/dist/tracker/linear/adapter.js +52 -0
- package/dist/tracker/linear/client.js +270 -0
- package/dist/tracker/linear/links.js +113 -0
- package/dist/tracker/links.js +104 -0
- package/dist/tracker/merged.js +163 -0
- package/dist/tracker/peers.js +117 -0
- package/dist/tracker/registry.js +35 -0
- package/dist/tracker/routes.js +329 -0
- package/dist/tracker/runtime.js +54 -0
- package/dist/tracker/secret.js +28 -0
- package/dist/tracker/settings.js +213 -0
- package/dist/tracker/store.js +267 -0
- package/dist/tracker/stories.js +144 -0
- package/dist/tracker/ticket-source.js +46 -0
- package/dist/tracker/types.js +2 -0
- package/dist/tracker/worker.js +814 -0
- package/package.json +1 -1
- package/public/assets/{AiFixTab-CzugrcNK.js → AiFixTab-Cq2Wdm2l.js} +1 -1
- package/public/assets/ClaudeReviewTab-C6WftwSM.js +16 -0
- package/public/assets/{PrBotBehaviourTab-Cc1F4O6z.js → PrBotBehaviourTab-CY_iLmFp.js} +1 -1
- package/public/assets/index-CB6bLAqG.js +77 -0
- package/public/assets/index-gwxOLty-.css +1 -0
- package/public/index.html +2 -2
- package/dist/review/plugin-providers.js +0 -12
- package/public/assets/ClaudeReviewTab-OGu_QicR.js +0 -16
- package/public/assets/index-1ieo_9fr.js +0 -77
- package/public/assets/index-C9m8ITkB.css +0 -1
|
@@ -117,6 +117,21 @@ function tierFor(method, path) {
|
|
|
117
117
|
// `startsWith('/api/workspaces')` and emphatically not `startsWith('/api/workspace')`:
|
|
118
118
|
// the `/api/workspace-metrics` family is a SIBLING vocabulary, and a loose prefix over two
|
|
119
119
|
// sibling vocabularies is precisely how one silently swallows the other.
|
|
120
|
+
// ⚠ THREE WORKSPACE ROUTES SPEND THE CUSTOMER'S TRACKER QUOTA, so they are decided ABOVE the
|
|
121
|
+
// `read` line below, by exact shape (tracker/routes.ts):
|
|
122
|
+
// PUT /api/workspaces/:id/tracker saving a tracker or token KICKS the ticket
|
|
123
|
+
// worker for the account (up to 40 reads);
|
|
124
|
+
// GET /api/workspaces/:id/tracker/jira-fields the Settings connection check — one call to
|
|
125
|
+
// the customer's Jira with the saved token.
|
|
126
|
+
// GET /api/workspaces/:id/tracker/linear-check the Linear connection check — one call to
|
|
127
|
+
// Linear with the saved key.
|
|
128
|
+
// All three take the 60/min `search` bucket, the "one upstream call per request" tier. The plain
|
|
129
|
+
// `GET …/tracker` is DB-only and stays on `read` with the rest of the family.
|
|
130
|
+
if (method === 'PUT' && /^\/api\/workspaces\/\d+\/tracker$/.test(path))
|
|
131
|
+
return [TIERS.search, TIERS.read];
|
|
132
|
+
if (!mutating && /^\/api\/workspaces\/\d+\/tracker\/(jira-fields|linear-check)$/.test(path)) {
|
|
133
|
+
return [TIERS.search, TIERS.read];
|
|
134
|
+
}
|
|
120
135
|
if (path === '/api/workspaces' || path.startsWith('/api/workspaces/'))
|
|
121
136
|
return [TIERS.read];
|
|
122
137
|
// ---- Per-account settings writes: `read`, RECORDED rather than inherited ----
|
|
@@ -407,35 +422,32 @@ function tierFor(method, path) {
|
|
|
407
422
|
return [TIERS.read];
|
|
408
423
|
if (mutating && path === '/api/pro/slack/test')
|
|
409
424
|
return [TIERS.ai, TIERS.aiHourly];
|
|
410
|
-
// ----
|
|
411
|
-
// GET /api/
|
|
412
|
-
// the customer's
|
|
413
|
-
// limits per user) and up to a 10s wait
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
//
|
|
417
|
-
|
|
425
|
+
// ---- The issue tracker's PR routes (CORE since apiVersion 23 — tracker/routes.ts) ----
|
|
426
|
+
// GET /api/prs/:id/tracker-ticket answers a STORED row, but a ticket the worker never reached is
|
|
427
|
+
// read ONCE from the customer's tracker with the workspace's saved token — a THIRD-PARTY quota
|
|
428
|
+
// (Jira Cloud rate limits per user) and up to a 10s wait. `POST …/refresh` re-reads it now and
|
|
429
|
+
// `PUT …/ac-field` saves the criteria field and re-reads it: one upstream call each. Following
|
|
430
|
+
// the token: theirs, not ours, so the 60/min `search` bucket. Anchored at BOTH ends, so a sibling
|
|
431
|
+
// `/api/prs/:id/*` route is not swept in — and the segment is `tracker-ticket`, never a prefix of
|
|
432
|
+
// `ticket-reviews` (the ticket review's own, `read`-tier family below).
|
|
433
|
+
if (!mutating && /^\/api\/prs\/\d+\/tracker-ticket$/.test(path))
|
|
418
434
|
return [TIERS.search, TIERS.read];
|
|
419
|
-
if (
|
|
435
|
+
if (method === 'POST' && /^\/api\/prs\/\d+\/tracker-ticket\/refresh$/.test(path)) {
|
|
420
436
|
return [TIERS.search, TIERS.read];
|
|
421
437
|
}
|
|
422
|
-
|
|
423
|
-
// that ticket from Jira again now, and `PUT …/jira-ticket/ac-field` saves the criteria field for
|
|
424
|
-
// its issue type and re-reads it — one upstream call each, the customer's quota. Spelled by exact
|
|
425
|
-
// verb + path: without these lines the catch-all parks a mutating /api/pro/ route on `ai`.
|
|
426
|
-
if (method === 'POST' && /^\/api\/pro\/prs\/[^/]+\/jira-ticket\/refresh$/.test(path)) {
|
|
438
|
+
if (method === 'PUT' && /^\/api\/prs\/\d+\/tracker-ticket\/ac-field$/.test(path)) {
|
|
427
439
|
return [TIERS.search, TIERS.read];
|
|
428
440
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
//
|
|
433
|
-
|
|
434
|
-
// background worker, which spends the customer's Jira quota — so `search`, not `read`. A POST
|
|
435
|
-
// only because it carries a list of PR ids; it writes nothing itself. Without this line the catch-all would tier it
|
|
436
|
-
// on the verb and park a read on the 20/min `ai` bucket.
|
|
437
|
-
if (path === '/api/pro/ticket-links')
|
|
441
|
+
// POST /api/ticket-links — the Open PRs cards' ticket row, ONE request per board: DB-only
|
|
442
|
+
// detection plus the STORED ticket rows; a detected ticket with no row kicks the background
|
|
443
|
+
// worker, which spends the customer's tracker quota — so `search`, not `read`. A POST only
|
|
444
|
+
// because it carries a list of PR ids. EXACT `===`.
|
|
445
|
+
if (path === '/api/ticket-links')
|
|
438
446
|
return [TIERS.search, TIERS.read];
|
|
447
|
+
// GET /api/ticket-merged-prs — the stacks' "Merged (n)" panel: DB-only (stored rows joined to
|
|
448
|
+
// pull_requests), no tracker call. `read`, DECIDED rather than inherited.
|
|
449
|
+
if (!mutating && path === '/api/ticket-merged-prs')
|
|
450
|
+
return [TIERS.read];
|
|
439
451
|
// ---- AI generation ----
|
|
440
452
|
// ⚠ RE-DECIDED, not inherited: `POST /api/pro/prs/:id/annotations/run` now spends GITHUB quota
|
|
441
453
|
// as well as model tokens — one PR_DETAIL_QUERY per uncached PR for the anchor hunks
|
package/dist/app.js
CHANGED
|
@@ -12,6 +12,7 @@ import { authRoutes } from './api/routes/auth.js';
|
|
|
12
12
|
import { healthRoutes } from './api/routes/health.js';
|
|
13
13
|
import { aiRuntimeRoutes } from './api/routes/ai-runtime.js';
|
|
14
14
|
import { registerAgenticRoutes } from './review/agentic.js';
|
|
15
|
+
import { registerTracker } from './tracker/index.js';
|
|
15
16
|
import { repoRoutes } from './api/routes/repos.js';
|
|
16
17
|
import { workspaceRoutes } from './api/routes/workspaces.js';
|
|
17
18
|
import { userRoutes } from './api/routes/users.js';
|
|
@@ -271,6 +272,10 @@ export async function buildApp() {
|
|
|
271
272
|
// memory and AI Fix's fixer. CORE and FREE, LOCAL ONLY: `registerAgenticRoutes` registers
|
|
272
273
|
// NOTHING in cloud (an explicit `isCloud` check) or under LIMN_AI_DISABLED. review/agentic.ts.
|
|
273
274
|
registerAgenticRoutes(app);
|
|
275
|
+
// THE ISSUE TRACKER (CORE, FREE, BOTH MODES — apiVersion 23; docs/TRACKERS.md): the workspace's
|
|
276
|
+
// tracker settings, the stored-ticket routes behind the PR pane's story panel, the Open PRs ticket
|
|
277
|
+
// row and stacks. Unconditional: no capability, no plugin.
|
|
278
|
+
registerTracker(app);
|
|
274
279
|
return app;
|
|
275
280
|
}
|
|
276
281
|
//# sourceMappingURL=app.js.map
|
package/dist/config.js
CHANGED
|
@@ -536,6 +536,9 @@ export const config = {
|
|
|
536
536
|
// every member's worktree.
|
|
537
537
|
ticketReviewBudgetUsd: floatFromEnv('TICKET_REVIEW_BUDGET_USD', 4),
|
|
538
538
|
ticketReviewMaxTurns: intFromEnv('TICKET_REVIEW_MAX_TURNS', 40),
|
|
539
|
+
// The per-card spend cap of the ticket review's CARD PRE-PASS (Sonnet 5, diff-only, one tool —
|
|
540
|
+
// review/ticket-review/prepass.ts). Its spend is added to the ticket run's cost. Env only.
|
|
541
|
+
ticketCardBudgetUsd: floatFromEnv('TICKET_CARD_BUDGET_USD', 0.4),
|
|
539
542
|
// AUTOMATIC ticket reviews (trigger 'auto' / 'cascade') per workspace per UTC day. Not shared with
|
|
540
543
|
// the PR review's own auto cap. Manual runs never count. Default = shared TICKET_REVIEW_DAILY_CAP.
|
|
541
544
|
ticketReviewDailyCap: intFromEnv('TICKET_REVIEW_DAILY_CAP', 20),
|
package/dist/db/erase-account.js
CHANGED
|
@@ -128,6 +128,12 @@ export async function eraseAccountData(accountId) {
|
|
|
128
128
|
.delete(schema.ticketReviews)
|
|
129
129
|
.where(eq(schema.ticketReviews.accountId, accountId))
|
|
130
130
|
.execute();
|
|
131
|
+
// Ticket review contribution cards (migration 0086 / pg 0073): model text describing the user's
|
|
132
|
+
// PRs. The repo loop has normally taken them with their PRs; explicit, like every agentic table.
|
|
133
|
+
await tx
|
|
134
|
+
.delete(schema.ticketReviewPrCards)
|
|
135
|
+
.where(eq(schema.ticketReviewPrCards.accountId, accountId))
|
|
136
|
+
.execute();
|
|
131
137
|
// CI reviews (migration 0082 / pg 0069), items first. The repo loop has normally taken them with
|
|
132
138
|
// their PRs; explicit, like every agentic table.
|
|
133
139
|
await tx
|
|
@@ -138,6 +144,14 @@ export async function eraseAccountData(accountId) {
|
|
|
138
144
|
// AI Fix runs (patches of the user's code + the prompts they were built from). Core since
|
|
139
145
|
// migration 0074 / pg 0061 — the plugin's erasure hook used to own them.
|
|
140
146
|
await tx.delete(schema.aiFixes).where(eq(schema.aiFixes.accountId, accountId)).execute();
|
|
147
|
+
// THE ISSUE TRACKER (core since migration 0088 / pg 0075 — the plugin's erasure hook used to own
|
|
148
|
+
// these): the stored tickets (story text from the customer's tracker), the acceptance-criteria
|
|
149
|
+
// field choices, and the workspace tracker rows — which hold the customer's internal tracker
|
|
150
|
+
// hostname AND the sealed API token. No FKs on the first two, so the explicit deletes are the
|
|
151
|
+
// whole guarantee; workspace_trackers cascades from workspaces too, and is explicit anyway.
|
|
152
|
+
await tx.delete(schema.trackerTickets).where(eq(schema.trackerTickets.accountId, accountId)).execute();
|
|
153
|
+
await tx.delete(schema.jiraAcFields).where(eq(schema.jiraAcFields.accountId, accountId)).execute();
|
|
154
|
+
await tx.delete(schema.workspaceTrackers).where(eq(schema.workspaceTrackers.accountId, accountId)).execute();
|
|
141
155
|
// The AI spend ledger (token/credit counts — no prompt text).
|
|
142
156
|
await tx.delete(aiUsage).where(eq(aiUsage.accountId, accountId)).execute();
|
|
143
157
|
// Any aggregate rows contributed to the cross-org benchmark. Consent was the basis for
|
|
@@ -218,6 +232,12 @@ export function accountScopedTables() {
|
|
|
218
232
|
col: schema.ticketReviewItems.accountId,
|
|
219
233
|
table: schema.ticketReviewItems,
|
|
220
234
|
},
|
|
235
|
+
// Contribution cards (migration 0086 / pg 0073) — one per (PR, head); erased explicitly above.
|
|
236
|
+
{
|
|
237
|
+
name: 'ticketReviewPrCards',
|
|
238
|
+
col: schema.ticketReviewPrCards.accountId,
|
|
239
|
+
table: schema.ticketReviewPrCards,
|
|
240
|
+
},
|
|
221
241
|
// CI reviews (migration 0082 / pg 0069) — the runs and their per-check items. Both carry their
|
|
222
242
|
// own accountId; both are erased explicitly above.
|
|
223
243
|
{ name: 'ciReviews', col: schema.ciReviews.accountId, table: schema.ciReviews },
|
|
@@ -227,6 +247,11 @@ export function accountScopedTables() {
|
|
|
227
247
|
// cascades: the explicit delete above is the whole guarantee. (`reviewLearnings`, review
|
|
228
248
|
// memory's table, sat here until migration 0075 / pg 0062 DROPPED it.)
|
|
229
249
|
{ name: 'aiFixes', col: schema.aiFixes.accountId, table: schema.aiFixes },
|
|
250
|
+
// The issue tracker (migration 0088 / pg 0075). All three carry their own accountId and are
|
|
251
|
+
// erased explicitly above; `workspaceTrackers` holds a credential.
|
|
252
|
+
{ name: 'trackerTickets', col: schema.trackerTickets.accountId, table: schema.trackerTickets },
|
|
253
|
+
{ name: 'jiraAcFields', col: schema.jiraAcFields.accountId, table: schema.jiraAcFields },
|
|
254
|
+
{ name: 'workspaceTrackers', col: schema.workspaceTrackers.accountId, table: schema.workspaceTrackers },
|
|
230
255
|
// `myTurnDismissals` sat here until migration 0060 / pg 0047 DROPPED the table. It is named
|
|
231
256
|
// rather than silently absent because this list is a checklist, and a checklist that shortens
|
|
232
257
|
// with no explanation reads as an omission — the exact failure this function guards against.
|
|
@@ -72,6 +72,21 @@ export async function exportAccountData(accountId) {
|
|
|
72
72
|
// The child tables reach their account through prId. An account with no PRs short-circuits
|
|
73
73
|
// to empty arrays rather than issuing an `IN ()`.
|
|
74
74
|
const childRows = async (fn) => (prIds.length === 0 ? [] : fn(prIds));
|
|
75
|
+
// The tracker rows — explicit columns, the token reduced to its presence below.
|
|
76
|
+
const trackerRows = await db
|
|
77
|
+
.select({
|
|
78
|
+
workspaceId: schema.workspaceTrackers.workspaceId,
|
|
79
|
+
provider: schema.workspaceTrackers.provider,
|
|
80
|
+
baseUrl: schema.workspaceTrackers.baseUrl,
|
|
81
|
+
projectKeys: schema.workspaceTrackers.projectKeys,
|
|
82
|
+
matchScope: schema.workspaceTrackers.matchScope,
|
|
83
|
+
email: schema.workspaceTrackers.authEmail,
|
|
84
|
+
hasToken: schema.workspaceTrackers.authToken,
|
|
85
|
+
updatedAt: schema.workspaceTrackers.updatedAt,
|
|
86
|
+
})
|
|
87
|
+
.from(schema.workspaceTrackers)
|
|
88
|
+
.where(eq(schema.workspaceTrackers.accountId, accountId))
|
|
89
|
+
.execute();
|
|
75
90
|
const [reviewRows, threadRows, reviewCommentRows, prCommentRows, eventRows, workspaceRows, workspaceRepoRows, usageRows, workspaceReviewerRows, benchmarkRows, autoMergeRows,] = await Promise.all([
|
|
76
91
|
childRows((ids) => db.select().from(reviews).where(inArray(reviews.prId, ids)).execute()),
|
|
77
92
|
childRows((ids) => db.select().from(reviewThreads).where(inArray(reviewThreads.prId, ids)).execute()),
|
|
@@ -184,6 +199,8 @@ export async function exportAccountData(accountId) {
|
|
|
184
199
|
workspaceReviewers: workspaceReviewerRows,
|
|
185
200
|
benchmarkContributions: benchmarkRows,
|
|
186
201
|
autoMergeRequests: autoMergeRows,
|
|
202
|
+
// ⚠ PRESENCE ONLY — never the stored token, in any form.
|
|
203
|
+
workspaceTrackers: trackerRows.map((t) => ({ ...t, hasToken: t.hasToken != null && t.hasToken !== '' })),
|
|
187
204
|
};
|
|
188
205
|
}
|
|
189
206
|
//# sourceMappingURL=export-account.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- AUTO AI FIX IS OFF BY DEFAULT. 0083 added `workspaces.auto_fix_enabled` DEFAULT 1 so nothing
|
|
2
|
+
-- changed on upgrade; the product decision since is OFF until someone switches it on. Every
|
|
3
|
+
-- existing workspace is switched off once here (the switch shipped one release earlier, so no one
|
|
4
|
+
-- has had time to choose it). SQLite cannot change a column default in place, so the 0083 DDL
|
|
5
|
+
-- default stays 1; both workspace inserts in db/queries.ts write `autoFixEnabled: false`
|
|
6
|
+
-- explicitly. The Postgres twin is migrations-pg/0071_auto_fix_off_by_default.sql.
|
|
7
|
+
UPDATE `workspaces` SET `auto_fix_enabled` = 0;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- AUTO REVIEW DAILY CAP, PER WORKSPACE. How many auto Claude reviews a workspace may start per UTC
|
|
2
|
+
-- day. OVERRIDES ONLY: NULL = the product default (20, `AUTO_REVIEW_DAILY_CAP`), resolved through
|
|
3
|
+
-- `resolveAutoReviewDailyCap` (review/claude-review/auto-settings.ts); the PUT route bounds it
|
|
4
|
+
-- 1..500. Nullable with no default, so no workspace insert has to name it. The Postgres twin is
|
|
5
|
+
-- migrations-pg/0072_auto_review_daily_cap.sql.
|
|
6
|
+
ALTER TABLE `workspaces` ADD `auto_review_daily_cap` integer;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- TICKET REVIEW CONTRIBUTION CARDS. One row per (account, PR, head commit): a model-written,
|
|
2
|
+
-- verdict-free description of what that PR's head does (summary, interfaces, the story criteria it
|
|
3
|
+
-- moves forward, loose ends) plus the PR's changed files at that head (server-written). A ticket
|
|
4
|
+
-- review reads a member whose CURRENT head has a card as the card, not as its diff; the run writes a
|
|
5
|
+
-- card for every member it read as a diff (source 'story_check') and a cheap per-PR pre-pass writes
|
|
6
|
+
-- the overflow (source 'prepass', with its own cost). Re-writing the same head replaces the card.
|
|
7
|
+
-- Tenancy: a composite FK against pull_requests(id, account_id). Both delete paths (deleteRepo,
|
|
8
|
+
-- retention's deletePrSubtree, via db/ticket-review-prune.ts) and eraseAccountData delete these rows
|
|
9
|
+
-- explicitly. The Postgres twin is migrations-pg/0073_ticket_review_pr_cards.sql.
|
|
10
|
+
CREATE TABLE IF NOT EXISTS `ticket_review_pr_cards` (
|
|
11
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
12
|
+
`account_id` integer NOT NULL,
|
|
13
|
+
`pr_id` integer NOT NULL,
|
|
14
|
+
`head_sha` text NOT NULL,
|
|
15
|
+
`card` text NOT NULL,
|
|
16
|
+
`source` text NOT NULL,
|
|
17
|
+
`model` text NOT NULL,
|
|
18
|
+
`cost_usd` real,
|
|
19
|
+
`created_at` integer DEFAULT (unixepoch()) NOT NULL,
|
|
20
|
+
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
21
|
+
CONSTRAINT `trpc_pr_account_fk` FOREIGN KEY (`pr_id`,`account_id`) REFERENCES `pull_requests`(`id`,`account_id`) ON UPDATE no action ON DELETE cascade
|
|
22
|
+
);
|
|
23
|
+
--> statement-breakpoint
|
|
24
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `trpc_account_pr_head_ux` ON `ticket_review_pr_cards` (`account_id`,`pr_id`,`head_sha`);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- AUTO-POSTING OF CLAUDE REVIEW OUTPUT (review/claude-review/auto-post.ts, review/ticket-review/
|
|
2
|
+
-- auto-post.ts). A per-workspace master switch, OFF for every workspace existing and new, plus the
|
|
3
|
+
-- per-run records of what was posted and the per-item "posted automatically" flag.
|
|
4
|
+
-- workspaces.auto_post_enabled NULL/false = off. Nullable, no default: no insert names it.
|
|
5
|
+
-- workspaces.auto_post_settings JSON, OVERRIDES ONLY ({ scope?, kinds? }); NULL = defaults.
|
|
6
|
+
-- claude_reviews.auto_post JSON ClaudeAutoPostRecord; NULL = never looked at.
|
|
7
|
+
-- claude_review_findings.posted_auto true = posted by auto-posting.
|
|
8
|
+
-- ticket_reviews.auto_post JSON TicketAutoPostRecord; NULL = never looked at.
|
|
9
|
+
-- ticket_review_items.posted_auto true = posted by auto-posting (carried with the posting).
|
|
10
|
+
-- The Postgres twin is migrations-pg/0074_auto_post.sql.
|
|
11
|
+
ALTER TABLE `workspaces` ADD `auto_post_enabled` integer;
|
|
12
|
+
--> statement-breakpoint
|
|
13
|
+
ALTER TABLE `workspaces` ADD `auto_post_settings` text;
|
|
14
|
+
--> statement-breakpoint
|
|
15
|
+
ALTER TABLE `claude_reviews` ADD `auto_post` text;
|
|
16
|
+
--> statement-breakpoint
|
|
17
|
+
ALTER TABLE `claude_review_findings` ADD `posted_auto` integer;
|
|
18
|
+
--> statement-breakpoint
|
|
19
|
+
ALTER TABLE `ticket_reviews` ADD `auto_post` text;
|
|
20
|
+
--> statement-breakpoint
|
|
21
|
+
ALTER TABLE `ticket_review_items` ADD `posted_auto` integer;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
-- THE ISSUE TRACKER MOVES TO CORE (apiVersion 23). Ticket links, the stored tickets, the story panel
|
|
2
|
+
-- and the Open PRs ticket stacks are FREE and run in the public `npx limn-review` install, so their
|
|
3
|
+
-- tables leave the private plugin. The Postgres twin is migrations-pg/0075_issue_tracker.sql;
|
|
4
|
+
-- docs/TRACKERS.md has the contract and docs/MIGRATIONS.md the history.
|
|
5
|
+
--
|
|
6
|
+
-- workspace_trackers NEW. ONE tracker per workspace: provider, base URL, project-key allowlist,
|
|
7
|
+
-- match scope, and the Jira email + SEALED token. The values move here from
|
|
8
|
+
-- the plugin's `pro_workspace_settings` (plugin 0031/0035).
|
|
9
|
+
-- tracker_tickets NEW. The provider-aware generalisation of the plugin's
|
|
10
|
+
-- `pro_pr_jira_tickets` (plugin 0038/0039) — the same columns plus
|
|
11
|
+
-- `provider` (DEFAULT 'jira': every row that existed was a Jira row).
|
|
12
|
+
-- pro_jira_ac_fields ADOPTED IN PLACE, exactly the ai_fixes precedent (0074): same name, same
|
|
13
|
+
-- columns, same index name. Where the plugin created it this is a no-op and
|
|
14
|
+
-- its rows stay; on a fresh or plugin-less install it is created here.
|
|
15
|
+
--
|
|
16
|
+
-- ⚠ NO DATA IS COPIED BY THIS FILE, AND THAT IS DELIBERATE. The source rows live in PLUGIN tables,
|
|
17
|
+
-- which do not exist on a fresh install, on a plugin-less install, or (in the pg twin's case) may
|
|
18
|
+
-- not exist at all — and SQLite has no conditional DDL/DML to test for a table. The values are
|
|
19
|
+
-- MOVED by a guarded BOOT-TIME step instead (src/tracker/legacy-import.ts, run after the plugin
|
|
20
|
+
-- binds): it tests each source table and column for existence, copies with ON CONFLICT DO NOTHING,
|
|
21
|
+
-- and then CLEARS the source (deletes the ticket rows, NULLs the tracker columns) in the same
|
|
22
|
+
-- transaction — so a second boot finds nothing to move, a token is never left in two places, and a
|
|
23
|
+
-- value cleared in core is never resurrected from the old copy.
|
|
24
|
+
--
|
|
25
|
+
-- ⚠ WHY A NEW TICKETS TABLE RATHER THAN ADOPTING `pro_pr_jira_tickets` + ADD COLUMN `provider`.
|
|
26
|
+
-- Adopting needs `ALTER TABLE … ADD COLUMN provider` on a table this file may or may not have just
|
|
27
|
+
-- created, and `changed_at` (plugin 0039) may or may not already be on it — SQLite has no
|
|
28
|
+
-- ADD COLUMN IF NOT EXISTS, so one of the two install shapes would fail the boot. A new table has
|
|
29
|
+
-- one shape everywhere. Plugin 0038/0039 are stripped to no-ops in the same change, so a fresh
|
|
30
|
+
-- install never grows the old table at all.
|
|
31
|
+
--
|
|
32
|
+
-- Tenancy: `workspace_trackers.workspace_id` arrives in a request PATH, so its FK is the named
|
|
33
|
+
-- COMPOSITE one onto `workspaces (id, account_id)`. `tracker_tickets` and `pro_jira_ac_fields` are
|
|
34
|
+
-- written only by the server (the worker, and a route that resolves the PR's own workspace): no FKs,
|
|
35
|
+
-- like the tables they replace; every read predicates on account_id, both delete paths prune
|
|
36
|
+
-- tracker_tickets, and all three are in `accountScopedTables()`.
|
|
37
|
+
CREATE TABLE IF NOT EXISTS `workspace_trackers` (
|
|
38
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
39
|
+
`account_id` integer NOT NULL,
|
|
40
|
+
`workspace_id` integer NOT NULL,
|
|
41
|
+
`provider` text,
|
|
42
|
+
`base_url` text,
|
|
43
|
+
`project_keys` text,
|
|
44
|
+
`match_scope` text,
|
|
45
|
+
`auth_email` text,
|
|
46
|
+
`auth_token` text,
|
|
47
|
+
`updated_at` integer DEFAULT (unixepoch()) NOT NULL,
|
|
48
|
+
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
49
|
+
CONSTRAINT `workspace_trackers_workspace_account_fk` FOREIGN KEY (`workspace_id`,`account_id`) REFERENCES `workspaces`(`id`,`account_id`) ON UPDATE no action ON DELETE cascade
|
|
50
|
+
);
|
|
51
|
+
--> statement-breakpoint
|
|
52
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `workspace_trackers_account_workspace` ON `workspace_trackers` (`account_id`,`workspace_id`);
|
|
53
|
+
--> statement-breakpoint
|
|
54
|
+
CREATE TABLE IF NOT EXISTS `tracker_tickets` (
|
|
55
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
56
|
+
`account_id` integer NOT NULL,
|
|
57
|
+
`workspace_id` integer NOT NULL,
|
|
58
|
+
`pr_id` integer NOT NULL,
|
|
59
|
+
`provider` text DEFAULT 'jira' NOT NULL,
|
|
60
|
+
`issue_key` text NOT NULL,
|
|
61
|
+
`detected_from` text NOT NULL,
|
|
62
|
+
`detect_order` integer NOT NULL,
|
|
63
|
+
`api_root` text NOT NULL,
|
|
64
|
+
`url` text NOT NULL,
|
|
65
|
+
`state` text NOT NULL,
|
|
66
|
+
`error_code` text,
|
|
67
|
+
`title` text,
|
|
68
|
+
`description` text,
|
|
69
|
+
`acceptance_criteria` text,
|
|
70
|
+
`ac_field_id` text,
|
|
71
|
+
`ac_field_name` text,
|
|
72
|
+
`ac_field_source` text,
|
|
73
|
+
`issue_type_id` text,
|
|
74
|
+
`issue_type_name` text,
|
|
75
|
+
`status_name` text,
|
|
76
|
+
`status_category` text,
|
|
77
|
+
`assignee_name` text,
|
|
78
|
+
`assignee_account_id` text,
|
|
79
|
+
`assignee_avatar_url` text,
|
|
80
|
+
`candidates_json` text,
|
|
81
|
+
`omitted_candidates` integer DEFAULT 0 NOT NULL,
|
|
82
|
+
`fetched_at` integer,
|
|
83
|
+
`checked_at` integer NOT NULL,
|
|
84
|
+
`next_check_at` integer NOT NULL,
|
|
85
|
+
`changed_at` integer
|
|
86
|
+
);
|
|
87
|
+
--> statement-breakpoint
|
|
88
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `tracker_tickets_account_pr_key` ON `tracker_tickets` (`account_id`,`pr_id`,`issue_key`);
|
|
89
|
+
--> statement-breakpoint
|
|
90
|
+
CREATE INDEX IF NOT EXISTS `tracker_tickets_account_ws_type` ON `tracker_tickets` (`account_id`,`workspace_id`,`issue_type_id`);
|
|
91
|
+
--> statement-breakpoint
|
|
92
|
+
CREATE INDEX IF NOT EXISTS `tracker_tickets_account_site_key` ON `tracker_tickets` (`account_id`,`provider`,`api_root`,`issue_key`);
|
|
93
|
+
--> statement-breakpoint
|
|
94
|
+
CREATE INDEX IF NOT EXISTS `tracker_tickets_account_changed` ON `tracker_tickets` (`account_id`,`changed_at`);
|
|
95
|
+
--> statement-breakpoint
|
|
96
|
+
CREATE INDEX IF NOT EXISTS `tracker_tickets_pr` ON `tracker_tickets` (`pr_id`);
|
|
97
|
+
--> statement-breakpoint
|
|
98
|
+
CREATE TABLE IF NOT EXISTS `pro_jira_ac_fields` (
|
|
99
|
+
`id` integer PRIMARY KEY AUTOINCREMENT,
|
|
100
|
+
`account_id` integer NOT NULL,
|
|
101
|
+
`workspace_id` integer NOT NULL,
|
|
102
|
+
`api_root` text NOT NULL,
|
|
103
|
+
`issue_type_id` text NOT NULL,
|
|
104
|
+
`field_id` text NOT NULL,
|
|
105
|
+
`field_name` text NOT NULL,
|
|
106
|
+
`updated_at` integer NOT NULL
|
|
107
|
+
);
|
|
108
|
+
--> statement-breakpoint
|
|
109
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `pro_jira_ac_fields_account_ws_site_type` ON `pro_jira_ac_fields` (`account_id`,`workspace_id`,`api_root`,`issue_type_id`);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- GITHUB ISSUES — the tracker's second reading adapter (docs/TRACKERS.md § GitHub Issues). The
|
|
2
|
+
-- Postgres twin is migrations-pg/0076_github_issue_links.sql.
|
|
3
|
+
--
|
|
4
|
+
-- A GitHub Issues workspace links a pull request to the issues it CLOSES — GitHub's own
|
|
5
|
+
-- `closingIssuesReferences` ("Fixes #12", "Closes owner/repo#12", a Development-panel link), never
|
|
6
|
+
-- a bare "#12" mention. That list is a fact about the PR that the view paths (the PR pane's chips,
|
|
7
|
+
-- the Open PRs ticket row) must read without calling GitHub, so it is stored on the PR:
|
|
8
|
+
--
|
|
9
|
+
-- closing_issues JSON array of lower-cased `owner/repo#12` keys, in GitHub's order.
|
|
10
|
+
-- closing_issues_checked_at when it was last read.
|
|
11
|
+
--
|
|
12
|
+
-- ⚠ NULL IS "NEVER READ", NOT "CLOSES NOTHING" (`[]` is GitHub's positive statement). Both are
|
|
13
|
+
-- written ONLY by the tracker worker's targeted `nodes(ids:)` step, and only for PRs in a workspace
|
|
14
|
+
-- whose tracker is GitHub Issues — the repo walk's query is unchanged, so every other workspace pays
|
|
15
|
+
-- nothing for this. Additive; no data to move.
|
|
16
|
+
ALTER TABLE `pull_requests` ADD `closing_issues` text;
|
|
17
|
+
--> statement-breakpoint
|
|
18
|
+
ALTER TABLE `pull_requests` ADD `closing_issues_checked_at` integer;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-- LINEAR — the tracker's third reading adapter (docs/TRACKERS.md § Linear). The Postgres twin is
|
|
2
|
+
-- migrations-pg/0077_linear_links.sql.
|
|
3
|
+
--
|
|
4
|
+
-- A Linear workspace links a pull request to the Linear issues Linear's GitHub integration ATTACHED
|
|
5
|
+
-- it to (`attachmentsForURL` on the PR's GitHub URL — it sees the PR body, which lean storage never
|
|
6
|
+
-- keeps), in addition to the keys detection finds in the title and branch. That list is a fact the
|
|
7
|
+
-- view paths must read without calling Linear, so it is stored on the PR:
|
|
8
|
+
--
|
|
9
|
+
-- linear_links JSON array of upper-cased `ENG-123` keys, in Linear's order.
|
|
10
|
+
-- linear_links_root the Linear workspace they were read against (`https://linear.app/<key>`);
|
|
11
|
+
-- a different current root means "never read" for this workspace.
|
|
12
|
+
-- linear_links_checked_at when they were last read.
|
|
13
|
+
--
|
|
14
|
+
-- ⚠ NULL IS "NEVER READ", NOT "ATTACHED TO NOTHING" (`[]` is Linear's positive statement) — and for
|
|
15
|
+
-- Linear an unread PR still shows the tickets detection finds. Written ONLY by the tracker worker,
|
|
16
|
+
-- only for PRs in a workspace whose tracker is Linear with a saved key; the repo walk is unchanged,
|
|
17
|
+
-- so every other workspace pays nothing. Additive; no data to move.
|
|
18
|
+
ALTER TABLE `pull_requests` ADD `linear_links` text;
|
|
19
|
+
--> statement-breakpoint
|
|
20
|
+
ALTER TABLE `pull_requests` ADD `linear_links_root` text;
|
|
21
|
+
--> statement-breakpoint
|
|
22
|
+
ALTER TABLE `pull_requests` ADD `linear_links_checked_at` integer;
|
|
@@ -589,6 +589,55 @@
|
|
|
589
589
|
"when": 1790665200000,
|
|
590
590
|
"tag": "0083_workspace_auto_fix",
|
|
591
591
|
"breakpoints": true
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
"idx": 84,
|
|
595
|
+
"version": "6",
|
|
596
|
+
"when": 1790751600000,
|
|
597
|
+
"tag": "0084_auto_fix_off_by_default",
|
|
598
|
+
"breakpoints": true
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
"idx": 85,
|
|
602
|
+
"version": "6",
|
|
603
|
+
"when": 1790838000000,
|
|
604
|
+
"tag": "0085_auto_review_daily_cap",
|
|
605
|
+
"breakpoints": true
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
"idx": 86,
|
|
609
|
+
"version": "6",
|
|
610
|
+
"when": 1790841600000,
|
|
611
|
+
"tag": "0086_ticket_review_pr_cards",
|
|
612
|
+
"breakpoints": true
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
"idx": 87,
|
|
616
|
+
"version": "6",
|
|
617
|
+
"when": 1790928000000,
|
|
618
|
+
"tag": "0087_auto_post",
|
|
619
|
+
"breakpoints": true
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
"idx": 88,
|
|
623
|
+
"version": "6",
|
|
624
|
+
"when": 1791014400000,
|
|
625
|
+
"tag": "0088_issue_tracker",
|
|
626
|
+
"breakpoints": true
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
"idx": 89,
|
|
630
|
+
"version": "6",
|
|
631
|
+
"when": 1791100800000,
|
|
632
|
+
"tag": "0089_github_issue_links",
|
|
633
|
+
"breakpoints": true
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
"idx": 90,
|
|
637
|
+
"version": "6",
|
|
638
|
+
"when": 1791187200000,
|
|
639
|
+
"tag": "0090_linear_links",
|
|
640
|
+
"breakpoints": true
|
|
592
641
|
}
|
|
593
642
|
]
|
|
594
643
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- Postgres twin of migrations/0084_auto_fix_off_by_default.sql: auto AI Fix is OFF by default,
|
|
2
|
+
-- and every existing workspace is switched off once.
|
|
3
|
+
ALTER TABLE "workspaces" ALTER COLUMN "auto_fix_enabled" SET DEFAULT false;
|
|
4
|
+
--> statement-breakpoint
|
|
5
|
+
UPDATE "workspaces" SET "auto_fix_enabled" = false;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Postgres twin of migrations/0086_ticket_review_pr_cards.sql: ticket review contribution cards,
|
|
2
|
+
-- one row per (account, PR, head commit). The contract lives in schema.sqlite.ts.
|
|
3
|
+
CREATE TABLE IF NOT EXISTS "ticket_review_pr_cards" (
|
|
4
|
+
"id" serial PRIMARY KEY NOT NULL,
|
|
5
|
+
"account_id" integer NOT NULL,
|
|
6
|
+
"pr_id" integer NOT NULL,
|
|
7
|
+
"head_sha" text NOT NULL,
|
|
8
|
+
"card" jsonb NOT NULL,
|
|
9
|
+
"source" text NOT NULL,
|
|
10
|
+
"model" text NOT NULL,
|
|
11
|
+
"cost_usd" double precision,
|
|
12
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
13
|
+
CONSTRAINT "ticket_review_pr_cards_account_id_accounts_id_fk" FOREIGN KEY ("account_id") REFERENCES "accounts"("id") ON DELETE cascade,
|
|
14
|
+
CONSTRAINT "trpc_pr_account_fk" FOREIGN KEY ("pr_id","account_id") REFERENCES "pull_requests"("id","account_id") ON DELETE cascade
|
|
15
|
+
);
|
|
16
|
+
--> statement-breakpoint
|
|
17
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "trpc_account_pr_head_ux" ON "ticket_review_pr_cards" USING btree ("account_id","pr_id","head_sha");
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- Postgres twin of migrations/0087_auto_post.sql: auto-posting of Claude review output. A
|
|
2
|
+
-- per-workspace switch (NULL/false = off) + overrides-only settings, the per-run records and the
|
|
3
|
+
-- per-item "posted automatically" flags. The contract lives in schema.sqlite.ts.
|
|
4
|
+
ALTER TABLE "workspaces" ADD COLUMN IF NOT EXISTS "auto_post_enabled" boolean;
|
|
5
|
+
--> statement-breakpoint
|
|
6
|
+
ALTER TABLE "workspaces" ADD COLUMN IF NOT EXISTS "auto_post_settings" jsonb;
|
|
7
|
+
--> statement-breakpoint
|
|
8
|
+
ALTER TABLE "claude_reviews" ADD COLUMN IF NOT EXISTS "auto_post" jsonb;
|
|
9
|
+
--> statement-breakpoint
|
|
10
|
+
ALTER TABLE "claude_review_findings" ADD COLUMN IF NOT EXISTS "posted_auto" boolean;
|
|
11
|
+
--> statement-breakpoint
|
|
12
|
+
ALTER TABLE "ticket_reviews" ADD COLUMN IF NOT EXISTS "auto_post" jsonb;
|
|
13
|
+
--> statement-breakpoint
|
|
14
|
+
ALTER TABLE "ticket_review_items" ADD COLUMN IF NOT EXISTS "posted_auto" boolean;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
-- Postgres twin of migrations/0088_issue_tracker.sql: the issue tracker moves to CORE
|
|
2
|
+
-- (apiVersion 23). `workspace_trackers` and `tracker_tickets` are new; `pro_jira_ac_fields` is
|
|
3
|
+
-- ADOPTED IN PLACE (the plugin's pg 0038 shape, same index name). No data is copied here — the
|
|
4
|
+
-- boot-time move (src/tracker/legacy-import.ts) does that, guarded on the plugin tables existing.
|
|
5
|
+
-- Rationale in the sqlite twin and docs/TRACKERS.md.
|
|
6
|
+
CREATE TABLE IF NOT EXISTS "workspace_trackers" (
|
|
7
|
+
"id" serial PRIMARY KEY NOT NULL,
|
|
8
|
+
"account_id" integer NOT NULL REFERENCES "accounts"("id") ON DELETE cascade,
|
|
9
|
+
"workspace_id" integer NOT NULL,
|
|
10
|
+
"provider" text,
|
|
11
|
+
"base_url" text,
|
|
12
|
+
"project_keys" text,
|
|
13
|
+
"match_scope" text,
|
|
14
|
+
"auth_email" text,
|
|
15
|
+
"auth_token" text,
|
|
16
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
17
|
+
CONSTRAINT "workspace_trackers_workspace_account_fk" FOREIGN KEY ("workspace_id","account_id") REFERENCES "workspaces"("id","account_id") ON DELETE cascade
|
|
18
|
+
);
|
|
19
|
+
--> statement-breakpoint
|
|
20
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "workspace_trackers_account_workspace" ON "workspace_trackers" USING btree ("account_id","workspace_id");
|
|
21
|
+
--> statement-breakpoint
|
|
22
|
+
CREATE TABLE IF NOT EXISTS "tracker_tickets" (
|
|
23
|
+
"id" serial PRIMARY KEY NOT NULL,
|
|
24
|
+
"account_id" integer NOT NULL,
|
|
25
|
+
"workspace_id" integer NOT NULL,
|
|
26
|
+
"pr_id" integer NOT NULL,
|
|
27
|
+
"provider" text DEFAULT 'jira' NOT NULL,
|
|
28
|
+
"issue_key" text NOT NULL,
|
|
29
|
+
"detected_from" text NOT NULL,
|
|
30
|
+
"detect_order" integer NOT NULL,
|
|
31
|
+
"api_root" text NOT NULL,
|
|
32
|
+
"url" text NOT NULL,
|
|
33
|
+
"state" text NOT NULL,
|
|
34
|
+
"error_code" text,
|
|
35
|
+
"title" text,
|
|
36
|
+
"description" text,
|
|
37
|
+
"acceptance_criteria" text,
|
|
38
|
+
"ac_field_id" text,
|
|
39
|
+
"ac_field_name" text,
|
|
40
|
+
"ac_field_source" text,
|
|
41
|
+
"issue_type_id" text,
|
|
42
|
+
"issue_type_name" text,
|
|
43
|
+
"status_name" text,
|
|
44
|
+
"status_category" text,
|
|
45
|
+
"assignee_name" text,
|
|
46
|
+
"assignee_account_id" text,
|
|
47
|
+
"assignee_avatar_url" text,
|
|
48
|
+
"candidates_json" text,
|
|
49
|
+
"omitted_candidates" integer DEFAULT 0 NOT NULL,
|
|
50
|
+
"fetched_at" timestamp with time zone,
|
|
51
|
+
"checked_at" timestamp with time zone NOT NULL,
|
|
52
|
+
"next_check_at" timestamp with time zone NOT NULL,
|
|
53
|
+
"changed_at" timestamp with time zone
|
|
54
|
+
);
|
|
55
|
+
--> statement-breakpoint
|
|
56
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "tracker_tickets_account_pr_key" ON "tracker_tickets" USING btree ("account_id","pr_id","issue_key");
|
|
57
|
+
--> statement-breakpoint
|
|
58
|
+
CREATE INDEX IF NOT EXISTS "tracker_tickets_account_ws_type" ON "tracker_tickets" USING btree ("account_id","workspace_id","issue_type_id");
|
|
59
|
+
--> statement-breakpoint
|
|
60
|
+
CREATE INDEX IF NOT EXISTS "tracker_tickets_account_site_key" ON "tracker_tickets" USING btree ("account_id","provider","api_root","issue_key");
|
|
61
|
+
--> statement-breakpoint
|
|
62
|
+
CREATE INDEX IF NOT EXISTS "tracker_tickets_account_changed" ON "tracker_tickets" USING btree ("account_id","changed_at");
|
|
63
|
+
--> statement-breakpoint
|
|
64
|
+
CREATE INDEX IF NOT EXISTS "tracker_tickets_pr" ON "tracker_tickets" USING btree ("pr_id");
|
|
65
|
+
--> statement-breakpoint
|
|
66
|
+
CREATE TABLE IF NOT EXISTS "pro_jira_ac_fields" (
|
|
67
|
+
"id" serial PRIMARY KEY,
|
|
68
|
+
"account_id" integer NOT NULL,
|
|
69
|
+
"workspace_id" integer NOT NULL,
|
|
70
|
+
"api_root" text NOT NULL,
|
|
71
|
+
"issue_type_id" text NOT NULL,
|
|
72
|
+
"field_id" text NOT NULL,
|
|
73
|
+
"field_name" text NOT NULL,
|
|
74
|
+
"updated_at" timestamptz NOT NULL
|
|
75
|
+
);
|
|
76
|
+
--> statement-breakpoint
|
|
77
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "pro_jira_ac_fields_account_ws_site_type" ON "pro_jira_ac_fields" ("account_id","workspace_id","api_root","issue_type_id");
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- GITHUB ISSUES LINKS — the Postgres twin of migrations/0089_github_issue_links.sql (read that file
|
|
2
|
+
-- for the rationale). The issues a PR closes, as GitHub states them, read only for GitHub Issues
|
|
3
|
+
-- workspaces; NULL is "never read", never "closes nothing". Additive.
|
|
4
|
+
ALTER TABLE "pull_requests" ADD COLUMN IF NOT EXISTS "closing_issues" jsonb;
|
|
5
|
+
--> statement-breakpoint
|
|
6
|
+
ALTER TABLE "pull_requests" ADD COLUMN IF NOT EXISTS "closing_issues_checked_at" timestamp with time zone;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- LINEAR LINKS — the Postgres twin of migrations/0090_linear_links.sql (read that file for the
|
|
2
|
+
-- rationale). The Linear issues a PR is attached to, read only for Linear workspaces with a saved
|
|
3
|
+
-- key, and the Linear workspace they were read against; NULL is "never read". Additive.
|
|
4
|
+
ALTER TABLE "pull_requests" ADD COLUMN IF NOT EXISTS "linear_links" jsonb;
|
|
5
|
+
--> statement-breakpoint
|
|
6
|
+
ALTER TABLE "pull_requests" ADD COLUMN IF NOT EXISTS "linear_links_root" text;
|
|
7
|
+
--> statement-breakpoint
|
|
8
|
+
ALTER TABLE "pull_requests" ADD COLUMN IF NOT EXISTS "linear_links_checked_at" timestamp with time zone;
|