circuschief 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/package.json +33 -0
- package/packages/server/bin/cli.js +4 -0
- package/packages/server/src/agents/AgentGateway.js +64 -0
- package/packages/server/src/agents/BaseAgent.js +41 -0
- package/packages/server/src/agents/LoggingAgentWrapper.js +73 -0
- package/packages/server/src/agents/adapters/ClaudeCodeAdapter.js +33 -0
- package/packages/server/src/agents/adapters/CodexAdapter.js +26 -0
- package/packages/server/src/agents/types.js +43 -0
- package/packages/server/src/agents/vcr/CassetteStore.js +111 -0
- package/packages/server/src/agents/vcr/VCRAgentAdapter.js +126 -0
- package/packages/server/src/agents/vcr/VCRSummaryWrapper.js +71 -0
- package/packages/server/src/api/canvas-helpers.js +249 -0
- package/packages/server/src/api/canvas-trash-routes.js +205 -0
- package/packages/server/src/api/canvas.js +331 -0
- package/packages/server/src/api/commandButtons.js +312 -0
- package/packages/server/src/api/commands.js +169 -0
- package/packages/server/src/api/filesystem.js +62 -0
- package/packages/server/src/api/git.js +85 -0
- package/packages/server/src/api/index.js +44 -0
- package/packages/server/src/api/kanban.js +342 -0
- package/packages/server/src/api/metrics.js +194 -0
- package/packages/server/src/api/projects-helpers.js +43 -0
- package/packages/server/src/api/projects-session-helpers.js +295 -0
- package/packages/server/src/api/projects.js +384 -0
- package/packages/server/src/api/providers.js +249 -0
- package/packages/server/src/api/quickResponses.js +129 -0
- package/packages/server/src/api/sessions-archive.js +69 -0
- package/packages/server/src/api/sessions-commands.js +220 -0
- package/packages/server/src/api/sessions-conversations.js +168 -0
- package/packages/server/src/api/sessions-draft.js +72 -0
- package/packages/server/src/api/sessions-lifecycle.js +190 -0
- package/packages/server/src/api/sessions-messages.js +141 -0
- package/packages/server/src/api/sessions-notes.js +51 -0
- package/packages/server/src/api/sessions-patch.js +252 -0
- package/packages/server/src/api/sessions-streaming.js +86 -0
- package/packages/server/src/api/sessions.js +269 -0
- package/packages/server/src/api/settings.js +194 -0
- package/packages/server/src/api/templates.js +63 -0
- package/packages/server/src/app.js +51 -0
- package/packages/server/src/database.js +58 -0
- package/packages/server/src/db/AgentCallLogRepository.js +322 -0
- package/packages/server/src/db/AttachmentRepository.js +191 -0
- package/packages/server/src/db/BaseRepository.js +39 -0
- package/packages/server/src/db/CanvasItemRepository.js +315 -0
- package/packages/server/src/db/CommandButtonRepository.js +75 -0
- package/packages/server/src/db/CommandRunRepository.js +219 -0
- package/packages/server/src/db/ConversationRepository.js +379 -0
- package/packages/server/src/db/DatabaseManager.js +91 -0
- package/packages/server/src/db/KanbanBoardRepository.js +92 -0
- package/packages/server/src/db/KanbanCardRepository.js +286 -0
- package/packages/server/src/db/KanbanLaneRepository.js +279 -0
- package/packages/server/src/db/MessageRepository.js +156 -0
- package/packages/server/src/db/ProjectDefaultsRepository.js +173 -0
- package/packages/server/src/db/ProjectRepository.js +110 -0
- package/packages/server/src/db/ProviderRepository.js +307 -0
- package/packages/server/src/db/QuickResponseRepository.js +186 -0
- package/packages/server/src/db/SessionNoteRepository.js +60 -0
- package/packages/server/src/db/SessionRepository.js +314 -0
- package/packages/server/src/db/SessionSummaryRepository.js +200 -0
- package/packages/server/src/db/SessionTemplateRepository.js +171 -0
- package/packages/server/src/db/SettingsRepository.js +211 -0
- package/packages/server/src/db/TodoRepository.js +132 -0
- package/packages/server/src/db/WorkLogRepository.js +122 -0
- package/packages/server/src/db/conversation-helpers.js +119 -0
- package/packages/server/src/db/index.js +100 -0
- package/packages/server/src/db/migrations/canvasItemsMigrations.js +109 -0
- package/packages/server/src/db/migrations/conversationsMigrations.js +183 -0
- package/packages/server/src/db/migrations/index.js +199 -0
- package/packages/server/src/db/migrations/kanbanMigrations.js +99 -0
- package/packages/server/src/db/migrations/migrationUtils.js +55 -0
- package/packages/server/src/db/migrations/miscMigrations.js +242 -0
- package/packages/server/src/db/migrations/projectsMigrations.js +95 -0
- package/packages/server/src/db/migrations/sessionsMigrations.js +282 -0
- package/packages/server/src/db/session-helpers.js +150 -0
- package/packages/server/src/index.js +106 -0
- package/packages/server/src/logger.js +22 -0
- package/packages/server/src/middleware/sessionLookup.js +57 -0
- package/packages/server/src/middleware/upload.js +94 -0
- package/packages/server/src/schema.sql +363 -0
- package/packages/server/src/services/agentCallLogger.js +116 -0
- package/packages/server/src/services/canvasStore.js +56 -0
- package/packages/server/src/services/childSessionContext.js +61 -0
- package/packages/server/src/services/commandRunner.js +422 -0
- package/packages/server/src/services/conversationContext.js +72 -0
- package/packages/server/src/services/diffService.js +172 -0
- package/packages/server/src/services/draftSessionService.js +181 -0
- package/packages/server/src/services/encryption.js +134 -0
- package/packages/server/src/services/ghService.js +169 -0
- package/packages/server/src/services/gitService.js +520 -0
- package/packages/server/src/services/gitSessionSetup.js +48 -0
- package/packages/server/src/services/hookService.js +60 -0
- package/packages/server/src/services/kanbanService.js +262 -0
- package/packages/server/src/services/kanbanTriggers.js +273 -0
- package/packages/server/src/services/nodeSpawnHelper.js +63 -0
- package/packages/server/src/services/prStatusService.js +204 -0
- package/packages/server/src/services/prUrlService.js +224 -0
- package/packages/server/src/services/providerTestService.js +81 -0
- package/packages/server/src/services/scheduleService.js +110 -0
- package/packages/server/src/services/schedulerService.js +281 -0
- package/packages/server/src/services/sessionDuplicator.js +63 -0
- package/packages/server/src/services/sessionErrors.js +173 -0
- package/packages/server/src/services/sessionExecution.js +378 -0
- package/packages/server/src/services/sessionManager.js +356 -0
- package/packages/server/src/services/sessionPrompts.js +427 -0
- package/packages/server/src/services/sessionProvider.js +107 -0
- package/packages/server/src/services/slashCommandDiscovery.js +258 -0
- package/packages/server/src/services/slashCommandPluginDiscovery.js +216 -0
- package/packages/server/src/services/slashCommandService.js +306 -0
- package/packages/server/src/services/streamEventCallbacks.js +170 -0
- package/packages/server/src/services/streamEventHandler.js +488 -0
- package/packages/server/src/services/streamUsageHandler.js +228 -0
- package/packages/server/src/services/summaryBroadcast.js +61 -0
- package/packages/server/src/services/summaryClaudeClient.js +180 -0
- package/packages/server/src/services/summaryPrompts.js +169 -0
- package/packages/server/src/services/summaryService.js +552 -0
- package/packages/server/src/services/summaryStaleCheck.js +35 -0
- package/packages/server/src/services/systemMonitor.js +281 -0
- package/packages/server/src/services/templateTriggerService.js +197 -0
- package/packages/server/src/services/terminalOutput.js +160 -0
- package/packages/server/src/services/todoStore.js +58 -0
- package/packages/server/src/services/usageTracker.js +69 -0
- package/packages/server/src/services/withConcurrencyGuard.js +110 -0
- package/packages/server/src/websocket.js +10 -0
- package/packages/server/src/ws/WebSocketManager.js +240 -0
- package/packages/server/src/ws/index.js +50 -0
- package/packages/shared/package.json +27 -0
- package/packages/shared/src/constants.js +44 -0
- package/packages/shared/src/contracts/canvas.js +25 -0
- package/packages/shared/src/contracts/commandButtons.js +36 -0
- package/packages/shared/src/contracts/kanban.js +142 -0
- package/packages/shared/src/contracts/projects.js +63 -0
- package/packages/shared/src/contracts/providers.js +81 -0
- package/packages/shared/src/contracts/quickResponses.js +44 -0
- package/packages/shared/src/contracts/sessions.js +112 -0
- package/packages/shared/src/contracts/templates.js +51 -0
- package/packages/shared/src/index.js +5 -0
- package/packages/shared/src/protocol.js +76 -0
- package/packages/shared/src/routeParams.js +36 -0
- package/packages/shared/src/types.js +167 -0
- package/packages/shared/src/utils.js +101 -0
- package/packages/web/dist/assets/ActiveSessionsView-BQc76Jc8.js +1 -0
- package/packages/web/dist/assets/ActiveSessionsView-ofSvx-K1.css +1 -0
- package/packages/web/dist/assets/AgentLogsView-CTCjHjsu.js +2 -0
- package/packages/web/dist/assets/AgentLogsView-D90PnQVk.css +1 -0
- package/packages/web/dist/assets/ApiClient-Dbs1H78V.js +1 -0
- package/packages/web/dist/assets/ArchiveConfirmModal-CCxSZ52u.js +1 -0
- package/packages/web/dist/assets/ArchiveConfirmModal-CQZeuYBz.css +1 -0
- package/packages/web/dist/assets/CommandButtonDetailView-CF_-LXpU.js +1 -0
- package/packages/web/dist/assets/CommandButtonDetailView-DBm3rzhw.css +1 -0
- package/packages/web/dist/assets/EffortLevelSelector-BQaQmU2d.css +1 -0
- package/packages/web/dist/assets/EffortLevelSelector-DPofLvm-.js +1 -0
- package/packages/web/dist/assets/GeneralSettingsView-BCf53fpC.css +1 -0
- package/packages/web/dist/assets/GeneralSettingsView-BY1G-Kv8.js +1 -0
- package/packages/web/dist/assets/InterpolationHelp-CgdbNcJB.js +1 -0
- package/packages/web/dist/assets/InterpolationHelp-iNxTxmhs.css +1 -0
- package/packages/web/dist/assets/MarkdownEditor-CqT1U8lo.js +2 -0
- package/packages/web/dist/assets/MarkdownEditor-enuH2yvP.css +1 -0
- package/packages/web/dist/assets/ModelSelector-BBn_Ve0D.js +1 -0
- package/packages/web/dist/assets/ModelSelector-DPPD-92R.css +1 -0
- package/packages/web/dist/assets/NewSessionView-Bo5l49nu.js +3 -0
- package/packages/web/dist/assets/NewSessionView-Byoi1XdQ.css +1 -0
- package/packages/web/dist/assets/PathChooser-BoMGzeg2.css +1 -0
- package/packages/web/dist/assets/PathChooser-Cx9gQ-Qt.js +1 -0
- package/packages/web/dist/assets/ProjectEditView-BFuscj-V.js +1 -0
- package/packages/web/dist/assets/ProjectEditView-DNwBUNRk.css +1 -0
- package/packages/web/dist/assets/ProjectListView-C55H1JHQ.css +1 -0
- package/packages/web/dist/assets/ProjectListView-Dj0jBZ46.js +1 -0
- package/packages/web/dist/assets/ProjectNewView-Brdp-xUu.js +1 -0
- package/packages/web/dist/assets/ProjectNewView-CpgE4R-l.css +1 -0
- package/packages/web/dist/assets/ProvidersView-B_QQF3RM.css +1 -0
- package/packages/web/dist/assets/ProvidersView-Cxc-1skq.js +1 -0
- package/packages/web/dist/assets/QuickResponseSettings-B2eVAtHW.js +1 -0
- package/packages/web/dist/assets/QuickResponseSettings-B8188A1D.css +1 -0
- package/packages/web/dist/assets/QuickResponsesPanel-DIBQFj0W.css +1 -0
- package/packages/web/dist/assets/QuickResponsesPanel-lU8pW2B0.js +1 -0
- package/packages/web/dist/assets/ResizableTextarea-B5nAA0RV.css +1 -0
- package/packages/web/dist/assets/ResizableTextarea-DSy1mWGY.js +1 -0
- package/packages/web/dist/assets/SessionCard-BvjLwVYg.js +1 -0
- package/packages/web/dist/assets/SessionCard-D20G3bX8.css +1 -0
- package/packages/web/dist/assets/SessionDetailView-BQbPg-RJ.js +36 -0
- package/packages/web/dist/assets/SessionDetailView-BrMG4p2-.css +1 -0
- package/packages/web/dist/assets/SessionFormOptions-BgqFR-5f.js +1 -0
- package/packages/web/dist/assets/SessionFormOptions-BuLlDF-7.css +1 -0
- package/packages/web/dist/assets/SessionListView-BAIBtJF7.css +1 -0
- package/packages/web/dist/assets/SessionListView-CYIHI8qF.js +1 -0
- package/packages/web/dist/assets/SessionLogStream-B-FwUMJQ.js +18 -0
- package/packages/web/dist/assets/SessionLogStream-zPUTiGbe.css +1 -0
- package/packages/web/dist/assets/SettingsView-DC8-hTQ-.css +1 -0
- package/packages/web/dist/assets/SettingsView-fZxpiGp7.js +1 -0
- package/packages/web/dist/assets/SlashCommandWizard-BB30cSvo.css +1 -0
- package/packages/web/dist/assets/SlashCommandWizard-BgaOw9W3.js +1 -0
- package/packages/web/dist/assets/SummarySettingsView-DcsmSVJI.css +1 -0
- package/packages/web/dist/assets/SummarySettingsView-eeu1Xq86.js +1 -0
- package/packages/web/dist/assets/TemplateDetailView-DEPKSwDo.js +1 -0
- package/packages/web/dist/assets/TemplateDetailView-DT2m06W7.css +1 -0
- package/packages/web/dist/assets/apl-B4CMkyY2.js +1 -0
- package/packages/web/dist/assets/asciiarmor-Df11BRmG.js +1 -0
- package/packages/web/dist/assets/asn1-EdZsLKOL.js +1 -0
- package/packages/web/dist/assets/asterisk-B-8jnY81.js +1 -0
- package/packages/web/dist/assets/brainfuck-C4LP7Hcl.js +1 -0
- package/packages/web/dist/assets/clike-B9uivgTg.js +1 -0
- package/packages/web/dist/assets/clojure-BMjYHr_A.js +1 -0
- package/packages/web/dist/assets/cmake-BQqOBYOt.js +1 -0
- package/packages/web/dist/assets/cobol-CWcv1MsR.js +1 -0
- package/packages/web/dist/assets/coffeescript-S37ZYGWr.js +1 -0
- package/packages/web/dist/assets/commandButtons-DNSHH8IA.js +4 -0
- package/packages/web/dist/assets/commonlisp-DBKNyK5s.js +1 -0
- package/packages/web/dist/assets/crystal-SjHAIU92.js +1 -0
- package/packages/web/dist/assets/css-BnMrqG3P.js +1 -0
- package/packages/web/dist/assets/cypher-C_CwsFkJ.js +1 -0
- package/packages/web/dist/assets/d-pRatUO7H.js +1 -0
- package/packages/web/dist/assets/diff-DbItnlRl.js +1 -0
- package/packages/web/dist/assets/dockerfile-BKs6k2Af.js +1 -0
- package/packages/web/dist/assets/dtd-DF_7sFjM.js +1 -0
- package/packages/web/dist/assets/dylan-DwRh75JA.js +1 -0
- package/packages/web/dist/assets/ebnf-CDyGwa7X.js +1 -0
- package/packages/web/dist/assets/ecl-Cabwm37j.js +1 -0
- package/packages/web/dist/assets/eiffel-CnydiIhH.js +1 -0
- package/packages/web/dist/assets/elm-vLlmbW-K.js +1 -0
- package/packages/web/dist/assets/erlang-BNw1qcRV.js +1 -0
- package/packages/web/dist/assets/factor-kuTfRLto.js +1 -0
- package/packages/web/dist/assets/fcl-Kvtd6kyn.js +1 -0
- package/packages/web/dist/assets/forth-Ffai-XNe.js +1 -0
- package/packages/web/dist/assets/fortran-DYz_wnZ1.js +1 -0
- package/packages/web/dist/assets/gas-Bneqetm1.js +1 -0
- package/packages/web/dist/assets/gherkin-heZmZLOM.js +1 -0
- package/packages/web/dist/assets/groovy-D9Dt4D0W.js +1 -0
- package/packages/web/dist/assets/haskell-BWDZoCOh.js +1 -0
- package/packages/web/dist/assets/haxe-H-WmDvRZ.js +1 -0
- package/packages/web/dist/assets/http-DBlCnlav.js +1 -0
- package/packages/web/dist/assets/idl-BEugSyMb.js +1 -0
- package/packages/web/dist/assets/index-BZlHgDSz.js +1 -0
- package/packages/web/dist/assets/index-BhWX8AfE.js +2 -0
- package/packages/web/dist/assets/index-Bi3XvF_f.js +1 -0
- package/packages/web/dist/assets/index-BqXoPf_D.js +1 -0
- package/packages/web/dist/assets/index-CAuTOZSD.js +1 -0
- package/packages/web/dist/assets/index-CKYk-fkb.js +1 -0
- package/packages/web/dist/assets/index-CTumW_tV.js +318 -0
- package/packages/web/dist/assets/index-CVOJVSsC.js +82 -0
- package/packages/web/dist/assets/index-CXK2Z3_z.js +1 -0
- package/packages/web/dist/assets/index-CYllQ3Vd.js +1 -0
- package/packages/web/dist/assets/index-CpsfI08O.js +1 -0
- package/packages/web/dist/assets/index-DQkhDeTA.js +3 -0
- package/packages/web/dist/assets/index-DWP8iCBp.js +1 -0
- package/packages/web/dist/assets/index-DkVb9W_J.js +1 -0
- package/packages/web/dist/assets/index-DmKHPbIa.js +1 -0
- package/packages/web/dist/assets/index-DrlQi03X.js +1 -0
- package/packages/web/dist/assets/index-gmCCsCQ1.css +1 -0
- package/packages/web/dist/assets/index-prTEzzgO.js +1 -0
- package/packages/web/dist/assets/index-wqgejMCM.js +1 -0
- package/packages/web/dist/assets/index-yh0ZHIWw.js +7 -0
- package/packages/web/dist/assets/javascript-qCveANmP.js +1 -0
- package/packages/web/dist/assets/julia-DuME0IfC.js +1 -0
- package/packages/web/dist/assets/livescript-BwQOo05w.js +1 -0
- package/packages/web/dist/assets/lua-BgMRiT3U.js +1 -0
- package/packages/web/dist/assets/mathematica-DTrFuWx2.js +1 -0
- package/packages/web/dist/assets/mbox-CNhZ1qSd.js +1 -0
- package/packages/web/dist/assets/mirc-CjQqDB4T.js +1 -0
- package/packages/web/dist/assets/mllike-CXdrOF99.js +1 -0
- package/packages/web/dist/assets/modelica-Dc1JOy9r.js +1 -0
- package/packages/web/dist/assets/mscgen-BA5vi2Kp.js +1 -0
- package/packages/web/dist/assets/mumps-BT43cFF4.js +1 -0
- package/packages/web/dist/assets/nginx-DdIZxoE0.js +1 -0
- package/packages/web/dist/assets/nsis-LdVXkNf5.js +1 -0
- package/packages/web/dist/assets/ntriples-BfvgReVJ.js +1 -0
- package/packages/web/dist/assets/octave-Ck1zUtKM.js +1 -0
- package/packages/web/dist/assets/oz-BzwKVEFT.js +1 -0
- package/packages/web/dist/assets/pascal--L3eBynH.js +1 -0
- package/packages/web/dist/assets/perl-CdXCOZ3F.js +1 -0
- package/packages/web/dist/assets/pig-CevX1Tat.js +1 -0
- package/packages/web/dist/assets/powershell-CFHJl5sT.js +1 -0
- package/packages/web/dist/assets/projects-DbBQQH-V.js +1 -0
- package/packages/web/dist/assets/properties-C78fOPTZ.js +1 -0
- package/packages/web/dist/assets/protobuf-ChK-085T.js +1 -0
- package/packages/web/dist/assets/providers-ceCc4xRU.js +1 -0
- package/packages/web/dist/assets/pug-DukmZTjD.js +1 -0
- package/packages/web/dist/assets/puppet-DMA9R1ak.js +1 -0
- package/packages/web/dist/assets/python-BuPzkPfP.js +1 -0
- package/packages/web/dist/assets/q-pXgVlZs6.js +1 -0
- package/packages/web/dist/assets/r-DUYO_cvP.js +1 -0
- package/packages/web/dist/assets/rpm-CTu-6PCP.js +1 -0
- package/packages/web/dist/assets/ruby-B2Rjki9n.js +1 -0
- package/packages/web/dist/assets/sas-B4kiWyti.js +1 -0
- package/packages/web/dist/assets/scheme-C41bIUwD.js +1 -0
- package/packages/web/dist/assets/sessions-D681M81k.js +1 -0
- package/packages/web/dist/assets/settings-D0evez2V.js +1 -0
- package/packages/web/dist/assets/shell-CjFT_Tl9.js +1 -0
- package/packages/web/dist/assets/sieve-C3Gn_uJK.js +1 -0
- package/packages/web/dist/assets/simple-mode-GW_nhZxv.js +1 -0
- package/packages/web/dist/assets/smalltalk-CnHTOXQT.js +1 -0
- package/packages/web/dist/assets/solr-DehyRSwq.js +1 -0
- package/packages/web/dist/assets/sparql-DkYu6x3z.js +1 -0
- package/packages/web/dist/assets/spreadsheet-BCZA_wO0.js +1 -0
- package/packages/web/dist/assets/sql-D0XecflT.js +1 -0
- package/packages/web/dist/assets/stex-C3f8Ysf7.js +1 -0
- package/packages/web/dist/assets/style-BTin-zR_.css +1 -0
- package/packages/web/dist/assets/stylus-B533Al4x.js +1 -0
- package/packages/web/dist/assets/swift-BzpIVaGY.js +1 -0
- package/packages/web/dist/assets/tcl-DVfN8rqt.js +1 -0
- package/packages/web/dist/assets/textile-CnDTJFAw.js +1 -0
- package/packages/web/dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
- package/packages/web/dist/assets/tiki-DGYXhP31.js +1 -0
- package/packages/web/dist/assets/toml-Bm5Em-hy.js +1 -0
- package/packages/web/dist/assets/troff-wAsdV37c.js +1 -0
- package/packages/web/dist/assets/ttcn-CfJYG6tj.js +1 -0
- package/packages/web/dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
- package/packages/web/dist/assets/turtle-B1tBg_DP.js +1 -0
- package/packages/web/dist/assets/vb-CmGdzxic.js +1 -0
- package/packages/web/dist/assets/vbscript-BuJXcnF6.js +1 -0
- package/packages/web/dist/assets/velocity-D8B20fx6.js +1 -0
- package/packages/web/dist/assets/verilog-C6RDOZhf.js +1 -0
- package/packages/web/dist/assets/vhdl-lSbBsy5d.js +1 -0
- package/packages/web/dist/assets/webidl-ZXfAyPTL.js +1 -0
- package/packages/web/dist/assets/xquery-CQfU5ijd.js +1 -0
- package/packages/web/dist/assets/yacas-BJ4BC0dw.js +1 -0
- package/packages/web/dist/assets/z80-Hz9HOZM7.js +1 -0
- package/packages/web/dist/favicon.png +0 -0
- package/packages/web/dist/index.html +17 -0
- package/packages/web/dist/logo.png +0 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { BaseRepository } from './BaseRepository.js';
|
|
2
|
+
import { databaseManager } from './DatabaseManager.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Kanban card repository class
|
|
6
|
+
*/
|
|
7
|
+
export class KanbanCardRepository extends BaseRepository {
|
|
8
|
+
constructor() {
|
|
9
|
+
super('kanban_cards', KanbanCardRepository.#mapCard);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static #mapCard(row) {
|
|
13
|
+
const card = {
|
|
14
|
+
id: row.id,
|
|
15
|
+
laneId: row.lane_id,
|
|
16
|
+
sortOrder: row.sort_order,
|
|
17
|
+
createdAt: row.created_at,
|
|
18
|
+
updatedAt: row.updated_at,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// If session data is joined, include it
|
|
22
|
+
if (row.session_id !== undefined) {
|
|
23
|
+
card.sessions = row.session_id
|
|
24
|
+
? [
|
|
25
|
+
{
|
|
26
|
+
id: row.session_id,
|
|
27
|
+
name: row.session_name,
|
|
28
|
+
status: row.session_status,
|
|
29
|
+
mode: row.session_mode,
|
|
30
|
+
costUsd: row.session_cost_usd,
|
|
31
|
+
starred: Boolean(row.session_starred),
|
|
32
|
+
prUrl: row.session_pr_url,
|
|
33
|
+
createdAt: row.session_created_at,
|
|
34
|
+
updatedAt: row.session_updated_at,
|
|
35
|
+
},
|
|
36
|
+
]
|
|
37
|
+
: [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return card;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get all cards for a lane with session data, ordered by sort_order
|
|
45
|
+
* @param {string} laneId
|
|
46
|
+
* @returns {Array}
|
|
47
|
+
*/
|
|
48
|
+
getByLaneId(laneId) {
|
|
49
|
+
const rows = this.db
|
|
50
|
+
.prepare(
|
|
51
|
+
`SELECT kc.*,
|
|
52
|
+
kcs.session_id,
|
|
53
|
+
s.name as session_name,
|
|
54
|
+
s.status as session_status,
|
|
55
|
+
s.mode as session_mode,
|
|
56
|
+
s.cost_usd as session_cost_usd,
|
|
57
|
+
s.starred as session_starred,
|
|
58
|
+
s.pr_url as session_pr_url,
|
|
59
|
+
s.created_at as session_created_at,
|
|
60
|
+
s.updated_at as session_updated_at
|
|
61
|
+
FROM kanban_cards kc
|
|
62
|
+
LEFT JOIN kanban_card_sessions kcs ON kc.id = kcs.card_id
|
|
63
|
+
LEFT JOIN sessions s ON kcs.session_id = s.id
|
|
64
|
+
WHERE kc.lane_id = ?
|
|
65
|
+
ORDER BY kc.sort_order`
|
|
66
|
+
)
|
|
67
|
+
.all(laneId);
|
|
68
|
+
return this.mapAll(rows);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get all cards for a board with session data
|
|
73
|
+
* @param {string} boardId
|
|
74
|
+
* @returns {Array}
|
|
75
|
+
*/
|
|
76
|
+
getByBoardId(boardId) {
|
|
77
|
+
const rows = this.db
|
|
78
|
+
.prepare(
|
|
79
|
+
`SELECT kc.*,
|
|
80
|
+
kcs.session_id,
|
|
81
|
+
s.name as session_name,
|
|
82
|
+
s.status as session_status,
|
|
83
|
+
s.mode as session_mode,
|
|
84
|
+
s.cost_usd as session_cost_usd,
|
|
85
|
+
s.starred as session_starred,
|
|
86
|
+
s.pr_url as session_pr_url,
|
|
87
|
+
s.created_at as session_created_at,
|
|
88
|
+
s.updated_at as session_updated_at
|
|
89
|
+
FROM kanban_cards kc
|
|
90
|
+
JOIN kanban_lanes kl ON kc.lane_id = kl.id
|
|
91
|
+
LEFT JOIN kanban_card_sessions kcs ON kc.id = kcs.card_id
|
|
92
|
+
LEFT JOIN sessions s ON kcs.session_id = s.id
|
|
93
|
+
WHERE kl.board_id = ?
|
|
94
|
+
ORDER BY kl.sort_order, kc.sort_order`
|
|
95
|
+
)
|
|
96
|
+
.all(boardId);
|
|
97
|
+
return this.mapAll(rows);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get the card for a specific session
|
|
102
|
+
* @param {string} sessionId
|
|
103
|
+
* @returns {Object|null}
|
|
104
|
+
*/
|
|
105
|
+
getBySessionId(sessionId) {
|
|
106
|
+
const row = this.db
|
|
107
|
+
.prepare(
|
|
108
|
+
`SELECT kc.*,
|
|
109
|
+
kcs.session_id,
|
|
110
|
+
s.name as session_name,
|
|
111
|
+
s.status as session_status,
|
|
112
|
+
s.mode as session_mode,
|
|
113
|
+
s.cost_usd as session_cost_usd,
|
|
114
|
+
s.starred as session_starred,
|
|
115
|
+
s.pr_url as session_pr_url,
|
|
116
|
+
s.created_at as session_created_at,
|
|
117
|
+
s.updated_at as session_updated_at
|
|
118
|
+
FROM kanban_cards kc
|
|
119
|
+
JOIN kanban_card_sessions kcs ON kc.id = kcs.card_id
|
|
120
|
+
LEFT JOIN sessions s ON kcs.session_id = s.id
|
|
121
|
+
WHERE kcs.session_id = ?`
|
|
122
|
+
)
|
|
123
|
+
.get(sessionId);
|
|
124
|
+
return this.map(row);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create a card for a session in a lane
|
|
129
|
+
* @param {string} laneId
|
|
130
|
+
* @param {string} sessionId
|
|
131
|
+
* @param {Object} [options]
|
|
132
|
+
* @param {number} [options.sortOrder]
|
|
133
|
+
* @returns {Object}
|
|
134
|
+
*/
|
|
135
|
+
create(laneId, sessionId, options = {}) {
|
|
136
|
+
const cardId = databaseManager.generateId();
|
|
137
|
+
const cardSessionId = databaseManager.generateId();
|
|
138
|
+
const now = Date.now();
|
|
139
|
+
|
|
140
|
+
// If no sortOrder provided, put it at the end
|
|
141
|
+
let sortOrder = options.sortOrder;
|
|
142
|
+
if (sortOrder === undefined || sortOrder === null) {
|
|
143
|
+
const maxRow = this.db
|
|
144
|
+
.prepare('SELECT MAX(sort_order) as max_order FROM kanban_cards WHERE lane_id = ?')
|
|
145
|
+
.get(laneId);
|
|
146
|
+
sortOrder = (maxRow?.max_order ?? -1) + 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return databaseManager.transaction(() => {
|
|
150
|
+
// Create the card
|
|
151
|
+
this.db
|
|
152
|
+
.prepare(
|
|
153
|
+
`INSERT INTO kanban_cards (id, lane_id, sort_order, created_at, updated_at)
|
|
154
|
+
VALUES (?, ?, ?, ?, ?)`
|
|
155
|
+
)
|
|
156
|
+
.run(cardId, laneId, sortOrder, now, now);
|
|
157
|
+
|
|
158
|
+
// Link the session to the card
|
|
159
|
+
this.db
|
|
160
|
+
.prepare(
|
|
161
|
+
`INSERT INTO kanban_card_sessions (id, card_id, session_id, created_at)
|
|
162
|
+
VALUES (?, ?, ?, ?)`
|
|
163
|
+
)
|
|
164
|
+
.run(cardSessionId, cardId, sessionId, now);
|
|
165
|
+
|
|
166
|
+
return this.getBySessionId(sessionId);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Move a card to a different lane
|
|
172
|
+
* @param {string} cardId
|
|
173
|
+
* @param {string} targetLaneId
|
|
174
|
+
* @param {number} [sortOrder]
|
|
175
|
+
* @returns {Object}
|
|
176
|
+
*/
|
|
177
|
+
moveToLane(cardId, targetLaneId, sortOrder) {
|
|
178
|
+
const now = Date.now();
|
|
179
|
+
|
|
180
|
+
// If no sortOrder provided, put it at the end of the target lane
|
|
181
|
+
let order = sortOrder;
|
|
182
|
+
if (order === undefined || order === null) {
|
|
183
|
+
const maxRow = this.db
|
|
184
|
+
.prepare('SELECT MAX(sort_order) as max_order FROM kanban_cards WHERE lane_id = ?')
|
|
185
|
+
.get(targetLaneId);
|
|
186
|
+
order = (maxRow?.max_order ?? -1) + 1;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this.db
|
|
190
|
+
.prepare('UPDATE kanban_cards SET lane_id = ?, sort_order = ?, updated_at = ? WHERE id = ?')
|
|
191
|
+
.run(targetLaneId, order, now, cardId);
|
|
192
|
+
|
|
193
|
+
return this.getById(cardId);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Reorder cards within a lane
|
|
198
|
+
* @param {string} laneId
|
|
199
|
+
* @param {string[]} cardIds - Ordered array of card IDs
|
|
200
|
+
*/
|
|
201
|
+
reorder(laneId, cardIds) {
|
|
202
|
+
const now = Date.now();
|
|
203
|
+
|
|
204
|
+
databaseManager.transaction(() => {
|
|
205
|
+
const updateStmt = this.db.prepare(
|
|
206
|
+
'UPDATE kanban_cards SET sort_order = ?, updated_at = ? WHERE id = ? AND lane_id = ?'
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
cardIds.forEach((cardId, index) => {
|
|
210
|
+
updateStmt.run(index, now, cardId, laneId);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Delete a card (does not delete the session)
|
|
217
|
+
* @param {string} cardId
|
|
218
|
+
*/
|
|
219
|
+
delete(cardId) {
|
|
220
|
+
super.delete(cardId);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get card by ID with full session data
|
|
225
|
+
* @param {string} id
|
|
226
|
+
* @returns {Object|null}
|
|
227
|
+
*/
|
|
228
|
+
getById(id) {
|
|
229
|
+
const row = this.db
|
|
230
|
+
.prepare(
|
|
231
|
+
`SELECT kc.*,
|
|
232
|
+
kcs.session_id,
|
|
233
|
+
s.name as session_name,
|
|
234
|
+
s.status as session_status,
|
|
235
|
+
s.mode as session_mode,
|
|
236
|
+
s.cost_usd as session_cost_usd,
|
|
237
|
+
s.starred as session_starred,
|
|
238
|
+
s.pr_url as session_pr_url,
|
|
239
|
+
s.created_at as session_created_at,
|
|
240
|
+
s.updated_at as session_updated_at
|
|
241
|
+
FROM kanban_cards kc
|
|
242
|
+
LEFT JOIN kanban_card_sessions kcs ON kc.id = kcs.card_id
|
|
243
|
+
LEFT JOIN sessions s ON kcs.session_id = s.id
|
|
244
|
+
WHERE kc.id = ?`
|
|
245
|
+
)
|
|
246
|
+
.get(id);
|
|
247
|
+
return this.map(row);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Get card with lane info (useful for knowing current lane when moving)
|
|
252
|
+
* @param {string} id
|
|
253
|
+
* @returns {Object|null}
|
|
254
|
+
*/
|
|
255
|
+
getByIdWithLane(id) {
|
|
256
|
+
const row = this.db
|
|
257
|
+
.prepare(
|
|
258
|
+
`SELECT kc.*,
|
|
259
|
+
kl.board_id,
|
|
260
|
+
kl.name as lane_name,
|
|
261
|
+
kcs.session_id,
|
|
262
|
+
s.name as session_name,
|
|
263
|
+
s.status as session_status,
|
|
264
|
+
s.mode as session_mode,
|
|
265
|
+
s.cost_usd as session_cost_usd,
|
|
266
|
+
s.starred as session_starred,
|
|
267
|
+
s.pr_url as session_pr_url,
|
|
268
|
+
s.created_at as session_created_at,
|
|
269
|
+
s.updated_at as session_updated_at
|
|
270
|
+
FROM kanban_cards kc
|
|
271
|
+
JOIN kanban_lanes kl ON kc.lane_id = kl.id
|
|
272
|
+
LEFT JOIN kanban_card_sessions kcs ON kc.id = kcs.card_id
|
|
273
|
+
LEFT JOIN sessions s ON kcs.session_id = s.id
|
|
274
|
+
WHERE kc.id = ?`
|
|
275
|
+
)
|
|
276
|
+
.get(id);
|
|
277
|
+
|
|
278
|
+
if (!row) return null;
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
...this.map(row),
|
|
282
|
+
boardId: row.board_id,
|
|
283
|
+
laneName: row.lane_name,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { BaseRepository } from './BaseRepository.js';
|
|
2
|
+
import { databaseManager } from './DatabaseManager.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Convert a boolean value to SQLite integer (1/0) or null.
|
|
6
|
+
* @param {boolean|null|undefined} value
|
|
7
|
+
* @param {number|null} [defaultValue] - Default value if undefined
|
|
8
|
+
* @returns {number|null}
|
|
9
|
+
*/
|
|
10
|
+
function boolToSqlite(value, defaultValue = null) {
|
|
11
|
+
if (value === undefined) return defaultValue;
|
|
12
|
+
if (value === null) return null;
|
|
13
|
+
return value ? 1 : 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Prepare lane insert values from data object.
|
|
18
|
+
* @param {Object} data - Lane data
|
|
19
|
+
* @returns {Array} Array of values for INSERT
|
|
20
|
+
*/
|
|
21
|
+
function prepareLaneValues(data) {
|
|
22
|
+
return [
|
|
23
|
+
data.onEnterTemplateId || null,
|
|
24
|
+
data.onEnterPrompt || null,
|
|
25
|
+
data.onEnterMode || null,
|
|
26
|
+
data.onEnterModel || null,
|
|
27
|
+
data.onEnterEffortLevel || null,
|
|
28
|
+
boolToSqlite(data.onEnterThinkingEnabled),
|
|
29
|
+
data.onEnterAutoRescheduleEnabled ? 1 : 0,
|
|
30
|
+
data.onEnterRescheduleDelayMinutes ?? 15,
|
|
31
|
+
boolToSqlite(data.onEnterRescheduleOnTokenLimit, 1),
|
|
32
|
+
boolToSqlite(data.onEnterRescheduleOnServiceError, 1),
|
|
33
|
+
data.onEnterMaxRescheduleCount ?? null,
|
|
34
|
+
data.onEnterMaxTotalTokens ?? null,
|
|
35
|
+
data.onEnterRescheduleAtTokenCount ?? null,
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Boolean field configurations for update operations.
|
|
41
|
+
* - nullable: true means null values are preserved (converts to null in DB)
|
|
42
|
+
* - nullable: false means values are coerced to 0/1
|
|
43
|
+
*/
|
|
44
|
+
const BOOLEAN_FIELDS = {
|
|
45
|
+
onEnterThinkingEnabled: { nullable: true },
|
|
46
|
+
onEnterAutoRescheduleEnabled: { nullable: false },
|
|
47
|
+
onEnterRescheduleOnTokenLimit: { nullable: false },
|
|
48
|
+
onEnterRescheduleOnServiceError: { nullable: false },
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Convert a field value for SQL update, handling booleans specially.
|
|
53
|
+
* @param {string} fieldName - The camelCase field name
|
|
54
|
+
* @param {*} value - The value to convert
|
|
55
|
+
* @returns {*} The converted value
|
|
56
|
+
*/
|
|
57
|
+
function convertFieldValue(fieldName, value) {
|
|
58
|
+
const boolConfig = BOOLEAN_FIELDS[fieldName];
|
|
59
|
+
if (!boolConfig) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
if (boolConfig.nullable && value === null) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return value ? 1 : 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Kanban lane repository class
|
|
70
|
+
*/
|
|
71
|
+
export class KanbanLaneRepository extends BaseRepository {
|
|
72
|
+
constructor() {
|
|
73
|
+
super('kanban_lanes', KanbanLaneRepository.#mapLane);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static #mapLane(row) {
|
|
77
|
+
return {
|
|
78
|
+
id: row.id,
|
|
79
|
+
boardId: row.board_id,
|
|
80
|
+
name: row.name,
|
|
81
|
+
sortOrder: row.sort_order,
|
|
82
|
+
onEnterTemplateId: row.on_enter_template_id,
|
|
83
|
+
onEnterPrompt: row.on_enter_prompt,
|
|
84
|
+
onEnterMode: row.on_enter_mode,
|
|
85
|
+
onEnterModel: row.on_enter_model,
|
|
86
|
+
onEnterEffortLevel: row.on_enter_effort_level,
|
|
87
|
+
onEnterThinkingEnabled: row.on_enter_thinking_enabled === null ? null : Boolean(row.on_enter_thinking_enabled),
|
|
88
|
+
onEnterAutoRescheduleEnabled: Boolean(row.on_enter_auto_reschedule_enabled),
|
|
89
|
+
onEnterRescheduleDelayMinutes: row.on_enter_reschedule_delay_minutes,
|
|
90
|
+
onEnterRescheduleOnTokenLimit: row.on_enter_reschedule_on_token_limit === null ? null : Boolean(row.on_enter_reschedule_on_token_limit),
|
|
91
|
+
onEnterRescheduleOnServiceError: row.on_enter_reschedule_on_service_error === null ? null : Boolean(row.on_enter_reschedule_on_service_error),
|
|
92
|
+
onEnterMaxRescheduleCount: row.on_enter_max_reschedule_count,
|
|
93
|
+
onEnterMaxTotalTokens: row.on_enter_max_total_tokens,
|
|
94
|
+
onEnterRescheduleAtTokenCount: row.on_enter_reschedule_at_token_count,
|
|
95
|
+
createdAt: row.created_at,
|
|
96
|
+
updatedAt: row.updated_at,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get all lanes for a board, ordered by sort_order
|
|
102
|
+
* @param {string} boardId
|
|
103
|
+
* @returns {Array}
|
|
104
|
+
*/
|
|
105
|
+
getByBoardId(boardId) {
|
|
106
|
+
const rows = this.db
|
|
107
|
+
.prepare('SELECT * FROM kanban_lanes WHERE board_id = ? ORDER BY sort_order')
|
|
108
|
+
.all(boardId);
|
|
109
|
+
return this.mapAll(rows);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Create a new lane
|
|
114
|
+
* @param {string} boardId
|
|
115
|
+
* @param {Object} data
|
|
116
|
+
* @param {string} data.name
|
|
117
|
+
* @param {number} [data.sortOrder]
|
|
118
|
+
* @param {string|null} [data.onEnterTemplateId]
|
|
119
|
+
* @param {string|null} [data.onEnterPrompt]
|
|
120
|
+
* @returns {Object}
|
|
121
|
+
*/
|
|
122
|
+
create(boardId, data) {
|
|
123
|
+
const id = databaseManager.generateId();
|
|
124
|
+
const now = Date.now();
|
|
125
|
+
const sortOrder = this.#resolveSortOrder(boardId, data.sortOrder);
|
|
126
|
+
const laneValues = prepareLaneValues(data);
|
|
127
|
+
|
|
128
|
+
this.db
|
|
129
|
+
.prepare(
|
|
130
|
+
`INSERT INTO kanban_lanes (
|
|
131
|
+
id, board_id, name, sort_order, on_enter_template_id, on_enter_prompt,
|
|
132
|
+
on_enter_mode, on_enter_model, on_enter_effort_level, on_enter_thinking_enabled,
|
|
133
|
+
on_enter_auto_reschedule_enabled, on_enter_reschedule_delay_minutes,
|
|
134
|
+
on_enter_reschedule_on_token_limit, on_enter_reschedule_on_service_error,
|
|
135
|
+
on_enter_max_reschedule_count, on_enter_max_total_tokens,
|
|
136
|
+
on_enter_reschedule_at_token_count,
|
|
137
|
+
created_at, updated_at
|
|
138
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
139
|
+
)
|
|
140
|
+
.run(id, boardId, data.name, sortOrder, ...laneValues, now, now);
|
|
141
|
+
|
|
142
|
+
return this.getById(id);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Resolve sort order, defaulting to end of list if not provided.
|
|
147
|
+
* @param {string} boardId
|
|
148
|
+
* @param {number|undefined|null} sortOrder
|
|
149
|
+
* @returns {number}
|
|
150
|
+
*/
|
|
151
|
+
#resolveSortOrder(boardId, sortOrder) {
|
|
152
|
+
if (sortOrder !== undefined && sortOrder !== null) {
|
|
153
|
+
return sortOrder;
|
|
154
|
+
}
|
|
155
|
+
const maxRow = this.db
|
|
156
|
+
.prepare('SELECT MAX(sort_order) as max_order FROM kanban_lanes WHERE board_id = ?')
|
|
157
|
+
.get(boardId);
|
|
158
|
+
return (maxRow?.max_order ?? -1) + 1;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Update a lane
|
|
163
|
+
* @param {string} id
|
|
164
|
+
* @param {Object} data
|
|
165
|
+
* @param {string} [data.name]
|
|
166
|
+
* @param {number} [data.sortOrder]
|
|
167
|
+
* @param {string|null} [data.onEnterTemplateId]
|
|
168
|
+
* @param {string|null} [data.onEnterPrompt]
|
|
169
|
+
* @returns {Object}
|
|
170
|
+
*/
|
|
171
|
+
update(id, data) {
|
|
172
|
+
// Field mapping: camelCase -> snake_case
|
|
173
|
+
const fieldMap = {
|
|
174
|
+
name: 'name',
|
|
175
|
+
sortOrder: 'sort_order',
|
|
176
|
+
onEnterTemplateId: 'on_enter_template_id',
|
|
177
|
+
onEnterPrompt: 'on_enter_prompt',
|
|
178
|
+
onEnterMode: 'on_enter_mode',
|
|
179
|
+
onEnterModel: 'on_enter_model',
|
|
180
|
+
onEnterEffortLevel: 'on_enter_effort_level',
|
|
181
|
+
onEnterThinkingEnabled: 'on_enter_thinking_enabled',
|
|
182
|
+
onEnterAutoRescheduleEnabled: 'on_enter_auto_reschedule_enabled',
|
|
183
|
+
onEnterRescheduleDelayMinutes: 'on_enter_reschedule_delay_minutes',
|
|
184
|
+
onEnterRescheduleOnTokenLimit: 'on_enter_reschedule_on_token_limit',
|
|
185
|
+
onEnterRescheduleOnServiceError: 'on_enter_reschedule_on_service_error',
|
|
186
|
+
onEnterMaxRescheduleCount: 'on_enter_max_reschedule_count',
|
|
187
|
+
onEnterMaxTotalTokens: 'on_enter_max_total_tokens',
|
|
188
|
+
onEnterRescheduleAtTokenCount: 'on_enter_reschedule_at_token_count',
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const updates = [];
|
|
192
|
+
const values = [];
|
|
193
|
+
|
|
194
|
+
// Build update clauses dynamically
|
|
195
|
+
for (const [camelKey, snakeKey] of Object.entries(fieldMap)) {
|
|
196
|
+
if (data[camelKey] !== undefined) {
|
|
197
|
+
updates.push(`${snakeKey} = ?`);
|
|
198
|
+
values.push(convertFieldValue(camelKey, data[camelKey]));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (updates.length === 0) return this.getById(id);
|
|
203
|
+
|
|
204
|
+
updates.push('updated_at = ?');
|
|
205
|
+
values.push(Date.now());
|
|
206
|
+
values.push(id);
|
|
207
|
+
|
|
208
|
+
this.db.prepare(`UPDATE kanban_lanes SET ${updates.join(', ')} WHERE id = ?`).run(...values);
|
|
209
|
+
|
|
210
|
+
return this.getById(id);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Reorder lanes based on an array of lane IDs
|
|
215
|
+
* @param {string} boardId
|
|
216
|
+
* @param {string[]} laneIds - Ordered array of lane IDs
|
|
217
|
+
*/
|
|
218
|
+
reorder(boardId, laneIds) {
|
|
219
|
+
const now = Date.now();
|
|
220
|
+
|
|
221
|
+
databaseManager.transaction(() => {
|
|
222
|
+
const updateStmt = this.db.prepare(
|
|
223
|
+
'UPDATE kanban_lanes SET sort_order = ?, updated_at = ? WHERE id = ? AND board_id = ?'
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
laneIds.forEach((laneId, index) => {
|
|
227
|
+
updateStmt.run(index, now, laneId, boardId);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get a single lane with its board info
|
|
234
|
+
* @param {string} id
|
|
235
|
+
* @returns {Object|null}
|
|
236
|
+
*/
|
|
237
|
+
getById(id) {
|
|
238
|
+
const row = this.db.prepare('SELECT * FROM kanban_lanes WHERE id = ?').get(id);
|
|
239
|
+
return this.map(row);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get lane by ID with template info (for on-enter triggers)
|
|
244
|
+
* @param {string} id
|
|
245
|
+
* @returns {Object|null}
|
|
246
|
+
*/
|
|
247
|
+
getByIdWithTemplate(id) {
|
|
248
|
+
const row = this.db
|
|
249
|
+
.prepare(
|
|
250
|
+
`SELECT kl.*, st.name as template_name, st.prompt as template_prompt
|
|
251
|
+
FROM kanban_lanes kl
|
|
252
|
+
LEFT JOIN session_templates st ON kl.on_enter_template_id = st.id
|
|
253
|
+
WHERE kl.id = ?`
|
|
254
|
+
)
|
|
255
|
+
.get(id);
|
|
256
|
+
|
|
257
|
+
if (!row) return null;
|
|
258
|
+
|
|
259
|
+
const mappedLane = this.map(row);
|
|
260
|
+
return {
|
|
261
|
+
...mappedLane,
|
|
262
|
+
template: row.template_name
|
|
263
|
+
? {
|
|
264
|
+
id: row.on_enter_template_id,
|
|
265
|
+
name: row.template_name,
|
|
266
|
+
prompt: row.template_prompt,
|
|
267
|
+
}
|
|
268
|
+
: null,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Delete a lane
|
|
274
|
+
* @param {string} id
|
|
275
|
+
*/
|
|
276
|
+
delete(id) {
|
|
277
|
+
super.delete(id);
|
|
278
|
+
}
|
|
279
|
+
}
|