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.
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/better-sqlite3-fU3G4xnX.cjs +2254 -0
- package/dist/better-sqlite3-fU3G4xnX.cjs.map +1 -0
- package/dist/cli.cjs +42949 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/dist-Cd6wg8pp.cjs +942 -0
- package/dist/dist-Cd6wg8pp.cjs.map +1 -0
- package/dist/drizzle-postgres/0000_board.sql +135 -0
- package/dist/drizzle-postgres/0001_history_order.sql +2 -0
- package/dist/drizzle-postgres/0002_issue_pull_requests.sql +16 -0
- package/dist/drizzle-postgres/0003_milestone_start_date.sql +1 -0
- package/dist/drizzle-postgres/0004_status_entry_rules.sql +1 -0
- package/dist/drizzle-postgres/0005_run_external_session_ref.sql +1 -0
- package/dist/drizzle-postgres/README.md +61 -0
- package/dist/drizzle-postgres/meta/0000_snapshot.json +1078 -0
- package/dist/drizzle-postgres/meta/0001_snapshot.json +1090 -0
- package/dist/drizzle-postgres/meta/0002_snapshot.json +1239 -0
- package/dist/drizzle-postgres/meta/0003_snapshot.json +1245 -0
- package/dist/drizzle-postgres/meta/0004_snapshot.json +1251 -0
- package/dist/drizzle-postgres/meta/0005_snapshot.json +1257 -0
- package/dist/drizzle-postgres/meta/_journal.json +48 -0
- package/dist/drizzle-sqlite/0000_board.sql +133 -0
- package/dist/drizzle-sqlite/0001_issue_pull_requests.sql +15 -0
- package/dist/drizzle-sqlite/0002_milestone_start_date.sql +1 -0
- package/dist/drizzle-sqlite/0003_status_entry_rules.sql +1 -0
- package/dist/drizzle-sqlite/0004_run_external_session_ref.sql +1 -0
- package/dist/drizzle-sqlite/README.md +67 -0
- package/dist/drizzle-sqlite/meta/0000_snapshot.json +946 -0
- package/dist/drizzle-sqlite/meta/0001_snapshot.json +1054 -0
- package/dist/drizzle-sqlite/meta/0002_snapshot.json +1061 -0
- package/dist/drizzle-sqlite/meta/0003_snapshot.json +1068 -0
- package/dist/drizzle-sqlite/meta/0004_snapshot.json +1075 -0
- package/dist/drizzle-sqlite/meta/_journal.json +41 -0
- package/dist/lib/board-store-B16YarvX.d.mts +281 -0
- package/dist/lib/board-store-BHHo_ZlR.d.cts +281 -0
- package/dist/lib/index.cjs +340 -0
- package/dist/lib/index.cjs.map +1 -0
- package/dist/lib/index.d.cts +1608 -0
- package/dist/lib/index.d.mts +1608 -0
- package/dist/lib/index.mjs +284 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/manifest-C0EcwwgO.mjs +7866 -0
- package/dist/lib/manifest-C0EcwwgO.mjs.map +1 -0
- package/dist/lib/manifest-CpZOcB_6.cjs +8272 -0
- package/dist/lib/manifest-CpZOcB_6.cjs.map +1 -0
- package/dist/lib/mcp/index.cjs +184 -0
- package/dist/lib/mcp/index.cjs.map +1 -0
- package/dist/lib/mcp/index.d.cts +346 -0
- package/dist/lib/mcp/index.d.mts +346 -0
- package/dist/lib/mcp/index.mjs +173 -0
- package/dist/lib/mcp/index.mjs.map +1 -0
- package/dist/lib/migrate-BhYi9cXw.mjs +656 -0
- package/dist/lib/migrate-BhYi9cXw.mjs.map +1 -0
- package/dist/lib/migrate-DnMjTCvu.cjs +709 -0
- package/dist/lib/migrate-DnMjTCvu.cjs.map +1 -0
- package/dist/lib/migrations-path-CZxVOgeD.cjs +109 -0
- package/dist/lib/migrations-path-CZxVOgeD.cjs.map +1 -0
- package/dist/lib/migrations-path-Ciwan537.mjs +80 -0
- package/dist/lib/migrations-path-Ciwan537.mjs.map +1 -0
- package/dist/lib/postgres/index.cjs +56 -0
- package/dist/lib/postgres/index.cjs.map +1 -0
- package/dist/lib/postgres/index.d.cts +3403 -0
- package/dist/lib/postgres/index.d.mts +3403 -0
- package/dist/lib/postgres/index.mjs +35 -0
- package/dist/lib/postgres/index.mjs.map +1 -0
- package/dist/lib/roles.sql-B9rt-x4o.cjs +1033 -0
- package/dist/lib/roles.sql-B9rt-x4o.cjs.map +1 -0
- package/dist/lib/roles.sql-CvyCGt38.mjs +920 -0
- package/dist/lib/roles.sql-CvyCGt38.mjs.map +1 -0
- package/dist/lib/schema-epoch-ZyumVL_A.d.cts +16 -0
- package/dist/lib/schema-epoch-ZyumVL_A.d.mts +16 -0
- package/dist/lib/schema-fsHqNAip.d.cts +3612 -0
- package/dist/lib/schema-fsHqNAip.d.mts +3612 -0
- package/dist/lib/sqlite/index.cjs +23 -0
- package/dist/lib/sqlite/index.d.cts +175 -0
- package/dist/lib/sqlite/index.d.mts +175 -0
- package/dist/lib/sqlite/index.mjs +4 -0
- package/dist/lib/sqlite/schema.cjs +266 -0
- package/dist/lib/sqlite/schema.cjs.map +1 -0
- package/dist/lib/sqlite/schema.d.cts +2 -0
- package/dist/lib/sqlite/schema.d.mts +2 -0
- package/dist/lib/sqlite/schema.mjs +256 -0
- package/dist/lib/sqlite/schema.mjs.map +1 -0
- package/dist/lib/tool-names-9cmCn0gP.d.cts +112 -0
- package/dist/lib/tool-names-Dxg1UTUl.d.mts +112 -0
- package/dist/page/board.css +477 -0
- package/dist/page/board.js +2 -0
- package/drizzle-postgres/0000_board.sql +135 -0
- package/drizzle-postgres/0001_history_order.sql +2 -0
- package/drizzle-postgres/0002_issue_pull_requests.sql +16 -0
- package/drizzle-postgres/0003_milestone_start_date.sql +1 -0
- package/drizzle-postgres/0004_status_entry_rules.sql +1 -0
- package/drizzle-postgres/0005_run_external_session_ref.sql +1 -0
- package/drizzle-postgres/README.md +61 -0
- package/drizzle-postgres/meta/0000_snapshot.json +1078 -0
- package/drizzle-postgres/meta/0001_snapshot.json +1090 -0
- package/drizzle-postgres/meta/0002_snapshot.json +1239 -0
- package/drizzle-postgres/meta/0003_snapshot.json +1245 -0
- package/drizzle-postgres/meta/0004_snapshot.json +1251 -0
- package/drizzle-postgres/meta/0005_snapshot.json +1257 -0
- package/drizzle-postgres/meta/_journal.json +48 -0
- package/drizzle-sqlite/0000_board.sql +133 -0
- package/drizzle-sqlite/0001_issue_pull_requests.sql +15 -0
- package/drizzle-sqlite/0002_milestone_start_date.sql +1 -0
- package/drizzle-sqlite/0003_status_entry_rules.sql +1 -0
- package/drizzle-sqlite/0004_run_external_session_ref.sql +1 -0
- package/drizzle-sqlite/README.md +67 -0
- package/drizzle-sqlite/meta/0000_snapshot.json +946 -0
- package/drizzle-sqlite/meta/0001_snapshot.json +1054 -0
- package/drizzle-sqlite/meta/0002_snapshot.json +1061 -0
- package/drizzle-sqlite/meta/0003_snapshot.json +1068 -0
- package/drizzle-sqlite/meta/0004_snapshot.json +1075 -0
- package/drizzle-sqlite/meta/_journal.json +41 -0
- 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,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;
|