pi-kot 0.1.21 → 0.1.23
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/bin/pi-kot.mjs +148 -0
- package/dist/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/client/assets/index-CE_Na97I.js +75 -0
- package/dist/client/assets/index-CE_Na97I.js.map +1 -0
- package/dist/client/assets/index-QP95zkpd.css +1 -0
- package/dist/client/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/dist/client/assets/vendor-codemirror-CD3uCqRj.js +48 -0
- package/dist/client/assets/vendor-codemirror-CD3uCqRj.js.map +1 -0
- package/dist/client/assets/vendor-icons-W8thHNMl.js +2 -0
- package/dist/client/assets/vendor-icons-W8thHNMl.js.map +1 -0
- package/dist/client/assets/vendor-katex-4z5K3dyr.js +260 -0
- package/dist/client/assets/vendor-katex-4z5K3dyr.js.map +1 -0
- package/dist/client/assets/vendor-katex-CYlHEDRF.css +1 -0
- package/dist/client/assets/vendor-markdown-BSzxNR_7.js +35 -0
- package/dist/client/assets/vendor-markdown-BSzxNR_7.js.map +1 -0
- package/dist/client/assets/vendor-prism-CQGp13s2.js +4 -0
- package/dist/client/assets/vendor-prism-CQGp13s2.js.map +1 -0
- package/dist/client/assets/vendor-xterm-BrP-ENHg.css +1 -0
- package/dist/client/assets/vendor-xterm-DXwh06H3.js +36 -0
- package/dist/client/assets/vendor-xterm-DXwh06H3.js.map +1 -0
- package/dist/client/index.html +23 -0
- package/dist/server/ask-user-question/envelope.d.ts +11 -0
- package/dist/server/ask-user-question/envelope.d.ts.map +1 -0
- package/dist/server/ask-user-question/envelope.js +41 -0
- package/dist/server/ask-user-question/envelope.js.map +1 -0
- package/dist/server/ask-user-question/plan-mode-question-tool.d.ts +26 -0
- package/dist/server/ask-user-question/plan-mode-question-tool.d.ts.map +1 -0
- package/dist/server/ask-user-question/plan-mode-question-tool.js +273 -0
- package/dist/server/ask-user-question/plan-mode-question-tool.js.map +1 -0
- package/dist/server/ask-user-question/prompt-strings.d.ts +4 -0
- package/dist/server/ask-user-question/prompt-strings.d.ts.map +1 -0
- package/dist/server/ask-user-question/prompt-strings.js +18 -0
- package/dist/server/ask-user-question/prompt-strings.js.map +1 -0
- package/dist/server/ask-user-question/registry.d.ts +39 -0
- package/dist/server/ask-user-question/registry.d.ts.map +1 -0
- package/dist/server/ask-user-question/registry.js +124 -0
- package/dist/server/ask-user-question/registry.js.map +1 -0
- package/dist/server/ask-user-question/tool.d.ts +4 -0
- package/dist/server/ask-user-question/tool.d.ts.map +1 -0
- package/dist/server/ask-user-question/tool.js +68 -0
- package/dist/server/ask-user-question/tool.js.map +1 -0
- package/dist/server/ask-user-question/types.d.ts +50 -0
- package/dist/server/ask-user-question/types.d.ts.map +1 -0
- package/dist/server/ask-user-question/types.js +7 -0
- package/dist/server/ask-user-question/types.js.map +1 -0
- package/dist/server/ask-user-question/validate.d.ts +3 -0
- package/dist/server/ask-user-question/validate.d.ts.map +1 -0
- package/dist/server/ask-user-question/validate.js +67 -0
- package/dist/server/ask-user-question/validate.js.map +1 -0
- package/dist/server/clone-provider.d.ts +55 -0
- package/dist/server/clone-provider.d.ts.map +1 -0
- package/dist/server/clone-provider.js +172 -0
- package/dist/server/clone-provider.js.map +1 -0
- package/dist/server/compaction-cards.d.ts +62 -0
- package/dist/server/compaction-cards.d.ts.map +1 -0
- package/dist/server/compaction-cards.js +180 -0
- package/dist/server/compaction-cards.js.map +1 -0
- package/dist/server/compaction-continuation.d.ts +112 -0
- package/dist/server/compaction-continuation.d.ts.map +1 -0
- package/dist/server/compaction-continuation.js +65 -0
- package/dist/server/compaction-continuation.js.map +1 -0
- package/dist/server/config-store.d.ts +97 -0
- package/dist/server/config-store.d.ts.map +1 -0
- package/dist/server/config-store.js +351 -0
- package/dist/server/config-store.js.map +1 -0
- package/dist/server/config.d.ts +24 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +67 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/event-stream.d.ts +28 -0
- package/dist/server/event-stream.d.ts.map +1 -0
- package/dist/server/event-stream.js +153 -0
- package/dist/server/event-stream.js.map +1 -0
- package/dist/server/extension-manager.d.ts +116 -0
- package/dist/server/extension-manager.d.ts.map +1 -0
- package/dist/server/extension-manager.js +586 -0
- package/dist/server/extension-manager.js.map +1 -0
- package/dist/server/extension-scanner.d.ts +26 -0
- package/dist/server/extension-scanner.d.ts.map +1 -0
- package/dist/server/extension-scanner.js +107 -0
- package/dist/server/extension-scanner.js.map +1 -0
- package/dist/server/extension-ui-bridge.d.ts +35 -0
- package/dist/server/extension-ui-bridge.d.ts.map +1 -0
- package/dist/server/extension-ui-bridge.js +228 -0
- package/dist/server/extension-ui-bridge.js.map +1 -0
- package/dist/server/file-manager.d.ts +79 -0
- package/dist/server/file-manager.d.ts.map +1 -0
- package/dist/server/file-manager.js +535 -0
- package/dist/server/file-manager.js.map +1 -0
- package/dist/server/file-searcher.d.ts +29 -0
- package/dist/server/file-searcher.d.ts.map +1 -0
- package/dist/server/file-searcher.js +318 -0
- package/dist/server/file-searcher.js.map +1 -0
- package/dist/server/git-operations.d.ts +346 -0
- package/dist/server/git-operations.d.ts.map +1 -0
- package/dist/server/git-operations.js +884 -0
- package/dist/server/git-operations.js.map +1 -0
- package/dist/server/hunk-stager.d.ts +56 -0
- package/dist/server/hunk-stager.d.ts.map +1 -0
- package/dist/server/hunk-stager.js +137 -0
- package/dist/server/hunk-stager.js.map +1 -0
- package/dist/server/index.d.ts +21 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +262 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp/config.d.ts +23 -0
- package/dist/server/mcp/config.d.ts.map +1 -0
- package/dist/server/mcp/config.js +139 -0
- package/dist/server/mcp/config.js.map +1 -0
- package/dist/server/mcp/manager.d.ts +40 -0
- package/dist/server/mcp/manager.d.ts.map +1 -0
- package/dist/server/mcp/manager.js +435 -0
- package/dist/server/mcp/manager.js.map +1 -0
- package/dist/server/mcp/stdio-trust.d.ts +5 -0
- package/dist/server/mcp/stdio-trust.d.ts.map +1 -0
- package/dist/server/mcp/stdio-trust.js +78 -0
- package/dist/server/mcp/stdio-trust.js.map +1 -0
- package/dist/server/mcp/tool-bridge.d.ts +33 -0
- package/dist/server/mcp/tool-bridge.d.ts.map +1 -0
- package/dist/server/mcp/tool-bridge.js +138 -0
- package/dist/server/mcp/tool-bridge.js.map +1 -0
- package/dist/server/orchestration/config.d.ts +5 -0
- package/dist/server/orchestration/config.d.ts.map +1 -0
- package/dist/server/orchestration/config.js +35 -0
- package/dist/server/orchestration/config.js.map +1 -0
- package/dist/server/orchestration/event-bridge.d.ts +32 -0
- package/dist/server/orchestration/event-bridge.d.ts.map +1 -0
- package/dist/server/orchestration/event-bridge.js +110 -0
- package/dist/server/orchestration/event-bridge.js.map +1 -0
- package/dist/server/orchestration/inbox.d.ts +9 -0
- package/dist/server/orchestration/inbox.d.ts.map +1 -0
- package/dist/server/orchestration/inbox.js +186 -0
- package/dist/server/orchestration/inbox.js.map +1 -0
- package/dist/server/orchestration/init.d.ts +2 -0
- package/dist/server/orchestration/init.d.ts.map +1 -0
- package/dist/server/orchestration/init.js +22 -0
- package/dist/server/orchestration/init.js.map +1 -0
- package/dist/server/orchestration/store.d.ts +33 -0
- package/dist/server/orchestration/store.d.ts.map +1 -0
- package/dist/server/orchestration/store.js +331 -0
- package/dist/server/orchestration/store.js.map +1 -0
- package/dist/server/orchestration/tools.d.ts +15 -0
- package/dist/server/orchestration/tools.d.ts.map +1 -0
- package/dist/server/orchestration/tools.js +621 -0
- package/dist/server/orchestration/tools.js.map +1 -0
- package/dist/server/orchestration/types.d.ts +68 -0
- package/dist/server/orchestration/types.d.ts.map +1 -0
- package/dist/server/orchestration/types.js +43 -0
- package/dist/server/orchestration/types.js.map +1 -0
- package/dist/server/orchestration/worker-lifecycle.d.ts +15 -0
- package/dist/server/orchestration/worker-lifecycle.d.ts.map +1 -0
- package/dist/server/orchestration/worker-lifecycle.js +45 -0
- package/dist/server/orchestration/worker-lifecycle.js.map +1 -0
- package/dist/server/path-refs.d.ts +5 -0
- package/dist/server/path-refs.d.ts.map +1 -0
- package/dist/server/path-refs.js +249 -0
- package/dist/server/path-refs.js.map +1 -0
- package/dist/server/routes/_schemas.d.ts +16 -0
- package/dist/server/routes/_schemas.d.ts.map +1 -0
- package/dist/server/routes/_schemas.js +12 -0
- package/dist/server/routes/_schemas.js.map +1 -0
- package/dist/server/routes/ask-user-question.d.ts +3 -0
- package/dist/server/routes/ask-user-question.d.ts.map +1 -0
- package/dist/server/routes/ask-user-question.js +105 -0
- package/dist/server/routes/ask-user-question.js.map +1 -0
- package/dist/server/routes/auth.d.ts +8 -0
- package/dist/server/routes/auth.d.ts.map +1 -0
- package/dist/server/routes/auth.js +225 -0
- package/dist/server/routes/auth.js.map +1 -0
- package/dist/server/routes/config.d.ts +3 -0
- package/dist/server/routes/config.d.ts.map +1 -0
- package/dist/server/routes/config.js +602 -0
- package/dist/server/routes/config.js.map +1 -0
- package/dist/server/routes/control.d.ts +3 -0
- package/dist/server/routes/control.d.ts.map +1 -0
- package/dist/server/routes/control.js +365 -0
- package/dist/server/routes/control.js.map +1 -0
- package/dist/server/routes/exec.d.ts +3 -0
- package/dist/server/routes/exec.d.ts.map +1 -0
- package/dist/server/routes/exec.js +426 -0
- package/dist/server/routes/exec.js.map +1 -0
- package/dist/server/routes/extension-commands.d.ts +22 -0
- package/dist/server/routes/extension-commands.d.ts.map +1 -0
- package/dist/server/routes/extension-commands.js +178 -0
- package/dist/server/routes/extension-commands.js.map +1 -0
- package/dist/server/routes/extensions.d.ts +8 -0
- package/dist/server/routes/extensions.d.ts.map +1 -0
- package/dist/server/routes/extensions.js +414 -0
- package/dist/server/routes/extensions.js.map +1 -0
- package/dist/server/routes/files.d.ts +3 -0
- package/dist/server/routes/files.d.ts.map +1 -0
- package/dist/server/routes/files.js +835 -0
- package/dist/server/routes/files.js.map +1 -0
- package/dist/server/routes/git.d.ts +3 -0
- package/dist/server/routes/git.d.ts.map +1 -0
- package/dist/server/routes/git.js +1058 -0
- package/dist/server/routes/git.js.map +1 -0
- package/dist/server/routes/mcp.d.ts +3 -0
- package/dist/server/routes/mcp.d.ts.map +1 -0
- package/dist/server/routes/mcp.js +403 -0
- package/dist/server/routes/mcp.js.map +1 -0
- package/dist/server/routes/orchestration.d.ts +3 -0
- package/dist/server/routes/orchestration.d.ts.map +1 -0
- package/dist/server/routes/orchestration.js +251 -0
- package/dist/server/routes/orchestration.js.map +1 -0
- package/dist/server/routes/projects.d.ts +3 -0
- package/dist/server/routes/projects.d.ts.map +1 -0
- package/dist/server/routes/projects.js +421 -0
- package/dist/server/routes/projects.js.map +1 -0
- package/dist/server/routes/prompt.d.ts +3 -0
- package/dist/server/routes/prompt.d.ts.map +1 -0
- package/dist/server/routes/prompt.js +311 -0
- package/dist/server/routes/prompt.js.map +1 -0
- package/dist/server/routes/session-extensions.d.ts +11 -0
- package/dist/server/routes/session-extensions.d.ts.map +1 -0
- package/dist/server/routes/session-extensions.js +171 -0
- package/dist/server/routes/session-extensions.js.map +1 -0
- package/dist/server/routes/sessions.d.ts +3 -0
- package/dist/server/routes/sessions.d.ts.map +1 -0
- package/dist/server/routes/sessions.js +706 -0
- package/dist/server/routes/sessions.js.map +1 -0
- package/dist/server/routes/skills.d.ts +14 -0
- package/dist/server/routes/skills.d.ts.map +1 -0
- package/dist/server/routes/skills.js +448 -0
- package/dist/server/routes/skills.js.map +1 -0
- package/dist/server/routes/stream.d.ts +3 -0
- package/dist/server/routes/stream.d.ts.map +1 -0
- package/dist/server/routes/stream.js +112 -0
- package/dist/server/routes/stream.js.map +1 -0
- package/dist/server/routes/terminal.d.ts +28 -0
- package/dist/server/routes/terminal.d.ts.map +1 -0
- package/dist/server/routes/terminal.js +211 -0
- package/dist/server/routes/terminal.js.map +1 -0
- package/dist/server/routes/tunnel.d.ts +13 -0
- package/dist/server/routes/tunnel.d.ts.map +1 -0
- package/dist/server/routes/tunnel.js +231 -0
- package/dist/server/routes/tunnel.js.map +1 -0
- package/dist/server/session-alerts.d.ts +28 -0
- package/dist/server/session-alerts.d.ts.map +1 -0
- package/dist/server/session-alerts.js +38 -0
- package/dist/server/session-alerts.js.map +1 -0
- package/dist/server/session-store.d.ts +164 -0
- package/dist/server/session-store.d.ts.map +1 -0
- package/dist/server/session-store.js +754 -0
- package/dist/server/session-store.js.map +1 -0
- package/dist/server/skill-policy.d.ts +47 -0
- package/dist/server/skill-policy.d.ts.map +1 -0
- package/dist/server/skill-policy.js +178 -0
- package/dist/server/skill-policy.js.map +1 -0
- package/dist/server/terminal-provider.d.ts +54 -0
- package/dist/server/terminal-provider.d.ts.map +1 -0
- package/dist/server/terminal-provider.js +220 -0
- package/dist/server/terminal-provider.js.map +1 -0
- package/dist/server/tool-policy.d.ts +39 -0
- package/dist/server/tool-policy.d.ts.map +1 -0
- package/dist/server/tool-policy.js +121 -0
- package/dist/server/tool-policy.js.map +1 -0
- package/dist/server/tunnel/executable-search.d.ts +43 -0
- package/dist/server/tunnel/executable-search.d.ts.map +1 -0
- package/dist/server/tunnel/executable-search.js +148 -0
- package/dist/server/tunnel/executable-search.js.map +1 -0
- package/dist/server/tunnel/install-help.d.ts +19 -0
- package/dist/server/tunnel/install-help.d.ts.map +1 -0
- package/dist/server/tunnel/install-help.js +47 -0
- package/dist/server/tunnel/install-help.js.map +1 -0
- package/dist/server/tunnel/providers/ngrok.d.ts +31 -0
- package/dist/server/tunnel/providers/ngrok.d.ts.map +1 -0
- package/dist/server/tunnel/providers/ngrok.js +461 -0
- package/dist/server/tunnel/providers/ngrok.js.map +1 -0
- package/dist/server/tunnel/registry.d.ts +13 -0
- package/dist/server/tunnel/registry.d.ts.map +1 -0
- package/dist/server/tunnel/registry.js +56 -0
- package/dist/server/tunnel/registry.js.map +1 -0
- package/dist/server/tunnel/service.d.ts +13 -0
- package/dist/server/tunnel/service.d.ts.map +1 -0
- package/dist/server/tunnel/service.js +156 -0
- package/dist/server/tunnel/service.js.map +1 -0
- package/dist/server/tunnel/types.d.ts +163 -0
- package/dist/server/tunnel/types.d.ts.map +1 -0
- package/dist/server/tunnel/types.js +214 -0
- package/dist/server/tunnel/types.js.map +1 -0
- package/dist/server/ui-settings-store.d.ts +25 -0
- package/dist/server/ui-settings-store.d.ts.map +1 -0
- package/dist/server/ui-settings-store.js +91 -0
- package/dist/server/ui-settings-store.js.map +1 -0
- package/dist/server/workspace-store.d.ts +25 -0
- package/dist/server/workspace-store.d.ts.map +1 -0
- package/dist/server/workspace-store.js +157 -0
- package/dist/server/workspace-store.js.map +1 -0
- package/package.json +5 -3
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
import { buildCompactionHistory } from "../compaction-cards.js";
|
|
2
|
+
import { createSession, disposeSession, listSessions, listSessionsForProject, getSession, renameSession, archiveSession, unarchiveSession, listArchivedSessions, resumeSessionById, forkSession, } from "../session-store.js";
|
|
3
|
+
import { getProject } from "../workspace-store.js";
|
|
4
|
+
import { bridgeWorkerDeleted } from "../orchestration/event-bridge.js";
|
|
5
|
+
import { getSupervisorIdForWorker } from "../orchestration/store.js";
|
|
6
|
+
import { buildSnapshot } from "../event-stream.js";
|
|
7
|
+
export const sessionRoutes = async (fastify) => {
|
|
8
|
+
// POST /api/v1/sessions — create a new session
|
|
9
|
+
fastify.post("/sessions", {
|
|
10
|
+
schema: {
|
|
11
|
+
description: "Create a new session.",
|
|
12
|
+
tags: ["sessions"],
|
|
13
|
+
body: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
projectId: { type: "string", description: "Project ID (default: 'default')" },
|
|
17
|
+
workspacePath: { type: "string", description: "Working directory (default: config.workspacePath)" },
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
response: {
|
|
21
|
+
201: {
|
|
22
|
+
type: "object",
|
|
23
|
+
required: ["sessionId"],
|
|
24
|
+
properties: {
|
|
25
|
+
sessionId: { type: "string" },
|
|
26
|
+
projectId: { type: "string" },
|
|
27
|
+
createdAt: { type: "string" },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
}, async (req, reply) => {
|
|
33
|
+
let projectId = req.body.projectId ?? "default";
|
|
34
|
+
// Backward compat: resolve "default" to the Default project's UUID
|
|
35
|
+
if (projectId === "default") {
|
|
36
|
+
const { listProjects } = await import("../workspace-store.js");
|
|
37
|
+
const projects = await listProjects();
|
|
38
|
+
if (projects.length > 0) {
|
|
39
|
+
projectId = projects[0].id;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Resolve the project to get its path as workspacePath
|
|
43
|
+
const { getProject } = await import("../workspace-store.js");
|
|
44
|
+
const project = await getProject(projectId);
|
|
45
|
+
if (project === undefined) {
|
|
46
|
+
return reply.code(404).send({ error: "project_not_found" });
|
|
47
|
+
}
|
|
48
|
+
const workspacePath = req.body.workspacePath ?? project.path;
|
|
49
|
+
const live = await createSession(projectId, workspacePath);
|
|
50
|
+
return reply.code(201).send({
|
|
51
|
+
sessionId: live.sessionId,
|
|
52
|
+
projectId: live.projectId,
|
|
53
|
+
createdAt: live.createdAt.toISOString(),
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
// GET /api/v1/sessions — list sessions, optionally filtered by projectId.
|
|
57
|
+
// When projectId is specified, returns unified view (live + disk).
|
|
58
|
+
// When omitted, returns only live sessions (backward compat).
|
|
59
|
+
// When archived=true is set (requires projectId), returns archived sessions.
|
|
60
|
+
fastify.get("/sessions", {
|
|
61
|
+
schema: {
|
|
62
|
+
description: "List sessions. When projectId is specified, returns " +
|
|
63
|
+
"both live and disk sessions with names and message counts. " +
|
|
64
|
+
"When omitted, returns only live sessions. " +
|
|
65
|
+
"Use ?archived=true to list archived (soft-deleted) sessions.",
|
|
66
|
+
tags: ["sessions"],
|
|
67
|
+
querystring: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
projectId: { type: "string" },
|
|
71
|
+
archived: { type: "string" },
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
response: {
|
|
75
|
+
200: {
|
|
76
|
+
type: "object",
|
|
77
|
+
required: ["sessions"],
|
|
78
|
+
properties: {
|
|
79
|
+
sessions: {
|
|
80
|
+
type: "array",
|
|
81
|
+
items: {
|
|
82
|
+
type: "object",
|
|
83
|
+
required: ["sessionId", "projectId", "isLive", "createdAt", "lastActivityAt"],
|
|
84
|
+
properties: {
|
|
85
|
+
sessionId: { type: "string" },
|
|
86
|
+
projectId: { type: "string" },
|
|
87
|
+
isLive: { type: "boolean" },
|
|
88
|
+
name: { type: "string" },
|
|
89
|
+
createdAt: { type: "string" },
|
|
90
|
+
lastActivityAt: { type: "string" },
|
|
91
|
+
messageCount: { type: "integer" },
|
|
92
|
+
supervisorId: { type: "string" },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
}, async (req) => {
|
|
101
|
+
let { projectId, archived } = req.query;
|
|
102
|
+
// Backward compat: resolve "default" to the Default project's UUID
|
|
103
|
+
if (projectId === "default") {
|
|
104
|
+
const { listProjects } = await import("../workspace-store.js");
|
|
105
|
+
const projects = await listProjects();
|
|
106
|
+
if (projects.length > 0) {
|
|
107
|
+
projectId = projects[0].id;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (projectId !== undefined) {
|
|
111
|
+
const { config } = await import("../config.js");
|
|
112
|
+
const project = await getProject(projectId);
|
|
113
|
+
const workspacePath = project?.path ?? config.workspacePath;
|
|
114
|
+
// If archived=true, list archived sessions
|
|
115
|
+
if (archived === "true") {
|
|
116
|
+
const archivedSessions = await listArchivedSessions(projectId, workspacePath);
|
|
117
|
+
const sessions = await Promise.all(archivedSessions.map(async (s) => ({
|
|
118
|
+
sessionId: s.sessionId,
|
|
119
|
+
projectId: s.projectId,
|
|
120
|
+
isLive: s.isLive,
|
|
121
|
+
name: s.name,
|
|
122
|
+
createdAt: s.createdAt.toISOString(),
|
|
123
|
+
lastActivityAt: s.lastActivityAt.toISOString(),
|
|
124
|
+
messageCount: s.messageCount,
|
|
125
|
+
supervisorId: (await getSupervisorIdForWorker(s.sessionId)) ?? undefined,
|
|
126
|
+
})));
|
|
127
|
+
return { sessions };
|
|
128
|
+
}
|
|
129
|
+
// Unified view: live + disk sessions for this project
|
|
130
|
+
const unified = await listSessionsForProject(projectId, workspacePath);
|
|
131
|
+
const unifiedSessions = await Promise.all(unified.map(async (s) => ({
|
|
132
|
+
sessionId: s.sessionId,
|
|
133
|
+
projectId: s.projectId,
|
|
134
|
+
isLive: s.isLive,
|
|
135
|
+
name: s.name,
|
|
136
|
+
createdAt: s.createdAt.toISOString(),
|
|
137
|
+
lastActivityAt: s.lastActivityAt.toISOString(),
|
|
138
|
+
messageCount: s.messageCount,
|
|
139
|
+
supervisorId: (await getSupervisorIdForWorker(s.sessionId)) ?? undefined,
|
|
140
|
+
})));
|
|
141
|
+
return { sessions: unifiedSessions };
|
|
142
|
+
}
|
|
143
|
+
// Backward compat: only live sessions
|
|
144
|
+
const liveSessions = listSessions();
|
|
145
|
+
const liveWithSupervisors = await Promise.all(liveSessions.map(async (s) => ({
|
|
146
|
+
sessionId: s.sessionId,
|
|
147
|
+
projectId: s.projectId,
|
|
148
|
+
isLive: true,
|
|
149
|
+
name: s.name ?? s.session.sessionName,
|
|
150
|
+
createdAt: s.createdAt.toISOString(),
|
|
151
|
+
lastActivityAt: s.lastActivityAt.toISOString(),
|
|
152
|
+
messageCount: s.session.messages.length,
|
|
153
|
+
supervisorId: (await getSupervisorIdForWorker(s.sessionId)) ?? undefined,
|
|
154
|
+
})));
|
|
155
|
+
return { sessions: liveWithSupervisors };
|
|
156
|
+
});
|
|
157
|
+
// GET /api/v1/sessions/:id/messages — get messages for a session
|
|
158
|
+
fastify.get("/sessions/:id/messages", {
|
|
159
|
+
schema: {
|
|
160
|
+
description: "Get message history for a session.",
|
|
161
|
+
tags: ["sessions"],
|
|
162
|
+
params: {
|
|
163
|
+
type: "object",
|
|
164
|
+
required: ["id"],
|
|
165
|
+
properties: { id: { type: "string" } },
|
|
166
|
+
},
|
|
167
|
+
response: {
|
|
168
|
+
200: {
|
|
169
|
+
type: "object",
|
|
170
|
+
required: ["messages"],
|
|
171
|
+
properties: {
|
|
172
|
+
messages: { type: "array" },
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
404: {
|
|
176
|
+
type: "object",
|
|
177
|
+
properties: { error: { type: "string" } },
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
}, async (req, reply) => {
|
|
182
|
+
const { SessionManager } = await import("@earendil-works/pi-coding-agent");
|
|
183
|
+
// Try live registry first
|
|
184
|
+
const live = getSession(req.params.id);
|
|
185
|
+
if (live !== undefined) {
|
|
186
|
+
return { messages: live.session.messages };
|
|
187
|
+
}
|
|
188
|
+
// Search for the session file on disk across all projects
|
|
189
|
+
const { readdir } = await import("node:fs/promises");
|
|
190
|
+
const { join } = await import("node:path");
|
|
191
|
+
const { config } = await import("../config.js");
|
|
192
|
+
try {
|
|
193
|
+
const projectDirs = await readdir(config.sessionDir, { withFileTypes: true });
|
|
194
|
+
for (const dir of projectDirs) {
|
|
195
|
+
if (!dir.isDirectory())
|
|
196
|
+
continue;
|
|
197
|
+
const projectDir = join(config.sessionDir, dir.name);
|
|
198
|
+
const files = await readdir(projectDir);
|
|
199
|
+
const matchFile = files.find((f) => f.endsWith(".jsonl") && f.includes(req.params.id));
|
|
200
|
+
if (matchFile) {
|
|
201
|
+
const sessionPath = join(projectDir, matchFile);
|
|
202
|
+
const sm = SessionManager.open(sessionPath);
|
|
203
|
+
const ctx = sm.buildSessionContext();
|
|
204
|
+
return { messages: ctx.messages };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// Session not found on disk either
|
|
210
|
+
}
|
|
211
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
212
|
+
});
|
|
213
|
+
// PATCH /api/v1/sessions/:id/name — rename a session
|
|
214
|
+
fastify.patch("/sessions/:id/name", {
|
|
215
|
+
schema: {
|
|
216
|
+
description: "Rename a session. Persists to disk via SessionManager.appendSessionInfo.",
|
|
217
|
+
tags: ["sessions"],
|
|
218
|
+
params: {
|
|
219
|
+
type: "object",
|
|
220
|
+
required: ["id"],
|
|
221
|
+
properties: { id: { type: "string" } },
|
|
222
|
+
},
|
|
223
|
+
body: {
|
|
224
|
+
type: "object",
|
|
225
|
+
required: ["name"],
|
|
226
|
+
properties: { name: { type: "string", minLength: 1 } },
|
|
227
|
+
},
|
|
228
|
+
response: {
|
|
229
|
+
200: {
|
|
230
|
+
type: "object",
|
|
231
|
+
required: ["renamed"],
|
|
232
|
+
properties: { renamed: { type: "boolean" } },
|
|
233
|
+
},
|
|
234
|
+
404: {
|
|
235
|
+
type: "object",
|
|
236
|
+
properties: { error: { type: "string" } },
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
}, async (req, reply) => {
|
|
241
|
+
const ok = renameSession(req.params.id, req.body.name);
|
|
242
|
+
if (!ok) {
|
|
243
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
244
|
+
}
|
|
245
|
+
return { renamed: true };
|
|
246
|
+
});
|
|
247
|
+
// POST /api/v1/sessions/:id/archive — archive a session (moves JSONL to _archived/)
|
|
248
|
+
fastify.post("/sessions/:id/archive", {
|
|
249
|
+
schema: {
|
|
250
|
+
description: "Archive a session: moves the JSONL file to an _archived/ subfolder " +
|
|
251
|
+
"and removes from the live registry. The session data is preserved " +
|
|
252
|
+
"and can be restored later via POST /sessions/:id/unarchive. " +
|
|
253
|
+
"For disk-only sessions, provide { projectId } in the body.",
|
|
254
|
+
tags: ["sessions"],
|
|
255
|
+
params: {
|
|
256
|
+
type: "object",
|
|
257
|
+
required: ["id"],
|
|
258
|
+
properties: { id: { type: "string" } },
|
|
259
|
+
},
|
|
260
|
+
body: {
|
|
261
|
+
type: "object",
|
|
262
|
+
properties: { projectId: { type: "string" } },
|
|
263
|
+
},
|
|
264
|
+
response: {
|
|
265
|
+
200: {
|
|
266
|
+
type: "object",
|
|
267
|
+
required: ["archived"],
|
|
268
|
+
properties: { archived: { type: "boolean" } },
|
|
269
|
+
},
|
|
270
|
+
404: {
|
|
271
|
+
type: "object",
|
|
272
|
+
properties: { error: { type: "string" } },
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
}, async (req, reply) => {
|
|
277
|
+
const projectId = req.body?.projectId;
|
|
278
|
+
const archived = await archiveSession(req.params.id, projectId);
|
|
279
|
+
if (!archived) {
|
|
280
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
281
|
+
}
|
|
282
|
+
return { archived: true };
|
|
283
|
+
});
|
|
284
|
+
// POST /api/v1/sessions/:id/unarchive — restore an archived session
|
|
285
|
+
fastify.post("/sessions/:id/unarchive", {
|
|
286
|
+
schema: {
|
|
287
|
+
description: "Restore an archived session: moves the JSONL file back from " +
|
|
288
|
+
"_archived/ to the main session directory. The session will appear " +
|
|
289
|
+
"again on the next SSE connect or page refresh.",
|
|
290
|
+
tags: ["sessions"],
|
|
291
|
+
params: {
|
|
292
|
+
type: "object",
|
|
293
|
+
required: ["id"],
|
|
294
|
+
properties: { id: { type: "string" } },
|
|
295
|
+
},
|
|
296
|
+
body: {
|
|
297
|
+
type: "object",
|
|
298
|
+
required: ["projectId"],
|
|
299
|
+
properties: { projectId: { type: "string" } },
|
|
300
|
+
},
|
|
301
|
+
response: {
|
|
302
|
+
200: {
|
|
303
|
+
type: "object",
|
|
304
|
+
required: ["unarchived"],
|
|
305
|
+
properties: { unarchived: { type: "boolean" } },
|
|
306
|
+
},
|
|
307
|
+
404: {
|
|
308
|
+
type: "object",
|
|
309
|
+
properties: { error: { type: "string" } },
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
}, async (req, reply) => {
|
|
314
|
+
const unarchived = await unarchiveSession(req.params.id, req.body.projectId);
|
|
315
|
+
if (!unarchived) {
|
|
316
|
+
return reply.code(404).send({ error: "archived_session_not_found" });
|
|
317
|
+
}
|
|
318
|
+
return { unarchived: true };
|
|
319
|
+
});
|
|
320
|
+
// DELETE /api/v1/sessions/:id — dispose a session (remove from registry)
|
|
321
|
+
fastify.delete("/sessions/:id", {
|
|
322
|
+
schema: {
|
|
323
|
+
description: "Dispose a session (remove from registry). The JSONL file stays on disk.",
|
|
324
|
+
tags: ["sessions"],
|
|
325
|
+
params: {
|
|
326
|
+
type: "object",
|
|
327
|
+
required: ["id"],
|
|
328
|
+
properties: { id: { type: "string" } },
|
|
329
|
+
},
|
|
330
|
+
response: {
|
|
331
|
+
200: {
|
|
332
|
+
type: "object",
|
|
333
|
+
required: ["disposed"],
|
|
334
|
+
properties: { disposed: { type: "boolean" } },
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
}, async (req) => {
|
|
339
|
+
const sessionId = req.params.id;
|
|
340
|
+
const disposed = await disposeSession(sessionId);
|
|
341
|
+
// Fire worker.deleted if this session was an orchestration worker
|
|
342
|
+
void bridgeWorkerDeleted(sessionId, { wasLive: disposed }).catch(() => undefined);
|
|
343
|
+
return { disposed };
|
|
344
|
+
});
|
|
345
|
+
// ── Session Tree ──
|
|
346
|
+
// GET /sessions/:id/tree — branching history, lazy-resumes cold sessions
|
|
347
|
+
fastify.get("/sessions/:id/tree", {
|
|
348
|
+
schema: {
|
|
349
|
+
description: "Branching history of the session. Returns every entry on the " +
|
|
350
|
+
"tree (across all branches) plus the current leaf id and the " +
|
|
351
|
+
"set of entry ids on the active branch path. Lazy-resumes cold " +
|
|
352
|
+
"sessions on demand.",
|
|
353
|
+
tags: ["sessions"],
|
|
354
|
+
params: {
|
|
355
|
+
type: "object",
|
|
356
|
+
required: ["id"],
|
|
357
|
+
properties: { id: { type: "string" } },
|
|
358
|
+
},
|
|
359
|
+
response: {
|
|
360
|
+
200: {
|
|
361
|
+
type: "object",
|
|
362
|
+
required: ["leafId", "branchIds", "entries"],
|
|
363
|
+
properties: {
|
|
364
|
+
leafId: { type: ["string", "null"] },
|
|
365
|
+
branchIds: { type: "array", items: { type: "string" } },
|
|
366
|
+
entries: {
|
|
367
|
+
type: "array",
|
|
368
|
+
items: {
|
|
369
|
+
type: "object",
|
|
370
|
+
required: ["id", "parentId", "type", "timestamp"],
|
|
371
|
+
properties: {
|
|
372
|
+
id: { type: "string" },
|
|
373
|
+
parentId: { type: ["string", "null"] },
|
|
374
|
+
type: { type: "string" },
|
|
375
|
+
timestamp: { type: "string" },
|
|
376
|
+
role: { type: "string" },
|
|
377
|
+
preview: { type: "string" },
|
|
378
|
+
label: { type: "string" },
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
404: {
|
|
385
|
+
type: "object",
|
|
386
|
+
properties: { error: { type: "string" } },
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
}, async (req, reply) => {
|
|
391
|
+
let live = getSession(req.params.id);
|
|
392
|
+
if (live === undefined) {
|
|
393
|
+
try {
|
|
394
|
+
live = await resumeSessionById(req.params.id);
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
const sm = live.sessionManager;
|
|
401
|
+
const all = sm.getEntries();
|
|
402
|
+
const leafId = sm.getLeafId();
|
|
403
|
+
const branchIds = sm.getBranch().map((e) => e.id);
|
|
404
|
+
const entries = all.map((e) => {
|
|
405
|
+
const out = {
|
|
406
|
+
id: e.id,
|
|
407
|
+
parentId: e.parentId,
|
|
408
|
+
type: e.type,
|
|
409
|
+
timestamp: e.timestamp,
|
|
410
|
+
};
|
|
411
|
+
const label = sm.getLabel(e.id);
|
|
412
|
+
if (label !== undefined)
|
|
413
|
+
out.label = label;
|
|
414
|
+
if (e.type === "message" && e.message !== undefined) {
|
|
415
|
+
const m = e.message;
|
|
416
|
+
if (typeof m.role === "string")
|
|
417
|
+
out.role = m.role;
|
|
418
|
+
const preview = previewOfMessageContent(m.content);
|
|
419
|
+
if (preview !== undefined)
|
|
420
|
+
out.preview = preview;
|
|
421
|
+
}
|
|
422
|
+
return out;
|
|
423
|
+
});
|
|
424
|
+
return { leafId, branchIds, entries };
|
|
425
|
+
});
|
|
426
|
+
// ── Session Navigate ──
|
|
427
|
+
// POST /sessions/:id/navigate — navigate to a different tree leaf
|
|
428
|
+
fastify.post("/sessions/:id/navigate", {
|
|
429
|
+
schema: {
|
|
430
|
+
description: "Navigate the session leaf to a different entry on its tree. " +
|
|
431
|
+
"Operates IN-PLACE on the same session file (unlike fork which " +
|
|
432
|
+
"creates a new file). Session must be live.",
|
|
433
|
+
tags: ["sessions"],
|
|
434
|
+
params: {
|
|
435
|
+
type: "object",
|
|
436
|
+
required: ["id"],
|
|
437
|
+
properties: { id: { type: "string" } },
|
|
438
|
+
},
|
|
439
|
+
body: {
|
|
440
|
+
type: "object",
|
|
441
|
+
required: ["entryId"],
|
|
442
|
+
properties: {
|
|
443
|
+
entryId: { type: "string" },
|
|
444
|
+
summarize: { type: "boolean" },
|
|
445
|
+
customInstructions: { type: "string" },
|
|
446
|
+
label: { type: "string" },
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
response: {
|
|
450
|
+
200: {
|
|
451
|
+
type: "object",
|
|
452
|
+
required: ["cancelled"],
|
|
453
|
+
properties: {
|
|
454
|
+
cancelled: { type: "boolean" },
|
|
455
|
+
aborted: { type: "boolean" },
|
|
456
|
+
editorText: { type: "string" },
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
404: {
|
|
460
|
+
type: "object",
|
|
461
|
+
properties: { error: { type: "string" } },
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
}, async (req, reply) => {
|
|
466
|
+
const live = getSession(req.params.id);
|
|
467
|
+
if (live === undefined) {
|
|
468
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
469
|
+
}
|
|
470
|
+
const opts = {};
|
|
471
|
+
if (req.body.summarize !== undefined)
|
|
472
|
+
opts.summarize = req.body.summarize;
|
|
473
|
+
if (req.body.customInstructions !== undefined)
|
|
474
|
+
opts.customInstructions = req.body.customInstructions;
|
|
475
|
+
if (req.body.label !== undefined)
|
|
476
|
+
opts.label = req.body.label;
|
|
477
|
+
try {
|
|
478
|
+
const result = await live.session.navigateTree(req.body.entryId, opts);
|
|
479
|
+
const out = { cancelled: result.cancelled };
|
|
480
|
+
if (result.aborted !== undefined)
|
|
481
|
+
out.aborted = result.aborted;
|
|
482
|
+
if (result.editorText !== undefined)
|
|
483
|
+
out.editorText = result.editorText;
|
|
484
|
+
// Emit snapshot to all connected SSE clients so the chat UI
|
|
485
|
+
// reflects the new session leaf without a client-triggered refetch.
|
|
486
|
+
for (const client of live.clients) {
|
|
487
|
+
try {
|
|
488
|
+
client.send(buildSnapshot(live));
|
|
489
|
+
}
|
|
490
|
+
catch {
|
|
491
|
+
live.clients.delete(client);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return out;
|
|
495
|
+
}
|
|
496
|
+
catch (err) {
|
|
497
|
+
return reply.code(400).send({ error: "navigate_failed", message: err instanceof Error ? err.message : String(err) });
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
// ── Session Fork ──
|
|
501
|
+
// POST /sessions/:id/fork — fork into a new session
|
|
502
|
+
fastify.post("/sessions/:id/fork", {
|
|
503
|
+
schema: {
|
|
504
|
+
description: "Create a new session from an entry on the current session's " +
|
|
505
|
+
"tree. Writes a new .jsonl file containing the path-to-leaf and " +
|
|
506
|
+
"registers it as a fresh live session in the same project. The " +
|
|
507
|
+
"source session is left live and untouched.",
|
|
508
|
+
tags: ["sessions"],
|
|
509
|
+
params: {
|
|
510
|
+
type: "object",
|
|
511
|
+
required: ["id"],
|
|
512
|
+
properties: { id: { type: "string" } },
|
|
513
|
+
},
|
|
514
|
+
body: {
|
|
515
|
+
type: "object",
|
|
516
|
+
required: ["entryId"],
|
|
517
|
+
properties: { entryId: { type: "string" } },
|
|
518
|
+
},
|
|
519
|
+
response: {
|
|
520
|
+
201: {
|
|
521
|
+
type: "object",
|
|
522
|
+
required: ["sessionId", "projectId"],
|
|
523
|
+
properties: {
|
|
524
|
+
sessionId: { type: "string" },
|
|
525
|
+
projectId: { type: "string" },
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
400: {
|
|
529
|
+
type: "object",
|
|
530
|
+
properties: { error: { type: "string" } },
|
|
531
|
+
},
|
|
532
|
+
404: {
|
|
533
|
+
type: "object",
|
|
534
|
+
properties: { error: { type: "string" } },
|
|
535
|
+
},
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
}, async (req, reply) => {
|
|
539
|
+
try {
|
|
540
|
+
const forked = await forkSession(req.params.id, req.body.entryId);
|
|
541
|
+
return reply.code(201).send({
|
|
542
|
+
sessionId: forked.sessionId,
|
|
543
|
+
projectId: forked.projectId,
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
catch (err) {
|
|
547
|
+
if (err instanceof Error && err.message?.startsWith("session_not_found")) {
|
|
548
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
549
|
+
}
|
|
550
|
+
return reply.code(400).send({ error: "fork_failed", message: err instanceof Error ? err.message : String(err) });
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
// GET /api/v1/sessions/:id/context — context usage telemetry + session stats
|
|
554
|
+
fastify.get("/sessions/:id/context", {
|
|
555
|
+
schema: {
|
|
556
|
+
description: "Get context usage telemetry and session statistics.",
|
|
557
|
+
tags: ["sessions"],
|
|
558
|
+
params: {
|
|
559
|
+
type: "object",
|
|
560
|
+
required: ["id"],
|
|
561
|
+
properties: { id: { type: "string" } },
|
|
562
|
+
},
|
|
563
|
+
response: {
|
|
564
|
+
200: {
|
|
565
|
+
type: "object",
|
|
566
|
+
properties: {
|
|
567
|
+
contextUsage: {
|
|
568
|
+
type: "object",
|
|
569
|
+
properties: {
|
|
570
|
+
contextWindow: { type: "number" },
|
|
571
|
+
tokens: { type: "number", nullable: true },
|
|
572
|
+
percent: { type: "number", nullable: true },
|
|
573
|
+
},
|
|
574
|
+
},
|
|
575
|
+
stats: {
|
|
576
|
+
type: "object",
|
|
577
|
+
properties: {
|
|
578
|
+
userMessages: { type: "number" },
|
|
579
|
+
assistantMessages: { type: "number" },
|
|
580
|
+
toolCalls: { type: "number" },
|
|
581
|
+
toolResults: { type: "number" },
|
|
582
|
+
totalMessages: { type: "number" },
|
|
583
|
+
tokens: {
|
|
584
|
+
type: "object",
|
|
585
|
+
properties: {
|
|
586
|
+
input: { type: "number" },
|
|
587
|
+
output: { type: "number" },
|
|
588
|
+
cacheRead: { type: "number" },
|
|
589
|
+
cacheWrite: { type: "number" },
|
|
590
|
+
total: { type: "number" },
|
|
591
|
+
},
|
|
592
|
+
},
|
|
593
|
+
cost: { type: "number" },
|
|
594
|
+
},
|
|
595
|
+
},
|
|
596
|
+
},
|
|
597
|
+
},
|
|
598
|
+
404: {
|
|
599
|
+
type: "object",
|
|
600
|
+
properties: { error: { type: "string" } },
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
}, async (req, reply) => {
|
|
605
|
+
const live = getSession(req.params.id);
|
|
606
|
+
if (live === undefined) {
|
|
607
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
608
|
+
}
|
|
609
|
+
const usage = live.session.getContextUsage();
|
|
610
|
+
const stats = live.session.getSessionStats();
|
|
611
|
+
return { contextUsage: usage ?? null, stats };
|
|
612
|
+
});
|
|
613
|
+
// ── GET /sessions/:id/compactions — compaction history ──────────
|
|
614
|
+
// Returns the per-compaction archive that the SDK strips out of
|
|
615
|
+
// `live.session.messages` after each compact() call, so the chat
|
|
616
|
+
// view can render a "compacted N messages → Y tokens" card at each
|
|
617
|
+
// compaction point with the archived messages one click away.
|
|
618
|
+
// Server-side derivation keeps the entry-id arithmetic out of the
|
|
619
|
+
// client. See packages/server/src/compaction-cards.ts for the
|
|
620
|
+
// shape contract.
|
|
621
|
+
fastify.get("/sessions/:id/compactions", {
|
|
622
|
+
schema: {
|
|
623
|
+
description: "Per-compaction archive for the live session. Each entry " +
|
|
624
|
+
"carries the SDK-generated summary, the pre-compaction " +
|
|
625
|
+
"token count, and the AgentMessage[] that was archived (no " +
|
|
626
|
+
"longer in the LLM's context window). `insertBeforeIndex` " +
|
|
627
|
+
"tells the client where to splice a card into the post-" +
|
|
628
|
+
"compaction `messages` array.",
|
|
629
|
+
tags: ["sessions"],
|
|
630
|
+
params: {
|
|
631
|
+
type: "object",
|
|
632
|
+
required: ["id"],
|
|
633
|
+
properties: { id: { type: "string" } },
|
|
634
|
+
},
|
|
635
|
+
response: {
|
|
636
|
+
200: {
|
|
637
|
+
type: "object",
|
|
638
|
+
required: ["compactions"],
|
|
639
|
+
properties: {
|
|
640
|
+
compactions: {
|
|
641
|
+
type: "array",
|
|
642
|
+
items: {
|
|
643
|
+
type: "object",
|
|
644
|
+
required: [
|
|
645
|
+
"id",
|
|
646
|
+
"timestamp",
|
|
647
|
+
"summary",
|
|
648
|
+
"tokensBefore",
|
|
649
|
+
"insertBeforeIndex",
|
|
650
|
+
"archivedMessages",
|
|
651
|
+
],
|
|
652
|
+
properties: {
|
|
653
|
+
id: { type: "string" },
|
|
654
|
+
timestamp: { type: "string" },
|
|
655
|
+
summary: { type: "string" },
|
|
656
|
+
tokensBefore: { type: "integer" },
|
|
657
|
+
insertBeforeIndex: { type: "integer" },
|
|
658
|
+
archivedMessages: { type: "array" },
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
},
|
|
662
|
+
},
|
|
663
|
+
},
|
|
664
|
+
404: {
|
|
665
|
+
type: "object",
|
|
666
|
+
properties: { error: { type: "string" } },
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
}, async (req, reply) => {
|
|
671
|
+
const live = getSession(req.params.id);
|
|
672
|
+
if (live === undefined) {
|
|
673
|
+
return reply.code(404).send({ error: "session_not_found" });
|
|
674
|
+
}
|
|
675
|
+
return { compactions: buildCompactionHistory(live.session) };
|
|
676
|
+
});
|
|
677
|
+
};
|
|
678
|
+
/**
|
|
679
|
+
* Truncated text preview of a message's content for the session tree.
|
|
680
|
+
*/
|
|
681
|
+
const PREVIEW_MAX_CHARS = 200;
|
|
682
|
+
function previewOfMessageContent(content) {
|
|
683
|
+
let text;
|
|
684
|
+
if (typeof content === "string") {
|
|
685
|
+
text = content;
|
|
686
|
+
}
|
|
687
|
+
else if (Array.isArray(content)) {
|
|
688
|
+
const parts = [];
|
|
689
|
+
for (const c of content) {
|
|
690
|
+
const o = c;
|
|
691
|
+
if (o.type === "text" && typeof o.text === "string")
|
|
692
|
+
parts.push(o.text);
|
|
693
|
+
}
|
|
694
|
+
text = parts.join("\n");
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
return undefined;
|
|
698
|
+
}
|
|
699
|
+
text = text.trim();
|
|
700
|
+
if (text.length === 0)
|
|
701
|
+
return undefined;
|
|
702
|
+
if (text.length <= PREVIEW_MAX_CHARS)
|
|
703
|
+
return text;
|
|
704
|
+
return text.slice(0, PREVIEW_MAX_CHARS - 1) + "…";
|
|
705
|
+
}
|
|
706
|
+
//# sourceMappingURL=sessions.js.map
|