kanbo-cli 0.1.0

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.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -0
  3. package/dist/better-sqlite3-fU3G4xnX.cjs +2254 -0
  4. package/dist/better-sqlite3-fU3G4xnX.cjs.map +1 -0
  5. package/dist/cli.cjs +42949 -0
  6. package/dist/cli.cjs.map +1 -0
  7. package/dist/dist-Cd6wg8pp.cjs +942 -0
  8. package/dist/dist-Cd6wg8pp.cjs.map +1 -0
  9. package/dist/drizzle-postgres/0000_board.sql +135 -0
  10. package/dist/drizzle-postgres/0001_history_order.sql +2 -0
  11. package/dist/drizzle-postgres/0002_issue_pull_requests.sql +16 -0
  12. package/dist/drizzle-postgres/0003_milestone_start_date.sql +1 -0
  13. package/dist/drizzle-postgres/0004_status_entry_rules.sql +1 -0
  14. package/dist/drizzle-postgres/0005_run_external_session_ref.sql +1 -0
  15. package/dist/drizzle-postgres/README.md +61 -0
  16. package/dist/drizzle-postgres/meta/0000_snapshot.json +1078 -0
  17. package/dist/drizzle-postgres/meta/0001_snapshot.json +1090 -0
  18. package/dist/drizzle-postgres/meta/0002_snapshot.json +1239 -0
  19. package/dist/drizzle-postgres/meta/0003_snapshot.json +1245 -0
  20. package/dist/drizzle-postgres/meta/0004_snapshot.json +1251 -0
  21. package/dist/drizzle-postgres/meta/0005_snapshot.json +1257 -0
  22. package/dist/drizzle-postgres/meta/_journal.json +48 -0
  23. package/dist/drizzle-sqlite/0000_board.sql +133 -0
  24. package/dist/drizzle-sqlite/0001_issue_pull_requests.sql +15 -0
  25. package/dist/drizzle-sqlite/0002_milestone_start_date.sql +1 -0
  26. package/dist/drizzle-sqlite/0003_status_entry_rules.sql +1 -0
  27. package/dist/drizzle-sqlite/0004_run_external_session_ref.sql +1 -0
  28. package/dist/drizzle-sqlite/README.md +67 -0
  29. package/dist/drizzle-sqlite/meta/0000_snapshot.json +946 -0
  30. package/dist/drizzle-sqlite/meta/0001_snapshot.json +1054 -0
  31. package/dist/drizzle-sqlite/meta/0002_snapshot.json +1061 -0
  32. package/dist/drizzle-sqlite/meta/0003_snapshot.json +1068 -0
  33. package/dist/drizzle-sqlite/meta/0004_snapshot.json +1075 -0
  34. package/dist/drizzle-sqlite/meta/_journal.json +41 -0
  35. package/dist/lib/board-store-B16YarvX.d.mts +281 -0
  36. package/dist/lib/board-store-BHHo_ZlR.d.cts +281 -0
  37. package/dist/lib/index.cjs +340 -0
  38. package/dist/lib/index.cjs.map +1 -0
  39. package/dist/lib/index.d.cts +1608 -0
  40. package/dist/lib/index.d.mts +1608 -0
  41. package/dist/lib/index.mjs +284 -0
  42. package/dist/lib/index.mjs.map +1 -0
  43. package/dist/lib/manifest-C0EcwwgO.mjs +7866 -0
  44. package/dist/lib/manifest-C0EcwwgO.mjs.map +1 -0
  45. package/dist/lib/manifest-CpZOcB_6.cjs +8272 -0
  46. package/dist/lib/manifest-CpZOcB_6.cjs.map +1 -0
  47. package/dist/lib/mcp/index.cjs +184 -0
  48. package/dist/lib/mcp/index.cjs.map +1 -0
  49. package/dist/lib/mcp/index.d.cts +346 -0
  50. package/dist/lib/mcp/index.d.mts +346 -0
  51. package/dist/lib/mcp/index.mjs +173 -0
  52. package/dist/lib/mcp/index.mjs.map +1 -0
  53. package/dist/lib/migrate-BhYi9cXw.mjs +656 -0
  54. package/dist/lib/migrate-BhYi9cXw.mjs.map +1 -0
  55. package/dist/lib/migrate-DnMjTCvu.cjs +709 -0
  56. package/dist/lib/migrate-DnMjTCvu.cjs.map +1 -0
  57. package/dist/lib/migrations-path-CZxVOgeD.cjs +109 -0
  58. package/dist/lib/migrations-path-CZxVOgeD.cjs.map +1 -0
  59. package/dist/lib/migrations-path-Ciwan537.mjs +80 -0
  60. package/dist/lib/migrations-path-Ciwan537.mjs.map +1 -0
  61. package/dist/lib/postgres/index.cjs +56 -0
  62. package/dist/lib/postgres/index.cjs.map +1 -0
  63. package/dist/lib/postgres/index.d.cts +3403 -0
  64. package/dist/lib/postgres/index.d.mts +3403 -0
  65. package/dist/lib/postgres/index.mjs +35 -0
  66. package/dist/lib/postgres/index.mjs.map +1 -0
  67. package/dist/lib/roles.sql-B9rt-x4o.cjs +1033 -0
  68. package/dist/lib/roles.sql-B9rt-x4o.cjs.map +1 -0
  69. package/dist/lib/roles.sql-CvyCGt38.mjs +920 -0
  70. package/dist/lib/roles.sql-CvyCGt38.mjs.map +1 -0
  71. package/dist/lib/schema-epoch-ZyumVL_A.d.cts +16 -0
  72. package/dist/lib/schema-epoch-ZyumVL_A.d.mts +16 -0
  73. package/dist/lib/schema-fsHqNAip.d.cts +3612 -0
  74. package/dist/lib/schema-fsHqNAip.d.mts +3612 -0
  75. package/dist/lib/sqlite/index.cjs +23 -0
  76. package/dist/lib/sqlite/index.d.cts +175 -0
  77. package/dist/lib/sqlite/index.d.mts +175 -0
  78. package/dist/lib/sqlite/index.mjs +4 -0
  79. package/dist/lib/sqlite/schema.cjs +266 -0
  80. package/dist/lib/sqlite/schema.cjs.map +1 -0
  81. package/dist/lib/sqlite/schema.d.cts +2 -0
  82. package/dist/lib/sqlite/schema.d.mts +2 -0
  83. package/dist/lib/sqlite/schema.mjs +256 -0
  84. package/dist/lib/sqlite/schema.mjs.map +1 -0
  85. package/dist/lib/tool-names-9cmCn0gP.d.cts +112 -0
  86. package/dist/lib/tool-names-Dxg1UTUl.d.mts +112 -0
  87. package/dist/page/board.css +477 -0
  88. package/dist/page/board.js +2 -0
  89. package/drizzle-postgres/0000_board.sql +135 -0
  90. package/drizzle-postgres/0001_history_order.sql +2 -0
  91. package/drizzle-postgres/0002_issue_pull_requests.sql +16 -0
  92. package/drizzle-postgres/0003_milestone_start_date.sql +1 -0
  93. package/drizzle-postgres/0004_status_entry_rules.sql +1 -0
  94. package/drizzle-postgres/0005_run_external_session_ref.sql +1 -0
  95. package/drizzle-postgres/README.md +61 -0
  96. package/drizzle-postgres/meta/0000_snapshot.json +1078 -0
  97. package/drizzle-postgres/meta/0001_snapshot.json +1090 -0
  98. package/drizzle-postgres/meta/0002_snapshot.json +1239 -0
  99. package/drizzle-postgres/meta/0003_snapshot.json +1245 -0
  100. package/drizzle-postgres/meta/0004_snapshot.json +1251 -0
  101. package/drizzle-postgres/meta/0005_snapshot.json +1257 -0
  102. package/drizzle-postgres/meta/_journal.json +48 -0
  103. package/drizzle-sqlite/0000_board.sql +133 -0
  104. package/drizzle-sqlite/0001_issue_pull_requests.sql +15 -0
  105. package/drizzle-sqlite/0002_milestone_start_date.sql +1 -0
  106. package/drizzle-sqlite/0003_status_entry_rules.sql +1 -0
  107. package/drizzle-sqlite/0004_run_external_session_ref.sql +1 -0
  108. package/drizzle-sqlite/README.md +67 -0
  109. package/drizzle-sqlite/meta/0000_snapshot.json +946 -0
  110. package/drizzle-sqlite/meta/0001_snapshot.json +1054 -0
  111. package/drizzle-sqlite/meta/0002_snapshot.json +1061 -0
  112. package/drizzle-sqlite/meta/0003_snapshot.json +1068 -0
  113. package/drizzle-sqlite/meta/0004_snapshot.json +1075 -0
  114. package/drizzle-sqlite/meta/_journal.json +41 -0
  115. package/package.json +147 -0
