@akiojin/gwt 2.13.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +33 -0
- package/README.md +31 -0
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +17 -11
- package/dist/claude.js.map +1 -1
- package/dist/cli/ui/components/App.d.ts +0 -6
- package/dist/cli/ui/components/App.d.ts.map +1 -1
- package/dist/cli/ui/components/App.js +27 -88
- package/dist/cli/ui/components/App.js.map +1 -1
- package/dist/cli/ui/components/common/Select.js +2 -2
- package/dist/cli/ui/components/common/Select.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.js +14 -2
- package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchQuickStartScreen.js +3 -3
- package/dist/cli/ui/components/screens/BranchQuickStartScreen.js.map +1 -1
- package/dist/cli/ui/utils/continueSession.d.ts.map +1 -1
- package/dist/cli/ui/utils/continueSession.js +1 -1
- package/dist/cli/ui/utils/continueSession.js.map +1 -1
- package/dist/client/assets/index-DPWWHorC.js +72 -0
- package/dist/client/assets/index-DsDNCy5f.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/codex.d.ts.map +1 -1
- package/dist/codex.js +21 -11
- package/dist/codex.js.map +1 -1
- package/dist/config/builtin-tools.d.ts.map +1 -1
- package/dist/config/builtin-tools.js +3 -2
- package/dist/config/builtin-tools.js.map +1 -1
- package/dist/config/shared-env.d.ts +41 -0
- package/dist/config/shared-env.d.ts.map +1 -0
- package/dist/config/shared-env.js +114 -0
- package/dist/config/shared-env.js.map +1 -0
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +20 -17
- package/dist/gemini.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -7
- package/dist/index.js.map +1 -1
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/logging/logger.js +4 -1
- package/dist/logging/logger.js.map +1 -1
- package/dist/qwen.d.ts.map +1 -1
- package/dist/qwen.js +15 -11
- package/dist/qwen.js.map +1 -1
- package/dist/services/aiToolResolver.d.ts +41 -0
- package/dist/services/aiToolResolver.d.ts.map +1 -0
- package/dist/services/aiToolResolver.js +194 -0
- package/dist/services/aiToolResolver.js.map +1 -0
- package/dist/services/customToolResolver.d.ts +10 -0
- package/dist/services/customToolResolver.d.ts.map +1 -0
- package/dist/services/customToolResolver.js +71 -0
- package/dist/services/customToolResolver.js.map +1 -0
- package/dist/shared/aiToolConstants.d.ts +9 -0
- package/dist/shared/aiToolConstants.d.ts.map +1 -0
- package/dist/shared/aiToolConstants.js +29 -0
- package/dist/shared/aiToolConstants.js.map +1 -0
- package/dist/types/tools.d.ts +12 -0
- package/dist/types/tools.d.ts.map +1 -1
- package/dist/utils/prompt.d.ts.map +1 -1
- package/dist/utils/prompt.js.map +1 -1
- package/dist/utils/session.d.ts.map +1 -1
- package/dist/utils/session.js +15 -6
- package/dist/utils/session.js.map +1 -1
- package/dist/utils/terminal.d.ts +12 -3
- package/dist/utils/terminal.d.ts.map +1 -1
- package/dist/utils/terminal.js +5 -34
- package/dist/utils/terminal.js.map +1 -1
- package/dist/utils/webui.d.ts +8 -0
- package/dist/utils/webui.d.ts.map +1 -0
- package/dist/utils/webui.js +35 -0
- package/dist/utils/webui.js.map +1 -0
- package/dist/web/client/src/components/AIToolLaunchModal.d.ts +9 -0
- package/dist/web/client/src/components/AIToolLaunchModal.d.ts.map +1 -0
- package/dist/web/client/src/components/AIToolLaunchModal.js +363 -0
- package/dist/web/client/src/components/AIToolLaunchModal.js.map +1 -0
- package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
- package/dist/web/client/src/components/BranchGraph.js +46 -49
- package/dist/web/client/src/components/BranchGraph.js.map +1 -1
- package/dist/web/client/src/components/CustomToolForm.d.ts +23 -0
- package/dist/web/client/src/components/CustomToolForm.d.ts.map +1 -0
- package/dist/web/client/src/components/CustomToolForm.js +209 -0
- package/dist/web/client/src/components/CustomToolForm.js.map +1 -0
- package/dist/web/client/src/components/CustomToolList.d.ts +10 -0
- package/dist/web/client/src/components/CustomToolList.d.ts.map +1 -0
- package/dist/web/client/src/components/CustomToolList.js +57 -0
- package/dist/web/client/src/components/CustomToolList.js.map +1 -0
- package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
- package/dist/web/client/src/components/EnvEditor.js +33 -26
- package/dist/web/client/src/components/EnvEditor.js.map +1 -1
- package/dist/web/client/src/components/EnvironmentEditor.d.ts +17 -0
- package/dist/web/client/src/components/EnvironmentEditor.d.ts.map +1 -0
- package/dist/web/client/src/components/EnvironmentEditor.js +22 -0
- package/dist/web/client/src/components/EnvironmentEditor.js.map +1 -0
- package/dist/web/client/src/components/Terminal.d.ts.map +1 -1
- package/dist/web/client/src/components/Terminal.js +10 -3
- package/dist/web/client/src/components/Terminal.js.map +1 -1
- package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts +10 -0
- package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts.map +1 -0
- package/dist/web/client/src/components/branch-detail/BranchInfoCards.js +104 -0
- package/dist/web/client/src/components/branch-detail/BranchInfoCards.js.map +1 -0
- package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts +22 -0
- package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts.map +1 -0
- package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js +79 -0
- package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js.map +1 -0
- package/dist/web/client/src/components/branch-detail/TerminalPanel.d.ts +11 -0
- package/dist/web/client/src/components/branch-detail/TerminalPanel.d.ts.map +1 -0
- package/dist/web/client/src/components/branch-detail/TerminalPanel.js +32 -0
- package/dist/web/client/src/components/branch-detail/TerminalPanel.js.map +1 -0
- package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts +40 -0
- package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts.map +1 -0
- package/dist/web/client/src/components/branch-detail/ToolLauncher.js +147 -0
- package/dist/web/client/src/components/branch-detail/ToolLauncher.js.map +1 -0
- package/dist/web/client/src/components/branch-detail/index.d.ts +5 -0
- package/dist/web/client/src/components/branch-detail/index.d.ts.map +1 -0
- package/dist/web/client/src/components/branch-detail/index.js +5 -0
- package/dist/web/client/src/components/branch-detail/index.js.map +1 -0
- package/dist/web/client/src/components/common/BranchCard.d.ts +17 -0
- package/dist/web/client/src/components/common/BranchCard.d.ts.map +1 -0
- package/dist/web/client/src/components/common/BranchCard.js +36 -0
- package/dist/web/client/src/components/common/BranchCard.js.map +1 -0
- package/dist/web/client/src/components/common/MetricCard.d.ts +10 -0
- package/dist/web/client/src/components/common/MetricCard.d.ts.map +1 -0
- package/dist/web/client/src/components/common/MetricCard.js +10 -0
- package/dist/web/client/src/components/common/MetricCard.js.map +1 -0
- package/dist/web/client/src/components/common/PageHeader.d.ts +12 -0
- package/dist/web/client/src/components/common/PageHeader.d.ts.map +1 -0
- package/dist/web/client/src/components/common/PageHeader.js +14 -0
- package/dist/web/client/src/components/common/PageHeader.js.map +1 -0
- package/dist/web/client/src/components/common/SearchInput.d.ts +14 -0
- package/dist/web/client/src/components/common/SearchInput.d.ts.map +1 -0
- package/dist/web/client/src/components/common/SearchInput.js +15 -0
- package/dist/web/client/src/components/common/SearchInput.js.map +1 -0
- package/dist/web/client/src/components/common/StatusBadge.d.ts +10 -0
- package/dist/web/client/src/components/common/StatusBadge.d.ts.map +1 -0
- package/dist/web/client/src/components/common/StatusBadge.js +15 -0
- package/dist/web/client/src/components/common/StatusBadge.js.map +1 -0
- package/dist/web/client/src/components/common/index.d.ts +6 -0
- package/dist/web/client/src/components/common/index.d.ts.map +1 -0
- package/dist/web/client/src/components/common/index.js +6 -0
- package/dist/web/client/src/components/common/index.js.map +1 -0
- package/dist/web/client/src/components/ui/alert.d.ts +9 -0
- package/dist/web/client/src/components/ui/alert.d.ts.map +1 -0
- package/dist/web/client/src/components/ui/alert.js +25 -0
- package/dist/web/client/src/components/ui/alert.js.map +1 -0
- package/dist/web/client/src/components/ui/badge.d.ts +10 -0
- package/dist/web/client/src/components/ui/badge.d.ts.map +1 -0
- package/dist/web/client/src/components/ui/badge.js +25 -0
- package/dist/web/client/src/components/ui/badge.js.map +1 -0
- package/dist/web/client/src/components/ui/button.d.ts +12 -0
- package/dist/web/client/src/components/ui/button.d.ts.map +1 -0
- package/dist/web/client/src/components/ui/button.js +33 -0
- package/dist/web/client/src/components/ui/button.js.map +1 -0
- package/dist/web/client/src/components/ui/card.d.ts +9 -0
- package/dist/web/client/src/components/ui/card.d.ts.map +1 -0
- package/dist/web/client/src/components/ui/card.js +16 -0
- package/dist/web/client/src/components/ui/card.js.map +1 -0
- package/dist/web/client/src/components/ui/index.d.ts +8 -0
- package/dist/web/client/src/components/ui/index.d.ts.map +1 -0
- package/dist/web/client/src/components/ui/index.js +8 -0
- package/dist/web/client/src/components/ui/index.js.map +1 -0
- package/dist/web/client/src/components/ui/input.d.ts +4 -0
- package/dist/web/client/src/components/ui/input.d.ts.map +1 -0
- package/dist/web/client/src/components/ui/input.js +8 -0
- package/dist/web/client/src/components/ui/input.js.map +1 -0
- package/dist/web/client/src/components/ui/select.d.ts +14 -0
- package/dist/web/client/src/components/ui/select.d.ts.map +1 -0
- package/dist/web/client/src/components/ui/select.js +39 -0
- package/dist/web/client/src/components/ui/select.js.map +1 -0
- package/dist/web/client/src/components/ui/table.d.ts +11 -0
- package/dist/web/client/src/components/ui/table.d.ts.map +1 -0
- package/dist/web/client/src/components/ui/table.js +21 -0
- package/dist/web/client/src/components/ui/table.js.map +1 -0
- package/dist/web/client/src/hooks/useSessions.d.ts.map +1 -1
- package/dist/web/client/src/hooks/useSessions.js +6 -1
- package/dist/web/client/src/hooks/useSessions.js.map +1 -1
- package/dist/web/client/src/lib/utils.d.ts +7 -0
- package/dist/web/client/src/lib/utils.d.ts.map +1 -0
- package/dist/web/client/src/lib/utils.js +10 -0
- package/dist/web/client/src/lib/utils.js.map +1 -0
- package/dist/web/client/src/lib/websocket.d.ts +7 -0
- package/dist/web/client/src/lib/websocket.d.ts.map +1 -1
- package/dist/web/client/src/lib/websocket.js +44 -0
- package/dist/web/client/src/lib/websocket.js.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.js +113 -361
- package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.js +89 -127
- package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.js +46 -41
- package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
- package/dist/web/client/src/pages/ConfigPage.d.ts +3 -0
- package/dist/web/client/src/pages/ConfigPage.d.ts.map +1 -0
- package/dist/web/client/src/pages/ConfigPage.js +216 -0
- package/dist/web/client/src/pages/ConfigPage.js.map +1 -0
- package/dist/web/client/vite.config.d.ts.map +1 -1
- package/dist/web/client/vite.config.js +8 -1
- package/dist/web/client/vite.config.js.map +1 -1
- package/dist/web/server/index.d.ts +24 -2
- package/dist/web/server/index.d.ts.map +1 -1
- package/dist/web/server/index.js +46 -15
- package/dist/web/server/index.js.map +1 -1
- package/dist/web/server/pty/manager.d.ts +12 -10
- package/dist/web/server/pty/manager.d.ts.map +1 -1
- package/dist/web/server/pty/manager.js +76 -43
- package/dist/web/server/pty/manager.js.map +1 -1
- package/dist/web/server/routes/sessions.d.ts.map +1 -1
- package/dist/web/server/routes/sessions.js +35 -2
- package/dist/web/server/routes/sessions.js.map +1 -1
- package/dist/web/server/routes/worktrees.js +2 -2
- package/dist/web/server/routes/worktrees.js.map +1 -1
- package/dist/web/server/services/worktrees.d.ts.map +1 -1
- package/dist/web/server/services/worktrees.js +7 -1
- package/dist/web/server/services/worktrees.js.map +1 -1
- package/dist/web/server/tray.d.ts +24 -0
- package/dist/web/server/tray.d.ts.map +1 -0
- package/dist/web/server/tray.js +79 -0
- package/dist/web/server/tray.js.map +1 -0
- package/dist/web/server/websocket/handler.d.ts +18 -2
- package/dist/web/server/websocket/handler.d.ts.map +1 -1
- package/dist/web/server/websocket/handler.js +82 -9
- package/dist/web/server/websocket/handler.js.map +1 -1
- package/package.json +15 -2
- package/src/claude.ts +26 -15
- package/src/cli/ui/__tests__/components/common/Select.test.tsx +11 -0
- package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +17 -1
- package/src/cli/ui/__tests__/components/screens/BranchQuickStartScreen.test.tsx +4 -4
- package/src/cli/ui/components/App.tsx +33 -133
- package/src/cli/ui/components/common/Select.tsx +2 -2
- package/src/cli/ui/components/screens/BranchListScreen.tsx +43 -23
- package/src/cli/ui/components/screens/BranchQuickStartScreen.tsx +41 -46
- package/src/cli/ui/utils/continueSession.ts +1 -7
- package/src/codex.ts +31 -22
- package/src/config/builtin-tools.ts +6 -2
- package/src/config/shared-env.ts +139 -0
- package/src/gemini.ts +35 -22
- package/src/index.ts +54 -7
- package/src/logging/logger.ts +5 -2
- package/src/qwen.ts +28 -19
- package/src/services/aiToolResolver.ts +276 -0
- package/src/services/customToolResolver.ts +98 -0
- package/src/shared/aiToolConstants.ts +30 -0
- package/src/trayicon.d.ts +30 -0
- package/src/types/tools.ts +15 -0
- package/src/utils/prompt.ts +15 -9
- package/src/utils/session.ts +80 -26
- package/src/utils/terminal.ts +11 -41
- package/src/utils/webui.ts +43 -0
- package/src/web/client/components.json +21 -0
- package/src/web/client/src/components/AIToolLaunchModal.tsx +575 -0
- package/src/web/client/src/components/BranchGraph.tsx +95 -75
- package/src/web/client/src/components/CustomToolForm.tsx +386 -0
- package/src/web/client/src/components/CustomToolList.tsx +119 -0
- package/src/web/client/src/components/EnvEditor.tsx +91 -81
- package/src/web/client/src/components/EnvironmentEditor.tsx +97 -0
- package/src/web/client/src/components/Terminal.tsx +11 -3
- package/src/web/client/src/components/branch-detail/BranchInfoCards.tsx +179 -0
- package/src/web/client/src/components/branch-detail/SessionHistoryTable.tsx +181 -0
- package/src/web/client/src/components/branch-detail/TerminalPanel.tsx +92 -0
- package/src/web/client/src/components/branch-detail/ToolLauncher.tsx +327 -0
- package/src/web/client/src/components/branch-detail/index.ts +4 -0
- package/src/web/client/src/components/common/BranchCard.tsx +117 -0
- package/src/web/client/src/components/common/MetricCard.tsx +22 -0
- package/src/web/client/src/components/common/PageHeader.tsx +44 -0
- package/src/web/client/src/components/common/SearchInput.tsx +40 -0
- package/src/web/client/src/components/common/StatusBadge.tsx +37 -0
- package/src/web/client/src/components/common/index.ts +5 -0
- package/src/web/client/src/components/ui/alert.tsx +63 -0
- package/src/web/client/src/components/ui/badge.tsx +44 -0
- package/src/web/client/src/components/ui/button.tsx +57 -0
- package/src/web/client/src/components/ui/card.tsx +82 -0
- package/src/web/client/src/components/ui/index.ts +32 -0
- package/src/web/client/src/components/ui/input.tsx +21 -0
- package/src/web/client/src/components/ui/select.tsx +156 -0
- package/src/web/client/src/components/ui/table.tsx +119 -0
- package/src/web/client/src/hooks/useSessions.ts +10 -1
- package/src/web/client/src/index.css +46 -816
- package/src/web/client/src/lib/utils.ts +10 -0
- package/src/web/client/src/lib/websocket.ts +48 -1
- package/src/web/client/src/pages/BranchDetailPage.tsx +222 -694
- package/src/web/client/src/pages/BranchListPage.tsx +190 -236
- package/src/web/client/src/pages/ConfigManagementPage.tsx +94 -76
- package/src/web/client/src/pages/ConfigPage.tsx +362 -0
- package/src/web/client/vite.config.ts +8 -1
- package/src/web/server/index.ts +72 -15
- package/src/web/server/pty/manager.ts +128 -55
- package/src/web/server/routes/sessions.ts +59 -7
- package/src/web/server/routes/worktrees.ts +3 -3
- package/src/web/server/services/worktrees.ts +12 -4
- package/src/web/server/tray.ts +93 -0
- package/src/web/server/websocket/handler.ts +119 -13
- package/dist/client/assets/index-DeNwPosA.css +0 -1
- package/dist/client/assets/index-Dl798X5w.js +0 -32
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 仕様: specs/SPEC-d5e56259/contracts/websocket.md
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { FastifyRequest } from "fastify";
|
|
8
|
+
import type { FastifyRequest, FastifyBaseLogger } from "fastify";
|
|
9
9
|
import type { WebSocket } from "@fastify/websocket";
|
|
10
10
|
import type { PTYManager } from "../pty/manager.js";
|
|
11
11
|
import type {
|
|
@@ -22,17 +22,18 @@ import type {
|
|
|
22
22
|
* WebSocketハンドラー
|
|
23
23
|
*/
|
|
24
24
|
export class WebSocketHandler {
|
|
25
|
-
|
|
25
|
+
private cleanupTimers: Map<string, NodeJS.Timeout> = new Map();
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
private ptyManager: PTYManager,
|
|
29
|
+
private logger: FastifyBaseLogger,
|
|
30
|
+
) {}
|
|
26
31
|
|
|
27
32
|
/**
|
|
28
33
|
* WebSocket接続を処理
|
|
29
34
|
*/
|
|
30
35
|
public handle(connection: WebSocket, request: FastifyRequest): void {
|
|
31
|
-
const
|
|
32
|
-
request.url,
|
|
33
|
-
`http://${request.hostname || "localhost"}`,
|
|
34
|
-
);
|
|
35
|
-
const sessionId = url.searchParams.get("sessionId");
|
|
36
|
+
const sessionId = resolveSessionId(request);
|
|
36
37
|
|
|
37
38
|
if (!sessionId) {
|
|
38
39
|
this.sendError(connection, "Missing sessionId parameter");
|
|
@@ -47,7 +48,14 @@ export class WebSocketHandler {
|
|
|
47
48
|
return;
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
this.logger.info(
|
|
52
|
+
`WebSocket connection established for session ${sessionId} (pid=${instance.ptyProcess.pid})`,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
this.clearCleanupTimer(sessionId);
|
|
56
|
+
|
|
50
57
|
const { ptyProcess } = instance;
|
|
58
|
+
let hasExited = false;
|
|
51
59
|
|
|
52
60
|
// セッションステータスを更新
|
|
53
61
|
this.ptyManager.updateStatus(sessionId, "running");
|
|
@@ -59,6 +67,8 @@ export class WebSocketHandler {
|
|
|
59
67
|
|
|
60
68
|
// PTYプロセス終了時の処理
|
|
61
69
|
ptyProcess.onExit(({ exitCode, signal }) => {
|
|
70
|
+
hasExited = true;
|
|
71
|
+
this.clearCleanupTimer(sessionId);
|
|
62
72
|
this.ptyManager.updateStatus(sessionId, "completed", exitCode);
|
|
63
73
|
this.sendExit(connection, exitCode, signal);
|
|
64
74
|
connection.close();
|
|
@@ -66,6 +76,10 @@ export class WebSocketHandler {
|
|
|
66
76
|
|
|
67
77
|
// クライアントからのメッセージを処理
|
|
68
78
|
connection.on("message", (rawMessage) => {
|
|
79
|
+
if (hasExited) {
|
|
80
|
+
this.sendError(connection, "Session already exited");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
69
83
|
try {
|
|
70
84
|
const message: ClientMessage = JSON.parse(rawMessage.toString());
|
|
71
85
|
this.handleClientMessage(message, ptyProcess, connection);
|
|
@@ -77,7 +91,10 @@ export class WebSocketHandler {
|
|
|
77
91
|
|
|
78
92
|
// 接続エラー時の処理
|
|
79
93
|
connection.on("error", (error) => {
|
|
80
|
-
|
|
94
|
+
this.logger.error(
|
|
95
|
+
{ err: error, sessionId },
|
|
96
|
+
`WebSocket error for session ${sessionId}`,
|
|
97
|
+
);
|
|
81
98
|
this.ptyManager.updateStatus(
|
|
82
99
|
sessionId,
|
|
83
100
|
"failed",
|
|
@@ -87,9 +104,17 @@ export class WebSocketHandler {
|
|
|
87
104
|
});
|
|
88
105
|
|
|
89
106
|
// 接続クローズ時の処理
|
|
90
|
-
connection.on("close", () => {
|
|
91
|
-
|
|
92
|
-
|
|
107
|
+
connection.on("close", (code, reason) => {
|
|
108
|
+
const reasonText = reason?.toString()?.trim();
|
|
109
|
+
this.logger.info(
|
|
110
|
+
`WebSocket closed for session ${sessionId} (code=${code}${reasonText ? `, reason=${reasonText}` : ""})`,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
if (hasExited) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
this.scheduleCleanup(sessionId);
|
|
93
118
|
});
|
|
94
119
|
}
|
|
95
120
|
|
|
@@ -104,12 +129,22 @@ export class WebSocketHandler {
|
|
|
104
129
|
switch (message.type) {
|
|
105
130
|
case "input": {
|
|
106
131
|
const inputMsg = message as InputMessage;
|
|
107
|
-
|
|
132
|
+
try {
|
|
133
|
+
ptyProcess.write(inputMsg.data);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
136
|
+
this.sendError(connection, `Failed to write to session: ${reason}`);
|
|
137
|
+
}
|
|
108
138
|
break;
|
|
109
139
|
}
|
|
110
140
|
case "resize": {
|
|
111
141
|
const resizeMsg = message as ResizeMessage;
|
|
112
|
-
|
|
142
|
+
try {
|
|
143
|
+
ptyProcess.resize(resizeMsg.data.cols, resizeMsg.data.rows);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
146
|
+
this.sendError(connection, `Failed to resize terminal: ${reason}`);
|
|
147
|
+
}
|
|
113
148
|
break;
|
|
114
149
|
}
|
|
115
150
|
case "ping": {
|
|
@@ -177,4 +212,75 @@ export class WebSocketHandler {
|
|
|
177
212
|
};
|
|
178
213
|
connection.send(JSON.stringify(message));
|
|
179
214
|
}
|
|
215
|
+
|
|
216
|
+
private scheduleCleanup(sessionId: string): void {
|
|
217
|
+
this.clearCleanupTimer(sessionId);
|
|
218
|
+
const timer = setTimeout(() => {
|
|
219
|
+
this.cleanupTimers.delete(sessionId);
|
|
220
|
+
const tracked = this.ptyManager.get(sessionId);
|
|
221
|
+
if (!tracked) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (
|
|
226
|
+
tracked.session.status === "running" ||
|
|
227
|
+
tracked.session.status === "pending"
|
|
228
|
+
) {
|
|
229
|
+
this.logger.warn(
|
|
230
|
+
`Auto-cleaning session ${sessionId} after unexpected client disconnect`,
|
|
231
|
+
);
|
|
232
|
+
this.ptyManager.updateStatus(
|
|
233
|
+
sessionId,
|
|
234
|
+
"failed",
|
|
235
|
+
undefined,
|
|
236
|
+
"Client disconnected",
|
|
237
|
+
);
|
|
238
|
+
this.ptyManager.delete(sessionId);
|
|
239
|
+
}
|
|
240
|
+
}, CLEANUP_GRACE_PERIOD_MS);
|
|
241
|
+
this.cleanupTimers.set(sessionId, timer);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private clearCleanupTimer(sessionId: string): void {
|
|
245
|
+
const timer = this.cleanupTimers.get(sessionId);
|
|
246
|
+
if (timer) {
|
|
247
|
+
clearTimeout(timer);
|
|
248
|
+
this.cleanupTimers.delete(sessionId);
|
|
249
|
+
this.logger.info(`Cleared cleanup timer for session ${sessionId}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const CLEANUP_GRACE_PERIOD_MS = Number(process.env.WS_CLEANUP_GRACE_MS ?? 3000);
|
|
255
|
+
|
|
256
|
+
interface RequestLike {
|
|
257
|
+
params?: { sessionId?: string } | undefined;
|
|
258
|
+
url: string;
|
|
259
|
+
hostname?: string;
|
|
260
|
+
headers?: { host?: string | undefined };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function resolveSessionId(
|
|
264
|
+
request: FastifyRequest | RequestLike,
|
|
265
|
+
): string | null {
|
|
266
|
+
const paramsId = (request as RequestLike).params?.sessionId;
|
|
267
|
+
if (typeof paramsId === "string" && paramsId.length > 0) {
|
|
268
|
+
return paramsId;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
const host =
|
|
273
|
+
(request as FastifyRequest).headers?.host ??
|
|
274
|
+
(request as RequestLike).hostname ??
|
|
275
|
+
"localhost";
|
|
276
|
+
const parsed = new URL(request.url, `http://${host}`);
|
|
277
|
+
const queryId = parsed.searchParams.get("sessionId");
|
|
278
|
+
if (queryId && queryId.length > 0) {
|
|
279
|
+
return queryId;
|
|
280
|
+
}
|
|
281
|
+
} catch {
|
|
282
|
+
// ignore
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return null;
|
|
180
286
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility,.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{--color-background: #050912;--color-surface: #0f172a;--color-surface-muted: #111c30;--color-card: rgba(15, 23, 42, .92);--color-border: rgba(148, 163, 184, .2);--color-border-strong: rgba(148, 163, 184, .45);--color-text: #e2e8f0;--color-muted: #94a3b8;--color-accent: #5eead4;--color-accent-strong: #2dd4bf;--color-warning: #fbbf24;--color-error: #fb7185;--color-success: #34d399;--color-remote: #60a5fa;--color-local: #c084fc;--shadow-card: 0 20px 45px rgba(2, 6, 23, .55);--shadow-soft: 0 10px 25px rgba(15, 23, 42, .45);--radius-lg: 24px;--radius-md: 16px;--radius-pill: 999px;font-family:Inter,Noto Sans JP,-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif}*{box-sizing:border-box;margin:0;padding:0}body{font-family:Inter,Noto Sans JP,-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif;background:radial-gradient(circle at top,#0b1221,#050912 55%);color:var(--color-text);min-height:100vh;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#root{min-height:100vh}a{color:var(--color-accent);text-decoration:none}a:hover{color:var(--color-accent-strong)}button{font:inherit}.app-shell{min-height:100vh;padding:2.5rem 1.75rem 3rem;background:linear-gradient(135deg,#17255473,#0891b214)}@media(max-width:768px){.app-shell{padding:1.5rem 1rem 2rem}}.page-hero{background:radial-gradient(circle at 15% 20%,rgba(94,234,212,.25),transparent 55%),radial-gradient(circle at 80% 0%,rgba(14,165,233,.2),transparent 45%),var(--color-card);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:2rem;margin-bottom:2rem;box-shadow:var(--shadow-card)}.page-hero--compact{padding:1.75rem 2rem}.page-hero__eyebrow{letter-spacing:.3em;text-transform:uppercase;color:var(--color-muted);font-size:.8rem;margin-bottom:.75rem}.page-hero h1{font-size:clamp(1.8rem,3vw,2.8rem);margin-bottom:.5rem}.page-hero__subtitle,.page-hero__meta{color:var(--color-muted);margin-top:.5rem;font-size:.95rem}.page-hero__actions{display:flex;flex-wrap:wrap;gap:.8rem;margin-top:1.5rem}.page-content{width:min(1400px,100%);margin:0 auto;display:flex;flex-direction:column;gap:1.5rem}.page-content--wide{width:min(1600px,100%)}.page-content--narrow{max-width:960px}.metrics-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1rem}.metric-card{background:var(--color-card);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:1.25rem;box-shadow:var(--shadow-soft)}.metric-card__label{font-size:.85rem;text-transform:uppercase;letter-spacing:.1em;color:var(--color-muted)}.metric-card__value{font-size:2rem;font-weight:600;margin-top:.25rem}.metric-card__hint{margin-top:.35rem;color:var(--color-muted);font-size:.85rem}.page-layout{display:flex;flex-direction:column;gap:1rem}.page-layout--split{display:grid;grid-template-columns:minmax(320px,420px) minmax(0,1fr);gap:1.5rem;align-items:start}@media(max-width:1024px){.page-layout--split{grid-template-columns:1fr}}.info-stack{display:flex;flex-direction:column;gap:1rem}.terminal-column{position:relative;min-height:100%}.toolbar{display:flex;gap:1rem;align-items:center;flex-wrap:wrap}.toolbar__field{flex:1;display:flex;align-items:center;gap:.5rem;background:var(--color-surface);border-radius:var(--radius-md);border:1px solid var(--color-border);padding:.75rem 1rem;color:var(--color-muted)}.toolbar__icon{font-size:1rem}.search-input{flex:1;border:none;background:transparent;color:var(--color-text);font-size:1rem}.search-input:focus{outline:none}.toolbar__count{color:var(--color-muted);font-size:.9rem}.page-state{background:var(--color-card);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:2rem;box-shadow:var(--shadow-soft)}.page-state h1,.page-state h2,.page-state h3{margin-bottom:.5rem}.page-state--card{text-align:left}.page-state--centered{text-align:center}.empty-state{text-align:center;padding:2.5rem 2rem;border-radius:var(--radius-lg);border:1px dashed var(--color-border-strong);background:#0f172ab3}.branch-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:1.25rem}.branch-card{background:var(--color-card);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:1.5rem;display:flex;flex-direction:column;gap:1rem;box-shadow:var(--shadow-soft)}.branch-card__header{display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap}.branch-card__header h2{font-size:1.2rem;word-break:break-all}.branch-card__eyebrow{color:var(--color-muted);text-transform:uppercase;letter-spacing:.1em;font-size:.75rem;margin-bottom:.35rem}.branch-card__commit{color:var(--color-muted);line-height:1.5}.branch-card__actions{display:flex;justify-content:space-between;gap:.75rem;flex-wrap:wrap;align-items:center}.badge-group{display:flex;gap:.4rem;flex-wrap:wrap}.status-badge{padding:.25rem .75rem;border-radius:var(--radius-pill);font-size:.8rem;font-weight:600;border:1px solid transparent}.status-badge--local{color:#fdf4ff;background:#c084fc26;border-color:#c084fc59}.status-badge--remote{color:#dbeafe;background:#60a5fa1f;border-color:#60a5fa59}.status-badge--success{color:#042f2e;background:#34d399d9;border:none}.status-badge--warning{color:#451a03;background:#fbbf24e6;border:none}.status-badge--muted{color:var(--color-muted);background:#94a3b826;border-color:#94a3b866}.pill-group{display:flex;gap:.5rem;flex-wrap:wrap}.pill{padding:.25rem .85rem;border-radius:var(--radius-pill);background:#94a3b81f;color:var(--color-muted);font-size:.85rem}.pill--success{background:#34d39926;color:var(--color-success)}.pill--warning{background:#fbbf242e;color:var(--color-warning)}.info-pill{font-size:.85rem;padding:.3rem .85rem;border-radius:var(--radius-pill);border:1px solid var(--color-border);background:#0f172aa6;color:var(--color-muted)}.info-pill--success{border-color:#34d39973;color:var(--color-success)}.info-pill--warning{border-color:#fbbf2473;color:var(--color-warning)}.section-card{background:var(--color-card);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:1.75rem;box-shadow:var(--shadow-soft);display:flex;flex-direction:column;gap:.85rem}.section-card__body{color:var(--color-muted);line-height:1.6}.metadata-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1rem}.metadata-grid--compact{grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}.metadata-grid dt{font-size:.8rem;text-transform:uppercase;letter-spacing:.08em;color:var(--color-muted)}.metadata-grid dd{font-weight:600;margin-top:.25rem}.list-muted{list-style:none;color:var(--color-muted);line-height:1.7}.inline-banner{margin-top:1rem;padding:.85rem 1.25rem;border-radius:var(--radius-md);font-weight:500}.inline-banner--success{background:#34d39926;color:var(--color-success)}.inline-banner--error{background:#fb71852e;color:var(--color-error)}.inline-banner--info{background:#5eead41f;color:var(--color-accent)}.terminal-section{gap:1rem}.terminal-surface{border-radius:var(--radius-md);border:1px solid var(--color-border);background:#050912;min-height:clamp(380px,70vh,85vh);height:clamp(380px,70vh,85vh);overflow:hidden}.button{border-radius:var(--radius-pill);padding:.65rem 1.5rem;border:1px solid transparent;font-weight:600;cursor:pointer;transition:transform .15s ease,box-shadow .15s ease}.button--primary{background:linear-gradient(135deg,var(--color-accent),var(--color-accent-strong));color:#04121a;box-shadow:0 10px 25px #2dd4bf66}.button--secondary{border-color:#5eead480;color:var(--color-accent);background:transparent}.button--ghost{border-color:var(--color-border);background:transparent;color:var(--color-text)}.button:disabled{opacity:.55;cursor:not-allowed;transform:none;box-shadow:none}.button:not(:disabled):hover{transform:translateY(-1px)}.link-back{display:inline-flex;align-items:center;font-size:.9rem;color:var(--color-muted);margin-bottom:.75rem}.session-hint{border-style:dashed;border-color:#5eead459}.terminal-section__header{display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;align-items:flex-start}.terminal-section__controls{display:flex;gap:.5rem}.terminal-overlay-backdrop{position:fixed;inset:0;background:#020617bf;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:900}.terminal-section--fullscreen{position:fixed;inset:2rem;z-index:1000;width:calc(100vw - 4rem);max-width:calc(100vw - 4rem);height:calc(100vh - 4rem);box-shadow:0 30px 60px #020617b3;display:flex;flex-direction:column}@media(max-width:768px){.terminal-section--fullscreen{inset:1rem;width:calc(100vw - 2rem);max-width:calc(100vw - 2rem);height:calc(100vh - 2rem)}}.terminal-section--fullscreen .terminal-surface{flex:1;height:auto;min-height:unset}.terminal-section__close{position:absolute;top:1rem;right:1rem;width:2.5rem;height:2.5rem;border-radius:50%;border:1px solid rgba(255,255,255,.2);background:#0f172acc;color:var(--color-text);font-size:1.25rem;cursor:pointer}.terminal-section__close:hover{background:#0f172af2}.branch-graph-panel{background:var(--color-card);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:1.75rem 2rem;box-shadow:var(--shadow-card)}.branch-graph-panel+.metrics-grid{margin-top:1.5rem}.branch-graph-panel__header{display:flex;justify-content:space-between;gap:1.5rem;flex-wrap:wrap;margin-bottom:1.5rem}.branch-graph-panel__eyebrow{letter-spacing:.3em;text-transform:uppercase;color:var(--color-muted);font-size:.8rem;margin-bottom:.25rem}.branch-graph-panel__legend{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center}.branch-graph-panel__empty{text-align:center;color:var(--color-muted)}.graph-chip{font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;padding:.35rem .75rem;border-radius:var(--radius-pill);border:1px solid var(--color-border);background:#0f172ab3}.graph-chip--base{border-color:var(--color-accent);color:var(--color-accent)}.graph-chip--local{border-color:var(--color-local);color:var(--color-local)}.graph-chip--remote{border-color:var(--color-remote);color:var(--color-remote)}.graph-chip--worktree{border-color:var(--color-success);color:var(--color-success)}.branch-graph{display:flex;flex-direction:column;gap:1.25rem}.branch-graph__lane{display:flex;flex-direction:column;gap:.75rem;padding-bottom:.75rem;border-bottom:1px solid rgba(148,163,184,.2)}.branch-graph__lane:last-child{border-bottom:none;padding-bottom:0}.branch-graph__lane-heading{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;flex-wrap:wrap}.branch-graph__lane-label{font-weight:600}.branch-graph__lane-meta{margin-left:.5rem;font-size:.75rem;letter-spacing:.1em;color:var(--color-muted)}.lane-meta--muted{color:#94a3b899}.branch-graph__lane-count{color:var(--color-muted);font-size:.85rem}.branch-graph__track{display:flex;align-items:center;gap:1rem;overflow-x:auto;padding-bottom:.5rem}.branch-graph__node-link{position:relative;text-decoration:none;min-width:180px;flex-shrink:0}.branch-graph__node{position:relative;border:1px solid var(--color-border);border-radius:var(--radius-md);padding:.85rem 1rem;background:var(--color-surface-muted);box-shadow:var(--shadow-soft)}.branch-graph__node:before{content:"";position:absolute;width:28px;height:2px;background:var(--color-border-strong);left:-22px;top:50%;transform:translateY(-50%);opacity:.6}.branch-graph__node--base:before{display:none}.branch-graph__node--local{border-color:#c084fccc;box-shadow:0 15px 35px #9449ff40}.branch-graph__node--remote{border-color:#60a5facc;box-shadow:0 15px 35px #0ea5e940}.branch-graph__node--merged{background:#2563eb40}.branch-graph__node--active{background:#0891b240}.branch-graph__node-label{font-weight:600;display:block}.branch-graph__node-meta{font-size:.75rem;color:var(--color-muted)}.branch-graph__tooltip{position:absolute;bottom:calc(100% + .5rem);left:0;background:var(--color-surface);border:1px solid var(--color-border-strong);border-radius:var(--radius-md);padding:.75rem;width:min(260px,60vw);box-shadow:var(--shadow-card);opacity:0;pointer-events:none;transform:translateY(.4rem);transition:opacity .15s ease,transform .15s ease;z-index:5}.branch-graph__tooltip p{font-size:.8rem;color:var(--color-text)}.branch-graph__tooltip p+p{margin-top:.25rem;color:var(--color-muted)}.branch-graph__node:hover .branch-graph__tooltip,.branch-graph__node:focus-within .branch-graph__tooltip{opacity:1;transform:translateY(0)}@media(max-width:768px){.branch-graph__track{flex-direction:column;align-items:flex-start}.branch-graph__node:before{width:2px;height:24px;left:50%;top:-18px}.branch-graph__node-link{width:100%}}
|