@assistkick/create 1.3.0 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistkick/create",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Scaffold assistkick-product-system into any project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  "build": "tsc",
15
15
  "prepare_templates": "bash scripts/prepare_templates.sh",
16
16
  "prepublishOnly": "bash scripts/prepare_templates.sh && pnpm build",
17
- "publish": "npm publish --access public",
17
+ "publish": "npm publish",
18
18
  "test": "tsx --test tests/**/*.test.ts"
19
19
  },
20
20
  "devDependencies": {
@@ -0,0 +1,88 @@
1
+ # GitHub App Setup Guide
2
+
3
+ This guide walks you through creating a GitHub App and configuring it for use with AssistKick.
4
+
5
+ ## Step 1: Create the GitHub App
6
+
7
+ 1. Go to **GitHub Settings > Developer settings > GitHub Apps** (or navigate to `https://github.com/settings/apps`)
8
+ 2. Click **New GitHub App**
9
+ 3. Fill in the form:
10
+
11
+ | Field | Value |
12
+ |---------------------|------------------------------------------------|
13
+ | **GitHub App name** | Something unique, e.g. `assistkick-<your-org>` |
14
+ | **Homepage URL** | Your AssistKick instance URL (or any URL) |
15
+ | **Webhook** | Uncheck "Active" (webhooks are not needed) |
16
+
17
+ ### Permissions
18
+
19
+ Under **Repository permissions**, grant the following:
20
+
21
+ | Permission | Access |
22
+ |--------------|---------------------------|
23
+ | **Contents** | Read & write |
24
+ | **Metadata** | Read-only (auto-selected) |
25
+
26
+ You can add more permissions later if needed (e.g. Pull requests, Issues).
27
+
28
+ ### Installation access
29
+
30
+ Under **Where can this GitHub App be installed?**, choose:
31
+ - **Only on this account** — if you only need it for your own repos/org
32
+ - **Any account** — if multiple orgs will install it
33
+
34
+ 1. Click **Create GitHub App**
35
+
36
+ ## Step 2: Generate a Private Key
37
+
38
+ 1. After creating the app, you'll be on the app's settings page
39
+ 2. Scroll down to **Private keys**
40
+ 3. Click **Generate a private key**
41
+ 4. A `.pem` file will be downloaded — keep this safe
42
+ 5. **Convert to PKCS#8 and base64-encode** (required — GitHub generates PKCS#1 keys but the backend uses the `jose` library which requires PKCS#8):
43
+
44
+ ```bash
45
+ openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in your-app-name.pem | base64
46
+ ```
47
+
48
+ Use the base64 output as the `GITHUB_APP_PRIVATE_KEY` environment variable in Step 5.
49
+
50
+ ## Step 3: Note Your App ID
51
+
52
+ On the app's settings page, find the **App ID** near the top (it's a numeric value like `123456`).
53
+
54
+ ## Step 4: Install the App
55
+
56
+ 1. From the app's settings page, click **Install App** in the left sidebar
57
+ 2. Choose the organization or account where you want to install it
58
+ 3. Select **All repositories** or pick specific repos
59
+ 4. Click **Install**
60
+
61
+ ## Step 5: Configure Environment Variables
62
+
63
+ Set these two environment variables where AssistKick runs:
64
+
65
+ ```bash
66
+ GITHUB_APP_ID=123456
67
+ GITHUB_APP_PRIVATE_KEY=LS0tLS1CRUdJTi...
68
+ ```
69
+
70
+ The value is the base64-encoded PKCS#8 key from Step 2. The backend auto-detects whether the key is raw PEM or base64-encoded.
71
+
72
+ ## Step 6: Verify
73
+
74
+ 1. Open your project in AssistKick
75
+ 2. Open the **Git Repository** dialog
76
+ 3. Go to the **GitHub** tab
77
+ 4. Click **Test Connection**
78
+ 5. You should see your installations listed — select one, pick a repo, and connect
79
+
80
+ ## Troubleshooting
81
+
82
+ | Problem | Solution |
83
+ |-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
84
+ | "GitHub App not configured" | `GITHUB_APP_ID` or `GITHUB_APP_PRIVATE_KEY` is missing from env |
85
+ | "No installations found" | Install the app on your GitHub account/org (Step 4) |
86
+ | 401 / "Bad credentials" | Private key doesn't match the App ID, or the key is malformed |
87
+ | "pkcs8" must be PKCS#8 | Key is in PKCS#1 format — convert it with `openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in key.pem -out key-pkcs8.pem` |
88
+ | No repos listed | The installation doesn't have access to any repos — edit installation permissions on GitHub |
@@ -0,0 +1,17 @@
1
+ PRAGMA foreign_keys=OFF;--> statement-breakpoint
2
+ CREATE TABLE `__new_sessions` (
3
+ `session_number` integer NOT NULL,
4
+ `started_at` text NOT NULL,
5
+ `ended_at` text,
6
+ `summary` text,
7
+ `nodes_touched` text,
8
+ `questions_resolved` integer DEFAULT 0 NOT NULL,
9
+ `body` text,
10
+ `project_id` text NOT NULL,
11
+ PRIMARY KEY(`session_number`, `project_id`)
12
+ );
13
+ --> statement-breakpoint
14
+ INSERT INTO `__new_sessions`("session_number", "started_at", "ended_at", "summary", "nodes_touched", "questions_resolved", "body", "project_id") SELECT "session_number", "started_at", "ended_at", "summary", "nodes_touched", "questions_resolved", "body", "project_id" FROM `sessions`;--> statement-breakpoint
15
+ DROP TABLE `sessions`;--> statement-breakpoint
16
+ ALTER TABLE `__new_sessions` RENAME TO `sessions`;--> statement-breakpoint
17
+ PRAGMA foreign_keys=ON;
@@ -0,0 +1,862 @@
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "2e6f2cd3-e5a5-4a76-8ec4-58542d227370",
5
+ "prevId": "fc7b29f6-601b-4577-a78e-69ce32763e2d",
6
+ "tables": {
7
+ "coherence_reviews": {
8
+ "name": "coherence_reviews",
9
+ "columns": {
10
+ "id": {
11
+ "name": "id",
12
+ "type": "text",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": false
16
+ },
17
+ "type": {
18
+ "name": "type",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "from_id": {
25
+ "name": "from_id",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": false,
29
+ "autoincrement": false
30
+ },
31
+ "to_id": {
32
+ "name": "to_id",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": false,
36
+ "autoincrement": false
37
+ },
38
+ "relation": {
39
+ "name": "relation",
40
+ "type": "text",
41
+ "primaryKey": false,
42
+ "notNull": false,
43
+ "autoincrement": false
44
+ },
45
+ "proposed_node_type": {
46
+ "name": "proposed_node_type",
47
+ "type": "text",
48
+ "primaryKey": false,
49
+ "notNull": false,
50
+ "autoincrement": false
51
+ },
52
+ "proposed_node_name": {
53
+ "name": "proposed_node_name",
54
+ "type": "text",
55
+ "primaryKey": false,
56
+ "notNull": false,
57
+ "autoincrement": false
58
+ },
59
+ "target_node_id": {
60
+ "name": "target_node_id",
61
+ "type": "text",
62
+ "primaryKey": false,
63
+ "notNull": false,
64
+ "autoincrement": false
65
+ },
66
+ "proposed_description": {
67
+ "name": "proposed_description",
68
+ "type": "text",
69
+ "primaryKey": false,
70
+ "notNull": false,
71
+ "autoincrement": false
72
+ },
73
+ "confidence": {
74
+ "name": "confidence",
75
+ "type": "text",
76
+ "primaryKey": false,
77
+ "notNull": false,
78
+ "autoincrement": false
79
+ },
80
+ "batch_id": {
81
+ "name": "batch_id",
82
+ "type": "text",
83
+ "primaryKey": false,
84
+ "notNull": false,
85
+ "autoincrement": false
86
+ },
87
+ "reasoning": {
88
+ "name": "reasoning",
89
+ "type": "text",
90
+ "primaryKey": false,
91
+ "notNull": true,
92
+ "autoincrement": false
93
+ },
94
+ "status": {
95
+ "name": "status",
96
+ "type": "text",
97
+ "primaryKey": false,
98
+ "notNull": true,
99
+ "autoincrement": false
100
+ },
101
+ "created_at": {
102
+ "name": "created_at",
103
+ "type": "text",
104
+ "primaryKey": false,
105
+ "notNull": true,
106
+ "autoincrement": false
107
+ },
108
+ "resolved_at": {
109
+ "name": "resolved_at",
110
+ "type": "text",
111
+ "primaryKey": false,
112
+ "notNull": false,
113
+ "autoincrement": false
114
+ },
115
+ "project_id": {
116
+ "name": "project_id",
117
+ "type": "text",
118
+ "primaryKey": false,
119
+ "notNull": false,
120
+ "autoincrement": false
121
+ }
122
+ },
123
+ "indexes": {},
124
+ "foreignKeys": {},
125
+ "compositePrimaryKeys": {},
126
+ "uniqueConstraints": {},
127
+ "checkConstraints": {}
128
+ },
129
+ "edges": {
130
+ "name": "edges",
131
+ "columns": {
132
+ "from_id": {
133
+ "name": "from_id",
134
+ "type": "text",
135
+ "primaryKey": false,
136
+ "notNull": true,
137
+ "autoincrement": false
138
+ },
139
+ "relation": {
140
+ "name": "relation",
141
+ "type": "text",
142
+ "primaryKey": false,
143
+ "notNull": true,
144
+ "autoincrement": false
145
+ },
146
+ "to_id": {
147
+ "name": "to_id",
148
+ "type": "text",
149
+ "primaryKey": false,
150
+ "notNull": true,
151
+ "autoincrement": false
152
+ },
153
+ "project_id": {
154
+ "name": "project_id",
155
+ "type": "text",
156
+ "primaryKey": false,
157
+ "notNull": false,
158
+ "autoincrement": false
159
+ }
160
+ },
161
+ "indexes": {},
162
+ "foreignKeys": {},
163
+ "compositePrimaryKeys": {
164
+ "edges_from_id_relation_to_id_pk": {
165
+ "columns": [
166
+ "from_id",
167
+ "relation",
168
+ "to_id"
169
+ ],
170
+ "name": "edges_from_id_relation_to_id_pk"
171
+ }
172
+ },
173
+ "uniqueConstraints": {},
174
+ "checkConstraints": {}
175
+ },
176
+ "invitations": {
177
+ "name": "invitations",
178
+ "columns": {
179
+ "id": {
180
+ "name": "id",
181
+ "type": "text",
182
+ "primaryKey": true,
183
+ "notNull": true,
184
+ "autoincrement": false
185
+ },
186
+ "email": {
187
+ "name": "email",
188
+ "type": "text",
189
+ "primaryKey": false,
190
+ "notNull": true,
191
+ "autoincrement": false
192
+ },
193
+ "token_hash": {
194
+ "name": "token_hash",
195
+ "type": "text",
196
+ "primaryKey": false,
197
+ "notNull": true,
198
+ "autoincrement": false
199
+ },
200
+ "invited_by": {
201
+ "name": "invited_by",
202
+ "type": "text",
203
+ "primaryKey": false,
204
+ "notNull": true,
205
+ "autoincrement": false
206
+ },
207
+ "expires_at": {
208
+ "name": "expires_at",
209
+ "type": "text",
210
+ "primaryKey": false,
211
+ "notNull": true,
212
+ "autoincrement": false
213
+ },
214
+ "accepted_at": {
215
+ "name": "accepted_at",
216
+ "type": "text",
217
+ "primaryKey": false,
218
+ "notNull": false,
219
+ "autoincrement": false
220
+ },
221
+ "created_at": {
222
+ "name": "created_at",
223
+ "type": "text",
224
+ "primaryKey": false,
225
+ "notNull": true,
226
+ "autoincrement": false
227
+ }
228
+ },
229
+ "indexes": {},
230
+ "foreignKeys": {
231
+ "invitations_invited_by_users_id_fk": {
232
+ "name": "invitations_invited_by_users_id_fk",
233
+ "tableFrom": "invitations",
234
+ "tableTo": "users",
235
+ "columnsFrom": [
236
+ "invited_by"
237
+ ],
238
+ "columnsTo": [
239
+ "id"
240
+ ],
241
+ "onDelete": "no action",
242
+ "onUpdate": "no action"
243
+ }
244
+ },
245
+ "compositePrimaryKeys": {},
246
+ "uniqueConstraints": {},
247
+ "checkConstraints": {}
248
+ },
249
+ "kanban": {
250
+ "name": "kanban",
251
+ "columns": {
252
+ "node_id": {
253
+ "name": "node_id",
254
+ "type": "text",
255
+ "primaryKey": true,
256
+ "notNull": true,
257
+ "autoincrement": false
258
+ },
259
+ "column_name": {
260
+ "name": "column_name",
261
+ "type": "text",
262
+ "primaryKey": false,
263
+ "notNull": true,
264
+ "autoincrement": false
265
+ },
266
+ "position": {
267
+ "name": "position",
268
+ "type": "integer",
269
+ "primaryKey": false,
270
+ "notNull": true,
271
+ "autoincrement": false
272
+ },
273
+ "project_id": {
274
+ "name": "project_id",
275
+ "type": "text",
276
+ "primaryKey": false,
277
+ "notNull": false,
278
+ "autoincrement": false
279
+ }
280
+ },
281
+ "indexes": {},
282
+ "foreignKeys": {
283
+ "kanban_node_id_nodes_id_fk": {
284
+ "name": "kanban_node_id_nodes_id_fk",
285
+ "tableFrom": "kanban",
286
+ "tableTo": "nodes",
287
+ "columnsFrom": [
288
+ "node_id"
289
+ ],
290
+ "columnsTo": [
291
+ "id"
292
+ ],
293
+ "onDelete": "no action",
294
+ "onUpdate": "no action"
295
+ }
296
+ },
297
+ "compositePrimaryKeys": {},
298
+ "uniqueConstraints": {},
299
+ "checkConstraints": {}
300
+ },
301
+ "nodes": {
302
+ "name": "nodes",
303
+ "columns": {
304
+ "id": {
305
+ "name": "id",
306
+ "type": "text",
307
+ "primaryKey": true,
308
+ "notNull": true,
309
+ "autoincrement": false
310
+ },
311
+ "type": {
312
+ "name": "type",
313
+ "type": "text",
314
+ "primaryKey": false,
315
+ "notNull": true,
316
+ "autoincrement": false
317
+ },
318
+ "name": {
319
+ "name": "name",
320
+ "type": "text",
321
+ "primaryKey": false,
322
+ "notNull": true,
323
+ "autoincrement": false
324
+ },
325
+ "status": {
326
+ "name": "status",
327
+ "type": "text",
328
+ "primaryKey": false,
329
+ "notNull": true,
330
+ "autoincrement": false
331
+ },
332
+ "priority": {
333
+ "name": "priority",
334
+ "type": "text",
335
+ "primaryKey": false,
336
+ "notNull": true,
337
+ "autoincrement": false
338
+ },
339
+ "completeness": {
340
+ "name": "completeness",
341
+ "type": "real",
342
+ "primaryKey": false,
343
+ "notNull": true,
344
+ "autoincrement": false,
345
+ "default": 0
346
+ },
347
+ "open_questions_count": {
348
+ "name": "open_questions_count",
349
+ "type": "integer",
350
+ "primaryKey": false,
351
+ "notNull": true,
352
+ "autoincrement": false,
353
+ "default": 0
354
+ },
355
+ "kind": {
356
+ "name": "kind",
357
+ "type": "text",
358
+ "primaryKey": false,
359
+ "notNull": false,
360
+ "autoincrement": false
361
+ },
362
+ "created_at": {
363
+ "name": "created_at",
364
+ "type": "text",
365
+ "primaryKey": false,
366
+ "notNull": true,
367
+ "autoincrement": false
368
+ },
369
+ "updated_at": {
370
+ "name": "updated_at",
371
+ "type": "text",
372
+ "primaryKey": false,
373
+ "notNull": true,
374
+ "autoincrement": false
375
+ },
376
+ "body": {
377
+ "name": "body",
378
+ "type": "text",
379
+ "primaryKey": false,
380
+ "notNull": false,
381
+ "autoincrement": false
382
+ },
383
+ "project_id": {
384
+ "name": "project_id",
385
+ "type": "text",
386
+ "primaryKey": false,
387
+ "notNull": false,
388
+ "autoincrement": false
389
+ }
390
+ },
391
+ "indexes": {},
392
+ "foreignKeys": {},
393
+ "compositePrimaryKeys": {},
394
+ "uniqueConstraints": {},
395
+ "checkConstraints": {}
396
+ },
397
+ "password_reset_tokens": {
398
+ "name": "password_reset_tokens",
399
+ "columns": {
400
+ "id": {
401
+ "name": "id",
402
+ "type": "text",
403
+ "primaryKey": true,
404
+ "notNull": true,
405
+ "autoincrement": false
406
+ },
407
+ "user_id": {
408
+ "name": "user_id",
409
+ "type": "text",
410
+ "primaryKey": false,
411
+ "notNull": true,
412
+ "autoincrement": false
413
+ },
414
+ "token_hash": {
415
+ "name": "token_hash",
416
+ "type": "text",
417
+ "primaryKey": false,
418
+ "notNull": true,
419
+ "autoincrement": false
420
+ },
421
+ "expires_at": {
422
+ "name": "expires_at",
423
+ "type": "text",
424
+ "primaryKey": false,
425
+ "notNull": true,
426
+ "autoincrement": false
427
+ },
428
+ "created_at": {
429
+ "name": "created_at",
430
+ "type": "text",
431
+ "primaryKey": false,
432
+ "notNull": true,
433
+ "autoincrement": false
434
+ },
435
+ "used_at": {
436
+ "name": "used_at",
437
+ "type": "text",
438
+ "primaryKey": false,
439
+ "notNull": false,
440
+ "autoincrement": false
441
+ }
442
+ },
443
+ "indexes": {},
444
+ "foreignKeys": {
445
+ "password_reset_tokens_user_id_users_id_fk": {
446
+ "name": "password_reset_tokens_user_id_users_id_fk",
447
+ "tableFrom": "password_reset_tokens",
448
+ "tableTo": "users",
449
+ "columnsFrom": [
450
+ "user_id"
451
+ ],
452
+ "columnsTo": [
453
+ "id"
454
+ ],
455
+ "onDelete": "no action",
456
+ "onUpdate": "no action"
457
+ }
458
+ },
459
+ "compositePrimaryKeys": {},
460
+ "uniqueConstraints": {},
461
+ "checkConstraints": {}
462
+ },
463
+ "pipeline_state": {
464
+ "name": "pipeline_state",
465
+ "columns": {
466
+ "feature_id": {
467
+ "name": "feature_id",
468
+ "type": "text",
469
+ "primaryKey": true,
470
+ "notNull": true,
471
+ "autoincrement": false
472
+ },
473
+ "status": {
474
+ "name": "status",
475
+ "type": "text",
476
+ "primaryKey": false,
477
+ "notNull": true,
478
+ "autoincrement": false
479
+ },
480
+ "cycle": {
481
+ "name": "cycle",
482
+ "type": "integer",
483
+ "primaryKey": false,
484
+ "notNull": true,
485
+ "autoincrement": false,
486
+ "default": 1
487
+ },
488
+ "tasks_json": {
489
+ "name": "tasks_json",
490
+ "type": "text",
491
+ "primaryKey": false,
492
+ "notNull": false,
493
+ "autoincrement": false
494
+ },
495
+ "tool_calls_json": {
496
+ "name": "tool_calls_json",
497
+ "type": "text",
498
+ "primaryKey": false,
499
+ "notNull": false,
500
+ "autoincrement": false
501
+ },
502
+ "work_summaries_json": {
503
+ "name": "work_summaries_json",
504
+ "type": "text",
505
+ "primaryKey": false,
506
+ "notNull": false,
507
+ "autoincrement": false
508
+ },
509
+ "stage_stats_json": {
510
+ "name": "stage_stats_json",
511
+ "type": "text",
512
+ "primaryKey": false,
513
+ "notNull": false,
514
+ "autoincrement": false
515
+ },
516
+ "error": {
517
+ "name": "error",
518
+ "type": "text",
519
+ "primaryKey": false,
520
+ "notNull": false,
521
+ "autoincrement": false
522
+ },
523
+ "updated_at": {
524
+ "name": "updated_at",
525
+ "type": "text",
526
+ "primaryKey": false,
527
+ "notNull": true,
528
+ "autoincrement": false
529
+ },
530
+ "project_id": {
531
+ "name": "project_id",
532
+ "type": "text",
533
+ "primaryKey": false,
534
+ "notNull": false,
535
+ "autoincrement": false
536
+ }
537
+ },
538
+ "indexes": {},
539
+ "foreignKeys": {},
540
+ "compositePrimaryKeys": {},
541
+ "uniqueConstraints": {},
542
+ "checkConstraints": {}
543
+ },
544
+ "projects": {
545
+ "name": "projects",
546
+ "columns": {
547
+ "id": {
548
+ "name": "id",
549
+ "type": "text",
550
+ "primaryKey": true,
551
+ "notNull": true,
552
+ "autoincrement": false
553
+ },
554
+ "name": {
555
+ "name": "name",
556
+ "type": "text",
557
+ "primaryKey": false,
558
+ "notNull": true,
559
+ "autoincrement": false
560
+ },
561
+ "is_default": {
562
+ "name": "is_default",
563
+ "type": "integer",
564
+ "primaryKey": false,
565
+ "notNull": true,
566
+ "autoincrement": false,
567
+ "default": 0
568
+ },
569
+ "archived_at": {
570
+ "name": "archived_at",
571
+ "type": "text",
572
+ "primaryKey": false,
573
+ "notNull": false,
574
+ "autoincrement": false
575
+ },
576
+ "repo_url": {
577
+ "name": "repo_url",
578
+ "type": "text",
579
+ "primaryKey": false,
580
+ "notNull": false,
581
+ "autoincrement": false
582
+ },
583
+ "github_installation_id": {
584
+ "name": "github_installation_id",
585
+ "type": "text",
586
+ "primaryKey": false,
587
+ "notNull": false,
588
+ "autoincrement": false
589
+ },
590
+ "github_repo_full_name": {
591
+ "name": "github_repo_full_name",
592
+ "type": "text",
593
+ "primaryKey": false,
594
+ "notNull": false,
595
+ "autoincrement": false
596
+ },
597
+ "base_branch": {
598
+ "name": "base_branch",
599
+ "type": "text",
600
+ "primaryKey": false,
601
+ "notNull": false,
602
+ "autoincrement": false
603
+ },
604
+ "created_at": {
605
+ "name": "created_at",
606
+ "type": "text",
607
+ "primaryKey": false,
608
+ "notNull": true,
609
+ "autoincrement": false
610
+ },
611
+ "updated_at": {
612
+ "name": "updated_at",
613
+ "type": "text",
614
+ "primaryKey": false,
615
+ "notNull": true,
616
+ "autoincrement": false
617
+ }
618
+ },
619
+ "indexes": {},
620
+ "foreignKeys": {},
621
+ "compositePrimaryKeys": {},
622
+ "uniqueConstraints": {},
623
+ "checkConstraints": {}
624
+ },
625
+ "refresh_tokens": {
626
+ "name": "refresh_tokens",
627
+ "columns": {
628
+ "id": {
629
+ "name": "id",
630
+ "type": "text",
631
+ "primaryKey": true,
632
+ "notNull": true,
633
+ "autoincrement": false
634
+ },
635
+ "user_id": {
636
+ "name": "user_id",
637
+ "type": "text",
638
+ "primaryKey": false,
639
+ "notNull": true,
640
+ "autoincrement": false
641
+ },
642
+ "token_hash": {
643
+ "name": "token_hash",
644
+ "type": "text",
645
+ "primaryKey": false,
646
+ "notNull": true,
647
+ "autoincrement": false
648
+ },
649
+ "expires_at": {
650
+ "name": "expires_at",
651
+ "type": "text",
652
+ "primaryKey": false,
653
+ "notNull": true,
654
+ "autoincrement": false
655
+ },
656
+ "created_at": {
657
+ "name": "created_at",
658
+ "type": "text",
659
+ "primaryKey": false,
660
+ "notNull": true,
661
+ "autoincrement": false
662
+ }
663
+ },
664
+ "indexes": {},
665
+ "foreignKeys": {
666
+ "refresh_tokens_user_id_users_id_fk": {
667
+ "name": "refresh_tokens_user_id_users_id_fk",
668
+ "tableFrom": "refresh_tokens",
669
+ "tableTo": "users",
670
+ "columnsFrom": [
671
+ "user_id"
672
+ ],
673
+ "columnsTo": [
674
+ "id"
675
+ ],
676
+ "onDelete": "no action",
677
+ "onUpdate": "no action"
678
+ }
679
+ },
680
+ "compositePrimaryKeys": {},
681
+ "uniqueConstraints": {},
682
+ "checkConstraints": {}
683
+ },
684
+ "review_meta": {
685
+ "name": "review_meta",
686
+ "columns": {
687
+ "key": {
688
+ "name": "key",
689
+ "type": "text",
690
+ "primaryKey": true,
691
+ "notNull": true,
692
+ "autoincrement": false
693
+ },
694
+ "value": {
695
+ "name": "value",
696
+ "type": "text",
697
+ "primaryKey": false,
698
+ "notNull": true,
699
+ "autoincrement": false
700
+ },
701
+ "project_id": {
702
+ "name": "project_id",
703
+ "type": "text",
704
+ "primaryKey": false,
705
+ "notNull": false,
706
+ "autoincrement": false
707
+ }
708
+ },
709
+ "indexes": {},
710
+ "foreignKeys": {},
711
+ "compositePrimaryKeys": {},
712
+ "uniqueConstraints": {},
713
+ "checkConstraints": {}
714
+ },
715
+ "sessions": {
716
+ "name": "sessions",
717
+ "columns": {
718
+ "session_number": {
719
+ "name": "session_number",
720
+ "type": "integer",
721
+ "primaryKey": false,
722
+ "notNull": true,
723
+ "autoincrement": false
724
+ },
725
+ "started_at": {
726
+ "name": "started_at",
727
+ "type": "text",
728
+ "primaryKey": false,
729
+ "notNull": true,
730
+ "autoincrement": false
731
+ },
732
+ "ended_at": {
733
+ "name": "ended_at",
734
+ "type": "text",
735
+ "primaryKey": false,
736
+ "notNull": false,
737
+ "autoincrement": false
738
+ },
739
+ "summary": {
740
+ "name": "summary",
741
+ "type": "text",
742
+ "primaryKey": false,
743
+ "notNull": false,
744
+ "autoincrement": false
745
+ },
746
+ "nodes_touched": {
747
+ "name": "nodes_touched",
748
+ "type": "text",
749
+ "primaryKey": false,
750
+ "notNull": false,
751
+ "autoincrement": false
752
+ },
753
+ "questions_resolved": {
754
+ "name": "questions_resolved",
755
+ "type": "integer",
756
+ "primaryKey": false,
757
+ "notNull": true,
758
+ "autoincrement": false,
759
+ "default": 0
760
+ },
761
+ "body": {
762
+ "name": "body",
763
+ "type": "text",
764
+ "primaryKey": false,
765
+ "notNull": false,
766
+ "autoincrement": false
767
+ },
768
+ "project_id": {
769
+ "name": "project_id",
770
+ "type": "text",
771
+ "primaryKey": false,
772
+ "notNull": true,
773
+ "autoincrement": false
774
+ }
775
+ },
776
+ "indexes": {},
777
+ "foreignKeys": {},
778
+ "compositePrimaryKeys": {
779
+ "sessions_session_number_project_id_pk": {
780
+ "columns": [
781
+ "session_number",
782
+ "project_id"
783
+ ],
784
+ "name": "sessions_session_number_project_id_pk"
785
+ }
786
+ },
787
+ "uniqueConstraints": {},
788
+ "checkConstraints": {}
789
+ },
790
+ "users": {
791
+ "name": "users",
792
+ "columns": {
793
+ "id": {
794
+ "name": "id",
795
+ "type": "text",
796
+ "primaryKey": true,
797
+ "notNull": true,
798
+ "autoincrement": false
799
+ },
800
+ "email": {
801
+ "name": "email",
802
+ "type": "text",
803
+ "primaryKey": false,
804
+ "notNull": true,
805
+ "autoincrement": false
806
+ },
807
+ "password_hash": {
808
+ "name": "password_hash",
809
+ "type": "text",
810
+ "primaryKey": false,
811
+ "notNull": true,
812
+ "autoincrement": false
813
+ },
814
+ "role": {
815
+ "name": "role",
816
+ "type": "text",
817
+ "primaryKey": false,
818
+ "notNull": true,
819
+ "autoincrement": false,
820
+ "default": "'user'"
821
+ },
822
+ "created_at": {
823
+ "name": "created_at",
824
+ "type": "text",
825
+ "primaryKey": false,
826
+ "notNull": true,
827
+ "autoincrement": false
828
+ },
829
+ "updated_at": {
830
+ "name": "updated_at",
831
+ "type": "text",
832
+ "primaryKey": false,
833
+ "notNull": true,
834
+ "autoincrement": false
835
+ }
836
+ },
837
+ "indexes": {
838
+ "users_email_unique": {
839
+ "name": "users_email_unique",
840
+ "columns": [
841
+ "email"
842
+ ],
843
+ "isUnique": true
844
+ }
845
+ },
846
+ "foreignKeys": {},
847
+ "compositePrimaryKeys": {},
848
+ "uniqueConstraints": {},
849
+ "checkConstraints": {}
850
+ }
851
+ },
852
+ "views": {},
853
+ "enums": {},
854
+ "_meta": {
855
+ "schemas": {},
856
+ "tables": {},
857
+ "columns": {}
858
+ },
859
+ "internal": {
860
+ "indexes": {}
861
+ }
862
+ }
@@ -22,6 +22,13 @@
22
22
  "when": 1772807644324,
