@vibedeckx/linux-x64 0.1.10
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/dist/agent-provider.d.ts +92 -0
- package/dist/agent-provider.js +8 -0
- package/dist/agent-session-manager.d.ts +165 -0
- package/dist/agent-session-manager.js +985 -0
- package/dist/agent-types.d.ts +148 -0
- package/dist/agent-types.js +4 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +4 -0
- package/dist/browser-manager.d.ts +46 -0
- package/dist/browser-manager.js +182 -0
- package/dist/chat-session-manager.d.ts +101 -0
- package/dist/chat-session-manager.js +1425 -0
- package/dist/command.d.ts +1 -0
- package/dist/command.js +163 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.js +5 -0
- package/dist/conversation-patch.d.ts +103 -0
- package/dist/conversation-patch.js +69 -0
- package/dist/dialog.d.ts +1 -0
- package/dist/dialog.js +41 -0
- package/dist/entry-index-provider.d.ts +74 -0
- package/dist/entry-index-provider.js +105 -0
- package/dist/event-bus.d.ts +47 -0
- package/dist/event-bus.js +16 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/plugins/shared-services.d.ts +8 -0
- package/dist/plugins/shared-services.js +65 -0
- package/dist/process-manager.d.ts +146 -0
- package/dist/process-manager.js +779 -0
- package/dist/providers/claude-code-provider.d.ts +13 -0
- package/dist/providers/claude-code-provider.js +127 -0
- package/dist/providers/codex-provider.d.ts +41 -0
- package/dist/providers/codex-provider.js +354 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.js +19 -0
- package/dist/remote-patch-cache.d.ts +67 -0
- package/dist/remote-patch-cache.js +190 -0
- package/dist/reverse-connect-client.d.ts +27 -0
- package/dist/reverse-connect-client.js +255 -0
- package/dist/reverse-connect-manager.d.ts +31 -0
- package/dist/reverse-connect-manager.js +287 -0
- package/dist/reverse-connect-types.d.ts +55 -0
- package/dist/reverse-connect-types.js +7 -0
- package/dist/routes/agent-session-routes.d.ts +4 -0
- package/dist/routes/agent-session-routes.js +442 -0
- package/dist/routes/browser-proxy-routes.d.ts +25 -0
- package/dist/routes/browser-proxy-routes.js +421 -0
- package/dist/routes/browser-routes.d.ts +4 -0
- package/dist/routes/browser-routes.js +73 -0
- package/dist/routes/chat-session-routes.d.ts +7 -0
- package/dist/routes/chat-session-routes.js +69 -0
- package/dist/routes/diff-routes.d.ts +4 -0
- package/dist/routes/diff-routes.js +208 -0
- package/dist/routes/event-routes.d.ts +4 -0
- package/dist/routes/event-routes.js +52 -0
- package/dist/routes/executor-group-routes.d.ts +4 -0
- package/dist/routes/executor-group-routes.js +76 -0
- package/dist/routes/executor-routes.d.ts +4 -0
- package/dist/routes/executor-routes.js +106 -0
- package/dist/routes/file-routes.d.ts +4 -0
- package/dist/routes/file-routes.js +331 -0
- package/dist/routes/process-routes.d.ts +4 -0
- package/dist/routes/process-routes.js +183 -0
- package/dist/routes/project-remote-routes.d.ts +4 -0
- package/dist/routes/project-remote-routes.js +82 -0
- package/dist/routes/project-routes.d.ts +4 -0
- package/dist/routes/project-routes.js +286 -0
- package/dist/routes/remote-routes.d.ts +4 -0
- package/dist/routes/remote-routes.js +59 -0
- package/dist/routes/remote-server-routes.d.ts +4 -0
- package/dist/routes/remote-server-routes.js +157 -0
- package/dist/routes/reverse-connect-routes.d.ts +4 -0
- package/dist/routes/reverse-connect-routes.js +33 -0
- package/dist/routes/settings-routes.d.ts +4 -0
- package/dist/routes/settings-routes.js +129 -0
- package/dist/routes/task-routes.d.ts +4 -0
- package/dist/routes/task-routes.js +107 -0
- package/dist/routes/terminal-routes.d.ts +4 -0
- package/dist/routes/terminal-routes.js +187 -0
- package/dist/routes/translate-routes.d.ts +4 -0
- package/dist/routes/translate-routes.js +38 -0
- package/dist/routes/websocket-routes.d.ts +4 -0
- package/dist/routes/websocket-routes.js +604 -0
- package/dist/routes/worktree-routes.d.ts +4 -0
- package/dist/routes/worktree-routes.js +511 -0
- package/dist/server-types.d.ts +41 -0
- package/dist/server-types.js +1 -0
- package/dist/server.d.ts +23 -0
- package/dist/server.js +238 -0
- package/dist/storage/sqlite.d.ts +2 -0
- package/dist/storage/sqlite.js +1073 -0
- package/dist/storage/types.d.ts +281 -0
- package/dist/storage/types.js +1 -0
- package/dist/ui/404/index.html +1 -0
- package/dist/ui/404.html +1 -0
- package/dist/ui/__next.__PAGE__.txt +10 -0
- package/dist/ui/__next._full.txt +25 -0
- package/dist/ui/__next._head.txt +6 -0
- package/dist/ui/__next._index.txt +9 -0
- package/dist/ui/__next._tree.txt +6 -0
- package/dist/ui/_next/static/7vIIuOQPJu8rdb6uAhwtg/_buildManifest.js +11 -0
- package/dist/ui/_next/static/7vIIuOQPJu8rdb6uAhwtg/_clientMiddlewareManifest.json +1 -0
- package/dist/ui/_next/static/7vIIuOQPJu8rdb6uAhwtg/_ssgManifest.js +1 -0
- package/dist/ui/_next/static/chunks/002f5a047b8d07d4.js +1 -0
- package/dist/ui/_next/static/chunks/01178e167ba3e5b4.js +1 -0
- package/dist/ui/_next/static/chunks/020d675d21be28d4.js +1 -0
- package/dist/ui/_next/static/chunks/024926197424b4a5.js +1 -0
- package/dist/ui/_next/static/chunks/02c93f6ca211a65d.js +1 -0
- package/dist/ui/_next/static/chunks/0364437dee56dc96.js +1 -0
- package/dist/ui/_next/static/chunks/03fc6b527b16efdc.js +1 -0
- package/dist/ui/_next/static/chunks/04f9a7932751cf2d.js +1 -0
- package/dist/ui/_next/static/chunks/0624b8204e5ae457.js +136 -0
- package/dist/ui/_next/static/chunks/067d8978cf41b901.js +1 -0
- package/dist/ui/_next/static/chunks/06d96238e85cdbb3.js +1 -0
- package/dist/ui/_next/static/chunks/071b9575dbdf1dcb.js +1 -0
- package/dist/ui/_next/static/chunks/073d5b9dc87ceab0.js +1 -0
- package/dist/ui/_next/static/chunks/0876a7111934d6f7.js +1 -0
- package/dist/ui/_next/static/chunks/08ffc3bf406c665d.js +1 -0
- package/dist/ui/_next/static/chunks/0969e8274c92c2d8.js +1 -0
- package/dist/ui/_next/static/chunks/0a3f62f00d7bec78.js +1 -0
- package/dist/ui/_next/static/chunks/0b80166023d89049.js +5 -0
- package/dist/ui/_next/static/chunks/0c2a941e61c395b6.js +1 -0
- package/dist/ui/_next/static/chunks/0c5eac8493334420.js +1 -0
- package/dist/ui/_next/static/chunks/0cc61d37b2333469.js +1 -0
- package/dist/ui/_next/static/chunks/0d440843348b2871.js +1 -0
- package/dist/ui/_next/static/chunks/0da3d15845f17208.js +1 -0
- package/dist/ui/_next/static/chunks/0e1982b1a6cbd127.js +53 -0
- package/dist/ui/_next/static/chunks/0e81d5bc1c725b75.js +1 -0
- package/dist/ui/_next/static/chunks/0e862e51b01e904b.js +63 -0
- package/dist/ui/_next/static/chunks/0ed7b6d86744b723.js +1 -0
- package/dist/ui/_next/static/chunks/0f0b3025f4e268b1.js +1 -0
- package/dist/ui/_next/static/chunks/10a30eb52825da36.js +1 -0
- package/dist/ui/_next/static/chunks/10c48da576fd8eef.js +1 -0
- package/dist/ui/_next/static/chunks/133e9f1435ca5f45.js +29 -0
- package/dist/ui/_next/static/chunks/16f4db3a54f167fd.js +1 -0
- package/dist/ui/_next/static/chunks/1988e3ecf5ad06d3.js +1 -0
- package/dist/ui/_next/static/chunks/1acfae010fd77014.js +152 -0
- package/dist/ui/_next/static/chunks/1ae53c2f1fff8cc2.js +1 -0
- package/dist/ui/_next/static/chunks/1af4fbc6c1256fae.js +1 -0
- package/dist/ui/_next/static/chunks/1b758c732032b236.js +1 -0
- package/dist/ui/_next/static/chunks/1ba26455a9f70c08.js +1 -0
- package/dist/ui/_next/static/chunks/1d22644cb4049d6b.css +1 -0
- package/dist/ui/_next/static/chunks/1d241f3b57c14cf7.js +1 -0
- package/dist/ui/_next/static/chunks/1d640bbe1c2c7869.js +1 -0
- package/dist/ui/_next/static/chunks/1da6354c9cb6f0de.js +1 -0
- package/dist/ui/_next/static/chunks/1dcd49914412f67b.js +1 -0
- package/dist/ui/_next/static/chunks/1e3b3771294825a4.js +1 -0
- package/dist/ui/_next/static/chunks/1eaa8ad7eca7f957.js +1 -0
- package/dist/ui/_next/static/chunks/1ebc88f60cadb128.js +1 -0
- package/dist/ui/_next/static/chunks/1ecb57b258088259.js +1 -0
- package/dist/ui/_next/static/chunks/1f5ba6b80fe19200.js +1 -0
- package/dist/ui/_next/static/chunks/20a5531534828366.js +1 -0
- package/dist/ui/_next/static/chunks/20b511fc299dfe9a.js +1 -0
- package/dist/ui/_next/static/chunks/20bff4eb9a0a6872.css +1 -0
- package/dist/ui/_next/static/chunks/219b7d9e437c6bd8.js +15 -0
- package/dist/ui/_next/static/chunks/21b32f530e0df2c5.js +1 -0
- package/dist/ui/_next/static/chunks/21fc6dc60e7647b1.js +1 -0
- package/dist/ui/_next/static/chunks/221a27e65aa5fbfd.js +1 -0
- package/dist/ui/_next/static/chunks/23a1e247c32bcc61.js +93 -0
- package/dist/ui/_next/static/chunks/2473c16c0c2f6b5f.css +2 -0
- package/dist/ui/_next/static/chunks/2615c71c0f8fe9bd.js +1 -0
- package/dist/ui/_next/static/chunks/263327288d5e2703.js +1 -0
- package/dist/ui/_next/static/chunks/2663fbaf43239e38.js +1 -0
- package/dist/ui/_next/static/chunks/27332c590d59f4e5.js +1 -0
- package/dist/ui/_next/static/chunks/27ca4a4e8191093f.js +1 -0
- package/dist/ui/_next/static/chunks/29b7618dcaa8edba.js +1 -0
- package/dist/ui/_next/static/chunks/2ba1d2b55b82f4da.js +21 -0
- package/dist/ui/_next/static/chunks/2cb23686e72468c8.js +1 -0
- package/dist/ui/_next/static/chunks/2d46f05dcbf1cbc2.js +1 -0
- package/dist/ui/_next/static/chunks/2d4c0fd06ca34510.js +2 -0
- package/dist/ui/_next/static/chunks/2f3d1d07474b8f79.js +1 -0
- package/dist/ui/_next/static/chunks/2f85c2849249a0dd.js +1 -0
- package/dist/ui/_next/static/chunks/3001d378f166eec9.js +1 -0
- package/dist/ui/_next/static/chunks/3018714f3827e360.js +1 -0
- package/dist/ui/_next/static/chunks/301cc25e0d489351.js +1 -0
- package/dist/ui/_next/static/chunks/305242b22ba8b49b.js +1 -0
- package/dist/ui/_next/static/chunks/3067c6e369066bd6.js +1 -0
- package/dist/ui/_next/static/chunks/311a77c9d5cb9de9.js +1 -0
- package/dist/ui/_next/static/chunks/320c001380e81470.js +1 -0
- package/dist/ui/_next/static/chunks/329db6c551df0faf.js +1 -0
- package/dist/ui/_next/static/chunks/33da178724072b3d.js +1 -0
- package/dist/ui/_next/static/chunks/33e8248c9296537a.js +1 -0
- package/dist/ui/_next/static/chunks/35a9992a8958f93b.js +1 -0
- package/dist/ui/_next/static/chunks/35bb90cf09892b72.js +1 -0
- package/dist/ui/_next/static/chunks/379f91b92366dc15.js +1 -0
- package/dist/ui/_next/static/chunks/391f22359769763f.js +1 -0
- package/dist/ui/_next/static/chunks/39231cb1044f7823.js +1 -0
- package/dist/ui/_next/static/chunks/394e8b7a1c2c58c6.js +1 -0
- package/dist/ui/_next/static/chunks/3a2cfdeb5f76ebd2.js +1 -0
- package/dist/ui/_next/static/chunks/3a3bd015fd042386.js +1 -0
- package/dist/ui/_next/static/chunks/3ad1bee238af9b5a.js +1 -0
- package/dist/ui/_next/static/chunks/3b2b2f7a9b7b130d.js +1 -0
- package/dist/ui/_next/static/chunks/3b586f80547e3a22.js +1 -0
- package/dist/ui/_next/static/chunks/3ca412e72bd3707a.js +1 -0
- package/dist/ui/_next/static/chunks/3cbb3bdceb4230af.js +1 -0
- package/dist/ui/_next/static/chunks/3ed1465109fecc2d.js +1 -0
- package/dist/ui/_next/static/chunks/3fd0801238b3b099.js +1 -0
- package/dist/ui/_next/static/chunks/401df66bd5da2115.js +15 -0
- package/dist/ui/_next/static/chunks/4211f4efe510f7ac.js +1 -0
- package/dist/ui/_next/static/chunks/43085364d0a41d1d.js +1 -0
- package/dist/ui/_next/static/chunks/4310c821dbee7a16.js +1 -0
- package/dist/ui/_next/static/chunks/46382f31f63e59cf.js +1 -0
- package/dist/ui/_next/static/chunks/468836b90ddf24d6.js +1 -0
- package/dist/ui/_next/static/chunks/470d091143104517.js +1 -0
- package/dist/ui/_next/static/chunks/4712e4f7e6b6ddc1.js +1 -0
- package/dist/ui/_next/static/chunks/4899f1e3f21c077e.js +1 -0
- package/dist/ui/_next/static/chunks/492ce6930bf61811.js +1 -0
- package/dist/ui/_next/static/chunks/494485a20952ffa3.js +1 -0
- package/dist/ui/_next/static/chunks/49535db309898f43.js +1 -0
- package/dist/ui/_next/static/chunks/4b8d2612d69e2013.js +1 -0
- package/dist/ui/_next/static/chunks/4c4a0f67891826a3.js +1 -0
- package/dist/ui/_next/static/chunks/4cc11ce32f4453b0.js +1 -0
- package/dist/ui/_next/static/chunks/4d03a0bc963fc3d4.js +1 -0
- package/dist/ui/_next/static/chunks/4d603a66c067134e.js +1 -0
- package/dist/ui/_next/static/chunks/4d8d7e62c2743f71.js +15 -0
- package/dist/ui/_next/static/chunks/4da42f10a5460b36.js +1 -0
- package/dist/ui/_next/static/chunks/4e832ffb65e75807.js +1 -0
- package/dist/ui/_next/static/chunks/4e954e1cec89a9ea.js +1 -0
- package/dist/ui/_next/static/chunks/4f2bc7a7a6b05a8b.js +55 -0
- package/dist/ui/_next/static/chunks/4f9c934abf34ceb9.js +1 -0
- package/dist/ui/_next/static/chunks/4fa248b0d2586928.js +1 -0
- package/dist/ui/_next/static/chunks/4fafbac2156844ca.js +1 -0
- package/dist/ui/_next/static/chunks/502039e483cc5e48.js +1 -0
- package/dist/ui/_next/static/chunks/509c91c38224448a.js +1 -0
- package/dist/ui/_next/static/chunks/5159d6f8d4307f36.js +1 -0
- package/dist/ui/_next/static/chunks/5179ab56aaaed42d.js +1 -0
- package/dist/ui/_next/static/chunks/5269ea07faff562d.js +1 -0
- package/dist/ui/_next/static/chunks/529f3f0f7d42444a.js +1 -0
- package/dist/ui/_next/static/chunks/5317db6783ee8dc9.js +1 -0
- package/dist/ui/_next/static/chunks/53a7b7c0ab020902.js +1 -0
- package/dist/ui/_next/static/chunks/544869c670c1dd8e.js +1 -0
- package/dist/ui/_next/static/chunks/547c0db6a433370e.js +1 -0
- package/dist/ui/_next/static/chunks/54d5670f5fa2abbe.css +1 -0
- package/dist/ui/_next/static/chunks/55761e35a8946a1d.js +15 -0
- package/dist/ui/_next/static/chunks/558f73c16b7ff14f.js +1 -0
- package/dist/ui/_next/static/chunks/55c76f605958d671.js +1 -0
- package/dist/ui/_next/static/chunks/55dc6750fb117bf9.js +1 -0
- package/dist/ui/_next/static/chunks/584bad9cf2498405.js +1 -0
- package/dist/ui/_next/static/chunks/593b85b9abea3ea6.js +1 -0
- package/dist/ui/_next/static/chunks/5a79af73c96155d4.js +1 -0
- package/dist/ui/_next/static/chunks/5ee54b9b6b400134.js +1 -0
- package/dist/ui/_next/static/chunks/5f27ee48dc820109.js +1 -0
- package/dist/ui/_next/static/chunks/5ffd50a08d82e2f3.js +1 -0
- package/dist/ui/_next/static/chunks/61d65fe807f69413.js +62 -0
- package/dist/ui/_next/static/chunks/626a650bcaaecdb8.js +1 -0
- package/dist/ui/_next/static/chunks/62baecafed4dbced.js +1 -0
- package/dist/ui/_next/static/chunks/634a4b5b6a38ccab.js +1 -0
- package/dist/ui/_next/static/chunks/643c359cf3f7364e.js +1 -0
- package/dist/ui/_next/static/chunks/649e65f4820a772b.js +1 -0
- package/dist/ui/_next/static/chunks/65028938188a230c.js +1 -0
- package/dist/ui/_next/static/chunks/65b3658348e8d4fd.js +1 -0
- package/dist/ui/_next/static/chunks/65eed220466cbdbc.js +1 -0
- package/dist/ui/_next/static/chunks/66714687cfd91953.js +1 -0
- package/dist/ui/_next/static/chunks/66ccaa3e69ed7a69.js +1 -0
- package/dist/ui/_next/static/chunks/6754600af0c6b3a8.js +1 -0
- package/dist/ui/_next/static/chunks/67a1d37727697340.js +1 -0
- package/dist/ui/_next/static/chunks/67e965a7f9531cee.js +1 -0
- package/dist/ui/_next/static/chunks/6816bf02e4c22a55.js +1 -0
- package/dist/ui/_next/static/chunks/68621b90909ec4e6.js +1 -0
- package/dist/ui/_next/static/chunks/6929ceb718c6e4c6.js +1 -0
- package/dist/ui/_next/static/chunks/69362fff2240a17b.js +1 -0
- package/dist/ui/_next/static/chunks/69dab47a307b1a37.js +1 -0
- package/dist/ui/_next/static/chunks/6afa71c8b3358dd5.js +1 -0
- package/dist/ui/_next/static/chunks/6bf54dc328e667f7.js +1 -0
- package/dist/ui/_next/static/chunks/6c44508faf13f6f0.js +1 -0
- package/dist/ui/_next/static/chunks/6c9c2b61c905a2de.js +1 -0
- package/dist/ui/_next/static/chunks/6cc2e3d7873522b9.js +1 -0
- package/dist/ui/_next/static/chunks/6d01e8902e85bfe0.js +1 -0
- package/dist/ui/_next/static/chunks/6dc69e4a91f7a353.js +1 -0
- package/dist/ui/_next/static/chunks/6e832e016b60ae19.js +1 -0
- package/dist/ui/_next/static/chunks/6eab0d8815c18a6d.js +1 -0
- package/dist/ui/_next/static/chunks/6f862eb588fa3b7e.js +1 -0
- package/dist/ui/_next/static/chunks/6ff7b0a8653036b2.js +1 -0
- package/dist/ui/_next/static/chunks/710ce144a9645f3c.js +1 -0
- package/dist/ui/_next/static/chunks/71293e300c639b6b.js +1 -0
- package/dist/ui/_next/static/chunks/7186d7cce354a012.js +1 -0
- package/dist/ui/_next/static/chunks/7215d586009e8158.js +1 -0
- package/dist/ui/_next/static/chunks/726fdeaff53a89ac.js +1 -0
- package/dist/ui/_next/static/chunks/7322a00d61e7ffad.js +1 -0
- package/dist/ui/_next/static/chunks/73c60ee9f233051d.js +1 -0
- package/dist/ui/_next/static/chunks/740f5627b5c57baa.js +1 -0
- package/dist/ui/_next/static/chunks/74438794a8e9ba80.js +1 -0
- package/dist/ui/_next/static/chunks/74ffcd7d13b3fea0.js +1 -0
- package/dist/ui/_next/static/chunks/7510496048ab1ad4.js +1 -0
- package/dist/ui/_next/static/chunks/7636f89f38cbc3e3.js +1 -0
- package/dist/ui/_next/static/chunks/782a93ec4348b666.js +1 -0
- package/dist/ui/_next/static/chunks/7850bbac1925646c.js +1 -0
- package/dist/ui/_next/static/chunks/790dcc1e825d2504.js +1 -0
- package/dist/ui/_next/static/chunks/798597a1c1248d29.js +1 -0
- package/dist/ui/_next/static/chunks/7a70641f70a5c72d.js +60 -0
- package/dist/ui/_next/static/chunks/7c62789391c35dce.js +1 -0
- package/dist/ui/_next/static/chunks/7d533d3f2ab624f2.js +1 -0
- package/dist/ui/_next/static/chunks/7d6087c3fabf9ded.js +1 -0
- package/dist/ui/_next/static/chunks/7d84c9cb810e6902.js +1 -0
- package/dist/ui/_next/static/chunks/7dc4f5ba8c25c409.js +1 -0
- package/dist/ui/_next/static/chunks/7e10c0644fbb99d1.js +1 -0
- package/dist/ui/_next/static/chunks/7e7aaacf104c17f4.js +1 -0
- package/dist/ui/_next/static/chunks/7e92979509de57ed.js +1 -0
- package/dist/ui/_next/static/chunks/7f9a52e36f9f001e.js +1 -0
- package/dist/ui/_next/static/chunks/7fc4ae2e7cf2e37e.js +1 -0
- package/dist/ui/_next/static/chunks/801232fdde8ce252.js +1 -0
- package/dist/ui/_next/static/chunks/808ed0f189237446.js +1 -0
- package/dist/ui/_next/static/chunks/8199e6b3fa54b2ff.js +1 -0
- package/dist/ui/_next/static/chunks/81fa0fa05a94eb02.js +1 -0
- package/dist/ui/_next/static/chunks/821b5389566b82d2.js +1 -0
- package/dist/ui/_next/static/chunks/82b9e04f88e657df.js +1 -0
- package/dist/ui/_next/static/chunks/830c79cc12f2c5a4.js +1 -0
- package/dist/ui/_next/static/chunks/8388ae863590404b.js +4 -0
- package/dist/ui/_next/static/chunks/83ab70f11a82a8c6.js +1 -0
- package/dist/ui/_next/static/chunks/83faf7904ac18d7f.js +1 -0
- package/dist/ui/_next/static/chunks/850d850bd879606f.js +1 -0
- package/dist/ui/_next/static/chunks/864d4b5cf4ae2226.js +1 -0
- package/dist/ui/_next/static/chunks/86d8962196053f53.js +139 -0
- package/dist/ui/_next/static/chunks/8723d7000b263475.js +1 -0
- package/dist/ui/_next/static/chunks/87e5597a4336e2c1.js +1 -0
- package/dist/ui/_next/static/chunks/899fe56c4c707c65.js +1 -0
- package/dist/ui/_next/static/chunks/8bda52f55493ae9b.js +1 -0
- package/dist/ui/_next/static/chunks/8ce5668c3da0679a.js +1 -0
- package/dist/ui/_next/static/chunks/8d1c22aafb4783c5.js +1 -0
- package/dist/ui/_next/static/chunks/8deda0adfe811d18.js +1 -0
- package/dist/ui/_next/static/chunks/8eed597098a27801.js +1 -0
- package/dist/ui/_next/static/chunks/8ff7a1947b8d114b.js +1 -0
- package/dist/ui/_next/static/chunks/90367a2ee1e720b2.js +1 -0
- package/dist/ui/_next/static/chunks/9097640e1931c0de.js +1 -0
- package/dist/ui/_next/static/chunks/912457473a4c91c3.js +1 -0
- package/dist/ui/_next/static/chunks/91f7dd388c6b88c6.js +1 -0
- package/dist/ui/_next/static/chunks/932d4334e5f98b7c.js +1 -0
- package/dist/ui/_next/static/chunks/94b1efc14d44707b.js +1 -0
- package/dist/ui/_next/static/chunks/956107bc3ba52911.js +1 -0
- package/dist/ui/_next/static/chunks/962e5cad8ea716fc.js +36 -0
- package/dist/ui/_next/static/chunks/96acf903dff8ecf7.js +1 -0
- package/dist/ui/_next/static/chunks/96b274c82c194b4f.js +1 -0
- package/dist/ui/_next/static/chunks/96b3c1b1afe3201d.js +1 -0
- package/dist/ui/_next/static/chunks/9880c26551206d33.js +1 -0
- package/dist/ui/_next/static/chunks/98ea228d01556617.js +1 -0
- package/dist/ui/_next/static/chunks/9951c25a8b05148f.js +1 -0
- package/dist/ui/_next/static/chunks/9b10895d33be5f6e.js +1 -0
- package/dist/ui/_next/static/chunks/9b50a76ddbe4934d.js +1 -0
- package/dist/ui/_next/static/chunks/9bbb1c0146042008.js +1 -0
- package/dist/ui/_next/static/chunks/9ccab70823e99451.js +1 -0
- package/dist/ui/_next/static/chunks/9cd7bcb29e0b3418.js +24 -0
- package/dist/ui/_next/static/chunks/9d06bd5d701ace73.js +1 -0
- package/dist/ui/_next/static/chunks/9e5d9fc30c12fbdd.js +1 -0
- package/dist/ui/_next/static/chunks/9ec3bc5544bcc15a.js +1 -0
- package/dist/ui/_next/static/chunks/9f47133184a7455a.js +1 -0
- package/dist/ui/_next/static/chunks/a002d3850b7c7c59.js +1 -0
- package/dist/ui/_next/static/chunks/a0bc5573cadd1377.js +1 -0
- package/dist/ui/_next/static/chunks/a1d3de9e7615662e.js +160 -0
- package/dist/ui/_next/static/chunks/a2ce60768a8373e7.js +1 -0
- package/dist/ui/_next/static/chunks/a305087b1a55b367.js +1 -0
- package/dist/ui/_next/static/chunks/a41df0d443f66c68.js +1 -0
- package/dist/ui/_next/static/chunks/a49d2e9f31886b5e.js +1 -0
- package/dist/ui/_next/static/chunks/a50922e0883f65cd.js +1 -0
- package/dist/ui/_next/static/chunks/a60e84ee8b6c5ffc.js +43 -0
- package/dist/ui/_next/static/chunks/a6dad97d9634a72d.js +1 -0
- package/dist/ui/_next/static/chunks/a6dad97d9634a72d.js.map +1 -0
- package/dist/ui/_next/static/chunks/a7c40c289b5e2384.js +1 -0
- package/dist/ui/_next/static/chunks/a7fdfeea5fd894c1.js +59 -0
- package/dist/ui/_next/static/chunks/a81381241f4f484c.js +1 -0
- package/dist/ui/_next/static/chunks/a8a3989305bcc136.js +215 -0
- package/dist/ui/_next/static/chunks/a8cf26088e63128c.js +1 -0
- package/dist/ui/_next/static/chunks/aac4ca816d9ccdb6.js +1 -0
- package/dist/ui/_next/static/chunks/ab432bc28a971c8f.js +1 -0
- package/dist/ui/_next/static/chunks/abccff1b09b6effa.js +1 -0
- package/dist/ui/_next/static/chunks/ac8a8986f09ec520.js +1 -0
- package/dist/ui/_next/static/chunks/accbf306b5ddb732.js +1 -0
- package/dist/ui/_next/static/chunks/af7b09aba1d477ff.js +1 -0
- package/dist/ui/_next/static/chunks/af8114430894d79e.js +1 -0
- package/dist/ui/_next/static/chunks/afe2ff5d0727a240.js +1 -0
- package/dist/ui/_next/static/chunks/b096fa008120f0ae.js +1 -0
- package/dist/ui/_next/static/chunks/b0bc568eaff56dad.js +1 -0
- package/dist/ui/_next/static/chunks/b225dddc0852f85c.js +215 -0
- package/dist/ui/_next/static/chunks/b2342c5099957971.js +1 -0
- package/dist/ui/_next/static/chunks/b2d8c64d7d6a06b7.js +1 -0
- package/dist/ui/_next/static/chunks/b331c855cfc8fd57.js +1 -0
- package/dist/ui/_next/static/chunks/b356ee8615740392.js +1 -0
- package/dist/ui/_next/static/chunks/b3beaac9b7957d3f.js +1 -0
- package/dist/ui/_next/static/chunks/b4e7d4a109c4c080.js +1 -0
- package/dist/ui/_next/static/chunks/b5010f2ea9df9d00.js +77 -0
- package/dist/ui/_next/static/chunks/b5f9d21bd1b51a48.js +1 -0
- package/dist/ui/_next/static/chunks/b6a16eb77c5c9831.js +1 -0
- package/dist/ui/_next/static/chunks/b6a8e7c2216683ca.js +262 -0
- package/dist/ui/_next/static/chunks/b873c4d327a450e0.js +1 -0
- package/dist/ui/_next/static/chunks/b8aec8caed569fd2.js +24 -0
- package/dist/ui/_next/static/chunks/b8e7601e2379fd74.js +1 -0
- package/dist/ui/_next/static/chunks/ba3d03bf2f33f2a3.js +1 -0
- package/dist/ui/_next/static/chunks/ba698805336b2cb2.js +1 -0
- package/dist/ui/_next/static/chunks/bc48735eee7d1345.js +1 -0
- package/dist/ui/_next/static/chunks/bcb48aab1bdae96a.js +1 -0
- package/dist/ui/_next/static/chunks/bde2ca9d150d96ff.js +1 -0
- package/dist/ui/_next/static/chunks/be4af851547fc916.js +1 -0
- package/dist/ui/_next/static/chunks/be70ba8c4ba5cdb6.js +1 -0
- package/dist/ui/_next/static/chunks/be87578ee895734b.js +1 -0
- package/dist/ui/_next/static/chunks/c0aeb40fcca7d006.js +1 -0
- package/dist/ui/_next/static/chunks/c32156843c32ebca.js +1 -0
- package/dist/ui/_next/static/chunks/c57a3e045f3722c1.js +1 -0
- package/dist/ui/_next/static/chunks/c5add23cde4a234a.js +1 -0
- package/dist/ui/_next/static/chunks/c60897f3554a9388.js +1 -0
- package/dist/ui/_next/static/chunks/c648a36722afd12a.js +1 -0
- package/dist/ui/_next/static/chunks/c652f05e0a0d7b81.js +1 -0
- package/dist/ui/_next/static/chunks/c678d9303ed453b4.js +1 -0
- package/dist/ui/_next/static/chunks/c681430c24597d06.js +1 -0
- package/dist/ui/_next/static/chunks/c890870fb65940bc.js +1 -0
- package/dist/ui/_next/static/chunks/c94c394aeec71e21.js +1 -0
- package/dist/ui/_next/static/chunks/ca1eb1e2978389e4.js +1 -0
- package/dist/ui/_next/static/chunks/ca3512025a981c82.js +1 -0
- package/dist/ui/_next/static/chunks/ca6db0d999bad46b.js +1 -0
- package/dist/ui/_next/static/chunks/ca926babdf75597c.js +1 -0
- package/dist/ui/_next/static/chunks/cb0877764d4a31f2.js +1 -0
- package/dist/ui/_next/static/chunks/cb15e0c2ff49cf52.js +1 -0
- package/dist/ui/_next/static/chunks/cb1ae84204260ecd.js +1 -0
- package/dist/ui/_next/static/chunks/cb2ef733c53d80f7.js +1 -0
- package/dist/ui/_next/static/chunks/cbaa87ba8930fb75.js +1 -0
- package/dist/ui/_next/static/chunks/cbd29ba61906e19f.js +1 -0
- package/dist/ui/_next/static/chunks/ccf1e618faea3d02.js +148 -0
- package/dist/ui/_next/static/chunks/cd91712ea04f43ba.js +13 -0
- package/dist/ui/_next/static/chunks/cdd85dc039d450f3.js +1 -0
- package/dist/ui/_next/static/chunks/ce663833f73b1ec5.js +1 -0
- package/dist/ui/_next/static/chunks/ceda8fcac21d8e70.js +1 -0
- package/dist/ui/_next/static/chunks/cf565875b66f8cad.js +1 -0
- package/dist/ui/_next/static/chunks/d127ded39a594c84.js +1 -0
- package/dist/ui/_next/static/chunks/d34124988f5b8f6d.js +1 -0
- package/dist/ui/_next/static/chunks/d36807add3e11d59.js +60 -0
- package/dist/ui/_next/static/chunks/d3f2e4603faebed8.js +1 -0
- package/dist/ui/_next/static/chunks/d414302c23047b9b.js +1 -0
- package/dist/ui/_next/static/chunks/d42adc0237103e65.js +1 -0
- package/dist/ui/_next/static/chunks/d4a06b205f0a641b.js +1 -0
- package/dist/ui/_next/static/chunks/d4e5289ace3acef0.js +1 -0
- package/dist/ui/_next/static/chunks/d53b4725d3328076.js +1 -0
- package/dist/ui/_next/static/chunks/d5bd04634f922925.js +1 -0
- package/dist/ui/_next/static/chunks/d642c9229900dc48.js +1 -0
- package/dist/ui/_next/static/chunks/d6651bb78c09d144.js +5 -0
- package/dist/ui/_next/static/chunks/d7276c56aa62ceed.js +1 -0
- package/dist/ui/_next/static/chunks/d85cd9cda46f2d1b.js +1 -0
- package/dist/ui/_next/static/chunks/d8978f4b468bbad4.js +1 -0
- package/dist/ui/_next/static/chunks/d8fb9668a83c0603.js +1 -0
- package/dist/ui/_next/static/chunks/d95c62472fc41baf.js +1 -0
- package/dist/ui/_next/static/chunks/da13170b983f7ebf.js +1 -0
- package/dist/ui/_next/static/chunks/dae86e12c7741e6c.js +19 -0
- package/dist/ui/_next/static/chunks/db44023a744297d1.js +1 -0
- package/dist/ui/_next/static/chunks/dbe7840308be36b8.js +1 -0
- package/dist/ui/_next/static/chunks/dc0a4df8f7080b29.js +1 -0
- package/dist/ui/_next/static/chunks/dc4a6f59be156511.js +1 -0
- package/dist/ui/_next/static/chunks/dcda5e7b57ed88e0.js +1 -0
- package/dist/ui/_next/static/chunks/de9ff8c97f75b947.js +1 -0
- package/dist/ui/_next/static/chunks/df6abcdb3eb0b236.js +1 -0
- package/dist/ui/_next/static/chunks/df8a0933ca385a63.js +1 -0
- package/dist/ui/_next/static/chunks/dff6434c44c2dfaa.js +1 -0
- package/dist/ui/_next/static/chunks/e037ec5e62b2bdc3.js +1 -0
- package/dist/ui/_next/static/chunks/e212cf1f5a503899.js +1 -0
- package/dist/ui/_next/static/chunks/e2bfdac0a2305cc1.js +1 -0
- package/dist/ui/_next/static/chunks/e2dce648399ad4d4.js +1 -0
- package/dist/ui/_next/static/chunks/e318291bb8d74aee.js +1 -0
- package/dist/ui/_next/static/chunks/e33e40c2e7ab7629.js +1 -0
- package/dist/ui/_next/static/chunks/e410dfbcccddc478.js +1 -0
- package/dist/ui/_next/static/chunks/e411d58b52ab342b.js +1 -0
- package/dist/ui/_next/static/chunks/e57f7ffd0803a922.js +117 -0
- package/dist/ui/_next/static/chunks/e6b56ceb762e84c4.js +1 -0
- package/dist/ui/_next/static/chunks/e6d9a6ca68017eef.js +1 -0
- package/dist/ui/_next/static/chunks/e6ec2663605cf5a7.js +29 -0
- package/dist/ui/_next/static/chunks/e834330589be0639.js +1 -0
- package/dist/ui/_next/static/chunks/e8f662ba8bc76802.js +1 -0
- package/dist/ui/_next/static/chunks/e9e8e72d7ff45812.js +1 -0
- package/dist/ui/_next/static/chunks/eadd25eb66104a63.js +1 -0
- package/dist/ui/_next/static/chunks/ec3a7a7f48a8aca9.js +1 -0
- package/dist/ui/_next/static/chunks/ed62e349fb1ce14c.js +1 -0
- package/dist/ui/_next/static/chunks/ed6caa113f5769a5.js +1 -0
- package/dist/ui/_next/static/chunks/f02ac565bb5bc450.js +1 -0
- package/dist/ui/_next/static/chunks/f1a7a173e3da4ff4.js +1 -0
- package/dist/ui/_next/static/chunks/f268093817d3b260.js +1 -0
- package/dist/ui/_next/static/chunks/f6f811ccfe79e963.js +1 -0
- package/dist/ui/_next/static/chunks/f8955634331fd956.js +1 -0
- package/dist/ui/_next/static/chunks/f8c965a996875e30.js +56 -0
- package/dist/ui/_next/static/chunks/f9bb8411d37b06d7.js +1 -0
- package/dist/ui/_next/static/chunks/f9d4f77d8c130497.js +1 -0
- package/dist/ui/_next/static/chunks/fba113a516eb485f.js +1 -0
- package/dist/ui/_next/static/chunks/fc069e49a569d83c.js +1 -0
- package/dist/ui/_next/static/chunks/fc245016ffebdde3.js +1 -0
- package/dist/ui/_next/static/chunks/fc2d01d74dcf3921.js +1 -0
- package/dist/ui/_next/static/chunks/fe2ad0e00041a87d.js +1 -0
- package/dist/ui/_next/static/chunks/fe571740188dea3a.js +1 -0
- package/dist/ui/_next/static/chunks/turbopack-a5ce95b200d58f7a.js +4 -0
- package/dist/ui/_next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
- package/dist/ui/_next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
- package/dist/ui/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
- package/dist/ui/_next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_AMS-Regular.892f691b.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_AMS-Regular.c30af439.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_AMS-Regular.e6a3cada.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Caligraphic-Bold.2f97783e.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Caligraphic-Bold.a36b8125.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Caligraphic-Bold.db991531.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Caligraphic-Regular.2b13f013.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Caligraphic-Regular.7c50032c.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Caligraphic-Regular.c20eee08.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Fraktur-Bold.5fa2f5e4.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Fraktur-Bold.d514bd28.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Fraktur-Bold.e311399d.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Fraktur-Regular.18139813.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Fraktur-Regular.2a73476d.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Fraktur-Regular.5d62e468.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-Bold.6d137c77.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-Bold.c24b5ba7.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-Bold.f4e2828d.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-BoldItalic.079b33ae.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-BoldItalic.c003d3ec.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-BoldItalic.f1884480.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-Italic.26a3619b.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-Italic.61da3e93.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-Italic.a3746929.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-Regular.12644167.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-Regular.876b86ad.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Main-Regular.d511f158.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Math-BoldItalic.5c6a6a93.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Math-BoldItalic.ad4dffd5.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Math-BoldItalic.e73b3bf0.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Math-Italic.03974bc4.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Math-Italic.1cd2c488.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Math-Italic.d8564edb.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_SansSerif-Bold.a03f9428.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_SansSerif-Bold.d4608ed5.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_SansSerif-Bold.ff51ef5c.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_SansSerif-Italic.8ed740d6.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_SansSerif-Italic.9245afda.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_SansSerif-Italic.c0b22b1e.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_SansSerif-Regular.128c9bc2.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_SansSerif-Regular.156dbd4e.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_SansSerif-Regular.ee7b0a16.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Script-Regular.00d9a561.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Script-Regular.186c7155.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Script-Regular.afc2fd5a.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size1-Regular.4450ef36.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size1-Regular.9aaff96b.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size1-Regular.e5bf4c74.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size2-Regular.6a97527b.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size2-Regular.8fbd32af.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size2-Regular.f11810ed.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size3-Regular.45ae8eba.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size3-Regular.54b7ce9d.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size3-Regular.9812ade2.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size4-Regular.44a4d487.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size4-Regular.927fc5b9.woff2 +0 -0
- package/dist/ui/_next/static/media/KaTeX_Size4-Regular.b211e3d3.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Typewriter-Regular.68b6c3a9.woff +0 -0
- package/dist/ui/_next/static/media/KaTeX_Typewriter-Regular.a1a7ff52.ttf +0 -0
- package/dist/ui/_next/static/media/KaTeX_Typewriter-Regular.ff99d643.woff2 +0 -0
- package/dist/ui/_next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
- package/dist/ui/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
- package/dist/ui/_next/static/media/favicon.0b3bf435.ico +0 -0
- package/dist/ui/_not-found/__next._full.txt +18 -0
- package/dist/ui/_not-found/__next._head.txt +6 -0
- package/dist/ui/_not-found/__next._index.txt +9 -0
- package/dist/ui/_not-found/__next._not-found.__PAGE__.txt +5 -0
- package/dist/ui/_not-found/__next._not-found.txt +4 -0
- package/dist/ui/_not-found/__next._tree.txt +3 -0
- package/dist/ui/_not-found/index.html +1 -0
- package/dist/ui/_not-found/index.txt +18 -0
- package/dist/ui/favicon.ico +0 -0
- package/dist/ui/file.svg +1 -0
- package/dist/ui/globe.svg +1 -0
- package/dist/ui/index.html +1 -0
- package/dist/ui/index.txt +25 -0
- package/dist/ui/next.svg +1 -0
- package/dist/ui/vercel.svg +1 -0
- package/dist/ui/window.svg +1 -0
- package/dist/utils/chat-model.d.ts +11 -0
- package/dist/utils/chat-model.js +37 -0
- package/dist/utils/diff-parser.d.ts +20 -0
- package/dist/utils/diff-parser.js +100 -0
- package/dist/utils/proxy-manager.d.ts +18 -0
- package/dist/utils/proxy-manager.js +42 -0
- package/dist/utils/remote-proxy.d.ts +40 -0
- package/dist/utils/remote-proxy.js +145 -0
- package/dist/utils/worktree-paths.d.ts +13 -0
- package/dist/utils/worktree-paths.js +64 -0
- package/dist/virtual-ws-adapter.d.ts +26 -0
- package/dist/virtual-ws-adapter.js +54 -0
- package/package.json +19 -0
|
@@ -0,0 +1,985 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { randomUUID } from "crypto";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import { getProvider } from "./providers/index.js";
|
|
5
|
+
import { ConversationPatch } from "./conversation-patch.js";
|
|
6
|
+
import { EntryIndexProvider, EntryTracker } from "./entry-index-provider.js";
|
|
7
|
+
import { resolveWorktreePath } from "./utils/worktree-paths.js";
|
|
8
|
+
export class AgentSessionManager {
|
|
9
|
+
sessions = new Map();
|
|
10
|
+
storage;
|
|
11
|
+
eventBus = null;
|
|
12
|
+
constructor(storage) {
|
|
13
|
+
this.storage = storage;
|
|
14
|
+
}
|
|
15
|
+
setEventBus(eventBus) {
|
|
16
|
+
this.eventBus = eventBus;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get or create an agent session for a branch
|
|
20
|
+
*/
|
|
21
|
+
getOrCreateSession(projectId, branch, projectPath, skipDb = false, permissionMode = "edit", agentType = "claude-code") {
|
|
22
|
+
// Check if session already exists in memory (including dormant)
|
|
23
|
+
for (const [id, session] of this.sessions) {
|
|
24
|
+
if (session.projectId === projectId &&
|
|
25
|
+
session.branch === branch) {
|
|
26
|
+
if (session.dormant) {
|
|
27
|
+
// Dormant session found — update permission mode if needed, return ID
|
|
28
|
+
// Don't spawn process yet (lazy — wait for user message)
|
|
29
|
+
if (session.permissionMode !== permissionMode) {
|
|
30
|
+
session.permissionMode = permissionMode;
|
|
31
|
+
if (!session.skipDb) {
|
|
32
|
+
this.storage.agentSessions.updatePermissionMode(id, permissionMode);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
console.log(`[AgentSession] Returning dormant session ${id}`);
|
|
36
|
+
return id;
|
|
37
|
+
}
|
|
38
|
+
if (session.status === "running") {
|
|
39
|
+
// If permission mode differs, switch mode on existing session
|
|
40
|
+
if (session.permissionMode !== permissionMode) {
|
|
41
|
+
console.log(`[AgentSession] Session ${id} exists with mode ${session.permissionMode}, switching to ${permissionMode}`);
|
|
42
|
+
this.switchMode(id, projectPath, permissionMode);
|
|
43
|
+
}
|
|
44
|
+
console.log(`[AgentSession] Returning existing session ${id}`);
|
|
45
|
+
return id;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Check database for existing session (skip for remote path-based sessions)
|
|
50
|
+
if (!skipDb) {
|
|
51
|
+
const existingSession = this.storage.agentSessions.getByBranch(projectId, branch ?? "");
|
|
52
|
+
if (existingSession && this.sessions.has(existingSession.id)) {
|
|
53
|
+
const inMemory = this.sessions.get(existingSession.id);
|
|
54
|
+
if (inMemory.status !== "running") {
|
|
55
|
+
// Dead session — restart it so callers always get a running session
|
|
56
|
+
console.log(`[AgentSession] Session ${existingSession.id} is ${inMemory.status}, restarting`);
|
|
57
|
+
this.restartSession(existingSession.id, projectPath);
|
|
58
|
+
}
|
|
59
|
+
else if (inMemory.permissionMode !== permissionMode) {
|
|
60
|
+
console.log(`[AgentSession] Session ${existingSession.id} mode ${inMemory.permissionMode} → ${permissionMode}`);
|
|
61
|
+
this.switchMode(existingSession.id, projectPath, permissionMode);
|
|
62
|
+
}
|
|
63
|
+
return existingSession.id;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Create new session
|
|
67
|
+
const sessionId = randomUUID();
|
|
68
|
+
console.log(`[AgentSession] Creating new session ${sessionId}`);
|
|
69
|
+
// Calculate absolute worktree path
|
|
70
|
+
const absoluteWorktreePath = resolveWorktreePath(projectPath, branch);
|
|
71
|
+
console.log(`[AgentSession] projectPath=${projectPath}, branch=${branch}, absoluteWorktreePath=${absoluteWorktreePath}`);
|
|
72
|
+
// Create session in database (skip for remote path-based sessions)
|
|
73
|
+
if (!skipDb) {
|
|
74
|
+
this.storage.agentSessions.create({
|
|
75
|
+
id: sessionId,
|
|
76
|
+
project_id: projectId,
|
|
77
|
+
branch: branch ?? "",
|
|
78
|
+
permission_mode: permissionMode,
|
|
79
|
+
// agent_type passed to storage after Phase 4 migration (task 4.2/4.3)
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// Initialize message store with EntryIndexProvider
|
|
83
|
+
const indexProvider = new EntryIndexProvider();
|
|
84
|
+
const store = {
|
|
85
|
+
patches: [],
|
|
86
|
+
entries: [],
|
|
87
|
+
indexProvider,
|
|
88
|
+
toolTracker: new EntryTracker(indexProvider),
|
|
89
|
+
currentAssistantIndex: null,
|
|
90
|
+
};
|
|
91
|
+
// Initialize running session
|
|
92
|
+
const runningSession = {
|
|
93
|
+
id: sessionId,
|
|
94
|
+
projectId,
|
|
95
|
+
branch,
|
|
96
|
+
process: null,
|
|
97
|
+
dormant: false,
|
|
98
|
+
store,
|
|
99
|
+
subscribers: new Set(),
|
|
100
|
+
status: "running",
|
|
101
|
+
buffer: "",
|
|
102
|
+
skipDb,
|
|
103
|
+
permissionMode,
|
|
104
|
+
agentType,
|
|
105
|
+
};
|
|
106
|
+
this.sessions.set(sessionId, runningSession);
|
|
107
|
+
// Notify provider of session creation (for per-session state init)
|
|
108
|
+
getProvider(agentType).onSessionCreated?.(sessionId);
|
|
109
|
+
// Spawn Claude Code process
|
|
110
|
+
this.spawnAgent(runningSession, absoluteWorktreePath);
|
|
111
|
+
return sessionId;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Kill an agent process and its entire process tree.
|
|
115
|
+
* Uses negative PID to signal the process group (requires detached: true at spawn).
|
|
116
|
+
*/
|
|
117
|
+
killProcess(proc, signal = "SIGTERM") {
|
|
118
|
+
if (!proc?.pid)
|
|
119
|
+
return;
|
|
120
|
+
try {
|
|
121
|
+
process.kill(-proc.pid, signal);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Process group kill failed (e.g. already dead) — try direct kill as fallback
|
|
125
|
+
try {
|
|
126
|
+
proc.kill(signal);
|
|
127
|
+
}
|
|
128
|
+
catch { /* already dead */ }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Spawn agent process using the provider for this session's agent type
|
|
133
|
+
*/
|
|
134
|
+
spawnAgent(session, cwd) {
|
|
135
|
+
const provider = getProvider(session.agentType);
|
|
136
|
+
console.log(`[AgentSession] Spawning ${provider.getDisplayName()} in ${cwd}`);
|
|
137
|
+
// Verify cwd exists
|
|
138
|
+
if (!existsSync(cwd)) {
|
|
139
|
+
console.error(`[AgentSession] ERROR: cwd does not exist: ${cwd}`);
|
|
140
|
+
session.status = "error";
|
|
141
|
+
if (!session.skipDb)
|
|
142
|
+
this.storage.agentSessions.updateStatus(session.id, "error");
|
|
143
|
+
this.pushEntry(session.id, {
|
|
144
|
+
type: "error",
|
|
145
|
+
message: `Error: Working directory does not exist: ${cwd}`,
|
|
146
|
+
timestamp: Date.now(),
|
|
147
|
+
});
|
|
148
|
+
this.broadcastPatch(session.id, ConversationPatch.updateStatus("error"));
|
|
149
|
+
this.eventBus?.emit({ type: "session:status", projectId: session.projectId, branch: session.branch, sessionId: session.id, status: "error" });
|
|
150
|
+
this.broadcastRaw(session.id, { finished: true });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const config = provider.buildSpawnConfig(cwd, session.permissionMode);
|
|
154
|
+
const childProcess = spawn(config.command, config.args, {
|
|
155
|
+
cwd,
|
|
156
|
+
env: { ...process.env, FORCE_COLOR: "1", ...config.env },
|
|
157
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
158
|
+
shell: config.shell ?? false,
|
|
159
|
+
detached: true, // Own process group so we can kill the entire tree
|
|
160
|
+
});
|
|
161
|
+
session.process = childProcess;
|
|
162
|
+
console.log(`[AgentSession] Process ${session.id} started, PID: ${childProcess.pid}`);
|
|
163
|
+
// Pre-initialize provider protocol (e.g. Codex needs initialize + thread/start handshake)
|
|
164
|
+
if (provider.getInitializationMessages) {
|
|
165
|
+
const initMsgs = provider.getInitializationMessages(session.id);
|
|
166
|
+
if (initMsgs) {
|
|
167
|
+
childProcess.stdin?.write(initMsgs);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Handle stdout (JSON messages from Claude)
|
|
171
|
+
childProcess.stdout?.on("data", (data) => {
|
|
172
|
+
this.handleStdout(session, data.toString());
|
|
173
|
+
});
|
|
174
|
+
// Handle stderr (errors and debug info)
|
|
175
|
+
childProcess.stderr?.on("data", (data) => {
|
|
176
|
+
const text = data.toString();
|
|
177
|
+
console.log(`[AgentSession] stderr: ${text}`);
|
|
178
|
+
// Don't treat all stderr as errors - Claude Code uses it for progress
|
|
179
|
+
});
|
|
180
|
+
// Handle process exit
|
|
181
|
+
childProcess.on("close", (code) => {
|
|
182
|
+
console.log(`[AgentSession] Process ${session.id} exited with code ${code}`);
|
|
183
|
+
// Don't update status or send finished signal if this is an old process
|
|
184
|
+
// (happens when we restart - old process closes but new one is already running)
|
|
185
|
+
if (session.process !== childProcess) {
|
|
186
|
+
console.log(`[AgentSession] Old process closed, new process already running, skipping finished signal`);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
session.status = code === 0 ? "stopped" : "error";
|
|
190
|
+
if (!session.skipDb)
|
|
191
|
+
this.storage.agentSessions.updateStatus(session.id, session.status);
|
|
192
|
+
// Send status patch and finished signal
|
|
193
|
+
this.broadcastPatch(session.id, ConversationPatch.updateStatus(session.status));
|
|
194
|
+
this.eventBus?.emit({ type: "session:status", projectId: session.projectId, branch: session.branch, sessionId: session.id, status: session.status });
|
|
195
|
+
this.broadcastRaw(session.id, { finished: true });
|
|
196
|
+
});
|
|
197
|
+
// Handle spawn errors
|
|
198
|
+
childProcess.on("error", (error) => {
|
|
199
|
+
console.error(`[AgentSession] Process ${session.id} error:`, error);
|
|
200
|
+
session.status = "error";
|
|
201
|
+
if (!session.skipDb)
|
|
202
|
+
this.storage.agentSessions.updateStatus(session.id, "error");
|
|
203
|
+
this.pushEntry(session.id, {
|
|
204
|
+
type: "error",
|
|
205
|
+
message: error.message,
|
|
206
|
+
timestamp: Date.now(),
|
|
207
|
+
}, true);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Handle stdout data from agent process
|
|
212
|
+
*/
|
|
213
|
+
handleStdout(session, data) {
|
|
214
|
+
// Ignore output from a process that has been stopped — the process may
|
|
215
|
+
// still flush data to stdout while shutting down after SIGTERM.
|
|
216
|
+
if (session.dormant)
|
|
217
|
+
return;
|
|
218
|
+
// Add to buffer
|
|
219
|
+
session.buffer += data;
|
|
220
|
+
// Process complete lines
|
|
221
|
+
const lines = session.buffer.split("\n");
|
|
222
|
+
session.buffer = lines.pop() || ""; // Keep incomplete line in buffer
|
|
223
|
+
const provider = getProvider(session.agentType);
|
|
224
|
+
for (const line of lines) {
|
|
225
|
+
if (!line.trim())
|
|
226
|
+
continue;
|
|
227
|
+
const events = provider.parseStdoutLine(line, session.id);
|
|
228
|
+
for (const event of events) {
|
|
229
|
+
this.processAgentEvent(session.id, event);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Process a single parsed agent event (provider-agnostic).
|
|
235
|
+
* Routes each ParsedAgentEvent to the appropriate message store / broadcast action.
|
|
236
|
+
* Includes input_tokens/output_tokens in taskCompleted broadcast for token reporting.
|
|
237
|
+
*/
|
|
238
|
+
processAgentEvent(sessionId, event) {
|
|
239
|
+
const session = this.sessions.get(sessionId);
|
|
240
|
+
if (!session)
|
|
241
|
+
return;
|
|
242
|
+
const timestamp = Date.now();
|
|
243
|
+
switch (event.type) {
|
|
244
|
+
case "text":
|
|
245
|
+
this.updateAssistantMessage(sessionId, event.content, timestamp);
|
|
246
|
+
break;
|
|
247
|
+
case "tool_use": {
|
|
248
|
+
this.finalizeStreamingEntry(session);
|
|
249
|
+
session.store.currentAssistantIndex = null;
|
|
250
|
+
const tuKey = `tool_use:${event.toolUseId}`;
|
|
251
|
+
const { index: tuIndex, isNew: tuIsNew } = session.store.toolTracker.getOrCreate(tuKey);
|
|
252
|
+
const tuMessage = {
|
|
253
|
+
type: "tool_use",
|
|
254
|
+
tool: event.tool,
|
|
255
|
+
input: event.input,
|
|
256
|
+
toolUseId: event.toolUseId,
|
|
257
|
+
timestamp,
|
|
258
|
+
};
|
|
259
|
+
if (tuIsNew) {
|
|
260
|
+
session.store.entries[tuIndex] = tuMessage;
|
|
261
|
+
const patch = ConversationPatch.addEntry(tuIndex, tuMessage);
|
|
262
|
+
session.store.patches.push(patch);
|
|
263
|
+
this.broadcastPatch(sessionId, patch);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
session.store.entries[tuIndex] = tuMessage;
|
|
267
|
+
const patch = ConversationPatch.replaceEntry(tuIndex, tuMessage);
|
|
268
|
+
session.store.patches.push(patch);
|
|
269
|
+
this.broadcastPatch(sessionId, patch);
|
|
270
|
+
}
|
|
271
|
+
if (!session.skipDb) {
|
|
272
|
+
this.persistEntry(session, tuIndex, tuMessage);
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
case "tool_result": {
|
|
277
|
+
this.finalizeStreamingEntry(session);
|
|
278
|
+
session.store.currentAssistantIndex = null;
|
|
279
|
+
const trKey = `tool_result:${event.toolUseId}`;
|
|
280
|
+
const { index: trIndex, isNew: trIsNew } = session.store.toolTracker.getOrCreate(trKey);
|
|
281
|
+
const trMessage = {
|
|
282
|
+
type: "tool_result",
|
|
283
|
+
tool: event.tool,
|
|
284
|
+
output: event.output,
|
|
285
|
+
toolUseId: event.toolUseId,
|
|
286
|
+
timestamp,
|
|
287
|
+
};
|
|
288
|
+
if (trIsNew) {
|
|
289
|
+
session.store.entries[trIndex] = trMessage;
|
|
290
|
+
const patch = ConversationPatch.addEntry(trIndex, trMessage);
|
|
291
|
+
session.store.patches.push(patch);
|
|
292
|
+
this.broadcastPatch(sessionId, patch);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
session.store.entries[trIndex] = trMessage;
|
|
296
|
+
const patch = ConversationPatch.replaceEntry(trIndex, trMessage);
|
|
297
|
+
session.store.patches.push(patch);
|
|
298
|
+
this.broadcastPatch(sessionId, patch);
|
|
299
|
+
}
|
|
300
|
+
if (!session.skipDb) {
|
|
301
|
+
this.persistEntry(session, trIndex, trMessage);
|
|
302
|
+
}
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
case "thinking":
|
|
306
|
+
this.finalizeStreamingEntry(session);
|
|
307
|
+
session.store.currentAssistantIndex = null;
|
|
308
|
+
this.pushEntry(sessionId, {
|
|
309
|
+
type: "thinking",
|
|
310
|
+
content: event.content,
|
|
311
|
+
timestamp,
|
|
312
|
+
}, true);
|
|
313
|
+
break;
|
|
314
|
+
case "system":
|
|
315
|
+
this.finalizeStreamingEntry(session);
|
|
316
|
+
session.store.currentAssistantIndex = null;
|
|
317
|
+
this.pushEntry(sessionId, {
|
|
318
|
+
type: "system",
|
|
319
|
+
content: event.content,
|
|
320
|
+
timestamp,
|
|
321
|
+
}, true);
|
|
322
|
+
break;
|
|
323
|
+
case "error":
|
|
324
|
+
this.finalizeStreamingEntry(session);
|
|
325
|
+
session.store.currentAssistantIndex = null;
|
|
326
|
+
this.pushEntry(sessionId, {
|
|
327
|
+
type: "error",
|
|
328
|
+
message: event.message,
|
|
329
|
+
timestamp,
|
|
330
|
+
}, true);
|
|
331
|
+
break;
|
|
332
|
+
case "result":
|
|
333
|
+
this.finalizeStreamingEntry(session);
|
|
334
|
+
session.store.currentAssistantIndex = null;
|
|
335
|
+
if (event.subtype === "error" && event.error) {
|
|
336
|
+
this.pushEntry(sessionId, {
|
|
337
|
+
type: "error",
|
|
338
|
+
message: event.error,
|
|
339
|
+
timestamp,
|
|
340
|
+
}, true);
|
|
341
|
+
}
|
|
342
|
+
if (event.subtype === "success") {
|
|
343
|
+
this.broadcastRaw(sessionId, {
|
|
344
|
+
taskCompleted: {
|
|
345
|
+
duration_ms: event.duration_ms,
|
|
346
|
+
cost_usd: event.cost_usd,
|
|
347
|
+
input_tokens: event.input_tokens,
|
|
348
|
+
output_tokens: event.output_tokens,
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
// Auto-update task status to "done" for the branch's assigned task
|
|
352
|
+
const tasks = this.storage.tasks.getByProjectId(session.projectId);
|
|
353
|
+
const branchKey = session.branch ?? "";
|
|
354
|
+
const assignedTask = tasks.find(t => t.assigned_branch === branchKey);
|
|
355
|
+
if (assignedTask && assignedTask.status !== "done") {
|
|
356
|
+
this.storage.tasks.update(assignedTask.id, { status: "done" });
|
|
357
|
+
this.eventBus?.emit({
|
|
358
|
+
type: "task:updated",
|
|
359
|
+
projectId: session.projectId,
|
|
360
|
+
task: { ...assignedTask, status: "done" },
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
break;
|
|
365
|
+
case "approval_request":
|
|
366
|
+
this.finalizeStreamingEntry(session);
|
|
367
|
+
session.store.currentAssistantIndex = null;
|
|
368
|
+
if (event.requestType === "command") {
|
|
369
|
+
this.pushEntry(sessionId, {
|
|
370
|
+
type: "approval_request",
|
|
371
|
+
requestType: "command",
|
|
372
|
+
requestId: event.requestId,
|
|
373
|
+
command: event.command,
|
|
374
|
+
cwd: event.cwd,
|
|
375
|
+
timestamp,
|
|
376
|
+
}, true);
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
this.pushEntry(sessionId, {
|
|
380
|
+
type: "approval_request",
|
|
381
|
+
requestType: "fileChange",
|
|
382
|
+
requestId: event.requestId,
|
|
383
|
+
changes: event.changes,
|
|
384
|
+
timestamp,
|
|
385
|
+
}, true);
|
|
386
|
+
}
|
|
387
|
+
break;
|
|
388
|
+
case "stdin_write":
|
|
389
|
+
// Provider needs to send deferred data to the agent's stdin
|
|
390
|
+
session.process?.stdin?.write(event.content);
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Update or add an assistant message using JSON Patch semantics
|
|
396
|
+
* This is the key method that handles streaming updates correctly
|
|
397
|
+
*/
|
|
398
|
+
updateAssistantMessage(sessionId, content, timestamp) {
|
|
399
|
+
const session = this.sessions.get(sessionId);
|
|
400
|
+
if (!session)
|
|
401
|
+
return;
|
|
402
|
+
const { store } = session;
|
|
403
|
+
// Check if we have an ongoing assistant message (streaming update)
|
|
404
|
+
if (store.currentAssistantIndex !== null) {
|
|
405
|
+
const existingIndex = store.currentAssistantIndex;
|
|
406
|
+
const message = {
|
|
407
|
+
type: "assistant",
|
|
408
|
+
content,
|
|
409
|
+
timestamp,
|
|
410
|
+
};
|
|
411
|
+
// Update the entry in our store
|
|
412
|
+
store.entries[existingIndex] = message;
|
|
413
|
+
// Create and broadcast REPLACE patch
|
|
414
|
+
const patch = ConversationPatch.replaceEntry(existingIndex, message);
|
|
415
|
+
store.patches.push(patch);
|
|
416
|
+
this.broadcastPatch(sessionId, patch);
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
// Start new assistant message (ADD)
|
|
420
|
+
const message = {
|
|
421
|
+
type: "assistant",
|
|
422
|
+
content,
|
|
423
|
+
timestamp,
|
|
424
|
+
};
|
|
425
|
+
const index = this.pushEntry(sessionId, message, true);
|
|
426
|
+
// Remember this index for streaming updates
|
|
427
|
+
store.currentAssistantIndex = index;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Push a new entry with ADD patch
|
|
431
|
+
*/
|
|
432
|
+
pushEntry(sessionId, message, broadcast = true) {
|
|
433
|
+
const session = this.sessions.get(sessionId);
|
|
434
|
+
if (!session)
|
|
435
|
+
return -1;
|
|
436
|
+
const { store } = session;
|
|
437
|
+
// Get next index from provider
|
|
438
|
+
const index = store.indexProvider.next();
|
|
439
|
+
// Store the entry
|
|
440
|
+
store.entries[index] = message;
|
|
441
|
+
// Create ADD patch
|
|
442
|
+
const patch = ConversationPatch.addEntry(index, message);
|
|
443
|
+
store.patches.push(patch);
|
|
444
|
+
// Persist to DB (skip streaming assistant text — those get finalized later)
|
|
445
|
+
if (!session.skipDb && message.type !== "assistant") {
|
|
446
|
+
this.persistEntry(session, index, message);
|
|
447
|
+
}
|
|
448
|
+
if (broadcast) {
|
|
449
|
+
this.broadcastPatch(sessionId, patch);
|
|
450
|
+
}
|
|
451
|
+
return index;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Persist a single entry to the database
|
|
455
|
+
*/
|
|
456
|
+
persistEntry(session, index, message) {
|
|
457
|
+
try {
|
|
458
|
+
this.storage.agentSessions.upsertEntry(session.id, index, JSON.stringify(message));
|
|
459
|
+
}
|
|
460
|
+
catch (error) {
|
|
461
|
+
console.error(`[AgentSession] Failed to persist entry ${index}:`, error);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Finalize and persist the current streaming assistant message
|
|
466
|
+
*/
|
|
467
|
+
finalizeStreamingEntry(session) {
|
|
468
|
+
const index = session.store.currentAssistantIndex;
|
|
469
|
+
if (index === null || session.skipDb)
|
|
470
|
+
return;
|
|
471
|
+
const entry = session.store.entries[index];
|
|
472
|
+
if (entry) {
|
|
473
|
+
this.persistEntry(session, index, entry);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Send a user message to the agent
|
|
478
|
+
*/
|
|
479
|
+
sendUserMessage(sessionId, content, projectPath) {
|
|
480
|
+
const session = this.sessions.get(sessionId);
|
|
481
|
+
if (!session)
|
|
482
|
+
return false;
|
|
483
|
+
// If session is dormant, wake it up
|
|
484
|
+
if (session.dormant) {
|
|
485
|
+
if (!projectPath) {
|
|
486
|
+
console.error(`[AgentSession] Cannot wake dormant session ${sessionId} without projectPath`);
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
this.wakeDormantSession(session, projectPath, content);
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
if (session.status !== "running") {
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
// Clear current assistant key - user message breaks streaming
|
|
496
|
+
this.finalizeStreamingEntry(session);
|
|
497
|
+
session.store.currentAssistantIndex = null;
|
|
498
|
+
// Add user message with ADD patch
|
|
499
|
+
this.pushEntry(sessionId, {
|
|
500
|
+
type: "user",
|
|
501
|
+
content,
|
|
502
|
+
timestamp: Date.now(),
|
|
503
|
+
}, true);
|
|
504
|
+
// Send to agent stdin via provider
|
|
505
|
+
try {
|
|
506
|
+
const provider = getProvider(session.agentType);
|
|
507
|
+
const formatted = provider.formatUserInput(content, session.id);
|
|
508
|
+
session.process?.stdin?.write(formatted);
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
catch (error) {
|
|
512
|
+
console.error(`[AgentSession] Failed to send message:`, error);
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Send an approval response to the agent process (for agents with approval flow).
|
|
518
|
+
* Returns false if session not found, not running, or provider doesn't support approvals.
|
|
519
|
+
*/
|
|
520
|
+
sendApprovalResponse(sessionId, requestId, decision) {
|
|
521
|
+
const session = this.sessions.get(sessionId);
|
|
522
|
+
if (!session)
|
|
523
|
+
return false;
|
|
524
|
+
if (session.status !== "running" || !session.process?.stdin) {
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
try {
|
|
528
|
+
const provider = getProvider(session.agentType);
|
|
529
|
+
const formatted = provider.formatApprovalResponse?.(requestId, decision, session.id);
|
|
530
|
+
if (!formatted)
|
|
531
|
+
return false;
|
|
532
|
+
session.process.stdin.write(formatted);
|
|
533
|
+
return true;
|
|
534
|
+
}
|
|
535
|
+
catch (error) {
|
|
536
|
+
console.error(`[AgentSession] Failed to send approval response:`, error);
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Subscribe to session updates (WebSocket connection)
|
|
542
|
+
*/
|
|
543
|
+
subscribe(sessionId, ws) {
|
|
544
|
+
const session = this.sessions.get(sessionId);
|
|
545
|
+
if (!session) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
session.subscribers.add(ws);
|
|
549
|
+
// Send all historical patches to replay state
|
|
550
|
+
for (const patch of session.store.patches) {
|
|
551
|
+
const msg = { JsonPatch: patch };
|
|
552
|
+
ws.send(JSON.stringify(msg));
|
|
553
|
+
}
|
|
554
|
+
// Send Ready signal to indicate history is complete
|
|
555
|
+
ws.send(JSON.stringify({ Ready: true }));
|
|
556
|
+
// Send current status (dormant sessions report "running" since they wake on first message)
|
|
557
|
+
const effectiveStatus = session.dormant ? "running" : session.status;
|
|
558
|
+
const statusPatch = ConversationPatch.updateStatus(effectiveStatus);
|
|
559
|
+
ws.send(JSON.stringify({ JsonPatch: statusPatch }));
|
|
560
|
+
// Return unsubscribe function
|
|
561
|
+
return () => {
|
|
562
|
+
session.subscribers.delete(ws);
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Get all messages for a session (reconstructed from patches)
|
|
567
|
+
*/
|
|
568
|
+
getMessages(sessionId) {
|
|
569
|
+
const session = this.sessions.get(sessionId);
|
|
570
|
+
return session?.store.entries.filter(Boolean) ?? [];
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Get session info
|
|
574
|
+
*/
|
|
575
|
+
getSession(sessionId) {
|
|
576
|
+
return this.sessions.get(sessionId) ?? null;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Get session by branch
|
|
580
|
+
*/
|
|
581
|
+
getSessionByBranch(projectId, branch) {
|
|
582
|
+
for (const session of this.sessions.values()) {
|
|
583
|
+
if (session.projectId === projectId && session.branch === branch) {
|
|
584
|
+
return session;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return null;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Get all sessions for a project regardless of branch
|
|
591
|
+
*/
|
|
592
|
+
getSessionsByProject(projectId) {
|
|
593
|
+
const results = [];
|
|
594
|
+
for (const session of this.sessions.values()) {
|
|
595
|
+
if (session.projectId === projectId) {
|
|
596
|
+
results.push(session);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return results;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Check if a session is running
|
|
603
|
+
*/
|
|
604
|
+
isRunning(sessionId) {
|
|
605
|
+
const session = this.sessions.get(sessionId);
|
|
606
|
+
return session?.status === "running";
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Stop a session — kills the process but preserves conversation history
|
|
610
|
+
* (like pressing ESC in Claude Code). The session becomes dormant so the
|
|
611
|
+
* next user message will spawn a fresh process with full context replay.
|
|
612
|
+
* The WebSocket stays alive so the UI remains connected.
|
|
613
|
+
*/
|
|
614
|
+
stopSession(sessionId) {
|
|
615
|
+
const session = this.sessions.get(sessionId);
|
|
616
|
+
if (!session) {
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
try {
|
|
620
|
+
const proc = session.process;
|
|
621
|
+
// Try provider-specific interrupt first (e.g. $/cancelRequest for Codex)
|
|
622
|
+
const provider = getProvider(session.agentType);
|
|
623
|
+
const interruptMsg = provider.formatInterrupt?.(sessionId);
|
|
624
|
+
if (interruptMsg && proc?.stdin) {
|
|
625
|
+
proc.stdin.write(interruptMsg);
|
|
626
|
+
}
|
|
627
|
+
// Clear session.process before killing so the process close handler
|
|
628
|
+
// (which checks session.process !== childProcess) skips its cleanup —
|
|
629
|
+
// we handle status + broadcast here instead.
|
|
630
|
+
session.process = null;
|
|
631
|
+
this.killProcess(proc);
|
|
632
|
+
// Finalize any in-flight streaming assistant text
|
|
633
|
+
this.finalizeStreamingEntry(session);
|
|
634
|
+
session.store.currentAssistantIndex = null;
|
|
635
|
+
// Add a system message so the UI shows the stop event in the conversation
|
|
636
|
+
this.pushEntry(sessionId, {
|
|
637
|
+
type: "system",
|
|
638
|
+
content: "Session stopped by user.",
|
|
639
|
+
timestamp: Date.now(),
|
|
640
|
+
});
|
|
641
|
+
// Mark as dormant so the next message triggers wakeDormantSession
|
|
642
|
+
// (which spawns a new process and replays the full conversation context).
|
|
643
|
+
session.dormant = true;
|
|
644
|
+
session.status = "stopped";
|
|
645
|
+
if (!session.skipDb)
|
|
646
|
+
this.storage.agentSessions.updateStatus(sessionId, "stopped");
|
|
647
|
+
this.broadcastPatch(sessionId, ConversationPatch.updateStatus("stopped"));
|
|
648
|
+
this.eventBus?.emit({ type: "session:status", projectId: session.projectId, branch: session.branch, sessionId: session.id, status: "stopped" });
|
|
649
|
+
// Don't send { finished: true } — keep the WebSocket connection alive
|
|
650
|
+
// so the UI stays "Connected" and the user can continue the conversation.
|
|
651
|
+
return true;
|
|
652
|
+
}
|
|
653
|
+
catch (error) {
|
|
654
|
+
console.error(`[AgentSession] Failed to stop session:`, error);
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Delete a session (stop and remove)
|
|
660
|
+
*/
|
|
661
|
+
deleteSession(sessionId) {
|
|
662
|
+
const session = this.sessions.get(sessionId);
|
|
663
|
+
if (session) {
|
|
664
|
+
getProvider(session.agentType).onSessionDestroyed?.(sessionId);
|
|
665
|
+
}
|
|
666
|
+
this.stopSession(sessionId);
|
|
667
|
+
this.sessions.delete(sessionId);
|
|
668
|
+
if (!session?.skipDb)
|
|
669
|
+
this.storage.agentSessions.delete(sessionId);
|
|
670
|
+
return true;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Restart a session (stop process, clear history, respawn)
|
|
674
|
+
* Returns the same session ID with a fresh conversation
|
|
675
|
+
*/
|
|
676
|
+
restartSession(sessionId, projectPath, agentType) {
|
|
677
|
+
const session = this.sessions.get(sessionId);
|
|
678
|
+
if (!session) {
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
console.log(`[AgentSession] Restarting session ${sessionId}`);
|
|
682
|
+
// 1. Kill the existing process
|
|
683
|
+
this.killProcess(session.process);
|
|
684
|
+
// 2. Clear persisted entries
|
|
685
|
+
if (!session.skipDb) {
|
|
686
|
+
this.storage.agentSessions.deleteEntries(sessionId);
|
|
687
|
+
}
|
|
688
|
+
// 3. Clear message store
|
|
689
|
+
session.store.patches = [];
|
|
690
|
+
session.store.entries = [];
|
|
691
|
+
session.store.indexProvider.reset();
|
|
692
|
+
session.store.toolTracker.clear();
|
|
693
|
+
session.store.currentAssistantIndex = null;
|
|
694
|
+
session.buffer = "";
|
|
695
|
+
session.dormant = false;
|
|
696
|
+
// 4. Broadcast clear signal to all subscribers
|
|
697
|
+
const clearPatch = ConversationPatch.clearAll();
|
|
698
|
+
this.broadcastPatch(sessionId, clearPatch);
|
|
699
|
+
// 5. Update status to running
|
|
700
|
+
session.status = "running";
|
|
701
|
+
if (!session.skipDb)
|
|
702
|
+
this.storage.agentSessions.updateStatus(sessionId, "running");
|
|
703
|
+
this.broadcastPatch(sessionId, ConversationPatch.updateStatus("running"));
|
|
704
|
+
this.eventBus?.emit({ type: "session:status", projectId: session.projectId, branch: session.branch, sessionId: session.id, status: "running" });
|
|
705
|
+
// 6. Reset provider state and update agent type if specified
|
|
706
|
+
getProvider(session.agentType).onSessionDestroyed?.(sessionId);
|
|
707
|
+
if (agentType) {
|
|
708
|
+
session.agentType = agentType;
|
|
709
|
+
}
|
|
710
|
+
getProvider(session.agentType).onSessionCreated?.(sessionId);
|
|
711
|
+
// 7. Calculate absolute worktree path and respawn
|
|
712
|
+
const absoluteWorktreePath = resolveWorktreePath(projectPath, session.branch);
|
|
713
|
+
this.spawnAgent(session, absoluteWorktreePath);
|
|
714
|
+
return true;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Switch permission mode for a session (preserves conversation history)
|
|
718
|
+
*/
|
|
719
|
+
switchMode(sessionId, projectPath, newMode, initialMessage) {
|
|
720
|
+
const session = this.sessions.get(sessionId);
|
|
721
|
+
if (!session) {
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
console.log(`[AgentSession] Switching session ${sessionId} from ${session.permissionMode} to ${newMode}`);
|
|
725
|
+
// 1. Kill existing process
|
|
726
|
+
this.killProcess(session.process);
|
|
727
|
+
// 2. Keep message store intact (preserve history in UI)
|
|
728
|
+
// Only reset streaming state and buffer
|
|
729
|
+
this.finalizeStreamingEntry(session);
|
|
730
|
+
session.store.currentAssistantIndex = null;
|
|
731
|
+
session.buffer = "";
|
|
732
|
+
session.dormant = false;
|
|
733
|
+
// 3. Set new permission mode + persist
|
|
734
|
+
session.permissionMode = newMode;
|
|
735
|
+
if (!session.skipDb) {
|
|
736
|
+
this.storage.agentSessions.updatePermissionMode(session.id, newMode);
|
|
737
|
+
}
|
|
738
|
+
// 4. Update status to running, broadcast
|
|
739
|
+
session.status = "running";
|
|
740
|
+
if (!session.skipDb)
|
|
741
|
+
this.storage.agentSessions.updateStatus(sessionId, "running");
|
|
742
|
+
this.broadcastPatch(sessionId, ConversationPatch.updateStatus("running"));
|
|
743
|
+
this.eventBus?.emit({ type: "session:status", projectId: session.projectId, branch: session.branch, sessionId: session.id, status: "running" });
|
|
744
|
+
// 5. Respawn Claude Code with new mode flags
|
|
745
|
+
const absoluteWorktreePath = resolveWorktreePath(projectPath, session.branch);
|
|
746
|
+
this.spawnAgent(session, absoluteWorktreePath);
|
|
747
|
+
// 6. Send initial message or conversation summary
|
|
748
|
+
if (initialMessage) {
|
|
749
|
+
// Wait a bit for process to be ready, then send
|
|
750
|
+
setTimeout(() => {
|
|
751
|
+
this.sendUserMessage(sessionId, initialMessage);
|
|
752
|
+
}, 500);
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
// Build full conversation context from existing entries
|
|
756
|
+
const context = this.buildFullConversationContext(session.store.entries);
|
|
757
|
+
if (context) {
|
|
758
|
+
setTimeout(() => {
|
|
759
|
+
// Send context without adding to visible messages
|
|
760
|
+
const provider = getProvider(session.agentType);
|
|
761
|
+
const formatted = provider.formatUserInput(context, session.id);
|
|
762
|
+
try {
|
|
763
|
+
session.process?.stdin?.write(formatted);
|
|
764
|
+
}
|
|
765
|
+
catch (error) {
|
|
766
|
+
console.error(`[AgentSession] Failed to send conversation context:`, error);
|
|
767
|
+
}
|
|
768
|
+
}, 500);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return true;
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Accept a plan and restart the session in edit mode
|
|
775
|
+
*/
|
|
776
|
+
acceptPlanAndRestart(sessionId, projectPath, planContent) {
|
|
777
|
+
return this.switchMode(sessionId, projectPath, "edit", planContent);
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Build full conversation context from message entries for context transfer.
|
|
781
|
+
* Uses XML-tagged format to prevent Claude from confusing historical context
|
|
782
|
+
* with actual tool executions in the current session.
|
|
783
|
+
*/
|
|
784
|
+
buildFullConversationContext(entries) {
|
|
785
|
+
const lines = [];
|
|
786
|
+
for (const entry of entries) {
|
|
787
|
+
if (!entry)
|
|
788
|
+
continue;
|
|
789
|
+
switch (entry.type) {
|
|
790
|
+
case "user": {
|
|
791
|
+
const text = typeof entry.content === "string"
|
|
792
|
+
? entry.content
|
|
793
|
+
: entry.content.filter(p => p.type === "text").map(p => p.text).join("\n");
|
|
794
|
+
lines.push(`<user_message>${text}</user_message>`);
|
|
795
|
+
break;
|
|
796
|
+
}
|
|
797
|
+
case "assistant":
|
|
798
|
+
lines.push(`<assistant_message>${entry.content}</assistant_message>`);
|
|
799
|
+
break;
|
|
800
|
+
case "tool_use": {
|
|
801
|
+
const inputStr = typeof entry.input === "string"
|
|
802
|
+
? entry.input
|
|
803
|
+
: JSON.stringify(entry.input);
|
|
804
|
+
const truncatedInput = inputStr.length > 2000 ? inputStr.substring(0, 2000) + "..." : inputStr;
|
|
805
|
+
lines.push(`<historical_tool_call tool="${entry.tool}">${truncatedInput}</historical_tool_call>`);
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
808
|
+
case "tool_result": {
|
|
809
|
+
const truncatedOutput = entry.output.length > 2000 ? entry.output.substring(0, 2000) + "..." : entry.output;
|
|
810
|
+
lines.push(`<historical_tool_result>${truncatedOutput}</historical_tool_result>`);
|
|
811
|
+
break;
|
|
812
|
+
}
|
|
813
|
+
case "error":
|
|
814
|
+
lines.push(`<error>${entry.message}</error>`);
|
|
815
|
+
break;
|
|
816
|
+
case "system":
|
|
817
|
+
// Skip system messages (session lifecycle noise)
|
|
818
|
+
break;
|
|
819
|
+
// Skip thinking blocks (internal)
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
if (lines.length === 0)
|
|
823
|
+
return null;
|
|
824
|
+
return [
|
|
825
|
+
`<conversation_summary>`,
|
|
826
|
+
`This is a READ-ONLY summary of a previous conversation session. The session was interrupted and you are now in a NEW process.`,
|
|
827
|
+
``,
|
|
828
|
+
`IMPORTANT:`,
|
|
829
|
+
`- You did NOT execute any of the tool calls shown below in THIS session. They happened in a previous, now-terminated process.`,
|
|
830
|
+
`- Any file edits, reads, or other tool actions shown here may or may not have been applied. Do NOT assume they succeeded.`,
|
|
831
|
+
`- If you need to read or edit files, you MUST make new tool calls. Do not reference previous tool calls as if they are still in effect.`,
|
|
832
|
+
`- Respond naturally to the user's latest message below. Use your tools normally — do not format tool calls as text.`,
|
|
833
|
+
``,
|
|
834
|
+
...lines,
|
|
835
|
+
`</conversation_summary>`,
|
|
836
|
+
].join("\n");
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Wake a dormant session: spawn process, send full context + user message
|
|
840
|
+
*/
|
|
841
|
+
wakeDormantSession(session, projectPath, userMessage) {
|
|
842
|
+
console.log(`[AgentSession] Waking dormant session ${session.id}`);
|
|
843
|
+
session.dormant = false;
|
|
844
|
+
session.status = "running";
|
|
845
|
+
if (!session.skipDb)
|
|
846
|
+
this.storage.agentSessions.updateStatus(session.id, "running");
|
|
847
|
+
this.broadcastPatch(session.id, ConversationPatch.updateStatus("running"));
|
|
848
|
+
this.eventBus?.emit({ type: "session:status", projectId: session.projectId, branch: session.branch, sessionId: session.id, status: "running" });
|
|
849
|
+
// Spawn Claude Code process
|
|
850
|
+
const absoluteWorktreePath = resolveWorktreePath(projectPath, session.branch);
|
|
851
|
+
this.spawnAgent(session, absoluteWorktreePath);
|
|
852
|
+
// Push user message to store (+ persist to DB)
|
|
853
|
+
this.pushEntry(session.id, {
|
|
854
|
+
type: "user",
|
|
855
|
+
content: userMessage,
|
|
856
|
+
timestamp: Date.now(),
|
|
857
|
+
}, true);
|
|
858
|
+
// After process ready: send full context + new message to stdin
|
|
859
|
+
setTimeout(() => {
|
|
860
|
+
const context = this.buildFullConversationContext(session.store.entries);
|
|
861
|
+
if (context) {
|
|
862
|
+
const provider = getProvider(session.agentType);
|
|
863
|
+
const formatted = provider.formatUserInput(context, session.id);
|
|
864
|
+
try {
|
|
865
|
+
session.process?.stdin?.write(formatted);
|
|
866
|
+
}
|
|
867
|
+
catch (error) {
|
|
868
|
+
console.error(`[AgentSession] Failed to send context to woken session:`, error);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}, 500);
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Restore sessions from database on startup.
|
|
875
|
+
* Creates dormant RunningSession objects with process=null for sessions that have entries.
|
|
876
|
+
*/
|
|
877
|
+
restoreSessionsFromDb() {
|
|
878
|
+
const allSessions = this.storage.agentSessions.getAll();
|
|
879
|
+
let restoredCount = 0;
|
|
880
|
+
for (const dbSession of allSessions) {
|
|
881
|
+
// Skip sessions already in memory
|
|
882
|
+
if (this.sessions.has(dbSession.id))
|
|
883
|
+
continue;
|
|
884
|
+
const entries = this.storage.agentSessions.getEntries(dbSession.id);
|
|
885
|
+
// Skip sessions with no entries (stale metadata)
|
|
886
|
+
if (entries.length === 0)
|
|
887
|
+
continue;
|
|
888
|
+
// Rebuild MessageStore
|
|
889
|
+
const indexProvider = new EntryIndexProvider();
|
|
890
|
+
const toolTracker = new EntryTracker(indexProvider);
|
|
891
|
+
const store = {
|
|
892
|
+
patches: [],
|
|
893
|
+
entries: [],
|
|
894
|
+
indexProvider,
|
|
895
|
+
toolTracker,
|
|
896
|
+
currentAssistantIndex: null,
|
|
897
|
+
};
|
|
898
|
+
let maxIndex = -1;
|
|
899
|
+
for (const row of entries) {
|
|
900
|
+
try {
|
|
901
|
+
const message = JSON.parse(row.data);
|
|
902
|
+
const idx = row.entry_index;
|
|
903
|
+
store.entries[idx] = message;
|
|
904
|
+
// Generate ADD patch for history replay
|
|
905
|
+
const patch = ConversationPatch.addEntry(idx, message);
|
|
906
|
+
store.patches.push(patch);
|
|
907
|
+
// Rebuild tool tracker for tool_use and tool_result entries
|
|
908
|
+
if (message.type === "tool_use" && message.toolUseId) {
|
|
909
|
+
toolTracker.set(`tool_use:${message.toolUseId}`, idx);
|
|
910
|
+
}
|
|
911
|
+
else if (message.type === "tool_result" && message.toolUseId) {
|
|
912
|
+
toolTracker.set(`tool_result:${message.toolUseId}`, idx);
|
|
913
|
+
}
|
|
914
|
+
if (idx > maxIndex)
|
|
915
|
+
maxIndex = idx;
|
|
916
|
+
}
|
|
917
|
+
catch (error) {
|
|
918
|
+
console.error(`[AgentSession] Failed to parse entry for session ${dbSession.id}:`, error);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
// Set index provider to continue after the max restored index
|
|
922
|
+
indexProvider.setIndex(maxIndex + 1);
|
|
923
|
+
const permissionMode = (dbSession.permission_mode === "plan" ? "plan" : "edit");
|
|
924
|
+
const runningSession = {
|
|
925
|
+
id: dbSession.id,
|
|
926
|
+
projectId: dbSession.project_id,
|
|
927
|
+
branch: dbSession.branch || null,
|
|
928
|
+
process: null,
|
|
929
|
+
dormant: true,
|
|
930
|
+
store,
|
|
931
|
+
subscribers: new Set(),
|
|
932
|
+
status: "stopped",
|
|
933
|
+
buffer: "",
|
|
934
|
+
skipDb: false,
|
|
935
|
+
permissionMode,
|
|
936
|
+
agentType: dbSession.agent_type || "claude-code",
|
|
937
|
+
};
|
|
938
|
+
this.sessions.set(dbSession.id, runningSession);
|
|
939
|
+
// Update DB status to stopped (was likely "running" when server crashed)
|
|
940
|
+
this.storage.agentSessions.updateStatus(dbSession.id, "stopped");
|
|
941
|
+
restoredCount++;
|
|
942
|
+
}
|
|
943
|
+
if (restoredCount > 0) {
|
|
944
|
+
console.log(`[AgentSession] Restored ${restoredCount} dormant session(s) from database`);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* Kill all active session processes and clear state for graceful shutdown
|
|
949
|
+
*/
|
|
950
|
+
shutdown() {
|
|
951
|
+
for (const [id, session] of this.sessions) {
|
|
952
|
+
try {
|
|
953
|
+
getProvider(session.agentType).onSessionDestroyed?.(id);
|
|
954
|
+
}
|
|
955
|
+
catch { /* ignore - provider cleanup is best-effort */ }
|
|
956
|
+
this.killProcess(session.process);
|
|
957
|
+
}
|
|
958
|
+
this.sessions.clear();
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* Broadcast a JSON patch to all subscribers
|
|
962
|
+
*/
|
|
963
|
+
broadcastPatch(sessionId, patch) {
|
|
964
|
+
const msg = { JsonPatch: patch };
|
|
965
|
+
this.broadcastRaw(sessionId, msg);
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Broadcast a raw message to all subscribers
|
|
969
|
+
*/
|
|
970
|
+
broadcastRaw(sessionId, message) {
|
|
971
|
+
const session = this.sessions.get(sessionId);
|
|
972
|
+
if (!session)
|
|
973
|
+
return;
|
|
974
|
+
const json = JSON.stringify(message);
|
|
975
|
+
for (const ws of session.subscribers) {
|
|
976
|
+
try {
|
|
977
|
+
ws.send(json);
|
|
978
|
+
}
|
|
979
|
+
catch (error) {
|
|
980
|
+
// WebSocket might be closed
|
|
981
|
+
session.subscribers.delete(ws);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|