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,194 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { agentCallLogger } from '../services/agentCallLogger.js';
|
|
3
|
+
import { agentCallLogs } from '../database.js';
|
|
4
|
+
import { databaseManager } from '../db/DatabaseManager.js';
|
|
5
|
+
|
|
6
|
+
const router = Router();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolve metadata to a JSON string. Uses provided metadata or derives from session effortLevel.
|
|
10
|
+
*/
|
|
11
|
+
function resolveMetadataJson(providedMetadata, sessionId) {
|
|
12
|
+
let metadata = providedMetadata || {};
|
|
13
|
+
if (!providedMetadata) {
|
|
14
|
+
const session = agentCallLogs.db
|
|
15
|
+
.prepare('SELECT effort_level FROM sessions WHERE id = ?')
|
|
16
|
+
.get(sessionId);
|
|
17
|
+
if (session && session.effort_level) {
|
|
18
|
+
metadata = { effortLevel: session.effort_level };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// GET /api/sessions/:sessionId/agent-stats
|
|
25
|
+
// Returns aggregated stats for a session grouped by call_type
|
|
26
|
+
router.get('/sessions/:sessionId/agent-stats', (req, res) => {
|
|
27
|
+
const stats = agentCallLogger.getSessionStats(req.params.sessionId);
|
|
28
|
+
res.json(stats);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// GET /api/sessions/:sessionId/agent-calls?limit=100&offset=0
|
|
32
|
+
// Returns detailed call log entries for a session
|
|
33
|
+
router.get('/sessions/:sessionId/agent-calls', (req, res) => {
|
|
34
|
+
const { limit = 100, offset = 0 } = req.query;
|
|
35
|
+
const calls = agentCallLogs.getBySessionId(req.params.sessionId, {
|
|
36
|
+
limit: parseInt(limit),
|
|
37
|
+
offset: parseInt(offset),
|
|
38
|
+
});
|
|
39
|
+
res.json(calls);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// GET /api/agent-stats?startDate=...&endDate=...
|
|
43
|
+
// Returns global stats grouped by agent_type and call_type
|
|
44
|
+
router.get('/agent-stats', (req, res) => {
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
const start = req.query.startDate
|
|
47
|
+
? parseInt(req.query.startDate)
|
|
48
|
+
: now - 7 * 24 * 60 * 60 * 1000;
|
|
49
|
+
const end = req.query.endDate ? parseInt(req.query.endDate) : now;
|
|
50
|
+
const stats = agentCallLogger.getGlobalStats(start, end);
|
|
51
|
+
res.json(stats);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// GET /api/agent-calls/filter-options
|
|
55
|
+
// Returns distinct values for filter dropdowns
|
|
56
|
+
router.get('/agent-calls/filter-options', (req, res) => {
|
|
57
|
+
try {
|
|
58
|
+
const options = agentCallLogger.getFilterOptions();
|
|
59
|
+
res.json(options);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error('Failed to get filter options:', err);
|
|
62
|
+
res.status(500).json({ error: 'Failed to get filter options' });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// GET /api/agent-calls?limit=25&offset=0&agentType=...&callType=...&status=...&model=...&sessionId=...&startDate=...&endDate=...&sortBy=...&sortOrder=...
|
|
67
|
+
// Returns paginated call logs with optional filters
|
|
68
|
+
router.get('/agent-calls', (req, res) => {
|
|
69
|
+
try {
|
|
70
|
+
const limit = req.query.limit ? parseInt(req.query.limit) : 25;
|
|
71
|
+
const offset = req.query.offset ? parseInt(req.query.offset) : 0;
|
|
72
|
+
const startDate = req.query.startDate ? parseInt(req.query.startDate) : undefined;
|
|
73
|
+
const endDate = req.query.endDate ? parseInt(req.query.endDate) : undefined;
|
|
74
|
+
|
|
75
|
+
const result = agentCallLogger.getAll({
|
|
76
|
+
limit,
|
|
77
|
+
offset,
|
|
78
|
+
agentType: req.query.agentType,
|
|
79
|
+
callType: req.query.callType,
|
|
80
|
+
status: req.query.status,
|
|
81
|
+
model: req.query.model,
|
|
82
|
+
sessionId: req.query.sessionId,
|
|
83
|
+
startDate,
|
|
84
|
+
endDate,
|
|
85
|
+
sortBy: req.query.sortBy,
|
|
86
|
+
sortOrder: req.query.sortOrder,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
res.json({
|
|
90
|
+
logs: result.rows,
|
|
91
|
+
pagination: {
|
|
92
|
+
total: result.total,
|
|
93
|
+
limit,
|
|
94
|
+
offset,
|
|
95
|
+
hasMore: offset + limit < result.total,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
} catch (err) {
|
|
99
|
+
console.error('Failed to get agent call logs:', err);
|
|
100
|
+
res.status(500).json({ error: 'Failed to get agent call logs' });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// POST /api/agent-calls
|
|
105
|
+
// Seed a fully-formed agent call log entry (for E2E testing only).
|
|
106
|
+
// Accepts all fields directly, including computed ones (totalTokens, durationMs).
|
|
107
|
+
router.post('/agent-calls', (req, res) => {
|
|
108
|
+
try {
|
|
109
|
+
const {
|
|
110
|
+
sessionId,
|
|
111
|
+
agentType = 'claude-code',
|
|
112
|
+
callType = 'runSession',
|
|
113
|
+
model = null,
|
|
114
|
+
status = 'completed',
|
|
115
|
+
inputTokens = 0,
|
|
116
|
+
outputTokens = 0,
|
|
117
|
+
thinkingTokens = 0,
|
|
118
|
+
cacheReadTokens = 0,
|
|
119
|
+
cacheWriteTokens = 0,
|
|
120
|
+
durationMs = null,
|
|
121
|
+
startedAt = null,
|
|
122
|
+
errorMessage = null,
|
|
123
|
+
metadata: providedMetadata,
|
|
124
|
+
} = req.body;
|
|
125
|
+
|
|
126
|
+
if (!sessionId) {
|
|
127
|
+
return res.status(400).json({ error: 'sessionId is required' });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const metadataJson = resolveMetadataJson(providedMetadata, sessionId);
|
|
131
|
+
|
|
132
|
+
const id = databaseManager.generateId();
|
|
133
|
+
const now = Date.now();
|
|
134
|
+
const finalStartedAt = startedAt ?? now;
|
|
135
|
+
const completedAt =
|
|
136
|
+
status === 'completed' || status === 'error'
|
|
137
|
+
? durationMs != null
|
|
138
|
+
? finalStartedAt + durationMs
|
|
139
|
+
: now
|
|
140
|
+
: null;
|
|
141
|
+
const totalTokens =
|
|
142
|
+
inputTokens + outputTokens + thinkingTokens + cacheReadTokens + cacheWriteTokens;
|
|
143
|
+
const finalDurationMs = completedAt != null ? completedAt - finalStartedAt : null;
|
|
144
|
+
|
|
145
|
+
// Direct INSERT — bypasses create()/complete() flow to allow full control over all fields,
|
|
146
|
+
// including computed ones like totalTokens, durationMs, and startedAt.
|
|
147
|
+
const db = agentCallLogs.db;
|
|
148
|
+
db.prepare(`
|
|
149
|
+
INSERT INTO agent_call_logs (
|
|
150
|
+
id, session_id, agent_type, model, call_type, prompt_length,
|
|
151
|
+
input_tokens, output_tokens, thinking_tokens, cache_read_tokens, cache_write_tokens,
|
|
152
|
+
total_tokens, started_at, completed_at, duration_ms, status, error_message, metadata, created_at
|
|
153
|
+
) VALUES (?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
154
|
+
`).run(
|
|
155
|
+
id,
|
|
156
|
+
sessionId,
|
|
157
|
+
agentType,
|
|
158
|
+
model,
|
|
159
|
+
callType,
|
|
160
|
+
inputTokens,
|
|
161
|
+
outputTokens,
|
|
162
|
+
thinkingTokens,
|
|
163
|
+
cacheReadTokens,
|
|
164
|
+
cacheWriteTokens,
|
|
165
|
+
totalTokens,
|
|
166
|
+
finalStartedAt,
|
|
167
|
+
completedAt,
|
|
168
|
+
finalDurationMs,
|
|
169
|
+
status,
|
|
170
|
+
errorMessage,
|
|
171
|
+
metadataJson,
|
|
172
|
+
now
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
res.status(201).json(agentCallLogs.getById(id));
|
|
176
|
+
} catch (err) {
|
|
177
|
+
console.error('Failed to seed agent call log:', err);
|
|
178
|
+
res.status(500).json({ error: err.message });
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// DELETE /api/agent-calls
|
|
183
|
+
// Deletes all agent call logs from the database and clears the in-memory active calls map
|
|
184
|
+
router.delete('/agent-calls', (req, res) => {
|
|
185
|
+
try {
|
|
186
|
+
const deleted = agentCallLogger.deleteAllLogs();
|
|
187
|
+
res.json({ success: true, deleted });
|
|
188
|
+
} catch (err) {
|
|
189
|
+
console.error('Failed to delete agent call logs:', err);
|
|
190
|
+
res.status(500).json({ error: 'Failed to delete agent call logs' });
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
export default router;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isGitRepo } from '../services/gitService.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validate that git projects have required gitMode and gitBranch settings.
|
|
5
|
+
* @param {Object} config - The session configuration
|
|
6
|
+
* @param {Object} project - The project object
|
|
7
|
+
* @returns {Promise<string|null>} Error message if validation fails, null otherwise.
|
|
8
|
+
*/
|
|
9
|
+
export async function validateGitSettings(config, project) {
|
|
10
|
+
if (!config.gitMode || !config.gitBranch) {
|
|
11
|
+
const isGit = await isGitRepo(project.workingDirectory);
|
|
12
|
+
if (isGit) {
|
|
13
|
+
return 'Git projects require both gitMode and gitBranch. Set project defaults or provide them per-session.';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Build a merged index of latest command runs per session.
|
|
21
|
+
* Running commands from memory take precedence over completed DB runs.
|
|
22
|
+
* @param {Array} dbRuns - Completed runs from the database
|
|
23
|
+
* @param {Array} runningRuns - Currently running commands from memory
|
|
24
|
+
* @returns {Object} sessionId -> { buttonId -> run }
|
|
25
|
+
*/
|
|
26
|
+
export function buildRunsBySession(dbRuns, runningRuns) {
|
|
27
|
+
const runsBySession = {};
|
|
28
|
+
for (const run of dbRuns) {
|
|
29
|
+
if (!runsBySession[run.sessionId]) runsBySession[run.sessionId] = {};
|
|
30
|
+
runsBySession[run.sessionId][run.buttonId] = {
|
|
31
|
+
buttonId: run.buttonId, status: run.status, exitCode: run.exitCode,
|
|
32
|
+
runId: run.id, startedAt: run.startedAt, completedAt: run.completedAt,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
for (const run of runningRuns) {
|
|
36
|
+
if (!runsBySession[run.sessionId]) runsBySession[run.sessionId] = {};
|
|
37
|
+
runsBySession[run.sessionId][run.buttonId] = {
|
|
38
|
+
buttonId: run.buttonId, status: 'running', exitCode: null,
|
|
39
|
+
runId: run.runId, startedAt: run.startedAt,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return runsBySession;
|
|
43
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { sessions, sessionTemplates, attachments } from '../database.js';
|
|
2
|
+
import * as slashCommandService from '../services/slashCommandService.js';
|
|
3
|
+
import { setupGitForSession } from '../services/gitSessionSetup.js';
|
|
4
|
+
import { executeHookAsync } from '../services/hookService.js';
|
|
5
|
+
import { broadcastToProject } from '../websocket.js';
|
|
6
|
+
import { WS_MESSAGE_TYPES } from '../../../shared/src/index.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generate an initial session name from the prompt
|
|
10
|
+
* This will be replaced by a better name when the summary is generated
|
|
11
|
+
* @param {string} prompt - The user's initial prompt
|
|
12
|
+
* @returns {string} A truncated version of the prompt (max 50 chars)
|
|
13
|
+
*/
|
|
14
|
+
export function generateInitialName(prompt) {
|
|
15
|
+
const cleaned = prompt.trim().replace(/\s+/g, ' ');
|
|
16
|
+
if (cleaned.length <= 50) return cleaned;
|
|
17
|
+
const truncated = cleaned.substring(0, 50);
|
|
18
|
+
const lastSpace = truncated.lastIndexOf(' ');
|
|
19
|
+
return `${lastSpace > 20 ? truncated.substring(0, lastSpace) : truncated }...`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Parse a boolean-like value from a request body field.
|
|
24
|
+
* Handles true, false, 'true', 'false', and undefined/null.
|
|
25
|
+
* @param {*} value - The raw value from request body
|
|
26
|
+
* @returns {{ explicit: boolean, provided: boolean }} parsed result
|
|
27
|
+
*/
|
|
28
|
+
export function parseBooleanField(value) {
|
|
29
|
+
if (value === true || value === 'true') return { explicit: true, provided: true };
|
|
30
|
+
if (value === false || value === 'false') return { explicit: false, provided: true };
|
|
31
|
+
return { explicit: undefined, provided: false };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a value with cascading defaults: explicit > project default > system default
|
|
36
|
+
* @param {*} explicit - Explicitly provided value
|
|
37
|
+
* @param {*} projectDefault - Project-level default
|
|
38
|
+
* @param {*} systemDefault - System-level default
|
|
39
|
+
* @returns {*} The resolved value
|
|
40
|
+
*/
|
|
41
|
+
export function resolveDefault(explicit, projectDefault, systemDefault) {
|
|
42
|
+
if (explicit) return explicit;
|
|
43
|
+
if (projectDefault) return projectDefault;
|
|
44
|
+
return systemDefault;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Resolve thinkingEnabled with special boolean handling.
|
|
49
|
+
* @param {object} body - Request body
|
|
50
|
+
* @param {object|null} projectDefs - Project defaults
|
|
51
|
+
* @param {object} systemDefaults - System defaults
|
|
52
|
+
* @returns {boolean}
|
|
53
|
+
*/
|
|
54
|
+
export function resolveThinkingEnabled(body, projectDefs, systemDefaults) {
|
|
55
|
+
const thinkingParsed = parseBooleanField(body.thinkingEnabled);
|
|
56
|
+
if (thinkingParsed.provided) {
|
|
57
|
+
return thinkingParsed.explicit;
|
|
58
|
+
}
|
|
59
|
+
if (projectDefs?.thinkingEnabled !== undefined && projectDefs?.thinkingEnabled !== null) {
|
|
60
|
+
return projectDefs.thinkingEnabled;
|
|
61
|
+
}
|
|
62
|
+
return systemDefaults.thinkingEnabled;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Parse scheduling fields from request body.
|
|
67
|
+
* @param {object} body - Request body
|
|
68
|
+
* @returns {object} Scheduling configuration
|
|
69
|
+
*/
|
|
70
|
+
export function parseSchedulingConfig(body) {
|
|
71
|
+
return {
|
|
72
|
+
scheduledAt: body.scheduledAt ? parseInt(body.scheduledAt, 10) : undefined,
|
|
73
|
+
autoRescheduleEnabled: body.autoRescheduleEnabled === true || body.autoRescheduleEnabled === 'true',
|
|
74
|
+
rescheduleDelayMinutes: body.rescheduleDelayMinutes ? parseInt(body.rescheduleDelayMinutes, 10) : 15,
|
|
75
|
+
rescheduleOnTokenLimit: body.rescheduleOnTokenLimit !== false && body.rescheduleOnTokenLimit !== 'false',
|
|
76
|
+
rescheduleOnServiceError: body.rescheduleOnServiceError !== false && body.rescheduleOnServiceError !== 'false',
|
|
77
|
+
maxRescheduleCount: body.maxRescheduleCount ? parseInt(body.maxRescheduleCount, 10) : null,
|
|
78
|
+
maxTotalTokens: body.maxTotalTokens ? parseInt(body.maxTotalTokens, 10) : null,
|
|
79
|
+
rescheduleAtTokenCount: body.rescheduleAtTokenCount ? parseInt(body.rescheduleAtTokenCount, 10) : null,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Resolve startImmediately with special boolean handling.
|
|
85
|
+
* Default is true unless overridden by project/system defaults.
|
|
86
|
+
* @param {object} body - Request body
|
|
87
|
+
* @param {object|null} projectDefs - Project defaults
|
|
88
|
+
* @param {object} systemDefaults - System defaults
|
|
89
|
+
* @returns {boolean}
|
|
90
|
+
*/
|
|
91
|
+
export function resolveStartImmediately(body, projectDefs, systemDefaults) {
|
|
92
|
+
let startImmediately = body.startImmediately !== false && body.startImmediately !== 'false';
|
|
93
|
+
if (body.startImmediately === undefined || body.startImmediately === null) {
|
|
94
|
+
if (projectDefs?.startImmediately !== undefined && projectDefs?.startImmediately !== null) {
|
|
95
|
+
startImmediately = projectDefs.startImmediately;
|
|
96
|
+
} else {
|
|
97
|
+
startImmediately = systemDefaults.startImmediately;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return startImmediately;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Build session configuration from request body, project defaults, and system defaults.
|
|
105
|
+
* @param {object} body - The request body
|
|
106
|
+
* @param {object|null} projectDefs - Project-level defaults
|
|
107
|
+
* @param {object} systemDefaults - System-level defaults
|
|
108
|
+
* @returns {object} Session configuration
|
|
109
|
+
*/
|
|
110
|
+
export function prepareSessionConfig(body, projectDefs, systemDefaults) {
|
|
111
|
+
let effortLevel = resolveDefault(body.effortLevel || null, projectDefs?.effortLevel, systemDefaults.effortLevel);
|
|
112
|
+
// Normalize 'auto' to null
|
|
113
|
+
if (effortLevel === 'auto') {
|
|
114
|
+
effortLevel = null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
prompt: body.prompt,
|
|
119
|
+
name: body.name,
|
|
120
|
+
mode: resolveDefault(body.mode, projectDefs?.mode, systemDefaults.mode),
|
|
121
|
+
model: resolveDefault(body.model, projectDefs?.model, systemDefaults.model || null),
|
|
122
|
+
effortLevel,
|
|
123
|
+
gitBranch: resolveDefault(body.gitBranch, projectDefs?.gitBranch, null),
|
|
124
|
+
gitMode: resolveDefault(body.gitMode, projectDefs?.gitMode, null),
|
|
125
|
+
templateId: body.templateId,
|
|
126
|
+
parentSessionId: body.parentSessionId || null,
|
|
127
|
+
files: [],
|
|
128
|
+
thinkingEnabled: resolveThinkingEnabled(body, projectDefs, systemDefaults),
|
|
129
|
+
startImmediately: resolveStartImmediately(body, projectDefs, systemDefaults),
|
|
130
|
+
...parseSchedulingConfig(body),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Apply template overrides to session config.
|
|
136
|
+
* Mutates the config object in place.
|
|
137
|
+
* @param {object} configInput - Session config to modify
|
|
138
|
+
*/
|
|
139
|
+
export function applyTemplateOverrides(configInput) {
|
|
140
|
+
const config = configInput;
|
|
141
|
+
if (!config.templateId) return;
|
|
142
|
+
|
|
143
|
+
const template = sessionTemplates.getById(config.templateId);
|
|
144
|
+
if (!template) return;
|
|
145
|
+
|
|
146
|
+
if (template.thinkingEnabled !== null && template.thinkingEnabled !== undefined) {
|
|
147
|
+
config.thinkingEnabled = template.thinkingEnabled;
|
|
148
|
+
}
|
|
149
|
+
if (template.gitBranch) {
|
|
150
|
+
config.gitBranch = template.gitBranch;
|
|
151
|
+
}
|
|
152
|
+
if (template.gitMode) {
|
|
153
|
+
config.gitMode = template.gitMode;
|
|
154
|
+
}
|
|
155
|
+
if (template.effortLevel !== null && template.effortLevel !== undefined) {
|
|
156
|
+
config.effortLevel = template.effortLevel;
|
|
157
|
+
// Normalize 'auto' to null (same as prepareSessionConfig)
|
|
158
|
+
if (config.effortLevel === 'auto') {
|
|
159
|
+
config.effortLevel = null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
config.nextTemplateId = config.templateId;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Resolve the nextTemplateId from explicit body value or template-derived value.
|
|
167
|
+
* @param {object} body - Request body
|
|
168
|
+
* @param {string|null} derivedNextTemplateId - nextTemplateId derived from templateId
|
|
169
|
+
* @returns {{ nextTemplateId: string|null, error: string|null }}
|
|
170
|
+
*/
|
|
171
|
+
export function resolveNextTemplateId(body, derivedNextTemplateId) {
|
|
172
|
+
if (body.nextTemplateId === undefined) {
|
|
173
|
+
return { nextTemplateId: derivedNextTemplateId, error: null };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (body.nextTemplateId === null) {
|
|
177
|
+
return { nextTemplateId: null, error: null };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const nextTemplate = sessionTemplates.getById(body.nextTemplateId);
|
|
181
|
+
if (!nextTemplate) {
|
|
182
|
+
return { nextTemplateId: null, error: 'nextTemplateId references a non-existent template' };
|
|
183
|
+
}
|
|
184
|
+
return { nextTemplateId: body.nextTemplateId, error: null };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Determine the initial session status based on config.
|
|
189
|
+
* @param {object} config - Session config
|
|
190
|
+
* @returns {string|undefined} Initial status, or undefined for default
|
|
191
|
+
*/
|
|
192
|
+
export function determineInitialStatus(config) {
|
|
193
|
+
if (config.scheduledAt && config.scheduledAt > Date.now()) return 'scheduled';
|
|
194
|
+
if (!config.startImmediately) return 'waiting';
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Build the scheduling update object from config.
|
|
200
|
+
* @param {object} config - Session config
|
|
201
|
+
* @param {string|undefined} initialStatus - Initial session status
|
|
202
|
+
* @returns {object} Fields to update on the session for scheduling
|
|
203
|
+
*/
|
|
204
|
+
export function buildSchedulingUpdate(config, initialStatus) {
|
|
205
|
+
const update = {};
|
|
206
|
+
if (config.scheduledAt !== undefined) update.scheduledAt = config.scheduledAt;
|
|
207
|
+
if (config.autoRescheduleEnabled !== undefined) update.autoRescheduleEnabled = config.autoRescheduleEnabled;
|
|
208
|
+
if (config.rescheduleDelayMinutes !== undefined) update.rescheduleDelayMinutes = config.rescheduleDelayMinutes;
|
|
209
|
+
if (config.rescheduleOnTokenLimit !== undefined) update.rescheduleOnTokenLimit = config.rescheduleOnTokenLimit;
|
|
210
|
+
if (config.rescheduleOnServiceError !== undefined) update.rescheduleOnServiceError = config.rescheduleOnServiceError;
|
|
211
|
+
if (config.maxRescheduleCount !== undefined) update.maxRescheduleCount = config.maxRescheduleCount;
|
|
212
|
+
if (config.maxTotalTokens !== undefined) update.maxTotalTokens = config.maxTotalTokens;
|
|
213
|
+
if (config.rescheduleAtTokenCount !== undefined) update.rescheduleAtTokenCount = config.rescheduleAtTokenCount;
|
|
214
|
+
|
|
215
|
+
if (initialStatus === 'waiting' || initialStatus === 'scheduled') {
|
|
216
|
+
update.pendingPrompt = config.prompt;
|
|
217
|
+
update.pendingModel = config.model;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return update;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Handle git setup, session start, broadcasts, and hooks after session creation.
|
|
225
|
+
* @param {object} params
|
|
226
|
+
* @param {object} params.session - The created session record
|
|
227
|
+
* @param {object} params.config - Session config
|
|
228
|
+
* @param {object} params.project - Project record
|
|
229
|
+
* @param {string} params.projectId - Project ID
|
|
230
|
+
* @param {Array} params.files - Uploaded files
|
|
231
|
+
* @returns {Promise<{ updatedSession: object }>}
|
|
232
|
+
*/
|
|
233
|
+
export async function setupAndStartSession({ session, config, project, projectId, files }) {
|
|
234
|
+
let workingDirectory;
|
|
235
|
+
let gitWorktree = null;
|
|
236
|
+
|
|
237
|
+
// If this is a child session and the parent has a worktree, inherit it
|
|
238
|
+
// (mirrors templateTriggerService behavior)
|
|
239
|
+
const parentSession = config.parentSessionId ? sessions.getById(config.parentSessionId) : null;
|
|
240
|
+
if (parentSession?.gitWorktree) {
|
|
241
|
+
workingDirectory = parentSession.gitWorktree;
|
|
242
|
+
gitWorktree = parentSession.gitWorktree;
|
|
243
|
+
} else {
|
|
244
|
+
const gitSetup = await setupGitForSession({
|
|
245
|
+
projectDir: project.workingDirectory,
|
|
246
|
+
gitMode: config.gitMode || null,
|
|
247
|
+
gitBranch: config.gitBranch || null,
|
|
248
|
+
sessionId: session.id,
|
|
249
|
+
});
|
|
250
|
+
workingDirectory = gitSetup.workingDirectory;
|
|
251
|
+
gitWorktree = gitSetup.gitWorktree;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (gitWorktree) {
|
|
255
|
+
sessions.update(session.id, { gitWorktree });
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const sessionAttachments = attachments.createBatch(session.id, null, files, workingDirectory);
|
|
259
|
+
|
|
260
|
+
const isScheduled = config.scheduledAt && config.scheduledAt > Date.now();
|
|
261
|
+
if (config.startImmediately && !isScheduled) {
|
|
262
|
+
const resolved = await slashCommandService.resolvePromptSkillOrCommand(
|
|
263
|
+
workingDirectory, config.prompt, project.systemPrompt
|
|
264
|
+
);
|
|
265
|
+
const finalPrompt = resolved ? resolved.userMessage : config.prompt;
|
|
266
|
+
const finalSystemPrompt = resolved ? resolved.systemPrompt : project.systemPrompt;
|
|
267
|
+
|
|
268
|
+
const { runSession } = await import('../services/sessionManager.js');
|
|
269
|
+
runSession(session.id, finalPrompt, workingDirectory, {
|
|
270
|
+
systemPrompt: finalSystemPrompt,
|
|
271
|
+
fileAttachments: sessionAttachments,
|
|
272
|
+
model: config.model,
|
|
273
|
+
}).catch((error) => {
|
|
274
|
+
console.error('Session error:', error);
|
|
275
|
+
sessions.update(session.id, { status: 'error', error: error.message });
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const updatedSession = sessions.getById(session.id);
|
|
280
|
+
|
|
281
|
+
broadcastToProject(projectId, WS_MESSAGE_TYPES.SESSION_CREATED, {
|
|
282
|
+
projectId,
|
|
283
|
+
session: updatedSession,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
if (project.onSessionCreated) {
|
|
287
|
+
executeHookAsync(project.onSessionCreated, workingDirectory, {
|
|
288
|
+
sessionId: session.id,
|
|
289
|
+
projectId: project.id,
|
|
290
|
+
sessionName: session.name,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return { updatedSession };
|
|
295
|
+
}
|