23
23
  "tag": "0002_greedy_excalibur",
24
24
  "breakpoints": true
25
+ },
26
+ {
27
+ "idx": 3,
28
+ "version": "6",
29
+ "when": 1772812820535,
30
+ "tag": "0003_lonely_cyclops",
31
+ "breakpoints": true
25
32
  }
26
33
  ]
27
34
  }
@@ -36,15 +36,17 @@ export const kanban = sqliteTable('kanban', {
36
36
 
37
37
  // --- sessions table ---
38
38
  export const sessions = sqliteTable('sessions', {
39
- sessionNumber: integer('session_number').primaryKey(),
39
+ sessionNumber: integer('session_number').notNull(),
40
40
  startedAt: text('started_at').notNull(),
41
41
  endedAt: text('ended_at'),
42
42
  summary: text('summary'),
43
43
  nodesTouched: text('nodes_touched'),
44
44
  questionsResolved: integer('questions_resolved').notNull().default(0),
45
45
  body: text('body'),
46
- projectId: text('project_id'),
47
- });
46
+ projectId: text('project_id').notNull(),
47
+ }, (table) => [
48
+ primaryKey({ columns: [table.sessionNumber, table.projectId] }),
49
+ ]);
48
50
 
49
51
  // --- coherence_reviews table ---
