@jacques-ai/server 0.0.7-alpha.1
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/config/config.d.ts +34 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +32 -0
- package/dist/config/config.js.map +1 -0
- package/dist/connection/applescript.d.ts +46 -0
- package/dist/connection/applescript.d.ts.map +1 -0
- package/dist/connection/applescript.js +62 -0
- package/dist/connection/applescript.js.map +1 -0
- package/dist/connection/applescript.test.d.ts +5 -0
- package/dist/connection/applescript.test.d.ts.map +1 -0
- package/dist/connection/applescript.test.js +64 -0
- package/dist/connection/applescript.test.js.map +1 -0
- package/dist/connection/constants.d.ts +88 -0
- package/dist/connection/constants.d.ts.map +1 -0
- package/dist/connection/constants.js +110 -0
- package/dist/connection/constants.js.map +1 -0
- package/dist/connection/git-info.d.ts +30 -0
- package/dist/connection/git-info.d.ts.map +1 -0
- package/dist/connection/git-info.js +52 -0
- package/dist/connection/git-info.js.map +1 -0
- package/dist/connection/git-info.test.d.ts +5 -0
- package/dist/connection/git-info.test.d.ts.map +1 -0
- package/dist/connection/git-info.test.js +35 -0
- package/dist/connection/git-info.test.js.map +1 -0
- package/dist/connection/index.d.ts +19 -0
- package/dist/connection/index.d.ts.map +1 -0
- package/dist/connection/index.js +36 -0
- package/dist/connection/index.js.map +1 -0
- package/dist/connection/process-detection.d.ts +58 -0
- package/dist/connection/process-detection.d.ts.map +1 -0
- package/dist/connection/process-detection.js +239 -0
- package/dist/connection/process-detection.js.map +1 -0
- package/dist/connection/process-detection.test.d.ts +5 -0
- package/dist/connection/process-detection.test.d.ts.map +1 -0
- package/dist/connection/process-detection.test.js +43 -0
- package/dist/connection/process-detection.test.js.map +1 -0
- package/dist/connection/session-discovery.d.ts +55 -0
- package/dist/connection/session-discovery.d.ts.map +1 -0
- package/dist/connection/session-discovery.js +311 -0
- package/dist/connection/session-discovery.js.map +1 -0
- package/dist/connection/terminal-key.d.ts +126 -0
- package/dist/connection/terminal-key.d.ts.map +1 -0
- package/dist/connection/terminal-key.js +271 -0
- package/dist/connection/terminal-key.js.map +1 -0
- package/dist/connection/terminal-key.test.d.ts +5 -0
- package/dist/connection/terminal-key.test.d.ts.map +1 -0
- package/dist/connection/terminal-key.test.js +221 -0
- package/dist/connection/terminal-key.test.js.map +1 -0
- package/dist/connection/worktree.d.ts +114 -0
- package/dist/connection/worktree.d.ts.map +1 -0
- package/dist/connection/worktree.js +320 -0
- package/dist/connection/worktree.js.map +1 -0
- package/dist/connection/worktree.test.d.ts +5 -0
- package/dist/connection/worktree.test.d.ts.map +1 -0
- package/dist/connection/worktree.test.js +113 -0
- package/dist/connection/worktree.test.js.map +1 -0
- package/dist/focus-watcher.d.ts +51 -0
- package/dist/focus-watcher.d.ts.map +1 -0
- package/dist/focus-watcher.js +169 -0
- package/dist/focus-watcher.js.map +1 -0
- package/dist/handlers/event-handler.d.ts +93 -0
- package/dist/handlers/event-handler.d.ts.map +1 -0
- package/dist/handlers/event-handler.js +196 -0
- package/dist/handlers/event-handler.js.map +1 -0
- package/dist/handlers/event-handler.test.d.ts +5 -0
- package/dist/handlers/event-handler.test.d.ts.map +1 -0
- package/dist/handlers/event-handler.test.js +305 -0
- package/dist/handlers/event-handler.test.js.map +1 -0
- package/dist/handlers/session-handler.d.ts +23 -0
- package/dist/handlers/session-handler.d.ts.map +1 -0
- package/dist/handlers/session-handler.js +104 -0
- package/dist/handlers/session-handler.js.map +1 -0
- package/dist/handlers/session-handler.test.d.ts +5 -0
- package/dist/handlers/session-handler.test.d.ts.map +1 -0
- package/dist/handlers/session-handler.test.js +89 -0
- package/dist/handlers/session-handler.test.js.map +1 -0
- package/dist/handlers/settings-handler.d.ts +32 -0
- package/dist/handlers/settings-handler.d.ts.map +1 -0
- package/dist/handlers/settings-handler.js +127 -0
- package/dist/handlers/settings-handler.js.map +1 -0
- package/dist/handlers/settings-handler.test.d.ts +5 -0
- package/dist/handlers/settings-handler.test.d.ts.map +1 -0
- package/dist/handlers/settings-handler.test.js +105 -0
- package/dist/handlers/settings-handler.test.js.map +1 -0
- package/dist/handlers/window-handler.d.ts +30 -0
- package/dist/handlers/window-handler.d.ts.map +1 -0
- package/dist/handlers/window-handler.js +486 -0
- package/dist/handlers/window-handler.js.map +1 -0
- package/dist/handlers/window-handler.test.d.ts +8 -0
- package/dist/handlers/window-handler.test.d.ts.map +1 -0
- package/dist/handlers/window-handler.test.js +167 -0
- package/dist/handlers/window-handler.test.js.map +1 -0
- package/dist/handlers/worktree-handler.d.ts +28 -0
- package/dist/handlers/worktree-handler.d.ts.map +1 -0
- package/dist/handlers/worktree-handler.js +268 -0
- package/dist/handlers/worktree-handler.js.map +1 -0
- package/dist/handlers/worktree-handler.test.d.ts +8 -0
- package/dist/handlers/worktree-handler.test.d.ts.map +1 -0
- package/dist/handlers/worktree-handler.test.js +118 -0
- package/dist/handlers/worktree-handler.test.js.map +1 -0
- package/dist/handlers/ws-utils.d.ts +12 -0
- package/dist/handlers/ws-utils.d.ts.map +1 -0
- package/dist/handlers/ws-utils.js +16 -0
- package/dist/handlers/ws-utils.js.map +1 -0
- package/dist/http-api.d.ts +26 -0
- package/dist/http-api.d.ts.map +1 -0
- package/dist/http-api.js +148 -0
- package/dist/http-api.js.map +1 -0
- package/dist/logger.d.ts +42 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +147 -0
- package/dist/logger.js.map +1 -0
- package/dist/logging/logger-factory.d.ts +51 -0
- package/dist/logging/logger-factory.d.ts.map +1 -0
- package/dist/logging/logger-factory.js +59 -0
- package/dist/logging/logger-factory.js.map +1 -0
- package/dist/mcp/search-tool.d.ts +65 -0
- package/dist/mcp/search-tool.d.ts.map +1 -0
- package/dist/mcp/search-tool.js +176 -0
- package/dist/mcp/search-tool.js.map +1 -0
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +152 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/process-scanner.d.ts +96 -0
- package/dist/process-scanner.d.ts.map +1 -0
- package/dist/process-scanner.js +194 -0
- package/dist/process-scanner.js.map +1 -0
- package/dist/routes/__tests__/archive-routes.test.d.ts +5 -0
- package/dist/routes/__tests__/archive-routes.test.d.ts.map +1 -0
- package/dist/routes/__tests__/archive-routes.test.js +158 -0
- package/dist/routes/__tests__/archive-routes.test.js.map +1 -0
- package/dist/routes/__tests__/config-routes.test.d.ts +5 -0
- package/dist/routes/__tests__/config-routes.test.d.ts.map +1 -0
- package/dist/routes/__tests__/config-routes.test.js +112 -0
- package/dist/routes/__tests__/config-routes.test.js.map +1 -0
- package/dist/routes/__tests__/http-utils.test.d.ts +5 -0
- package/dist/routes/__tests__/http-utils.test.d.ts.map +1 -0
- package/dist/routes/__tests__/http-utils.test.js +102 -0
- package/dist/routes/__tests__/http-utils.test.js.map +1 -0
- package/dist/routes/__tests__/notification-routes.test.d.ts +5 -0
- package/dist/routes/__tests__/notification-routes.test.d.ts.map +1 -0
- package/dist/routes/__tests__/notification-routes.test.js +91 -0
- package/dist/routes/__tests__/notification-routes.test.js.map +1 -0
- package/dist/routes/__tests__/project-routes.test.d.ts +5 -0
- package/dist/routes/__tests__/project-routes.test.d.ts.map +1 -0
- package/dist/routes/__tests__/project-routes.test.js +168 -0
- package/dist/routes/__tests__/project-routes.test.js.map +1 -0
- package/dist/routes/__tests__/session-routes.test.d.ts +5 -0
- package/dist/routes/__tests__/session-routes.test.d.ts.map +1 -0
- package/dist/routes/__tests__/session-routes.test.js +198 -0
- package/dist/routes/__tests__/session-routes.test.js.map +1 -0
- package/dist/routes/__tests__/source-routes.test.d.ts +5 -0
- package/dist/routes/__tests__/source-routes.test.d.ts.map +1 -0
- package/dist/routes/__tests__/source-routes.test.js +142 -0
- package/dist/routes/__tests__/source-routes.test.js.map +1 -0
- package/dist/routes/__tests__/sync-routes.test.d.ts +5 -0
- package/dist/routes/__tests__/sync-routes.test.d.ts.map +1 -0
- package/dist/routes/__tests__/sync-routes.test.js +77 -0
- package/dist/routes/__tests__/sync-routes.test.js.map +1 -0
- package/dist/routes/__tests__/test-helpers.d.ts +47 -0
- package/dist/routes/__tests__/test-helpers.d.ts.map +1 -0
- package/dist/routes/__tests__/test-helpers.js +97 -0
- package/dist/routes/__tests__/test-helpers.js.map +1 -0
- package/dist/routes/archive-routes.d.ts +15 -0
- package/dist/routes/archive-routes.d.ts.map +1 -0
- package/dist/routes/archive-routes.js +181 -0
- package/dist/routes/archive-routes.js.map +1 -0
- package/dist/routes/claude-routes.d.ts +9 -0
- package/dist/routes/claude-routes.d.ts.map +1 -0
- package/dist/routes/claude-routes.js +47 -0
- package/dist/routes/claude-routes.js.map +1 -0
- package/dist/routes/config-routes.d.ts +9 -0
- package/dist/routes/config-routes.d.ts.map +1 -0
- package/dist/routes/config-routes.js +56 -0
- package/dist/routes/config-routes.js.map +1 -0
- package/dist/routes/config-store.d.ts +41 -0
- package/dist/routes/config-store.d.ts.map +1 -0
- package/dist/routes/config-store.js +52 -0
- package/dist/routes/config-store.js.map +1 -0
- package/dist/routes/http-utils.d.ts +32 -0
- package/dist/routes/http-utils.d.ts.map +1 -0
- package/dist/routes/http-utils.js +123 -0
- package/dist/routes/http-utils.js.map +1 -0
- package/dist/routes/index.d.ts +19 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +17 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/notification-routes.d.ts +10 -0
- package/dist/routes/notification-routes.d.ts.map +1 -0
- package/dist/routes/notification-routes.js +64 -0
- package/dist/routes/notification-routes.js.map +1 -0
- package/dist/routes/project-routes.d.ts +22 -0
- package/dist/routes/project-routes.d.ts.map +1 -0
- package/dist/routes/project-routes.js +415 -0
- package/dist/routes/project-routes.js.map +1 -0
- package/dist/routes/session-routes.d.ts +18 -0
- package/dist/routes/session-routes.d.ts.map +1 -0
- package/dist/routes/session-routes.js +609 -0
- package/dist/routes/session-routes.js.map +1 -0
- package/dist/routes/source-routes.d.ts +12 -0
- package/dist/routes/source-routes.d.ts.map +1 -0
- package/dist/routes/source-routes.js +119 -0
- package/dist/routes/source-routes.js.map +1 -0
- package/dist/routes/static-routes.d.ts +12 -0
- package/dist/routes/static-routes.d.ts.map +1 -0
- package/dist/routes/static-routes.js +52 -0
- package/dist/routes/static-routes.js.map +1 -0
- package/dist/routes/sync-routes.d.ts +9 -0
- package/dist/routes/sync-routes.d.ts.map +1 -0
- package/dist/routes/sync-routes.js +78 -0
- package/dist/routes/sync-routes.js.map +1 -0
- package/dist/routes/tile-routes.d.ts +10 -0
- package/dist/routes/tile-routes.d.ts.map +1 -0
- package/dist/routes/tile-routes.js +108 -0
- package/dist/routes/tile-routes.js.map +1 -0
- package/dist/routes/types.d.ts +17 -0
- package/dist/routes/types.d.ts.map +1 -0
- package/dist/routes/types.js +5 -0
- package/dist/routes/types.js.map +1 -0
- package/dist/routes/usage-routes.d.ts +8 -0
- package/dist/routes/usage-routes.d.ts.map +1 -0
- package/dist/routes/usage-routes.js +18 -0
- package/dist/routes/usage-routes.js.map +1 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +173 -0
- package/dist/server.js.map +1 -0
- package/dist/services/branch-divergence-service.d.ts +48 -0
- package/dist/services/branch-divergence-service.d.ts.map +1 -0
- package/dist/services/branch-divergence-service.js +156 -0
- package/dist/services/branch-divergence-service.js.map +1 -0
- package/dist/services/broadcast-service.d.ts +68 -0
- package/dist/services/broadcast-service.d.ts.map +1 -0
- package/dist/services/broadcast-service.js +78 -0
- package/dist/services/broadcast-service.js.map +1 -0
- package/dist/services/broadcast-service.test.d.ts +5 -0
- package/dist/services/broadcast-service.test.d.ts.map +1 -0
- package/dist/services/broadcast-service.test.js +130 -0
- package/dist/services/broadcast-service.test.js.map +1 -0
- package/dist/services/chat-service.d.ts +72 -0
- package/dist/services/chat-service.d.ts.map +1 -0
- package/dist/services/chat-service.js +342 -0
- package/dist/services/chat-service.js.map +1 -0
- package/dist/services/chat-system-prompt.d.ts +14 -0
- package/dist/services/chat-system-prompt.d.ts.map +1 -0
- package/dist/services/chat-system-prompt.js +68 -0
- package/dist/services/chat-system-prompt.js.map +1 -0
- package/dist/services/notification-service.d.ts +115 -0
- package/dist/services/notification-service.d.ts.map +1 -0
- package/dist/services/notification-service.js +424 -0
- package/dist/services/notification-service.js.map +1 -0
- package/dist/services/notification-service.test.d.ts +5 -0
- package/dist/services/notification-service.test.d.ts.map +1 -0
- package/dist/services/notification-service.test.js +918 -0
- package/dist/services/notification-service.test.js.map +1 -0
- package/dist/session/cleanup-service.d.ts +51 -0
- package/dist/session/cleanup-service.d.ts.map +1 -0
- package/dist/session/cleanup-service.js +98 -0
- package/dist/session/cleanup-service.js.map +1 -0
- package/dist/session/cleanup-service.test.d.ts +5 -0
- package/dist/session/cleanup-service.test.d.ts.map +1 -0
- package/dist/session/cleanup-service.test.js +121 -0
- package/dist/session/cleanup-service.test.js.map +1 -0
- package/dist/session/process-monitor.d.ts +79 -0
- package/dist/session/process-monitor.d.ts.map +1 -0
- package/dist/session/process-monitor.js +270 -0
- package/dist/session/process-monitor.js.map +1 -0
- package/dist/session/process-monitor.test.d.ts +5 -0
- package/dist/session/process-monitor.test.d.ts.map +1 -0
- package/dist/session/process-monitor.test.js +367 -0
- package/dist/session/process-monitor.test.js.map +1 -0
- package/dist/session/session-factory.d.ts +29 -0
- package/dist/session/session-factory.d.ts.map +1 -0
- package/dist/session/session-factory.js +123 -0
- package/dist/session/session-factory.js.map +1 -0
- package/dist/session/session-factory.test.d.ts +5 -0
- package/dist/session/session-factory.test.d.ts.map +1 -0
- package/dist/session/session-factory.test.js +299 -0
- package/dist/session/session-factory.test.js.map +1 -0
- package/dist/session-registry.d.ts +168 -0
- package/dist/session-registry.d.ts.map +1 -0
- package/dist/session-registry.js +626 -0
- package/dist/session-registry.js.map +1 -0
- package/dist/session-registry.test.d.ts +5 -0
- package/dist/session-registry.test.d.ts.map +1 -0
- package/dist/session-registry.test.js +582 -0
- package/dist/session-registry.test.js.map +1 -0
- package/dist/start-server.d.ts +31 -0
- package/dist/start-server.d.ts.map +1 -0
- package/dist/start-server.js +408 -0
- package/dist/start-server.js.map +1 -0
- package/dist/terminal-activator.d.ts +29 -0
- package/dist/terminal-activator.d.ts.map +1 -0
- package/dist/terminal-activator.js +264 -0
- package/dist/terminal-activator.js.map +1 -0
- package/dist/terminal-activator.test.d.ts +9 -0
- package/dist/terminal-activator.test.d.ts.map +1 -0
- package/dist/terminal-activator.test.js +95 -0
- package/dist/terminal-activator.test.js.map +1 -0
- package/dist/terminal-launcher.d.ts +51 -0
- package/dist/terminal-launcher.d.ts.map +1 -0
- package/dist/terminal-launcher.js +298 -0
- package/dist/terminal-launcher.js.map +1 -0
- package/dist/terminal-launcher.test.d.ts +8 -0
- package/dist/terminal-launcher.test.d.ts.map +1 -0
- package/dist/terminal-launcher.test.js +222 -0
- package/dist/terminal-launcher.test.js.map +1 -0
- package/dist/types.d.ts +796 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/dist/unix-socket.d.ts +68 -0
- package/dist/unix-socket.d.ts.map +1 -0
- package/dist/unix-socket.js +180 -0
- package/dist/unix-socket.js.map +1 -0
- package/dist/usage-limits.d.ts +13 -0
- package/dist/usage-limits.d.ts.map +1 -0
- package/dist/usage-limits.js +112 -0
- package/dist/usage-limits.js.map +1 -0
- package/dist/watchers/handoff-watcher.d.ts +74 -0
- package/dist/watchers/handoff-watcher.d.ts.map +1 -0
- package/dist/watchers/handoff-watcher.js +124 -0
- package/dist/watchers/handoff-watcher.js.map +1 -0
- package/dist/watchers/handoff-watcher.test.d.ts +8 -0
- package/dist/watchers/handoff-watcher.test.d.ts.map +1 -0
- package/dist/watchers/handoff-watcher.test.js +142 -0
- package/dist/watchers/handoff-watcher.test.js.map +1 -0
- package/dist/websocket.d.ts +107 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +268 -0
- package/dist/websocket.js.map +1 -0
- package/dist/window-manager/index.d.ts +28 -0
- package/dist/window-manager/index.d.ts.map +1 -0
- package/dist/window-manager/index.js +56 -0
- package/dist/window-manager/index.js.map +1 -0
- package/dist/window-manager/layouts.d.ts +42 -0
- package/dist/window-manager/layouts.d.ts.map +1 -0
- package/dist/window-manager/layouts.js +133 -0
- package/dist/window-manager/layouts.js.map +1 -0
- package/dist/window-manager/linux-manager.d.ts +45 -0
- package/dist/window-manager/linux-manager.d.ts.map +1 -0
- package/dist/window-manager/linux-manager.js +299 -0
- package/dist/window-manager/linux-manager.js.map +1 -0
- package/dist/window-manager/macos-manager.d.ts +103 -0
- package/dist/window-manager/macos-manager.d.ts.map +1 -0
- package/dist/window-manager/macos-manager.js +637 -0
- package/dist/window-manager/macos-manager.js.map +1 -0
- package/dist/window-manager/smart-layouts.d.ts +116 -0
- package/dist/window-manager/smart-layouts.d.ts.map +1 -0
- package/dist/window-manager/smart-layouts.js +188 -0
- package/dist/window-manager/smart-layouts.js.map +1 -0
- package/dist/window-manager/smart-layouts.test.d.ts +8 -0
- package/dist/window-manager/smart-layouts.test.d.ts.map +1 -0
- package/dist/window-manager/smart-layouts.test.js +311 -0
- package/dist/window-manager/smart-layouts.test.js.map +1 -0
- package/dist/window-manager/tile-state.d.ts +87 -0
- package/dist/window-manager/tile-state.d.ts.map +1 -0
- package/dist/window-manager/tile-state.js +136 -0
- package/dist/window-manager/tile-state.js.map +1 -0
- package/dist/window-manager/tile-state.test.d.ts +8 -0
- package/dist/window-manager/tile-state.test.d.ts.map +1 -0
- package/dist/window-manager/tile-state.test.js +179 -0
- package/dist/window-manager/tile-state.test.js.map +1 -0
- package/dist/window-manager/types.d.ts +104 -0
- package/dist/window-manager/types.d.ts.map +1 -0
- package/dist/window-manager/types.js +8 -0
- package/dist/window-manager/types.js.map +1 -0
- package/dist/window-manager/windows-manager.d.ts +44 -0
- package/dist/window-manager/windows-manager.d.ts.map +1 -0
- package/dist/window-manager/windows-manager.js +281 -0
- package/dist/window-manager/windows-manager.js.map +1 -0
- package/dist/window-manager/windows-manager.test.d.ts +8 -0
- package/dist/window-manager/windows-manager.test.d.ts.map +1 -0
- package/dist/window-manager/windows-manager.test.js +183 -0
- package/dist/window-manager/windows-manager.test.js.map +1 -0
- package/gui-dist/assets/index-BmYIHRYe.js +142 -0
- package/gui-dist/assets/index-D_N5RH8O.css +1 -0
- package/gui-dist/assets/vendor-icons-ByXNrcwf.js +336 -0
- package/gui-dist/assets/vendor-markdown-DWPYwU1x.js +22 -0
- package/gui-dist/assets/vendor-react-CpILBTDM.js +59 -0
- package/gui-dist/index.html +17 -0
- package/gui-dist/jacsub.png +0 -0
- package/package.json +67 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worktree Management
|
|
3
|
+
*
|
|
4
|
+
* Creates, lists, inspects, and removes git worktrees for the project.
|
|
5
|
+
* Extends git-info.ts (read-only detection) with write operations.
|
|
6
|
+
*
|
|
7
|
+
* @module connection/worktree
|
|
8
|
+
*/
|
|
9
|
+
import { exec as execCb } from 'child_process';
|
|
10
|
+
import { promisify } from 'util';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { platform } from 'process';
|
|
14
|
+
const execAsync = promisify(execCb);
|
|
15
|
+
/**
|
|
16
|
+
* Cross-platform shell quoting for command arguments.
|
|
17
|
+
* Windows cmd.exe uses double quotes; Unix shells use single quotes.
|
|
18
|
+
*/
|
|
19
|
+
function q(s) {
|
|
20
|
+
if (platform === 'win32') {
|
|
21
|
+
return `"${s.replace(/"/g, '\\"')}"`;
|
|
22
|
+
}
|
|
23
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
24
|
+
}
|
|
25
|
+
// ─── Validation ───────────────────────────────────────────────
|
|
26
|
+
const VALID_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
27
|
+
export function validateWorktreeName(name) {
|
|
28
|
+
if (!name)
|
|
29
|
+
return 'Name is required';
|
|
30
|
+
if (!VALID_NAME_RE.test(name))
|
|
31
|
+
return 'Name must contain only letters, numbers, hyphens, and underscores';
|
|
32
|
+
if (name.length > 100)
|
|
33
|
+
return 'Name must be 100 characters or fewer';
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Compute the worktree path: sibling to repo root with name suffix.
|
|
38
|
+
* e.g. /path/to/project → /path/to/project-<name>
|
|
39
|
+
*/
|
|
40
|
+
export function computeWorktreePath(repoRoot, name) {
|
|
41
|
+
const parent = path.dirname(repoRoot);
|
|
42
|
+
const base = path.basename(repoRoot);
|
|
43
|
+
return path.join(parent, `${base}-${name}`);
|
|
44
|
+
}
|
|
45
|
+
// ─── Create Worktree ──────────────────────────────────────────
|
|
46
|
+
/**
|
|
47
|
+
* Create a new git worktree as a sibling directory.
|
|
48
|
+
*
|
|
49
|
+
* Runs `git worktree add -b <name> <path>` which creates both
|
|
50
|
+
* the worktree directory and a new branch.
|
|
51
|
+
*/
|
|
52
|
+
export async function createWorktree(options) {
|
|
53
|
+
const { repoRoot, name, baseBranch } = options;
|
|
54
|
+
// Validate name
|
|
55
|
+
const nameError = validateWorktreeName(name);
|
|
56
|
+
if (nameError) {
|
|
57
|
+
return { success: false, error: nameError };
|
|
58
|
+
}
|
|
59
|
+
// Validate repo root exists
|
|
60
|
+
if (!existsSync(repoRoot)) {
|
|
61
|
+
return { success: false, error: `Repository root does not exist: ${repoRoot}` };
|
|
62
|
+
}
|
|
63
|
+
// Compute target path
|
|
64
|
+
const worktreePath = computeWorktreePath(repoRoot, name);
|
|
65
|
+
// Check directory doesn't already exist
|
|
66
|
+
if (existsSync(worktreePath)) {
|
|
67
|
+
return { success: false, error: `Directory already exists: ${worktreePath}` };
|
|
68
|
+
}
|
|
69
|
+
// Build git command
|
|
70
|
+
const baseArg = baseBranch ? ` ${q(baseBranch)}` : '';
|
|
71
|
+
const cmd = `git -C ${q(repoRoot)} worktree add -b ${q(name)} ${q(worktreePath)}${baseArg}`;
|
|
72
|
+
try {
|
|
73
|
+
await execAsync(cmd, { timeout: 15000 });
|
|
74
|
+
return {
|
|
75
|
+
success: true,
|
|
76
|
+
worktreePath,
|
|
77
|
+
branch: name,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const message = err instanceof Error ? err.stderr || err.message : String(err);
|
|
82
|
+
// Detect common git errors
|
|
83
|
+
if (message.includes('already exists')) {
|
|
84
|
+
if (message.includes('branch')) {
|
|
85
|
+
return { success: false, error: `Branch '${name}' already exists` };
|
|
86
|
+
}
|
|
87
|
+
return { success: false, error: `Worktree or directory already exists for '${name}'` };
|
|
88
|
+
}
|
|
89
|
+
return { success: false, error: `Git worktree add failed: ${message.trim()}` };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// ─── List Worktrees ───────────────────────────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* List all worktrees for a repository.
|
|
95
|
+
* Prunes stale entries first, then wraps `git worktree list --porcelain`.
|
|
96
|
+
*/
|
|
97
|
+
export async function listWorktrees(repoRoot) {
|
|
98
|
+
try {
|
|
99
|
+
// Prune stale worktree entries (directories already removed)
|
|
100
|
+
try {
|
|
101
|
+
await execAsync(`git -C ${q(repoRoot)} worktree prune`, { timeout: 5000 });
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Prune failure is non-fatal
|
|
105
|
+
}
|
|
106
|
+
const { stdout } = await execAsync(`git -C ${q(repoRoot)} worktree list --porcelain`, { timeout: 5000 });
|
|
107
|
+
return parsePorcelainOutput(stdout, repoRoot);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Parse `git worktree list --porcelain` output into structured entries.
|
|
115
|
+
*
|
|
116
|
+
* Format:
|
|
117
|
+
* worktree /path/to/main
|
|
118
|
+
* HEAD abc123
|
|
119
|
+
* branch refs/heads/main
|
|
120
|
+
* (blank line)
|
|
121
|
+
* worktree /path/to/other
|
|
122
|
+
* HEAD def456
|
|
123
|
+
* branch refs/heads/feature
|
|
124
|
+
* (blank line)
|
|
125
|
+
*/
|
|
126
|
+
export function parsePorcelainOutput(output, repoRoot) {
|
|
127
|
+
const entries = [];
|
|
128
|
+
// Normalize \r\n to \n for cross-platform compatibility
|
|
129
|
+
const normalized = output.replace(/\r\n/g, '\n');
|
|
130
|
+
const blocks = normalized.trim().split('\n\n');
|
|
131
|
+
for (const block of blocks) {
|
|
132
|
+
if (!block.trim())
|
|
133
|
+
continue;
|
|
134
|
+
const lines = block.trim().split('\n');
|
|
135
|
+
let worktreePath = '';
|
|
136
|
+
let branch = null;
|
|
137
|
+
for (const line of lines) {
|
|
138
|
+
const trimmedLine = line.trim();
|
|
139
|
+
if (trimmedLine.startsWith('worktree ')) {
|
|
140
|
+
worktreePath = trimmedLine.slice('worktree '.length);
|
|
141
|
+
}
|
|
142
|
+
else if (trimmedLine.startsWith('branch ')) {
|
|
143
|
+
// refs/heads/main → main
|
|
144
|
+
branch = trimmedLine.slice('branch '.length).replace(/^refs\/heads\//, '');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (worktreePath) {
|
|
148
|
+
const resolvedRoot = path.resolve(repoRoot);
|
|
149
|
+
const resolvedWorktree = path.resolve(worktreePath);
|
|
150
|
+
entries.push({
|
|
151
|
+
name: path.basename(worktreePath),
|
|
152
|
+
path: worktreePath,
|
|
153
|
+
branch,
|
|
154
|
+
isMain: resolvedWorktree === resolvedRoot,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return entries;
|
|
159
|
+
}
|
|
160
|
+
// ─── Worktree Status ─────────────────────────────────────────
|
|
161
|
+
/**
|
|
162
|
+
* Detect the default branch for a repository (main or master).
|
|
163
|
+
* Tries `git symbolic-ref refs/remotes/origin/HEAD`, falls back to checking
|
|
164
|
+
* if 'main' or 'master' branch exists locally.
|
|
165
|
+
*/
|
|
166
|
+
export async function detectDefaultBranch(repoRoot) {
|
|
167
|
+
// Try symbolic-ref first (requires remote tracking)
|
|
168
|
+
try {
|
|
169
|
+
const { stdout } = await execAsync(`git -C ${q(repoRoot)} symbolic-ref refs/remotes/origin/HEAD`, { timeout: 5000 });
|
|
170
|
+
const ref = stdout.trim().replace(/^refs\/remotes\/origin\//, '');
|
|
171
|
+
if (ref)
|
|
172
|
+
return ref;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// No remote HEAD configured
|
|
176
|
+
}
|
|
177
|
+
// Fall back: check if 'main' branch exists
|
|
178
|
+
try {
|
|
179
|
+
await execAsync(`git -C ${q(repoRoot)} rev-parse --verify refs/heads/main`, { timeout: 5000 });
|
|
180
|
+
return 'main';
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// 'main' doesn't exist
|
|
184
|
+
}
|
|
185
|
+
// Final fallback: assume 'master'
|
|
186
|
+
return 'master';
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Check status of a single worktree: uncommitted changes and merge status.
|
|
190
|
+
*/
|
|
191
|
+
export async function checkWorktreeStatus(worktreePath, branch, defaultBranch, repoRoot) {
|
|
192
|
+
// Check for uncommitted changes
|
|
193
|
+
let hasUncommittedChanges = false;
|
|
194
|
+
try {
|
|
195
|
+
const { stdout } = await execAsync(`git -C ${q(worktreePath)} status --porcelain`, { timeout: 5000 });
|
|
196
|
+
hasUncommittedChanges = stdout.trim().length > 0;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// If status fails, assume clean
|
|
200
|
+
}
|
|
201
|
+
// Check if branch is merged into default branch.
|
|
202
|
+
// Three cases:
|
|
203
|
+
// 1. Branch is NOT an ancestor of default → has unmerged work → not merged
|
|
204
|
+
// 2. Branch IS an ancestor AND its tip is on default's first-parent line
|
|
205
|
+
// → branch just points at an old mainline commit (no unique work) → not merged
|
|
206
|
+
// 3. Branch IS an ancestor AND its tip is NOT on default's first-parent line
|
|
207
|
+
// → branch was merged via merge commit → merged
|
|
208
|
+
let isMergedToMain = false;
|
|
209
|
+
if (branch && branch !== defaultBranch) {
|
|
210
|
+
try {
|
|
211
|
+
// Step 1: is the branch an ancestor of the default branch?
|
|
212
|
+
await execAsync(`git -C ${q(repoRoot)} merge-base --is-ancestor ${q(branch)} ${q(defaultBranch)}`, { timeout: 5000 });
|
|
213
|
+
// Branch IS an ancestor — check if it was merged or is just at an old commit
|
|
214
|
+
const { stdout: tipOut } = await execAsync(`git -C ${q(repoRoot)} rev-parse ${q(branch)}`, { timeout: 5000 });
|
|
215
|
+
const branchTip = tipOut.trim();
|
|
216
|
+
// Step 2: check if branch tip is on default branch's first-parent line
|
|
217
|
+
let isOnFirstParentLine = false;
|
|
218
|
+
try {
|
|
219
|
+
const { stdout: fpCommits } = await execAsync(`git -C ${q(repoRoot)} rev-list --first-parent ${q(branchTip + '^..' + defaultBranch)}`, { timeout: 10000 });
|
|
220
|
+
isOnFirstParentLine = fpCommits.split('\n').some(h => h.trim() === branchTip);
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// rev-list failed (e.g., root commit has no parent)
|
|
224
|
+
isOnFirstParentLine = false;
|
|
225
|
+
}
|
|
226
|
+
// On first-parent line → just at old mainline commit, not "merged"
|
|
227
|
+
// NOT on first-parent line → was merged via merge commit
|
|
228
|
+
isMergedToMain = !isOnFirstParentLine;
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// is-ancestor failed → not merged
|
|
232
|
+
isMergedToMain = false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return { hasUncommittedChanges, isMergedToMain };
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* List all worktrees with their status (uncommitted changes, merge status).
|
|
239
|
+
* Returns all worktrees including main.
|
|
240
|
+
*/
|
|
241
|
+
export async function listWorktreesWithStatus(repoRoot) {
|
|
242
|
+
const entries = await listWorktrees(repoRoot);
|
|
243
|
+
if (entries.length === 0)
|
|
244
|
+
return [];
|
|
245
|
+
const defaultBranch = await detectDefaultBranch(repoRoot);
|
|
246
|
+
const results = [];
|
|
247
|
+
for (const entry of entries) {
|
|
248
|
+
if (entry.isMain) {
|
|
249
|
+
// Main worktree: skip status check, always safe
|
|
250
|
+
results.push({
|
|
251
|
+
...entry,
|
|
252
|
+
status: { hasUncommittedChanges: false, isMergedToMain: true },
|
|
253
|
+
});
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
const status = await checkWorktreeStatus(entry.path, entry.branch, defaultBranch, repoRoot);
|
|
257
|
+
results.push({ ...entry, status });
|
|
258
|
+
}
|
|
259
|
+
return results;
|
|
260
|
+
}
|
|
261
|
+
// ─── Remove Worktree ─────────────────────────────────────────
|
|
262
|
+
/**
|
|
263
|
+
* Remove a git worktree and optionally delete its branch.
|
|
264
|
+
*
|
|
265
|
+
* Runs `git worktree remove <path>` with optional --force flag.
|
|
266
|
+
* If deleteBranch is true, also runs `git branch -d <branch>`.
|
|
267
|
+
*/
|
|
268
|
+
export async function removeWorktree(options) {
|
|
269
|
+
const { repoRoot, worktreePath, force, deleteBranch } = options;
|
|
270
|
+
// Validate repo root exists
|
|
271
|
+
if (!existsSync(repoRoot)) {
|
|
272
|
+
return { success: false, error: `Repository root does not exist: ${repoRoot}` };
|
|
273
|
+
}
|
|
274
|
+
// Validate worktree path exists
|
|
275
|
+
if (!existsSync(worktreePath)) {
|
|
276
|
+
return { success: false, error: `Worktree does not exist: ${worktreePath}` };
|
|
277
|
+
}
|
|
278
|
+
// Don't allow removing the main worktree
|
|
279
|
+
if (path.resolve(worktreePath) === path.resolve(repoRoot)) {
|
|
280
|
+
return { success: false, error: 'Cannot remove the main worktree' };
|
|
281
|
+
}
|
|
282
|
+
// Detect branch name before removal (needed for branch deletion)
|
|
283
|
+
let branchName = null;
|
|
284
|
+
if (deleteBranch) {
|
|
285
|
+
try {
|
|
286
|
+
const { stdout } = await execAsync(`git -C ${q(worktreePath)} rev-parse --abbrev-ref HEAD`, { timeout: 5000 });
|
|
287
|
+
branchName = stdout.trim() || null;
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
// Can't detect branch, skip branch deletion
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// Remove the worktree
|
|
294
|
+
const forceFlag = force ? ' --force' : '';
|
|
295
|
+
const cmd = `git -C ${q(repoRoot)} worktree remove ${q(worktreePath)}${forceFlag}`;
|
|
296
|
+
try {
|
|
297
|
+
await execAsync(cmd, { timeout: 15000 });
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
const message = err instanceof Error ? err.stderr || err.message : String(err);
|
|
301
|
+
if (message.includes('untracked') || message.includes('modified')) {
|
|
302
|
+
return { success: false, error: `Worktree has uncommitted changes. Use force to remove anyway.` };
|
|
303
|
+
}
|
|
304
|
+
return { success: false, error: `Git worktree remove failed: ${message.trim()}` };
|
|
305
|
+
}
|
|
306
|
+
// Optionally delete the branch
|
|
307
|
+
let branchDeleted = false;
|
|
308
|
+
if (deleteBranch && branchName) {
|
|
309
|
+
const branchFlag = force ? '-D' : '-d';
|
|
310
|
+
try {
|
|
311
|
+
await execAsync(`git -C ${q(repoRoot)} branch ${branchFlag} ${q(branchName)}`, { timeout: 5000 });
|
|
312
|
+
branchDeleted = true;
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
// Branch deletion failed (e.g., not fully merged with -d), but worktree removal succeeded
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return { success: true, branchDeleted };
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/connection/worktree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.test.d.ts","sourceRoot":"","sources":["../../src/connection/worktree.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for worktree module
|
|
3
|
+
*/
|
|
4
|
+
import { validateWorktreeName, computeWorktreePath, parsePorcelainOutput, } from './worktree.js';
|
|
5
|
+
describe('validateWorktreeName', () => {
|
|
6
|
+
it('accepts valid names', () => {
|
|
7
|
+
expect(validateWorktreeName('feature')).toBeNull();
|
|
8
|
+
expect(validateWorktreeName('my-branch')).toBeNull();
|
|
9
|
+
expect(validateWorktreeName('fix_123')).toBeNull();
|
|
10
|
+
expect(validateWorktreeName('ABC-xyz-123')).toBeNull();
|
|
11
|
+
});
|
|
12
|
+
it('rejects empty names', () => {
|
|
13
|
+
expect(validateWorktreeName('')).toBe('Name is required');
|
|
14
|
+
});
|
|
15
|
+
it('rejects names with spaces', () => {
|
|
16
|
+
expect(validateWorktreeName('my branch')).toMatch(/letters, numbers/);
|
|
17
|
+
});
|
|
18
|
+
it('rejects names with special characters', () => {
|
|
19
|
+
expect(validateWorktreeName('feat/branch')).toMatch(/letters, numbers/);
|
|
20
|
+
expect(validateWorktreeName('feat.branch')).toMatch(/letters, numbers/);
|
|
21
|
+
expect(validateWorktreeName('feat@branch')).toMatch(/letters, numbers/);
|
|
22
|
+
expect(validateWorktreeName('feat!branch')).toMatch(/letters, numbers/);
|
|
23
|
+
});
|
|
24
|
+
it('rejects names over 100 characters', () => {
|
|
25
|
+
const longName = 'a'.repeat(101);
|
|
26
|
+
expect(validateWorktreeName(longName)).toMatch(/100 characters/);
|
|
27
|
+
});
|
|
28
|
+
it('accepts names of exactly 100 characters', () => {
|
|
29
|
+
const name = 'a'.repeat(100);
|
|
30
|
+
expect(validateWorktreeName(name)).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('computeWorktreePath', () => {
|
|
34
|
+
it('creates sibling directory with name suffix', () => {
|
|
35
|
+
expect(computeWorktreePath('/Users/dev/my-project', 'feature'))
|
|
36
|
+
.toBe('/Users/dev/my-project-feature');
|
|
37
|
+
});
|
|
38
|
+
it('handles repo roots with trailing slash-like naming', () => {
|
|
39
|
+
expect(computeWorktreePath('/home/user/app', 'hotfix'))
|
|
40
|
+
.toBe('/home/user/app-hotfix');
|
|
41
|
+
});
|
|
42
|
+
it('handles deeply nested repo roots', () => {
|
|
43
|
+
expect(computeWorktreePath('/a/b/c/d/repo', 'test'))
|
|
44
|
+
.toBe('/a/b/c/d/repo-test');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('parsePorcelainOutput', () => {
|
|
48
|
+
it('parses single worktree (main only)', () => {
|
|
49
|
+
const output = `worktree /Users/dev/project
|
|
50
|
+
HEAD abc123def456
|
|
51
|
+
branch refs/heads/main
|
|
52
|
+
|
|
53
|
+
`;
|
|
54
|
+
const entries = parsePorcelainOutput(output, '/Users/dev/project');
|
|
55
|
+
expect(entries).toHaveLength(1);
|
|
56
|
+
expect(entries[0]).toEqual({
|
|
57
|
+
name: 'project',
|
|
58
|
+
path: '/Users/dev/project',
|
|
59
|
+
branch: 'main',
|
|
60
|
+
isMain: true,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('parses multiple worktrees', () => {
|
|
64
|
+
const output = `worktree /Users/dev/project
|
|
65
|
+
HEAD abc123
|
|
66
|
+
branch refs/heads/main
|
|
67
|
+
|
|
68
|
+
worktree /Users/dev/project-feature
|
|
69
|
+
HEAD def456
|
|
70
|
+
branch refs/heads/feature
|
|
71
|
+
|
|
72
|
+
worktree /Users/dev/project-hotfix
|
|
73
|
+
HEAD 789012
|
|
74
|
+
branch refs/heads/hotfix
|
|
75
|
+
|
|
76
|
+
`;
|
|
77
|
+
const entries = parsePorcelainOutput(output, '/Users/dev/project');
|
|
78
|
+
expect(entries).toHaveLength(3);
|
|
79
|
+
expect(entries[0].isMain).toBe(true);
|
|
80
|
+
expect(entries[0].branch).toBe('main');
|
|
81
|
+
expect(entries[1].isMain).toBe(false);
|
|
82
|
+
expect(entries[1].name).toBe('project-feature');
|
|
83
|
+
expect(entries[1].branch).toBe('feature');
|
|
84
|
+
expect(entries[2].isMain).toBe(false);
|
|
85
|
+
expect(entries[2].name).toBe('project-hotfix');
|
|
86
|
+
expect(entries[2].branch).toBe('hotfix');
|
|
87
|
+
});
|
|
88
|
+
it('handles detached HEAD (no branch line)', () => {
|
|
89
|
+
const output = `worktree /Users/dev/project
|
|
90
|
+
HEAD abc123
|
|
91
|
+
detached
|
|
92
|
+
|
|
93
|
+
`;
|
|
94
|
+
const entries = parsePorcelainOutput(output, '/Users/dev/project');
|
|
95
|
+
expect(entries).toHaveLength(1);
|
|
96
|
+
expect(entries[0].branch).toBeNull();
|
|
97
|
+
expect(entries[0].isMain).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
it('handles empty output', () => {
|
|
100
|
+
expect(parsePorcelainOutput('', '/some/path')).toEqual([]);
|
|
101
|
+
expect(parsePorcelainOutput(' \n ', '/some/path')).toEqual([]);
|
|
102
|
+
});
|
|
103
|
+
it('strips refs/heads/ prefix from branch', () => {
|
|
104
|
+
const output = `worktree /Users/dev/project
|
|
105
|
+
HEAD abc123
|
|
106
|
+
branch refs/heads/feature/nested-branch
|
|
107
|
+
|
|
108
|
+
`;
|
|
109
|
+
const entries = parsePorcelainOutput(output, '/Users/dev/project');
|
|
110
|
+
expect(entries[0].branch).toBe('feature/nested-branch');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
//# sourceMappingURL=worktree.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.test.js","sourceRoot":"","sources":["../../src/connection/worktree.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Focus Watcher
|
|
3
|
+
*
|
|
4
|
+
* Monitors which terminal window is focused on macOS and sends
|
|
5
|
+
* focus hints to the Jacques server to update the active session.
|
|
6
|
+
*
|
|
7
|
+
* Supports:
|
|
8
|
+
* - iTerm2 (via ITERM_SESSION_ID)
|
|
9
|
+
* - Terminal.app (via TTY)
|
|
10
|
+
* - Other terminals (via window ID / PID)
|
|
11
|
+
*/
|
|
12
|
+
import type { Logger } from './logging/logger-factory.js';
|
|
13
|
+
export interface FocusInfo {
|
|
14
|
+
app: string;
|
|
15
|
+
iterm_session_id?: string;
|
|
16
|
+
tty?: string;
|
|
17
|
+
window_id?: string;
|
|
18
|
+
terminal_pid?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get focus info for the currently active terminal
|
|
22
|
+
*/
|
|
23
|
+
export declare function getTerminalFocusInfo(): Promise<FocusInfo | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Build terminal key candidates from focus info, ordered by specificity.
|
|
26
|
+
* Returns multiple keys to try (e.g., ITERM key first, then TTY fallback)
|
|
27
|
+
* because discovered sessions may use TTY keys even when running in iTerm.
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildTerminalKeysFromFocus(focus: FocusInfo): string[];
|
|
30
|
+
/**
|
|
31
|
+
* Build a single terminal key from focus info (primary key for change detection)
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildTerminalKeyFromFocus(focus: FocusInfo): string | null;
|
|
34
|
+
export interface FocusWatcherCallbacks {
|
|
35
|
+
onFocusChange: (terminalKey: string | null, allKeys?: string[]) => void;
|
|
36
|
+
/** Return true if the watcher should retry matching even when the terminal key hasn't changed */
|
|
37
|
+
shouldRetry?: () => boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface FocusWatcherOptions {
|
|
40
|
+
/** Suppress console output */
|
|
41
|
+
silent?: boolean;
|
|
42
|
+
/** Optional logger for dependency injection */
|
|
43
|
+
logger?: Logger;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Start watching for terminal focus changes
|
|
47
|
+
*/
|
|
48
|
+
export declare function startFocusWatcher(callbacks: FocusWatcherCallbacks, pollIntervalMs?: number, options?: FocusWatcherOptions): {
|
|
49
|
+
stop: () => void;
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=focus-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus-watcher.d.ts","sourceRoot":"","sources":["../src/focus-watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAK1D,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA2DD;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAuBtE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAYrE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAGzE;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACxE,iGAAiG;IACjG,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,8BAA8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,qBAAqB,EAChC,cAAc,GAAE,MAA8B,EAC9C,OAAO,GAAE,mBAAwB,GAChC;IAAE,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CA0DtB"}
|