circuschief 0.7.0 → 0.8.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 +1 -1
- package/packages/server/src/agents/adapters/CodexAdapter.js +5 -4
- package/packages/server/src/api/canvas.js +22 -57
- package/packages/server/src/api/index.js +2 -0
- package/packages/server/src/api/kanban.js +4 -2
- package/packages/server/src/api/projects-helpers.js +20 -3
- package/packages/server/src/api/projects-session-helpers.js +10 -4
- package/packages/server/src/api/projects.js +10 -0
- package/packages/server/src/api/providers.js +11 -1
- package/packages/server/src/api/sessions-commands.js +35 -17
- package/packages/server/src/api/sessions-lifecycle.js +10 -10
- package/packages/server/src/api/sessions-patch.js +4 -0
- package/packages/server/src/api/sessions.js +6 -5
- package/packages/server/src/database.js +0 -2
- package/packages/server/src/db/DatabaseManager.js +5 -1
- package/packages/server/src/db/ProjectDefaultsRepository.js +3 -3
- package/packages/server/src/db/ProviderRepository.js +87 -32
- package/packages/server/src/db/SessionRepository.js +1 -0
- package/packages/server/src/db/index.js +0 -3
- package/packages/server/src/db/migrations/index.js +36 -202
- package/packages/server/src/db/seedBaselineData.js +137 -0
- package/packages/server/src/db/session-helpers.js +6 -3
- package/packages/server/src/middleware/sessionLookup.js +81 -8
- package/packages/server/src/schema.sql +149 -132
- package/packages/server/src/scripts/backupDatabase.js +21 -0
- package/packages/server/src/scripts/dbUtils.js +81 -0
- package/packages/server/src/scripts/inspectDatabaseSchema.js +81 -0
- package/packages/server/src/scripts/validateDatabaseBaseline.js +212 -0
- package/packages/server/src/services/codexSpawnHelper.js +9 -0
- package/packages/server/src/services/commandButtonPrompts.js +8 -8
- package/packages/server/src/services/commandRunner.js +7 -1
- package/packages/server/src/services/e2eSpawnCapture.js +147 -0
- package/packages/server/src/services/gitCommitAttribution.js +120 -0
- package/packages/server/src/services/gitService.js +11 -2
- package/packages/server/src/services/gitSessionSetup.js +11 -1
- package/packages/server/src/services/kanbanTriggers.js +6 -3
- package/packages/server/src/services/nodeSpawnHelper.js +9 -0
- package/packages/server/src/services/prUrlService.js +3 -3
- package/packages/server/src/services/queryParamBuilder.js +90 -0
- package/packages/server/src/services/sessionDuplicator.js +1 -5
- package/packages/server/src/services/sessionExecution.js +56 -108
- package/packages/server/src/services/sessionPrompts.js +12 -47
- package/packages/server/src/services/sessionProvider.js +10 -0
- package/packages/server/src/services/summaryService.js +5 -3
- package/packages/server/src/services/summaryStaleCheck.js +23 -4
- package/packages/server/src/services/templateTriggerService.js +3 -1
- package/packages/shared/src/constants.js +3 -0
- package/packages/shared/src/contracts/commandButtons.js +16 -2
- package/packages/shared/src/contracts/projects.js +2 -2
- package/packages/shared/src/contracts/providers.js +60 -0
- package/packages/shared/src/contracts/sessions.js +2 -1
- package/packages/shared/src/contracts/templates.js +2 -2
- package/packages/shared/src/types.js +1 -9
- package/packages/shared/src/utils.js +2 -2
- package/packages/web/dist/assets/{ActiveSessionsView-UJsCILDL.js → ActiveSessionsView-B0XHqLmv.js} +1 -1
- package/packages/web/dist/assets/{AgentLogsView-BGFPLjLa.js → AgentLogsView-DmsjUMlB.js} +2 -2
- package/packages/web/dist/assets/ApiClient-C3ztI9s9.js +1 -0
- package/packages/web/dist/assets/ArchiveConfirmModal-BlCyn5Vt.js +1 -0
- package/packages/web/dist/assets/ArchiveConfirmModal-DeoCVGXt.css +1 -0
- package/packages/web/dist/assets/{CommandButtonDetailView-D8S258uP.js → CommandButtonDetailView-CdSCPp78.js} +1 -1
- package/packages/web/dist/assets/EffortLevelSelector-hc2MNKg6.js +1 -0
- package/packages/web/dist/assets/{GeneralSettingsView-DsHChEhv.js → GeneralSettingsView-D1nI8_zk.js} +1 -1
- package/packages/web/dist/assets/InputWithButton-CAkttyqx.js +1 -0
- package/packages/web/dist/assets/{InputWithButton-cYdrEmTs.css → InputWithButton-D9HMvfR5.css} +1 -1
- package/packages/web/dist/assets/{InterpolationHelp-CIkOSkWX.js → InterpolationHelp-BO1j9Z3_.js} +1 -1
- package/packages/web/dist/assets/MarkdownEditor-ucRAP_UM.js +2 -0
- package/packages/web/dist/assets/{ModelSelector-D8hbTRIt.css → ModelSelector-BSxKUSus.css} +1 -1
- package/packages/web/dist/assets/{ModelSelector-BMpR0DPr.js → ModelSelector-CwTz8ZWO.js} +1 -1
- package/packages/web/dist/assets/{NewSessionView-CUUdHkfv.css → NewSessionView-BDPb-1qr.css} +1 -1
- package/packages/web/dist/assets/NewSessionView-BsDrp8mj.js +3 -0
- package/packages/web/dist/assets/ProjectEditView-CwTOeSun.js +1 -0
- package/packages/web/dist/assets/{ProjectEditView-D9sK0fdH.css → ProjectEditView-J15mcsWz.css} +1 -1
- package/packages/web/dist/assets/{ProjectListView-B9FuWESY.js → ProjectListView-DcNyuINs.js} +1 -1
- package/packages/web/dist/assets/{ProjectNewView-D62jYlBL.js → ProjectNewView-B5YV62hv.js} +1 -1
- package/packages/web/dist/assets/ProvidersView-bZemq_Rv.css +1 -0
- package/packages/web/dist/assets/ProvidersView-nY9GnDdO.js +1 -0
- package/packages/web/dist/assets/QuickResponseSettings-B352c75l.css +1 -0
- package/packages/web/dist/assets/{QuickResponseSettings-CDm5vwP7.js → QuickResponseSettings-BQwQXuL7.js} +1 -1
- package/packages/web/dist/assets/{QuickResponsesPanel-DZ_Lre_l.js → QuickResponsesPanel-BzSYcCSP.js} +1 -1
- package/packages/web/dist/assets/{ResizableTextarea-DiIOEGjN.js → ResizableTextarea-B3YIdIXv.js} +1 -1
- package/packages/web/dist/assets/{SessionCard-DmjnVYWn.js → SessionCard-CjE1tXiT.js} +1 -1
- package/packages/web/dist/assets/SessionDetailView-3cPZrbS3.js +36 -0
- package/packages/web/dist/assets/SessionDetailView-CZRZMrfM.css +1 -0
- package/packages/web/dist/assets/{SessionFormOptions-DYUISplS.js → SessionFormOptions-B6AxyREh.js} +1 -1
- package/packages/web/dist/assets/SessionListView-B5_6gW49.css +1 -0
- package/packages/web/dist/assets/SessionListView-CLXBfLcq.js +1 -0
- package/packages/web/dist/assets/{SessionLogStream-DpUE6Xsh.js → SessionLogStream-LlZ3z_Xj.js} +1 -1
- package/packages/web/dist/assets/{SettingsView-BC055tIA.js → SettingsView-CTGiGvR2.js} +1 -1
- package/packages/web/dist/assets/{SlashCommandWizard-DmTyNG9O.js → SlashCommandWizard-Cy04d7-o.js} +1 -1
- package/packages/web/dist/assets/{SlashCommandWizard-Dn7sNaBd.css → SlashCommandWizard-DJzw3LP5.css} +1 -1
- package/packages/web/dist/assets/{SummarySettingsView-BgnRCwlq.js → SummarySettingsView-BR2ZjEa3.js} +1 -1
- package/packages/web/dist/assets/{TemplateDetailView-BlhOmLUX.js → TemplateDetailView-DH6Oswsp.js} +1 -1
- package/packages/web/dist/assets/{commandButtons-D4RPpLiu.js → commandButtons-BfqR-fqq.js} +1 -1
- package/packages/web/dist/assets/{index-CfL84oGW.js → index-1zziPL6l.js} +1 -1
- package/packages/web/dist/assets/{index-OfCywayk.js → index-7kzHPxSF.js} +1 -1
- package/packages/web/dist/assets/{index-PDesaJc6.js → index-B0N_obMc.js} +1 -1
- package/packages/web/dist/assets/{index-Cpy4-yv3.js → index-BNk_gdfI.js} +1 -1
- package/packages/web/dist/assets/{index-Cs2nxhrT.css → index-BY174HVJ.css} +1 -1
- package/packages/web/dist/assets/{index-9vb2KaAd.js → index-CSqaAH-0.js} +1 -1
- package/packages/web/dist/assets/{index-CNwkdB0T.js → index-C_q4WlK8.js} +1 -1
- package/packages/web/dist/assets/{index-B0CvZXuN.js → index-D1wpU4y0.js} +1 -1
- package/packages/web/dist/assets/{index-4rhEeO0B.js → index-D5zCA8sD.js} +1 -1
- package/packages/web/dist/assets/{index-CkmxO8Mm.js → index-DGR8ELWY.js} +1 -1
- package/packages/web/dist/assets/{index-CrAQJmoZ.js → index-DHga8pXo.js} +1 -1
- package/packages/web/dist/assets/{index-BUhvkAdF.js → index-DSby02Wl.js} +1 -1
- package/packages/web/dist/assets/{index-BGwH4Cfn.js → index-DgkC10TW.js} +3 -3
- package/packages/web/dist/assets/{index-DfrE0gAC.js → index-DqjXJTVI.js} +1 -1
- package/packages/web/dist/assets/{index-Bn5xdGFM.js → index-DtfUt785.js} +1 -1
- package/packages/web/dist/assets/{index-KwEyz0F3.js → index-_4S2uLDI.js} +1 -1
- package/packages/web/dist/assets/{index-B6G18FqB.js → index-fK8FIZgP.js} +15 -14
- package/packages/web/dist/assets/{index-BcnkUk2o.js → index-gmiZeFXN.js} +1 -1
- package/packages/web/dist/assets/{index-D6Ky9vJe.js → index-irD539ZM.js} +1 -1
- package/packages/web/dist/assets/{index-uB6nhSvz.js → index-yq-E1Y00.js} +1 -1
- package/packages/web/dist/assets/{projects-BUiOGmmb.js → projects-DXYQNJIi.js} +1 -1
- package/packages/web/dist/assets/{providers-Bh1ZiiJi.js → providers-1bnH-exJ.js} +1 -1
- package/packages/web/dist/assets/sessions-6zGUlFrt.js +1 -0
- package/packages/web/dist/assets/{settings-Z4AVVmkJ.js → settings-MbfRir0d.js} +1 -1
- package/packages/web/dist/index.html +2 -2
- package/packages/server/src/api/sessions-notes.js +0 -51
- package/packages/server/src/db/SessionNoteRepository.js +0 -60
- package/packages/server/src/db/migrations/canvasItemsMigrations.js +0 -109
- package/packages/server/src/db/migrations/conversationsMigrations.js +0 -187
- package/packages/server/src/db/migrations/kanbanMigrations.js +0 -99
- package/packages/server/src/db/migrations/miscMigrations.js +0 -369
- package/packages/server/src/db/migrations/projectsMigrations.js +0 -99
- package/packages/server/src/db/migrations/sessionsMigrations.js +0 -287
- package/packages/web/dist/assets/ApiClient-B4YTtyY4.js +0 -1
- package/packages/web/dist/assets/ArchiveConfirmModal-BQ-4gI0R.css +0 -1
- package/packages/web/dist/assets/ArchiveConfirmModal-OFaj_uX5.js +0 -1
- package/packages/web/dist/assets/EffortLevelSelector-C2378L8e.js +0 -1
- package/packages/web/dist/assets/InputWithButton-Ci15ox0a.js +0 -1
- package/packages/web/dist/assets/MarkdownEditor-5-bexzUT.js +0 -2
- package/packages/web/dist/assets/NewSessionView-BCqtIgWH.js +0 -3
- package/packages/web/dist/assets/ProjectEditView-RFaxHhAX.js +0 -1
- package/packages/web/dist/assets/ProvidersView-DDKMIQWZ.js +0 -1
- package/packages/web/dist/assets/ProvidersView-DE82G_5W.css +0 -1
- package/packages/web/dist/assets/QuickResponseSettings-B8188A1D.css +0 -1
- package/packages/web/dist/assets/SessionDetailView-CL7nmfiB.js +0 -36
- package/packages/web/dist/assets/SessionDetailView-CupIkI7u.css +0 -1
- package/packages/web/dist/assets/SessionListView-BcxGz4aC.js +0 -1
- package/packages/web/dist/assets/SessionListView-fHlQyecX.css +0 -1
- package/packages/web/dist/assets/sessions-DH1R-NhV.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{M as i,a7 as r}from"./index-fK8FIZgP.js";import{a as s}from"./ApiClient-C3ztI9s9.js";const l=i("settings",{state:()=>({tokenCostWeights:{...r},summarySettings:{disableSessionSummaries:!1,sessionTitlePrompt:"",summaryModel:"",summaryProviderId:null,defaultSessionTitlePrompt:""},generalSettings:{disableAnalytics:!1},loading:!1,error:null}),getters:{weights:t=>t.tokenCostWeights},actions:{async fetchTokenCostWeights(){this.loading=!0,this.error=null;try{const t=await s.getTokenCostWeights();this.tokenCostWeights=t}catch(t){this.error=t.message,this.tokenCostWeights={...r}}finally{this.loading=!1}},async updateTokenCostWeights(t){this.loading=!0,this.error=null;try{const e=await s.updateTokenCostWeights(t);return this.tokenCostWeights=e,e}catch(e){throw this.error=e.message,e}finally{this.loading=!1}},async resetTokenCostWeights(){this.loading=!0,this.error=null;try{const t=await s.resetTokenCostWeights();return this.tokenCostWeights=t,t}catch(t){throw this.error=t.message,t}finally{this.loading=!1}},async fetchSummarySettings(){this.loading=!0,this.error=null;try{const t=await s.getSummarySettings();this.summarySettings=t}catch(t){this.error=t.message,this.summarySettings={disableSessionSummaries:!1,sessionTitlePrompt:"",summaryModel:"",summaryProviderId:null,defaultSessionTitlePrompt:""}}finally{this.loading=!1}},async updateSummarySettings(t){this.loading=!0,this.error=null;try{const e=await s.updateSummarySettings(t);return this.summarySettings=e,e}catch(e){throw this.error=e.message,e}finally{this.loading=!1}},async resetSummarySettings(){this.loading=!0,this.error=null;try{const t=await s.resetSummarySettings();return this.summarySettings=t,t}catch(t){throw this.error=t.message,t}finally{this.loading=!1}},async fetchGeneralSettings(){this.loading=!0,this.error=null;try{const t=await s.getGeneralSettings();this.generalSettings=t}catch(t){this.error=t.message,this.generalSettings={disableAnalytics:!1}}finally{this.loading=!1}},async updateGeneralSettings(t){this.loading=!0,this.error=null;try{const e=await s.updateGeneralSettings(t);return this.generalSettings=e,e}catch(e){throw this.error=e.message,e}finally{this.loading=!1}},async resetGeneralSettings(){this.loading=!0,this.error=null;try{const t=await s.resetGeneralSettings();return this.generalSettings=t,t}catch(t){throw this.error=t.message,t}finally{this.loading=!1}}}});export{l as u};
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
|
|
10
10
|
<title>Circus Chief</title>
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-fK8FIZgP.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BY174HVJ.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="app"></div>
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { Router } from 'express';
|
|
2
|
-
import { sessionNotes } from '../database.js';
|
|
3
|
-
import { requireSession } from '../middleware/sessionLookup.js';
|
|
4
|
-
|
|
5
|
-
const router = Router();
|
|
6
|
-
|
|
7
|
-
// GET /api/sessions/:id/notes - Get session notes
|
|
8
|
-
router.get('/:id/notes', requireSession, (req, res) => {
|
|
9
|
-
const notes = sessionNotes.getBySessionId(req.params.id);
|
|
10
|
-
res.json(notes);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
// POST /api/sessions/:id/notes - Create session note
|
|
14
|
-
router.post('/:id/notes', requireSession, (req, res) => {
|
|
15
|
-
const { content } = req.body;
|
|
16
|
-
if (!content) {
|
|
17
|
-
return res.status(400).json({ error: 'Content is required' });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const note = sessionNotes.create(req.params.id, content);
|
|
21
|
-
res.status(201).json(note);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
// PUT /api/sessions/:id/notes/:noteId - Update session note
|
|
25
|
-
router.put('/:id/notes/:noteId', (req, res) => {
|
|
26
|
-
const note = sessionNotes.getById(req.params.noteId);
|
|
27
|
-
if (!note || note.sessionId !== req.params.id) {
|
|
28
|
-
return res.status(404).json({ error: 'Note not found' });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const { content } = req.body;
|
|
32
|
-
if (!content) {
|
|
33
|
-
return res.status(400).json({ error: 'Content is required' });
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const updated = sessionNotes.update(req.params.noteId, content);
|
|
37
|
-
res.json(updated);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// DELETE /api/sessions/:id/notes/:noteId - Delete session note
|
|
41
|
-
router.delete('/:id/notes/:noteId', (req, res) => {
|
|
42
|
-
const note = sessionNotes.getById(req.params.noteId);
|
|
43
|
-
if (!note || note.sessionId !== req.params.id) {
|
|
44
|
-
return res.status(404).json({ error: 'Note not found' });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
sessionNotes.delete(req.params.noteId);
|
|
48
|
-
res.status(204).send();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
export default router;
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { BaseRepository } from './BaseRepository.js';
|
|
2
|
-
import { databaseManager } from './DatabaseManager.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Session note repository class
|
|
6
|
-
*/
|
|
7
|
-
export class SessionNoteRepository extends BaseRepository {
|
|
8
|
-
constructor() {
|
|
9
|
-
super('session_notes', SessionNoteRepository.#mapNote);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
static #mapNote(row) {
|
|
13
|
-
return {
|
|
14
|
-
id: row.id,
|
|
15
|
-
sessionId: row.session_id,
|
|
16
|
-
content: row.content,
|
|
17
|
-
createdAt: row.created_at,
|
|
18
|
-
updatedAt: row.updated_at,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
create(sessionId, content) {
|
|
23
|
-
const id = databaseManager.generateId();
|
|
24
|
-
const now = Date.now();
|
|
25
|
-
this.db
|
|
26
|
-
.prepare(
|
|
27
|
-
`INSERT INTO session_notes (id, session_id, content, created_at, updated_at)
|
|
28
|
-
VALUES (?, ?, ?, ?, ?)`
|
|
29
|
-
)
|
|
30
|
-
.run(id, sessionId, content, now, now);
|
|
31
|
-
return this.getById(id);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
getBySessionId(sessionId) {
|
|
35
|
-
const rows = this.db
|
|
36
|
-
.prepare('SELECT * FROM session_notes WHERE session_id = ? ORDER BY created_at DESC')
|
|
37
|
-
.all(sessionId);
|
|
38
|
-
return this.mapAll(rows);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
update(id, content) {
|
|
42
|
-
this.db
|
|
43
|
-
.prepare('UPDATE session_notes SET content = ?, updated_at = ? WHERE id = ?')
|
|
44
|
-
.run(content, Date.now(), id);
|
|
45
|
-
return this.getById(id);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Duplicates all notes from one session to another.
|
|
50
|
-
* @param {string} sourceSessionId - Source session ID
|
|
51
|
-
* @param {string} targetSessionId - Target session ID
|
|
52
|
-
*/
|
|
53
|
-
duplicateForSession(sourceSessionId, targetSessionId) {
|
|
54
|
-
const notes = this.getBySessionId(sourceSessionId);
|
|
55
|
-
|
|
56
|
-
for (const note of notes) {
|
|
57
|
-
this.create(targetSessionId, note.content);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Migrations for the canvas_items table.
|
|
3
|
-
* Each export is an array of { name, up(db) } migration objects.
|
|
4
|
-
*/
|
|
5
|
-
import { addColumnIfMissing, getColumns, getTableSql } from './migrationUtils.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Migrate canvas_items table to include 'code' in type CHECK constraint.
|
|
9
|
-
* SQLite doesn't support ALTER TABLE to modify constraints, so we recreate the table.
|
|
10
|
-
*/
|
|
11
|
-
function migrateCanvasItemsTypeConstraint(db) {
|
|
12
|
-
const tableSql = getTableSql(db, 'canvas_items');
|
|
13
|
-
|
|
14
|
-
// If schema already includes 'code', no migration needed
|
|
15
|
-
if (tableSql?.includes("'code'")) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
db.exec(`
|
|
20
|
-
CREATE TABLE canvas_items_new (
|
|
21
|
-
id TEXT PRIMARY KEY,
|
|
22
|
-
session_id TEXT REFERENCES sessions(id) ON DELETE CASCADE,
|
|
23
|
-
type TEXT NOT NULL CHECK (type IN ('image', 'markdown', 'text', 'json', 'pdf', 'code')),
|
|
24
|
-
content TEXT,
|
|
25
|
-
data TEXT,
|
|
26
|
-
mime_type TEXT,
|
|
27
|
-
filename TEXT,
|
|
28
|
-
label TEXT,
|
|
29
|
-
width INTEGER,
|
|
30
|
-
height INTEGER,
|
|
31
|
-
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
INSERT INTO canvas_items_new SELECT * FROM canvas_items;
|
|
35
|
-
|
|
36
|
-
DROP TABLE canvas_items;
|
|
37
|
-
|
|
38
|
-
ALTER TABLE canvas_items_new RENAME TO canvas_items;
|
|
39
|
-
|
|
40
|
-
CREATE INDEX IF NOT EXISTS idx_canvas_session ON canvas_items(session_id);
|
|
41
|
-
`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Migrate canvas_items table to drop label column.
|
|
46
|
-
*/
|
|
47
|
-
function migrateCanvasItemsDropLabel(db) {
|
|
48
|
-
const columns = getColumns(db, 'canvas_items');
|
|
49
|
-
|
|
50
|
-
// If label column doesn't exist, migration already done
|
|
51
|
-
if (!columns.includes('label')) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
db.exec(`
|
|
56
|
-
CREATE TABLE canvas_items_new (
|
|
57
|
-
id TEXT PRIMARY KEY,
|
|
58
|
-
session_id TEXT REFERENCES sessions(id) ON DELETE CASCADE,
|
|
59
|
-
type TEXT NOT NULL CHECK (type IN ('image', 'markdown', 'text', 'json', 'pdf', 'code')),
|
|
60
|
-
content TEXT,
|
|
61
|
-
data TEXT,
|
|
62
|
-
mime_type TEXT,
|
|
63
|
-
filename TEXT,
|
|
64
|
-
width INTEGER,
|
|
65
|
-
height INTEGER,
|
|
66
|
-
deleted_at INTEGER,
|
|
67
|
-
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
INSERT INTO canvas_items_new (id, session_id, type, content, data, mime_type, filename, width, height, deleted_at, created_at)
|
|
71
|
-
SELECT id, session_id, type, content, data, mime_type, filename, width, height, deleted_at, created_at FROM canvas_items;
|
|
72
|
-
|
|
73
|
-
DROP TABLE canvas_items;
|
|
74
|
-
|
|
75
|
-
ALTER TABLE canvas_items_new RENAME TO canvas_items;
|
|
76
|
-
|
|
77
|
-
CREATE INDEX IF NOT EXISTS idx_canvas_session ON canvas_items(session_id);
|
|
78
|
-
CREATE INDEX IF NOT EXISTS idx_canvas_deleted ON canvas_items(deleted_at);
|
|
79
|
-
`);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** @type {Array<{name: string, up: (db: import('better-sqlite3').Database) => void}>} */
|
|
83
|
-
export const canvasItemsMigrations = [
|
|
84
|
-
{
|
|
85
|
-
name: 'canvas_items-migrate-type-constraint',
|
|
86
|
-
up(db) { migrateCanvasItemsTypeConstraint(db); },
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
name: 'canvas_items-add-deleted_at',
|
|
90
|
-
up(db) {
|
|
91
|
-
addColumnIfMissing(db, 'canvas_items', 'deleted_at', 'INTEGER');
|
|
92
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_canvas_deleted ON canvas_items(deleted_at)');
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
name: 'canvas_items-drop-label',
|
|
97
|
-
up(db) { migrateCanvasItemsDropLabel(db); },
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
name: 'canvas_items-add-updated_at',
|
|
101
|
-
up(db) {
|
|
102
|
-
const columns = getColumns(db, 'canvas_items');
|
|
103
|
-
if (!columns.includes('updated_at')) {
|
|
104
|
-
db.exec('ALTER TABLE canvas_items ADD COLUMN updated_at INTEGER');
|
|
105
|
-
db.exec('UPDATE canvas_items SET updated_at = created_at WHERE updated_at IS NULL');
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
];
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Migrations for the conversations, conversation_messages, and message_attachments tables.
|
|
3
|
-
* Each export is an array of { name, up(db) } migration objects.
|
|
4
|
-
*/
|
|
5
|
-
import crypto from 'crypto';
|
|
6
|
-
import { addColumnIfMissing, getColumns } from './migrationUtils.js';
|
|
7
|
-
|
|
8
|
-
// Table name constants for migrations
|
|
9
|
-
const TABLE_CONVERSATIONS = 'conversations';
|
|
10
|
-
|
|
11
|
-
// Column type constants
|
|
12
|
-
const COL_INTEGER_DEFAULT_0 = 'INTEGER DEFAULT 0';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Create default conversations for existing sessions that don't have any
|
|
16
|
-
* and associate orphaned messages with the default conversation.
|
|
17
|
-
*/
|
|
18
|
-
function migrateExistingSessionsToConversations(db) {
|
|
19
|
-
const sessionsWithoutConversations = db
|
|
20
|
-
.prepare(
|
|
21
|
-
`
|
|
22
|
-
SELECT DISTINCT s.id FROM sessions s
|
|
23
|
-
LEFT JOIN conversations c ON c.session_id = s.id
|
|
24
|
-
WHERE c.id IS NULL
|
|
25
|
-
AND EXISTS (SELECT 1 FROM conversation_messages m WHERE m.session_id = s.id)
|
|
26
|
-
`
|
|
27
|
-
)
|
|
28
|
-
.all();
|
|
29
|
-
|
|
30
|
-
for (const session of sessionsWithoutConversations) {
|
|
31
|
-
const convId = crypto.randomUUID();
|
|
32
|
-
const now = Date.now();
|
|
33
|
-
|
|
34
|
-
db.prepare(
|
|
35
|
-
`INSERT INTO conversations (id, session_id, name, is_active, created_at, updated_at)
|
|
36
|
-
VALUES (?, ?, ?, 1, ?, ?)`
|
|
37
|
-
).run(convId, session.id, 'Initial', now, now);
|
|
38
|
-
|
|
39
|
-
db.prepare(
|
|
40
|
-
`UPDATE conversation_messages SET conversation_id = ? WHERE session_id = ? AND conversation_id IS NULL`
|
|
41
|
-
).run(convId, session.id);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** @type {Array<{name: string, up: (db: import('better-sqlite3').Database) => void}>} */
|
|
46
|
-
export const conversationsMigrations = [
|
|
47
|
-
// --- Session summaries PR columns ---
|
|
48
|
-
{
|
|
49
|
-
name: 'session_summaries-add-pr_merged',
|
|
50
|
-
up(db) { addColumnIfMissing(db, 'session_summaries', 'pr_merged', 'INTEGER'); },
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'session_summaries-add-pr_state',
|
|
54
|
-
up(db) { addColumnIfMissing(db, 'session_summaries', 'pr_state', 'TEXT'); },
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: 'session_summaries-add-has_merge_conflicts',
|
|
58
|
-
up(db) { addColumnIfMissing(db, 'session_summaries', 'has_merge_conflicts', 'INTEGER'); },
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: 'session_summaries-add-ci_status',
|
|
62
|
-
up(db) { addColumnIfMissing(db, 'session_summaries', 'ci_status', 'TEXT'); },
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
name: 'session_summaries-add-ci_failures',
|
|
66
|
-
up(db) { addColumnIfMissing(db, 'session_summaries', 'ci_failures', 'TEXT'); },
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
name: 'session_summaries-add-last_summarized_message_id',
|
|
70
|
-
up(db) { addColumnIfMissing(db, 'session_summaries', 'last_summarized_message_id', 'TEXT'); },
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
// --- Message attachments ---
|
|
74
|
-
{
|
|
75
|
-
name: 'message_attachments-add-file_path',
|
|
76
|
-
up(db) { addColumnIfMissing(db, 'message_attachments', 'file_path', 'TEXT'); },
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
// --- Conversation messages: conversation_id ---
|
|
80
|
-
{
|
|
81
|
-
name: 'conversation_messages-add-conversation_id',
|
|
82
|
-
up(db) {
|
|
83
|
-
const columns = getColumns(db, 'conversation_messages');
|
|
84
|
-
if (!columns.includes('conversation_id')) {
|
|
85
|
-
db.exec(
|
|
86
|
-
'ALTER TABLE conversation_messages ADD COLUMN conversation_id TEXT REFERENCES conversations(id) ON DELETE CASCADE'
|
|
87
|
-
);
|
|
88
|
-
db.exec(
|
|
89
|
-
'CREATE INDEX IF NOT EXISTS idx_messages_conversation ON conversation_messages(conversation_id)'
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
// --- Migrate existing sessions to conversations ---
|
|
96
|
-
{
|
|
97
|
-
name: 'conversations-migrate-existing-sessions',
|
|
98
|
-
up(db) { migrateExistingSessionsToConversations(db); },
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
// --- Conversations: claude_session_id ---
|
|
102
|
-
{
|
|
103
|
-
name: 'conversations-add-claude_session_id',
|
|
104
|
-
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'claude_session_id', 'TEXT'); },
|
|
105
|
-
},
|
|
106
|
-
|
|
107
|
-
// --- Conversations token usage ---
|
|
108
|
-
{
|
|
109
|
-
name: 'conversations-add-input_tokens',
|
|
110
|
-
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'input_tokens', COL_INTEGER_DEFAULT_0); },
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
name: 'conversations-add-output_tokens',
|
|
114
|
-
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'output_tokens', COL_INTEGER_DEFAULT_0); },
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
name: 'conversations-add-thinking_tokens',
|
|
118
|
-
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'thinking_tokens', COL_INTEGER_DEFAULT_0); },
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
name: 'conversations-add-cache_read_input_tokens',
|
|
122
|
-
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'cache_read_input_tokens', COL_INTEGER_DEFAULT_0); },
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
name: 'conversations-add-cache_creation_input_tokens',
|
|
126
|
-
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'cache_creation_input_tokens', COL_INTEGER_DEFAULT_0); },
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: 'conversations-add-web_search_requests',
|
|
130
|
-
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'web_search_requests', COL_INTEGER_DEFAULT_0); },
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: 'conversations-add-context_window',
|
|
134
|
-
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'context_window', 'INTEGER DEFAULT 200000'); },
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
name: 'conversations-add-model',
|
|
138
|
-
up(db) { addColumnIfMissing(db, TABLE_CONVERSATIONS, 'model', 'TEXT'); },
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
// --- Conversation branching ---
|
|
142
|
-
{
|
|
143
|
-
name: 'conversations-add-parent_conversation_id',
|
|
144
|
-
up(db) {
|
|
145
|
-
const columns = getColumns(db, TABLE_CONVERSATIONS);
|
|
146
|
-
if (!columns.includes('parent_conversation_id')) {
|
|
147
|
-
db.exec(
|
|
148
|
-
'ALTER TABLE conversations ADD COLUMN parent_conversation_id TEXT REFERENCES conversations(id) ON DELETE SET NULL'
|
|
149
|
-
);
|
|
150
|
-
db.exec(
|
|
151
|
-
'CREATE INDEX IF NOT EXISTS idx_conversations_parent ON conversations(parent_conversation_id)'
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
name: 'conversations-add-branch_from_message_id',
|
|
158
|
-
up(db) {
|
|
159
|
-
addColumnIfMissing(
|
|
160
|
-
db, TABLE_CONVERSATIONS, 'branch_from_message_id',
|
|
161
|
-
'TEXT REFERENCES conversation_messages(id) ON DELETE SET NULL'
|
|
162
|
-
);
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
|
|
166
|
-
// --- Session todos: conversation_id ---
|
|
167
|
-
{
|
|
168
|
-
name: 'session_todos-add-conversation_id',
|
|
169
|
-
up(db) {
|
|
170
|
-
const columns = getColumns(db, 'session_todos');
|
|
171
|
-
if (!columns.includes('conversation_id')) {
|
|
172
|
-
db.exec(
|
|
173
|
-
'ALTER TABLE session_todos ADD COLUMN conversation_id TEXT REFERENCES conversations(id) ON DELETE CASCADE'
|
|
174
|
-
);
|
|
175
|
-
db.exec(
|
|
176
|
-
'CREATE INDEX IF NOT EXISTS idx_todos_conversation ON session_todos(conversation_id)'
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
// --- Conversation messages: model ---
|
|
183
|
-
{
|
|
184
|
-
name: 'conversation_messages-add-model',
|
|
185
|
-
up(db) { addColumnIfMissing(db, 'conversation_messages', 'model', 'TEXT'); },
|
|
186
|
-
},
|
|
187
|
-
];
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Migrations for Kanban board feature: kanban_boards, kanban_lanes,
|
|
3
|
-
* kanban_cards, kanban_card_sessions tables, and related columns on
|
|
4
|
-
* projects, sessions, and session_templates.
|
|
5
|
-
*/
|
|
6
|
-
import { addColumnIfMissing } from './migrationUtils.js';
|
|
7
|
-
|
|
8
|
-
export const kanbanMigrations = [
|
|
9
|
-
{
|
|
10
|
-
name: 'projects-add-kanban_enabled',
|
|
11
|
-
up(db) {
|
|
12
|
-
addColumnIfMissing(db, 'projects', 'kanban_enabled', 'INTEGER NOT NULL DEFAULT 1');
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
name: 'kanban-create-tables',
|
|
17
|
-
up(db) {
|
|
18
|
-
db.exec(`
|
|
19
|
-
CREATE TABLE IF NOT EXISTS kanban_boards (
|
|
20
|
-
id TEXT PRIMARY KEY,
|
|
21
|
-
project_id TEXT NOT NULL UNIQUE REFERENCES projects(id) ON DELETE CASCADE,
|
|
22
|
-
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
|
|
23
|
-
updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
CREATE TABLE IF NOT EXISTS kanban_lanes (
|
|
27
|
-
id TEXT PRIMARY KEY,
|
|
28
|
-
board_id TEXT NOT NULL REFERENCES kanban_boards(id) ON DELETE CASCADE,
|
|
29
|
-
name TEXT NOT NULL,
|
|
30
|
-
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
31
|
-
on_enter_template_id TEXT REFERENCES session_templates(id) ON DELETE SET NULL,
|
|
32
|
-
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
|
|
33
|
-
updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
CREATE TABLE IF NOT EXISTS kanban_cards (
|
|
37
|
-
id TEXT PRIMARY KEY,
|
|
38
|
-
lane_id TEXT NOT NULL REFERENCES kanban_lanes(id) ON DELETE CASCADE,
|
|
39
|
-
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
40
|
-
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
|
|
41
|
-
updated_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
CREATE TABLE IF NOT EXISTS kanban_card_sessions (
|
|
45
|
-
id TEXT PRIMARY KEY,
|
|
46
|
-
card_id TEXT NOT NULL REFERENCES kanban_cards(id) ON DELETE CASCADE,
|
|
47
|
-
session_id TEXT NOT NULL UNIQUE REFERENCES sessions(id) ON DELETE CASCADE,
|
|
48
|
-
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
CREATE INDEX IF NOT EXISTS idx_kanban_boards_project ON kanban_boards(project_id);
|
|
52
|
-
CREATE INDEX IF NOT EXISTS idx_kanban_lanes_board ON kanban_lanes(board_id, sort_order);
|
|
53
|
-
CREATE INDEX IF NOT EXISTS idx_kanban_cards_lane ON kanban_cards(lane_id, sort_order);
|
|
54
|
-
CREATE INDEX IF NOT EXISTS idx_kanban_card_sessions_session ON kanban_card_sessions(session_id);
|
|
55
|
-
CREATE INDEX IF NOT EXISTS idx_kanban_card_sessions_card ON kanban_card_sessions(card_id);
|
|
56
|
-
`);
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: 'sessions-add-target_lane_id',
|
|
61
|
-
up(db) {
|
|
62
|
-
addColumnIfMissing(db, 'sessions', 'target_lane_id', 'TEXT REFERENCES kanban_lanes(id) ON DELETE SET NULL');
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
name: 'sessions-add-lane_trigger_depth',
|
|
67
|
-
up(db) {
|
|
68
|
-
addColumnIfMissing(db, 'sessions', 'lane_trigger_depth', 'INTEGER NOT NULL DEFAULT 0');
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
name: 'session_templates-add-target_lane_id',
|
|
73
|
-
up(db) {
|
|
74
|
-
addColumnIfMissing(db, 'session_templates', 'target_lane_id', 'TEXT REFERENCES kanban_lanes(id) ON DELETE SET NULL');
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
name: 'kanban_lanes-add-on_enter_prompt',
|
|
79
|
-
up(db) {
|
|
80
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_prompt', 'TEXT');
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
name: 'kanban_lanes-add-agent-settings',
|
|
85
|
-
up(db) {
|
|
86
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_mode', 'TEXT');
|
|
87
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_model', 'TEXT');
|
|
88
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_effort_level', 'TEXT');
|
|
89
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_thinking_enabled', 'INTEGER');
|
|
90
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_auto_reschedule_enabled', 'INTEGER DEFAULT 0');
|
|
91
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_reschedule_delay_minutes', 'INTEGER DEFAULT 15');
|
|
92
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_reschedule_on_token_limit', 'INTEGER DEFAULT 1');
|
|
93
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_reschedule_on_service_error', 'INTEGER DEFAULT 1');
|
|
94
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_max_reschedule_count', 'INTEGER');
|
|
95
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_max_total_tokens', 'INTEGER');
|
|
96
|
-
addColumnIfMissing(db, 'kanban_lanes', 'on_enter_reschedule_at_token_count', 'INTEGER');
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
];
|