@@ -0,0 +1,477 @@
1
+ /*
2
+ * The board page's look: a small set of colour and spacing tokens, with
3
+ * Tailwind's colour values written out. No web fonts: the page loads nothing
4
+ * but itself.
5
+ */
6
+
7
+ :root {
8
+ --neutral-50: oklch(98.5% 0 0);
9
+ --neutral-100: oklch(97% 0 0);
10
+ --neutral-400: oklch(70.8% 0 0);
11
+ --neutral-500: oklch(55.6% 0 0);
12
+ --neutral-800: oklch(26.9% 0 0);
13
+ --neutral-950: oklch(14.5% 0 0);
14
+ --amber-500: oklch(76.9% 0.188 70.08);
15
+ --emerald-500: oklch(69.6% 0.17 162.48);
16
+ --blue-500: oklch(62.3% 0.214 259.815);
17
+ --red-500: oklch(63.7% 0.237 25.331);
18
+
19
+ --radius: 0.625rem;
20
+ --topbar-height: 45px;
21
+ --background: var(--neutral-50);
22
+ --foreground: var(--neutral-800);
23
+ --card: #fff;
24
+ --primary: var(--neutral-800);
25
+ --primary-foreground: var(--neutral-50);
26
+ --muted: rgb(0 0 0 / 4%);
27
+ --muted-foreground: var(--neutral-500);
28
+ --accent: rgb(0 0 0 / 7%);
29
+ --border: rgb(0 0 0 / 6%);
30
+ --border-strong: rgb(0 0 0 / 14%);
31
+ --input: rgb(0 0 0 / 7%);
32
+ --ring: var(--neutral-400);
33
+ --destructive: var(--red-500);
34
+ --info: var(--blue-500);
35
+ --success: var(--emerald-500);
36
+ --warning: var(--amber-500);
37
+ --font-sans: 'Geist Variable', 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
38
+ --font-mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
39
+ color-scheme: light dark;
40
+ }
41
+
42
+ @media (prefers-color-scheme: dark) {
43
+ :root {
44
+ --background: color-mix(in srgb, var(--neutral-950) 94%, #fff);
45
+ --foreground: var(--neutral-100);
46
+ --card: color-mix(in srgb, var(--background) 98%, #fff);
47
+ --primary: var(--neutral-100);
48
+ --primary-foreground: var(--neutral-800);
49
+ --muted: rgb(255 255 255 / 4%);
50
+ --muted-foreground: color-mix(in srgb, var(--neutral-500) 90%, #fff);
51
+ --accent: rgb(255 255 255 / 8%);
52
+ --border: rgb(255 255 255 / 5%);
53
+ --border-strong: rgb(255 255 255 / 12%);
54
+ --input: rgb(255 255 255 / 7%);
55
+ --ring: var(--neutral-500);
56
+ --destructive: color-mix(in srgb, var(--red-500) 90%, #fff);
57
+ }
58
+ }
59
+
60
+ * {
61
+ box-sizing: border-box;
62
+ }
63
+
64
+ body {
65
+ margin: 0;
66
+ background: var(--background);
67
+ color: var(--foreground);
68
+ font-family: var(--font-sans);
69
+ font-size: 14px;
70
+ -webkit-font-smoothing: antialiased;
71
+ }
72
+
73
+ :focus-visible {
74
+ outline: 2px solid var(--ring);
75
+ outline-offset: 2px;
76
+ }
77
+
78
+ button {
79
+ font: inherit;
80
+ color: inherit;
81
+ cursor: pointer;
82
+ border: 0;
83
+ border-radius: calc(var(--radius) * 0.8);
84
+ padding: 4px 10px;
85
+ font-size: 12px;
86
+ font-weight: 500;
87
+ }
88
+
89
+ .primary {
90
+ background: var(--primary);
91
+ color: var(--primary-foreground);
92
+ }
93
+
94
+ .secondary {
95
+ background: var(--card);
96
+ box-shadow: inset 0 0 0 1px var(--border-strong);
97
+ }
98
+
99
+ .ghost {
100
+ background: transparent;
101
+ color: var(--muted-foreground);
102
+ }
103
+
104
+ .ghost:hover,
105
+ .secondary:hover {
106
+ background: var(--accent);
107
+ }
108
+
109
+ .field {
110
+ font: inherit;
111
+ font-size: 13px;
112
+ color: inherit;
113
+ width: 100%;
114
+ background: var(--card);
115
+ border: 1px solid var(--input);
116
+ border-radius: calc(var(--radius) * 0.8);
117
+ padding: 6px 8px;
118
+ resize: vertical;
119
+ }
120
+
121
+ .row {
122
+ display: flex;
123
+ gap: 6px;
124
+ margin-top: 6px;
125
+ }
126
+
127
+ /* The top bar */
128
+
129
+ .topbar {
130
+ display: flex;
131
+ align-items: center;
132
+ gap: 12px;
133
+ height: var(--topbar-height);
134
+ padding: 0 16px;
135
+ border-bottom: 1px solid var(--border);
136
+ }
137
+
138
+ .topbar-title {
139
+ margin: 0;
140
+ font-size: 14px;
141
+ font-weight: 600;
142
+ }
143
+
144
+ .workspace {
145
+ font-family: var(--font-mono);
146
+ font-size: 12px;
147
+ color: var(--muted-foreground);
148
+ }
149
+
150
+ .token-form {
151
+ margin-left: auto;
152
+ display: flex;
153
+ align-items: center;
154
+ gap: 6px;
155
+ }
156
+
157
+ .token-label {
158
+ display: flex;
159
+ align-items: center;
160
+ gap: 6px;
161
+ font-size: 12px;
162
+ color: var(--muted-foreground);
163
+ }
164
+
165
+ .token-input {
166
+ width: 180px;
167
+ padding: 3px 8px;
168
+ }
169
+
170
+ .notice {
171
+ margin: 8px 16px 0;
172
+ padding: 6px 10px;
173
+ border-radius: calc(var(--radius) * 0.8);
174
+ font-size: 12px;
175
+ background: var(--muted);
176
+ }
177
+
178
+ .notice[data-kind='error'] {
179
+ color: var(--destructive);
180
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--destructive) 40%, transparent);
181
+ }
182
+
183
+ /* The board */
184
+
185
+ .board {
186
+ display: flex;
187
+ gap: 12px;
188
+ align-items: flex-start;
189
+ padding: 12px 16px 24px;
190
+ overflow-x: auto;
191
+ min-height: calc(100vh - var(--topbar-height));
192
+ }
193
+
194
+ .column {
195
+ flex: 0 0 280px;
196
+ display: flex;
197
+ flex-direction: column;
198
+ gap: 8px;
199
+ padding: 6px;
200
+ border-radius: var(--radius);
201
+ min-height: 120px;
202
+ }
203
+
204
+ .column.drop-target {
205
+ background: var(--muted);
206
+ box-shadow: inset 0 0 0 1px var(--border-strong);
207
+ }
208
+
209
+ .column-head {
210
+ display: flex;
211
+ align-items: center;
212
+ gap: 6px;
213
+ padding: 2px 4px;
214
+ font-size: 13px;
215
+ font-weight: 500;
216
+ }
217
+
218
+ .column-count {
219
+ color: var(--muted-foreground);
220
+ font-variant-numeric: tabular-nums;
221
+ font-size: 12px;
222
+ }
223
+
224
+ .column-add {
225
+ margin-left: auto;
226
+ }
227
+
228
+ .column-cards {
229
+ display: flex;
230
+ flex-direction: column;
231
+ gap: 8px;
232
+ }
233
+
234
+ .draft {
235
+ padding: 8px;
236
+ background: var(--card);
237
+ border-radius: var(--radius);
238
+ box-shadow: inset 0 0 0 1px var(--border-strong);
239
+ }
240
+
241
+ /* A card */
242
+
243
+ .card {
244
+ position: relative;
245
+ display: flex;
246
+ flex-direction: column;
247
+ gap: 6px;
248
+ padding: 10px 12px;
249
+ background: var(--card);
250
+ border-radius: var(--radius);
251
+ box-shadow: inset 0 0 0 1px var(--border);
252
+ transition: box-shadow 150ms cubic-bezier(0.22, 1, 0.36, 1);
253
+ }
254
+
255
+ .card:hover {
256
+ box-shadow: inset 0 0 0 1px var(--border-strong);
257
+ }
258
+
259
+ .card.dragging {
260
+ opacity: 0.4;
261
+ }
262
+
263
+ .card-head {
264
+ display: flex;
265
+ align-items: center;
266
+ justify-content: space-between;
267
+ gap: 8px;
268
+ }
269
+
270
+ .card-key {
271
+ font-family: var(--font-mono);
272
+ font-size: 10px;
273
+ color: var(--muted-foreground);
274
+ font-variant-numeric: tabular-nums;
275
+ }
276
+
277
+ .card-title {
278
+ all: unset;
279
+ font-size: 13px;
280
+ font-weight: 500;
281
+ line-height: 1.375;
282
+ text-wrap: pretty;
283
+ overflow-wrap: anywhere;
284
+ cursor: pointer;
285
+ }
286
+
287
+ /* The title is the card's one button, stretched over the whole card. */
288
+ .card-title::after {
289
+ content: '';
290
+ position: absolute;
291
+ inset: 0;
292
+ border-radius: var(--radius);
293
+ }
294
+
295
+ .card-title:focus-visible::after {
296
+ outline: 2px solid var(--ring);
297
+ outline-offset: 2px;
298
+ }
299
+
300
+ .card-status {
301
+ display: flex;
302
+ align-items: center;
303
+ gap: 6px;
304
+ min-width: 0;
305
+ }
306
+
307
+ .status-line {
308
+ flex: 1;
309
+ min-width: 0;
310
+ margin: 0;
311
+ padding-left: 8px;
312
+ border-left: 2px solid var(--border);
313
+ font-size: 11px;
314
+ line-height: 1.375;
315
+ color: var(--muted-foreground);
316
+ white-space: nowrap;
317
+ overflow: hidden;
318
+ text-overflow: ellipsis;
319
+ }
320
+
321
+ .status-line[data-category='triage'] {
322
+ border-left-color: color-mix(in srgb, var(--info) 60%, transparent);
323
+ }
324
+
325
+ .status-line[data-category='started'] {
326
+ border-left-color: color-mix(in srgb, var(--warning) 60%, transparent);
327
+ }
328
+
329
+ .status-line[data-category='completed'] {
330
+ border-left-color: color-mix(in srgb, var(--success) 60%, transparent);
331
+ }
332
+
333
+ .waiting-badge {
334
+ flex-shrink: 0;
335
+ display: inline-flex;
336
+ align-items: center;
337
+ height: 20px;
338
+ padding: 0 6px;
339
+ border: 1px solid color-mix(in srgb, var(--warning) 50%, transparent);
340
+ border-radius: calc(var(--radius) * 0.6);
341
+ font-size: 11px;
342
+ font-weight: 500;
343
+ color: var(--warning);
344
+ }
345
+
346
+ .attempt-chip {
347
+ flex-shrink: 0;
348
+ font-family: var(--font-mono);
349
+ font-size: 10px;
350
+ color: var(--muted-foreground);
351
+ font-variant-numeric: tabular-nums;
352
+ }
353
+
354
+ .run-dot {
355
+ width: 6px;
356
+ height: 6px;
357
+ border-radius: 50%;
358
+ background: var(--info);
359
+ animation: run-pulse 1.4s ease-in-out infinite;
360
+ }
361
+
362
+ @keyframes run-pulse {
363
+ 50% {
364
+ opacity: 0.35;
365
+ }
366
+ }
367
+
368
+ @media (prefers-reduced-motion: reduce) {
369
+ .run-dot {
370
+ animation: none;
371
+ }
372
+ }
373
+
374
+ /* The side panel, below the top bar so the token stays in reach */
375
+
376
+ .panel {
377
+ position: fixed;
378
+ top: var(--topbar-height);
379
+ right: 0;
380
+ bottom: 0;
381
+ width: min(440px, 100vw);
382
+ overflow-y: auto;
383
+ padding: 14px 18px 24px;
384
+ background: var(--card);
385
+ border-left: 1px solid var(--border-strong);
386
+ }
387
+
388
+ .panel-head {
389
+ display: flex;
390
+ align-items: center;
391
+ justify-content: space-between;
392
+ }
393
+
394
+ .panel-title {
395
+ margin: 8px 0 4px;
396
+ font-size: 16px;
397
+ font-weight: 600;
398
+ overflow-wrap: anywhere;
399
+ }
400
+
401
+ .panel-facts {
402
+ margin: 0 0 8px;
403
+ display: flex;
404
+ align-items: center;
405
+ gap: 8px;
406
+ font-size: 12px;
407
+ color: var(--muted-foreground);
408
+ }
409
+
410
+ .panel .status-line {
411
+ white-space: normal;
412
+ }
413
+
414
+ .panel-notice {
415
+ margin: 10px 0;
416
+ padding: 6px 10px;
417
+ border-radius: calc(var(--radius) * 0.8);
418
+ font-size: 12px;
419
+ color: var(--destructive);
420
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--destructive) 40%, transparent);
421
+ }
422
+
423
+ .panel-section {
424
+ margin-top: 18px;
425
+ }
426
+
427
+ .panel-section h3 {
428
+ margin: 0 0 6px;
429
+ font-size: 12px;
430
+ font-weight: 600;
431
+ color: var(--muted-foreground);
432
+ }
433
+
434
+ .description {
435
+ font-size: 13px;
436
+ line-height: 1.5;
437
+ white-space: pre-wrap;
438
+ overflow-wrap: anywhere;
439
+ }
440
+
441
+ .empty,
442
+ .hint {
443
+ margin: 0;
444
+ font-size: 12px;
445
+ color: var(--muted-foreground);
446
+ }
447
+
448
+ .entries {
449
+ list-style: none;
450
+ margin: 0 0 8px;
451
+ padding: 0;
452
+ display: flex;
453
+ flex-direction: column;
454
+ gap: 8px;
455
+ }
456
+
457
+ .entry-meta {
458
+ display: flex;
459
+ gap: 8px;
460
+ font-size: 11px;
461
+ color: var(--muted-foreground);
462
+ }
463
+
464
+ .entry-author {
465
+ font-weight: 500;
466
+ color: var(--foreground);
467
+ }
468
+
469
+ .entry-text {
470
+ font-size: 13px;
471
+ white-space: pre-wrap;
472
+ overflow-wrap: anywhere;
473
+ }
474
+
475
+ [hidden] {
476
+ display: none !important;
477
+ }
@@ -0,0 +1,2 @@
1
+ (function(){var e=class extends Error{status;code;constructor(e,t,n){super(n),this.status=e,this.code=t}};function t(t){async function r(r,i,a){let o={},s=t();s&&(o.authorization=`Bearer ${s}`),r!==`GET`&&(o[`content-type`]=`application/json`);let c=await fetch(i,{method:r,headers:o,body:a===void 0?void 0:JSON.stringify(a)}),l=await c.text();if(!c.ok){let t=n(l);throw new e(c.status,t?.code??`unknown`,t?.message??`${c.status} ${c.statusText}`)}return JSON.parse(l)}let i=e=>`/issues/${encodeURIComponent(e)}`;return{version:async()=>(await r(`GET`,`/issues/version`)).seq,statuses:async()=>await r(`GET`,`/issues/statuses`),cards:async()=>await r(`GET`,`/issues`),createCard:async e=>await r(`POST`,`/issues`,e),moveCard:async(e,t)=>await r(`PATCH`,`${i(e)}/status/${encodeURIComponent(t)}`),comments:async e=>await r(`GET`,`${i(e)}/comments`),addComment:async(e,t)=>await r(`POST`,`${i(e)}/comments`,{content:t}),activity:async e=>await r(`GET`,`${i(e)}/activity`),runs:async e=>await r(`GET`,`${i(e)}/runs`),approve:async(e,t)=>await r(`POST`,`${i(e)}/approve`,{comment:t}),returnCard:async(e,t)=>await r(`POST`,`${i(e)}/return`,{comment:t})}}function n(e){try{return JSON.parse(e)}catch{return null}}function r(e){return e.title===e.id?i(e.description)??e.title:e.title}function i(e){for(let t of(e??``).split(`
2
+ `)){let e=a(t);if(e)return e.length>120?`${e.slice(0,119).trimEnd()}…`:e}return null}function a(e){return e.replace(/^\s*(?:>\s*)+/,``).replace(/^\s*#{1,6}\s+/,``).replace(/^\s*(?:[-*+]|\d+[.)])\s+(?:\[[ x]\]\s+)?/i,``).replace(/!\[([^\]]*)\]\([^)]*\)/g,`$1`).replace(/\[([^\]]*)\]\([^)]*\)/g,`$1`).replace(/<[^>]+>/g,``).replace(/[*_~`]/g,``).replace(/\s+/g,` `).trim()}function o(e,t,n){let r=document.createElement(e);return t&&(r.className=t),n!==void 0&&(r.textContent=n),r}function s(e,t,n){let r=o(`button`,t,e);return r.type=`button`,r.addEventListener(`click`,n),r}function c(e,t,n){let i=o(`article`,`card`);i.draggable=!0,i.dataset.cardId=e.id;let a=o(`div`,`card-head`);if(a.append(o(`span`,`card-key`,e.id)),e.activeRun?.state===`running`){let t=o(`span`,`run-dot`);t.title=`Running: ${e.activeRun.agentName}`,t.setAttribute(`role`,`img`),t.setAttribute(`aria-label`,t.title),a.append(t)}i.append(a);let s=o(`button`,`card-title`,r(e));s.type=`button`,s.addEventListener(`click`,()=>n(e)),i.append(s);let c=e.statusLine?.trim()??``,l=e.waitingFor===`human`,u=e.attemptCount>1;if(c||l||u){let n=o(`div`,`card-status`);if(c){let e=o(`p`,`status-line`,c);e.title=c,e.dataset.category=t??`unstarted`,n.append(e)}if(l&&n.append(o(`span`,`waiting-badge`,`Waiting for you`)),u){let t=o(`span`,`attempt-chip`,`×${e.attemptCount}`);t.title=`Attempt ${e.attemptCount}`,n.append(t)}i.append(n)}return i}function l(e,t){let n=new Set(t.map(e=>e.statusId)),r=e.filter(e=>e.category!==`canceled`||n.has(e.id)).map(e=>({id:e.id,name:e.name,status:e,cards:[]})),i=new Map(r.map(e=>[e.id,e])),a=new Set(e.map(e=>e.id));for(let e of t){let t=e.statusId??``,n=i.get(t);!n&&!a.has(t)&&(n={id:t,name:e.statusId??`No status`,status:null,cards:[]},i.set(t,n),r.push(n)),n?.cards.push(e)}return r}function u(e,t,n){let{card:i,status:a}=e,c=o(`aside`,`panel`);c.setAttribute(`aria-label`,`Card ${i.id}`);let l=o(`div`,`panel-head`);l.append(o(`span`,`card-key`,i.id),s(`Close`,`ghost`,t.close)),c.append(l),c.append(o(`h2`,`panel-title`,r(i)));let u=o(`p`,`panel-facts`,a?a.name:`No column`);if(i.waitingFor===`human`&&u.append(` `,o(`span`,`waiting-badge`,`Waiting for you`)),c.append(u),i.statusLine?.trim()){let e=o(`p`,`status-line`,i.statusLine.trim());e.dataset.category=a?.category??`unstarted`,c.append(e)}let _=o(`p`,`panel-notice`,n??``);return _.setAttribute(`role`,`alert`),_.hidden=!n,c.append(_),c.append(d(`Description`,i.description?.trim()?o(`div`,`description`,i.description):o(`p`,`empty`,`No description.`))),c.append(f(i,t)),c.append(d(`Comments`,...p(e.comments),m(t))),c.append(d(`Activity`,h(e.activity,e=>[g(e),e.createdAt],`No activity.`))),c.append(d(`Runs`,h(e.runs,e=>[v(e),e.startedAt],`No runs.`))),c}function d(e,...t){let n=o(`section`,`panel-section`);return n.append(o(`h3`,void 0,e),...t),n}function f(e,t){let n=o(`textarea`,`field`);n.rows=2,n.placeholder=e.waitingFor===`human`?`A note for the agent (needed to return)`:`Why it goes back (needed to return)`,n.setAttribute(`aria-label`,`Decision note`);let r=o(`p`,`hint`),i=o(`div`,`row`);return e.waitingFor===`human`&&i.append(s(`Approve`,`primary`,()=>t.approve(n.value.trim()||null))),i.append(s(`Return`,`secondary`,()=>{let e=n.value.trim();if(!e){r.textContent=`Say why in the note to return the card.`,n.focus();return}t.returnCard(e)})),d(`Decision`,n,i,r)}function p(e){if(e.length===0)return[o(`p`,`empty`,`No comments.`)];let t=o(`ul`,`entries`);for(let n of e){let e=o(`li`),r=o(`div`,`entry-meta`);r.append(o(`span`,`entry-author`,n.author.displayName),o(`span`,void 0,y(n.createdAt))),e.append(r,o(`div`,`entry-text`,n.content)),t.append(e)}return[t]}function m(e){let t=o(`div`,`comment-form`),n=o(`textarea`,`field`);return n.rows=2,n.placeholder=`Add a comment`,n.setAttribute(`aria-label`,`New comment`),t.append(n,s(`Comment`,`secondary`,()=>{let t=n.value.trim();t&&e.addComment(t)})),t}function h(e,t,n){if(e.length===0)return o(`p`,`empty`,n);let r=o(`ul`,`entries`);for(let n of e){let[e,i]=t(n),a=o(`li`);a.append(o(`div`,`entry-text`,e),o(`div`,`entry-meta`,y(i))),r.append(a)}return r}function g(e){let t=e.actor.displayName;if(e.kind===`created`)return`${t} created the card`;if(e.kind===`comment`)return`${t}: ${e.comment?.content??``}`;let n=e.fieldChange;if(!n)return`${t} changed the card`;switch(n.action){case`added-description`:return`${t} added the description`;case`updated-description`:return`${t} updated the description`;case`cleared-description`:return`${t} cleared the description`;case`renamed-issue`:return`${t} renamed the card to ${_(n.toValue)}`;case`changed-field`:{let e=n.fromValue?` from ${_(n.fromValue)}`:``;return`${t} changed ${n.field??`a field`}${e} to ${_(n.toValue)}`}}}function _(e){return e?e.kind===`text`?e.text:e.kind===`date`?(/* @__PURE__ */ new Date(e.timestamp*1e3)).toLocaleDateString():e.token===`current-user`?`you`:e.token.replaceAll(`-`,` `):`nothing`}function v(e){return[`Attempt ${e.attempt}`,e.agentName,e.state,e.branch].filter(Boolean).join(` · `)}function y(e){return(/* @__PURE__ */ new Date(e*1e3)).toLocaleString()}let b=`kanbo-serve-token`;function x(){try{return sessionStorage.getItem(b)}catch{return null}}function S(e){try{e?sessionStorage.setItem(b,e):sessionStorage.removeItem(b)}catch{}}let C=x(),w=t(()=>C),T=[],E=[],D=null,O=!1,k=!1,A=null,j=null,M=null,N=null,P=null,F=document.querySelector(`#app`)??document.body,I=o(`input`,`field token-input`),L=o(`p`,`notice`),R=o(`main`,`board`),z=o(`div`,`panel-host`);function B(){let e=o(`header`,`topbar`),t=o(`h1`,`topbar-title`,`Kanbo`),n=o(`span`,`workspace`);n.id=`workspace`;let r=o(`form`,`token-form`);I.type=`password`,I.autocomplete=`off`,I.placeholder=`Server token`,I.value=C??``;let i=o(`label`,`token-label`,`Token`);i.append(I);let a=o(`button`,`secondary`,`Save`);a.type=`submit`,r.append(i,a),r.addEventListener(`submit`,e=>{e.preventDefault(),C=I.value.trim()||null,S(C),O=!1,H(null),K()}),e.append(t,n,r),L.setAttribute(`role`,`status`),L.hidden=!0,F.replaceChildren(e,L,R,z)}let V=!1;function H(e,t=`info`){L.textContent=e??``,L.hidden=!e,L.dataset.kind=t,V=!1}function U(t){return t instanceof e?t.status===401?(O=!0,I.focus(),`This server needs its token. Enter it in the Token field above.`):t.message:t instanceof Error?t.message:String(t)}function W(e){H(U(e),`error`),V=!0}function G(){V&&(V=!1,H(null))}async function K(){if(!k){k=!0;try{let e=await w.version(),[t,n]=await Promise.all([w.statuses(),w.cards()]);D=e,T=t,E=n,J(),G(),j&&await Z()}catch(e){W(e)}finally{k=!1}}}async function q(){if(!(document.visibilityState!==`visible`||O||k))try{await w.version()===D?G():await K()}catch(e){W(e)}}function J(){let e=document.querySelector(`#workspace`);e&&(e.textContent=T[0]?.workspaceId??``);let t=A!==null&&document.activeElement===A.input,n=document.activeElement?.closest(`.card`)?.dataset.cardId??null;R.replaceChildren(...l(T,E).map(X)),t?A?.input.focus():n&&Y(n)}function Y(e){for(let t of R.querySelectorAll(`.card`))t.dataset.cardId===e&&t.querySelector(`.card-title`)?.focus()}function X(e){let t=o(`section`,`column`);t.setAttribute(`aria-label`,e.name);let n=o(`header`,`column-head`);n.append(o(`span`,`column-name`,e.name),o(`span`,`column-count`,String(e.cards.length)));let r=e.status;if(r){let t=s(`+ New`,`ghost column-add`,()=>te(r));t.setAttribute(`aria-label`,`New card in ${e.name}`),n.append(t)}let i=o(`div`,`column-cards`);A&&A.statusId===e.id&&i.append(A.form);for(let t of e.cards){let e=c(t,r?.category??null,e=>void ne(e.id));e.addEventListener(`dragstart`,n=>{P=t.id,n.dataTransfer?.setData(`text/plain`,t.id),e.classList.add(`dragging`)}),e.addEventListener(`dragend`,()=>{P=null,e.classList.remove(`dragging`)}),i.append(e)}return t.append(n,i),r&&(t.addEventListener(`dragover`,e=>{P&&(e.preventDefault(),t.classList.add(`drop-target`))}),t.addEventListener(`dragleave`,e=>{t.contains(e.relatedTarget)||t.classList.remove(`drop-target`)}),t.addEventListener(`drop`,e=>{e.preventDefault(),t.classList.remove(`drop-target`);let n=P;P=null,n&&ee(n,r)})),t}async function ee(e,t){if(E.find(t=>t.id===e)?.statusId!==t.id){try{let n=await w.moveCard(e,t.id),r=n.unmetRules??[];H(r.length>0?`${n.id} is in ${t.name}, but still misses: ${r.map(e=>e.detail).join(`; `)}`:null)}catch(e){H(U(e),`error`)}await K()}}function te(e){let t=o(`div`,`draft`),n=o(`textarea`,`field`);n.rows=3,n.placeholder=`Describe the card`,n.setAttribute(`aria-label`,`New card in ${e.name}`);let r=async()=>{let t=n.value.trim();if(!t){n.focus();return}try{let n=await w.createCard({workspaceId:e.workspaceId,statusId:e.id,description:t});A=null,H(n.unmetRules?.length?`${n.id} is in ${e.name}, but still misses: ${n.unmetRules.map(e=>e.detail).join(`; `)}`:null)}catch(e){H(U(e),`error`)}await K()},i=()=>{A=null,J()};n.addEventListener(`keydown`,e=>{e.key===`Enter`&&(e.metaKey||e.ctrlKey)?(e.preventDefault(),r()):e.key===`Escape`&&(e.stopPropagation(),i())});let a=o(`div`,`row`);a.append(s(`Create`,`primary`,()=>void r()),s(`Cancel`,`ghost`,i)),t.append(n,a),A={statusId:e.id,form:t,input:n},J(),n.focus()}async function ne(e){j=e,N=null,await Z()}async function Z(){let e=j,t=E.find(t=>t.id===e);if(!e||!t){$();return}if(!(M?.card.id===e&&re(z))){try{let[n,r,i]=await Promise.all([w.comments(e),w.activity(e),w.runs(e)]);M={card:t,status:T.find(e=>e.id===t.statusId)??null,comments:n,activity:r,runs:i}}catch(e){N=U(e)}ie()}}function re(e){return[...e.querySelectorAll(`textarea`)].some(e=>e.value.trim()!==``||document.activeElement===e)}function ie(){if(!M||M.card.id!==j){z.replaceChildren();return}let e=M.card.id,t=u(M,{close:$,addComment:t=>void Q(async()=>{await w.addComment(e,t)}),approve:t=>void Q(async()=>{await w.approve(e,t)}),returnCard:t=>void Q(async()=>{await w.returnCard(e,t)})},N),n=!z.firstChild;z.replaceChildren(t),n&&t.querySelector(`button`)?.focus()}async function Q(t){try{await t(),N=null;for(let e of z.querySelectorAll(`textarea`))e.value=``}catch(t){let n=U(t);N=t instanceof e&&t.status===403?`${n} Needs the server token: only a request holding the token this server was started with acts for a person.`:n;let r=z.querySelector(`.panel-notice`);r&&(r.textContent=N,r.hidden=!1);return}await K()}function $(){let e=j;j=null,M=null,N=null,z.replaceChildren(),e&&Y(e)}document.addEventListener(`keydown`,e=>{e.key===`Escape`&&j&&$()}),document.addEventListener(`visibilitychange`,()=>void q()),B(),K(),setInterval(()=>void q(),2e3)})();
@@ -0,0 +1,135 @@
1
+ CREATE TABLE "issue_comments" (
2
+ "id" text PRIMARY KEY NOT NULL,
3
+ "issue_id" text NOT NULL,
4
+ "content" text NOT NULL,
5
+ "author_kind" text DEFAULT 'user' NOT NULL,
6
+ "author_id" text,
7
+ "source_chat_session_id" text,
8
+ "agent_activity_id" text,
9
+ "dedupe_key" text,
10
+ "created_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL
11
+ );
12
+ --> statement-breakpoint
13
+ CREATE TABLE "issue_field_changes" (
14
+ "id" text PRIMARY KEY NOT NULL,
15
+ "issue_id" text NOT NULL,
16
+ "field" text NOT NULL,
17
+ "from_value" text,
18
+ "to_value" text,
19
+ "actor_kind" text DEFAULT 'user' NOT NULL,
20
+ "actor_id" text,
21
+ "source_chat_session_id" text,
22
+ "created_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL
23
+ );
24
+ --> statement-breakpoint
25
+ CREATE TABLE "issue_milestones" (
26
+ "id" text PRIMARY KEY NOT NULL,
27
+ "workspace_id" text NOT NULL,
28
+ "title" text NOT NULL,
29
+ "description" text,
30
+ "due_date" bigint,
31
+ "status" text DEFAULT 'open' NOT NULL,
32
+ "created_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL,
33
+ "updated_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL
34
+ );
35
+ --> statement-breakpoint
36
+ CREATE TABLE "issue_relations" (
37
+ "id" text PRIMARY KEY NOT NULL,
38
+ "source_issue_id" text NOT NULL,
39
+ "target_issue_id" text NOT NULL,
40
+ "type" text NOT NULL,
41
+ "created_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL
42
+ );
43
+ --> statement-breakpoint
44
+ CREATE TABLE "issue_runs" (
45
+ "id" text PRIMARY KEY NOT NULL,
46
+ "issue_id" text NOT NULL,
47
+ "launched_by_kind" text DEFAULT 'user' NOT NULL,
48
+ "launched_by_id" text,
49
+ "agent_id" text,
50
+ "agent_name" text NOT NULL,
51
+ "host" text,
52
+ "execution_mode" text DEFAULT 'worktree' NOT NULL,
53
+ "branch" text,
54
+ "worktree_path" text,
55
+ "state" text DEFAULT 'running' NOT NULL,
56
+ "chat_session_id" text,
57
+ "started_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL,
58
+ "ended_at" bigint,
59
+ "seq" bigserial NOT NULL
60
+ );
61
+ --> statement-breakpoint
62
+ CREATE TABLE "issue_statuses" (
63
+ "id" text PRIMARY KEY NOT NULL,
64
+ "workspace_id" text NOT NULL,
65
+ "name" text NOT NULL,
66
+ "description" text,
67
+ "color" text,
68
+ "category" text DEFAULT 'unstarted' NOT NULL,
69
+ "order" integer DEFAULT 0 NOT NULL,
70
+ "created_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL
71
+ );
72
+ --> statement-breakpoint
73
+ CREATE TABLE "issues" (
74
+ "id" text PRIMARY KEY NOT NULL,
75
+ "workspace_id" text NOT NULL,
76
+ "number" integer NOT NULL,
77
+ "status_id" text,
78
+ "milestone_id" text,
79
+ "parent_issue_id" text,
80
+ "title" text NOT NULL,
81
+ "description" text,
82
+ "priority" text DEFAULT 'none' NOT NULL,
83
+ "labels" text DEFAULT '[]' NOT NULL,
84
+ "assignee_kind" text,
85
+ "assignee_id" text,
86
+ "due_date" bigint,
87
+ "created_by_kind" text DEFAULT 'user' NOT NULL,
88
+ "created_by_id" text DEFAULT '__self__' NOT NULL,
89
+ "source_chat_session_id" text,
90
+ "delegate_agent_id" text,
91
+ "delegate_provider_target_id" text,
92
+ "context_refs" text DEFAULT '[]' NOT NULL,
93
+ "status_line" text,
94
+ "waiting_for" text,
95
+ "execution_mode" text DEFAULT 'worktree' NOT NULL,
96
+ "order" integer DEFAULT 0 NOT NULL,
97
+ "created_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL,
98
+ "updated_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL
99
+ );
100
+ --> statement-breakpoint
101
+ CREATE TABLE "kanban_meta" (
102
+ "key" text PRIMARY KEY NOT NULL,
103
+ "revision" integer DEFAULT 0 NOT NULL,
104
+ "updated_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL
105
+ );
106
+ --> statement-breakpoint
107
+ ALTER TABLE "issue_comments" ADD CONSTRAINT "issue_comments_issue_id_issues_id_fk" FOREIGN KEY ("issue_id") REFERENCES "public"."issues"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
108
+ ALTER TABLE "issue_field_changes" ADD CONSTRAINT "issue_field_changes_issue_id_issues_id_fk" FOREIGN KEY ("issue_id") REFERENCES "public"."issues"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
109
+ ALTER TABLE "issue_relations" ADD CONSTRAINT "issue_relations_source_issue_id_issues_id_fk" FOREIGN KEY ("source_issue_id") REFERENCES "public"."issues"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
110
+ ALTER TABLE "issue_relations" ADD CONSTRAINT "issue_relations_target_issue_id_issues_id_fk" FOREIGN KEY ("target_issue_id") REFERENCES "public"."issues"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
111
+ ALTER TABLE "issue_runs" ADD CONSTRAINT "issue_runs_issue_id_issues_id_fk" FOREIGN KEY ("issue_id") REFERENCES "public"."issues"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
112
+ ALTER TABLE "issues" ADD CONSTRAINT "issues_status_id_issue_statuses_id_fk" FOREIGN KEY ("status_id") REFERENCES "public"."issue_statuses"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
113
+ ALTER TABLE "issues" ADD CONSTRAINT "issues_milestone_id_issue_milestones_id_fk" FOREIGN KEY ("milestone_id") REFERENCES "public"."issue_milestones"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
114
+ ALTER TABLE "issues" ADD CONSTRAINT "issues_parent_issue_id_issues_id_fk" FOREIGN KEY ("parent_issue_id") REFERENCES "public"."issues"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
115
+ CREATE INDEX "issue_comments_issue_id_idx" ON "issue_comments" USING btree ("issue_id");--> statement-breakpoint
116
+ CREATE UNIQUE INDEX "issue_comments_issue_dedupe_idx" ON "issue_comments" USING btree ("issue_id","dedupe_key");--> statement-breakpoint
117
+ CREATE INDEX "issue_field_changes_issue_id_idx" ON "issue_field_changes" USING btree ("issue_id");--> statement-breakpoint
118
+ CREATE INDEX "issue_milestones_workspace_id_idx" ON "issue_milestones" USING btree ("workspace_id");--> statement-breakpoint
119
+ CREATE INDEX "issue_relations_source_issue_id_idx" ON "issue_relations" USING btree ("source_issue_id");--> statement-breakpoint
120
+ CREATE INDEX "issue_relations_target_issue_id_idx" ON "issue_relations" USING btree ("target_issue_id");--> statement-breakpoint
121
+ CREATE UNIQUE INDEX "issue_relations_pair_type_unique" ON "issue_relations" USING btree ("source_issue_id","target_issue_id","type");--> statement-breakpoint
122
+ CREATE INDEX "issue_runs_issue_id_idx" ON "issue_runs" USING btree ("issue_id");--> statement-breakpoint
123
+ CREATE INDEX "issue_runs_issue_state_idx" ON "issue_runs" USING btree ("issue_id","state");--> statement-breakpoint
124
+ CREATE INDEX "issue_runs_chat_session_idx" ON "issue_runs" USING btree ("chat_session_id");--> statement-breakpoint
125
+ CREATE INDEX "issue_statuses_workspace_id_idx" ON "issue_statuses" USING btree ("workspace_id");--> statement-breakpoint
126
+ CREATE UNIQUE INDEX "issue_statuses_workspace_name_unique" ON "issue_statuses" USING btree ("workspace_id","name");--> statement-breakpoint
127
+ CREATE INDEX "issues_workspace_id_idx" ON "issues" USING btree ("workspace_id");--> statement-breakpoint
128
+ CREATE UNIQUE INDEX "issues_workspace_number_unique" ON "issues" USING btree ("workspace_id","number");--> statement-breakpoint
129
+ CREATE INDEX "issues_status_id_idx" ON "issues" USING btree ("status_id");--> statement-breakpoint
130
+ CREATE INDEX "issues_milestone_id_idx" ON "issues" USING btree ("milestone_id");--> statement-breakpoint
131
+ CREATE INDEX "issues_parent_issue_id_idx" ON "issues" USING btree ("parent_issue_id");--> statement-breakpoint
132
+ CREATE INDEX "issues_delegate_agent_id_idx" ON "issues" USING btree ("delegate_agent_id");--> statement-breakpoint
133
+ CREATE INDEX "issues_delegate_provider_target_id_idx" ON "issues" USING btree ("delegate_provider_target_id");--> statement-breakpoint
134
+ INSERT INTO "kanban_meta" ("key", "revision") VALUES ('board', 0) ON CONFLICT ("key") DO NOTHING;--> statement-breakpoint
135
+ INSERT INTO "kanban_meta" ("key", "revision") VALUES ('schema_epoch', 1) ON CONFLICT ("key") DO NOTHING;
@@ -0,0 +1,2 @@
1
+ ALTER TABLE "issue_comments" ADD COLUMN "seq" bigserial NOT NULL;--> statement-breakpoint
2
+ ALTER TABLE "issue_field_changes" ADD COLUMN "seq" bigserial NOT NULL;
@@ -0,0 +1,16 @@
1
+ CREATE TABLE "issue_pull_requests" (
2
+ "id" text PRIMARY KEY NOT NULL,
3
+ "issue_id" text NOT NULL,
4
+ "owner" text NOT NULL,
5
+ "repo" text NOT NULL,
6
+ "number" integer NOT NULL,
7
+ "url" text NOT NULL,
8
+ "created_by_kind" text NOT NULL,
9
+ "created_by_id" text,
10
+ "created_at" bigint DEFAULT (extract(epoch from now())::bigint) NOT NULL,
11
+ "seq" bigserial NOT NULL
12
+ );
13
+ --> statement-breakpoint
14
+ ALTER TABLE "issue_pull_requests" ADD CONSTRAINT "issue_pull_requests_issue_id_issues_id_fk" FOREIGN KEY ("issue_id") REFERENCES "public"."issues"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
15
+ CREATE UNIQUE INDEX "issue_pull_requests_issue_pr_unique" ON "issue_pull_requests" USING btree ("issue_id","owner","repo","number");--> statement-breakpoint
16
+ CREATE INDEX "issue_pull_requests_pr_idx" ON "issue_pull_requests" USING btree ("owner","repo","number");
@@ -0,0 +1 @@
1
+ ALTER TABLE "issue_milestones" ADD COLUMN "start_date" bigint;
@@ -0,0 +1 @@
1
+ ALTER TABLE "issue_statuses" ADD COLUMN "entry_rules" text;
@@ -0,0 +1 @@
1
+ ALTER TABLE "issue_runs" ADD COLUMN "external_session_ref" text;