50
52
  export const coherenceReviews = sqliteTable('coherence_reviews', {
@@ -22,7 +22,7 @@ export const getNextSessionNumber = async (projectId?: string) => {
22
22
  /**
23
23
  * Create a new session record.
24
24
  */
25
- export const createSession = async (sessionNum, body, projectId?: string) => {
25
+ export const createSession = async (sessionNum, body, projectId: string) => {
26
26
  const db = getDb();
27
27
  const now = new Date().toISOString();
28
28
 
@@ -34,7 +34,7 @@ export const createSession = async (sessionNum, body, projectId?: string) => {
34
34
  nodesTouched: '[]',
35
35
  questionsResolved: 0,
36
36
  body: body || '',
37
- projectId: projectId || null,
37
+ projectId,
38
38
  });
39
39
 
40
40
  return { session: sessionNum, started_at: now };
@@ -55,7 +55,7 @@ export const getLatestSession = async (projectId?: string) => {
55
55
  /**
56
56
  * Update/end a session with summary and metadata.
57
57
  */
58
- export const endSession = async (sessionNum, updates) => {
58
+ export const endSession = async (sessionNum, updates, projectId: string) => {
59
59
  const db = getDb();
60
60
 
61
61
  const updateFields = {};
@@ -65,15 +65,19 @@ export const endSession = async (sessionNum, updates) => {
65
65
  if (updates.questions_resolved !== undefined) updateFields.questionsResolved = updates.questions_resolved;
66
66
  if (updates.body !== undefined) updateFields.body = updates.body;
67
67
 
68
- await db.update(sessions).set(updateFields).where(eq(sessions.sessionNumber, sessionNum));
68
+ await db.update(sessions).set(updateFields).where(
69
+ and(eq(sessions.sessionNumber, sessionNum), eq(sessions.projectId, projectId))
70
+ );
69
71
  };
70
72
 
71
73
  /**
72
74
  * Get a session by number.
73
75
  */
74
- export const getSession = async (sessionNum) => {
76
+ export const getSession = async (sessionNum, projectId: string) => {
75
77
  const db = getDb();
76
- const rows = await db.select().from(sessions).where(eq(sessions.sessionNumber, sessionNum));
78
+ const rows = await db.select().from(sessions).where(
79
+ and(eq(sessions.sessionNumber, sessionNum), eq(sessions.projectId, projectId))
80
+ );
77
81
  return rows[0];
78
82
  };
79
83
 
@@ -36,7 +36,7 @@ const opts = program.opts();
36
36
  }
37
37
 
38
38
  // Add gap analysis
39
- const graph = await readGraph();
39
+ const graph = await readGraph(opts.projectId);
40
40
  const graphNodes = graph.nodes;
41
41
  const totalNodes = graphNodes.length;
42
42
  const avgCompleteness = totalNodes > 0
@@ -74,7 +74,7 @@ const opts = program.opts();
74
74
  nodes_touched: opts.nodesTouched ? opts.nodesTouched.split(',').map(s => s.trim()) : [],
75
75
  questions_resolved: opts.questionsResolved,
76
76
  body: updatedBody,
77
- });
77
+ }, opts.projectId);
78
78
 
79
79
  console.log(chalk.green(`✓ Session ${session.sessionNumber} ended`));
80
80
  console.log(`Nodes: ${totalNodes} — ${Math.round(avgCompleteness * 100)}% complete`);
@@ -28,8 +28,15 @@ truth for **what matters, what's next, and why**.
28
28
  ## Session Start Protocol
29
29
  1. Call `start_session`
30
30
  2. Call `get_status` — check if this is a cold start or a continuation
31
- 3. If cold start (empty graph): begin with **Phase 1**
32
- 4. If continuing: call `get_gaps --blocking-only` and resume at the
31
+ 3. **Locate the project workspace** the codebase to scan lives at
32
+ `workspaces/<project-id>/` (a sibling of the `assistkick-product-system/`
33
+ directory). This is where repos are cloned or initialized. **Never scan
34
+ the `assistkick-product-system/` directory** — that is the interview
35
+ tool itself, not the user's project. If the workspace directory does
36
+ not exist or is empty, ask the user to connect a repository first via
37
+ the UI (Git Repository settings).
38
+ 4. If cold start (empty graph): begin with **Phase 1**
39
+ 5. If continuing: call `get_gaps --blocking-only` and resume at the
33
40
  appropriate phase
34
41
 
35
42
  ## Phase 1 — Project Survey (Codebase Scan)
@@ -37,6 +44,11 @@ truth for **what matters, what's next, and why**.
37
44
  **Goal:** Understand the project structure, tech stack, and domain without
38
45
  asking the user a single question yet.
39
46
 
47
+ **IMPORTANT:** All codebase scanning in this phase must target the project
48
+ workspace at `workspaces/<project-id>/` (sibling of `assistkick-product-system/`).
49
+ Never scan `assistkick-product-system/` — that is the interview tool, not the
50
+ user's project.
51
+
40
52
  1. **Explore the project root** — read `package.json`, `Cargo.toml`,
41
53
  `pyproject.toml`, `go.mod`, `Gemfile`, or equivalent to identify:
42
54
  - Language and framework