@jacques-ai/cli 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/assets/mascot-ansi.d.ts +8 -0
- package/dist/assets/mascot-ansi.d.ts.map +1 -0
- package/dist/assets/mascot-ansi.js +15 -0
- package/dist/assets/mascot-ansi.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +53 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/client-helper.d.ts +14 -0
- package/dist/commands/client-helper.d.ts.map +1 -0
- package/dist/commands/client-helper.js +38 -0
- package/dist/commands/client-helper.js.map +1 -0
- package/dist/commands/dashboard.d.ts +8 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +159 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +6 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/list.d.ts +5 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +13 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/search.d.ts +13 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +79 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/setup.d.ts +8 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +32 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +27 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/components/ActiveSessionsView.d.ts +18 -0
- package/dist/components/ActiveSessionsView.d.ts.map +1 -0
- package/dist/components/ActiveSessionsView.js +68 -0
- package/dist/components/ActiveSessionsView.js.map +1 -0
- package/dist/components/AddContextConfirmView.d.ts +21 -0
- package/dist/components/AddContextConfirmView.d.ts.map +1 -0
- package/dist/components/AddContextConfirmView.js +44 -0
- package/dist/components/AddContextConfirmView.js.map +1 -0
- package/dist/components/App.d.ts +11 -0
- package/dist/components/App.d.ts.map +1 -0
- package/dist/components/App.js +292 -0
- package/dist/components/App.js.map +1 -0
- package/dist/components/ArchiveBrowserView.d.ts +40 -0
- package/dist/components/ArchiveBrowserView.d.ts.map +1 -0
- package/dist/components/ArchiveBrowserView.js +161 -0
- package/dist/components/ArchiveBrowserView.js.map +1 -0
- package/dist/components/ArchiveInitProgressView.d.ts +16 -0
- package/dist/components/ArchiveInitProgressView.d.ts.map +1 -0
- package/dist/components/ArchiveInitProgressView.js +72 -0
- package/dist/components/ArchiveInitProgressView.js.map +1 -0
- package/dist/components/AutoCompactToggle.d.ts +16 -0
- package/dist/components/AutoCompactToggle.d.ts.map +1 -0
- package/dist/components/AutoCompactToggle.js +12 -0
- package/dist/components/AutoCompactToggle.js.map +1 -0
- package/dist/components/BottomControls.d.ts +12 -0
- package/dist/components/BottomControls.d.ts.map +1 -0
- package/dist/components/BottomControls.js +11 -0
- package/dist/components/BottomControls.js.map +1 -0
- package/dist/components/CompactHeader.d.ts +21 -0
- package/dist/components/CompactHeader.d.ts.map +1 -0
- package/dist/components/CompactHeader.js +63 -0
- package/dist/components/CompactHeader.js.map +1 -0
- package/dist/components/CompactPanel.d.ts +22 -0
- package/dist/components/CompactPanel.d.ts.map +1 -0
- package/dist/components/CompactPanel.js +31 -0
- package/dist/components/CompactPanel.js.map +1 -0
- package/dist/components/ContentBox.d.ts +14 -0
- package/dist/components/ContentBox.d.ts.map +1 -0
- package/dist/components/ContentBox.js +24 -0
- package/dist/components/ContentBox.js.map +1 -0
- package/dist/components/ContextProgress.d.ts +14 -0
- package/dist/components/ContextProgress.d.ts.map +1 -0
- package/dist/components/ContextProgress.js +36 -0
- package/dist/components/ContextProgress.js.map +1 -0
- package/dist/components/Dashboard.d.ts +46 -0
- package/dist/components/Dashboard.d.ts.map +1 -0
- package/dist/components/Dashboard.js +67 -0
- package/dist/components/Dashboard.js.map +1 -0
- package/dist/components/FilterSelectionView.d.ts +15 -0
- package/dist/components/FilterSelectionView.d.ts.map +1 -0
- package/dist/components/FilterSelectionView.js +27 -0
- package/dist/components/FilterSelectionView.js.map +1 -0
- package/dist/components/GoogleDocsBrowserView.d.ts +20 -0
- package/dist/components/GoogleDocsBrowserView.d.ts.map +1 -0
- package/dist/components/GoogleDocsBrowserView.js +72 -0
- package/dist/components/GoogleDocsBrowserView.js.map +1 -0
- package/dist/components/HandoffBrowserView.d.ts +20 -0
- package/dist/components/HandoffBrowserView.d.ts.map +1 -0
- package/dist/components/HandoffBrowserView.js +66 -0
- package/dist/components/HandoffBrowserView.js.map +1 -0
- package/dist/components/Header.d.ts +14 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.js +16 -0
- package/dist/components/Header.js.map +1 -0
- package/dist/components/HorizontalMenu.d.ts +24 -0
- package/dist/components/HorizontalMenu.d.ts.map +1 -0
- package/dist/components/HorizontalMenu.js +20 -0
- package/dist/components/HorizontalMenu.js.map +1 -0
- package/dist/components/ImageMascot.d.ts +8 -0
- package/dist/components/ImageMascot.d.ts.map +1 -0
- package/dist/components/ImageMascot.js +7 -0
- package/dist/components/ImageMascot.js.map +1 -0
- package/dist/components/LLMWorkingView.d.ts +19 -0
- package/dist/components/LLMWorkingView.d.ts.map +1 -0
- package/dist/components/LLMWorkingView.js +72 -0
- package/dist/components/LLMWorkingView.js.map +1 -0
- package/dist/components/LoadContextView.d.ts +22 -0
- package/dist/components/LoadContextView.d.ts.map +1 -0
- package/dist/components/LoadContextView.js +83 -0
- package/dist/components/LoadContextView.js.map +1 -0
- package/dist/components/MainMenuView.d.ts +20 -0
- package/dist/components/MainMenuView.d.ts.map +1 -0
- package/dist/components/MainMenuView.js +49 -0
- package/dist/components/MainMenuView.js.map +1 -0
- package/dist/components/Mascot.d.ts +24 -0
- package/dist/components/Mascot.d.ts.map +1 -0
- package/dist/components/Mascot.js +32 -0
- package/dist/components/Mascot.js.map +1 -0
- package/dist/components/Menu.d.ts +22 -0
- package/dist/components/Menu.d.ts.map +1 -0
- package/dist/components/Menu.js +28 -0
- package/dist/components/Menu.js.map +1 -0
- package/dist/components/NotionBrowserView.d.ts +21 -0
- package/dist/components/NotionBrowserView.d.ts.map +1 -0
- package/dist/components/NotionBrowserView.js +75 -0
- package/dist/components/NotionBrowserView.js.map +1 -0
- package/dist/components/ObsidianBrowserView.d.ts +21 -0
- package/dist/components/ObsidianBrowserView.d.ts.map +1 -0
- package/dist/components/ObsidianBrowserView.js +74 -0
- package/dist/components/ObsidianBrowserView.js.map +1 -0
- package/dist/components/ObsidianConfigView.d.ts +19 -0
- package/dist/components/ObsidianConfigView.d.ts.map +1 -0
- package/dist/components/ObsidianConfigView.js +45 -0
- package/dist/components/ObsidianConfigView.js.map +1 -0
- package/dist/components/PlaceholderView.d.ts +15 -0
- package/dist/components/PlaceholderView.d.ts.map +1 -0
- package/dist/components/PlaceholderView.js +20 -0
- package/dist/components/PlaceholderView.js.map +1 -0
- package/dist/components/PlanViewerView.d.ts +26 -0
- package/dist/components/PlanViewerView.d.ts.map +1 -0
- package/dist/components/PlanViewerView.js +170 -0
- package/dist/components/PlanViewerView.js.map +1 -0
- package/dist/components/ProgressBar.d.ts +24 -0
- package/dist/components/ProgressBar.d.ts.map +1 -0
- package/dist/components/ProgressBar.js +23 -0
- package/dist/components/ProgressBar.js.map +1 -0
- package/dist/components/ProjectDashboardView.d.ts +38 -0
- package/dist/components/ProjectDashboardView.d.ts.map +1 -0
- package/dist/components/ProjectDashboardView.js +129 -0
- package/dist/components/ProjectDashboardView.js.map +1 -0
- package/dist/components/SaveContextView.d.ts +32 -0
- package/dist/components/SaveContextView.d.ts.map +1 -0
- package/dist/components/SaveContextView.js +41 -0
- package/dist/components/SaveContextView.js.map +1 -0
- package/dist/components/SessionDetails.d.ts +14 -0
- package/dist/components/SessionDetails.d.ts.map +1 -0
- package/dist/components/SessionDetails.js +87 -0
- package/dist/components/SessionDetails.js.map +1 -0
- package/dist/components/SessionsExperimentView.d.ts +35 -0
- package/dist/components/SessionsExperimentView.d.ts.map +1 -0
- package/dist/components/SessionsExperimentView.js +347 -0
- package/dist/components/SessionsExperimentView.js.map +1 -0
- package/dist/components/SessionsList.d.ts +20 -0
- package/dist/components/SessionsList.d.ts.map +1 -0
- package/dist/components/SessionsList.js +75 -0
- package/dist/components/SessionsList.js.map +1 -0
- package/dist/components/SettingsView.d.ts +48 -0
- package/dist/components/SettingsView.d.ts.map +1 -0
- package/dist/components/SettingsView.js +156 -0
- package/dist/components/SettingsView.js.map +1 -0
- package/dist/components/SourceSelectionView.d.ts +26 -0
- package/dist/components/SourceSelectionView.d.ts.map +1 -0
- package/dist/components/SourceSelectionView.js +109 -0
- package/dist/components/SourceSelectionView.js.map +1 -0
- package/dist/components/VerticalMenu.d.ts +18 -0
- package/dist/components/VerticalMenu.d.ts.map +1 -0
- package/dist/components/VerticalMenu.js +15 -0
- package/dist/components/VerticalMenu.js.map +1 -0
- package/dist/components/ascii-art/index.d.ts +6 -0
- package/dist/components/ascii-art/index.d.ts.map +1 -0
- package/dist/components/ascii-art/index.js +6 -0
- package/dist/components/ascii-art/index.js.map +1 -0
- package/dist/components/ascii-art/progress.d.ts +53 -0
- package/dist/components/ascii-art/progress.d.ts.map +1 -0
- package/dist/components/ascii-art/progress.js +102 -0
- package/dist/components/ascii-art/progress.js.map +1 -0
- package/dist/components/ascii-art/scene.d.ts +34 -0
- package/dist/components/ascii-art/scene.d.ts.map +1 -0
- package/dist/components/ascii-art/scene.js +72 -0
- package/dist/components/ascii-art/scene.js.map +1 -0
- package/dist/components/index.d.ts +27 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +25 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/layout/HorizontalLayout.d.ts +19 -0
- package/dist/components/layout/HorizontalLayout.d.ts.map +1 -0
- package/dist/components/layout/HorizontalLayout.js +62 -0
- package/dist/components/layout/HorizontalLayout.js.map +1 -0
- package/dist/components/layout/VerticalLayout.d.ts +16 -0
- package/dist/components/layout/VerticalLayout.d.ts.map +1 -0
- package/dist/components/layout/VerticalLayout.js +32 -0
- package/dist/components/layout/VerticalLayout.js.map +1 -0
- package/dist/components/layout/index.d.ts +6 -0
- package/dist/components/layout/index.d.ts.map +1 -0
- package/dist/components/layout/index.js +4 -0
- package/dist/components/layout/index.js.map +1 -0
- package/dist/components/layout/theme.d.ts +20 -0
- package/dist/components/layout/theme.d.ts.map +1 -0
- package/dist/components/layout/theme.js +23 -0
- package/dist/components/layout/theme.js.map +1 -0
- package/dist/components/setup/DoneStep.d.ts +7 -0
- package/dist/components/setup/DoneStep.d.ts.map +1 -0
- package/dist/components/setup/DoneStep.js +31 -0
- package/dist/components/setup/DoneStep.js.map +1 -0
- package/dist/components/setup/InstallingStep.d.ts +11 -0
- package/dist/components/setup/InstallingStep.d.ts.map +1 -0
- package/dist/components/setup/InstallingStep.js +27 -0
- package/dist/components/setup/InstallingStep.js.map +1 -0
- package/dist/components/setup/OptionsStep.d.ts +9 -0
- package/dist/components/setup/OptionsStep.d.ts.map +1 -0
- package/dist/components/setup/OptionsStep.js +39 -0
- package/dist/components/setup/OptionsStep.js.map +1 -0
- package/dist/components/setup/PrerequisitesStep.d.ts +7 -0
- package/dist/components/setup/PrerequisitesStep.d.ts.map +1 -0
- package/dist/components/setup/PrerequisitesStep.js +31 -0
- package/dist/components/setup/PrerequisitesStep.js.map +1 -0
- package/dist/components/setup/SetupFrame.d.ts +17 -0
- package/dist/components/setup/SetupFrame.d.ts.map +1 -0
- package/dist/components/setup/SetupFrame.js +33 -0
- package/dist/components/setup/SetupFrame.js.map +1 -0
- package/dist/components/setup/SetupWizard.d.ts +9 -0
- package/dist/components/setup/SetupWizard.d.ts.map +1 -0
- package/dist/components/setup/SetupWizard.js +149 -0
- package/dist/components/setup/SetupWizard.js.map +1 -0
- package/dist/components/setup/Spinner.d.ts +10 -0
- package/dist/components/setup/Spinner.d.ts.map +1 -0
- package/dist/components/setup/Spinner.js +20 -0
- package/dist/components/setup/Spinner.js.map +1 -0
- package/dist/components/setup/SyncStep.d.ts +11 -0
- package/dist/components/setup/SyncStep.d.ts.map +1 -0
- package/dist/components/setup/SyncStep.js +47 -0
- package/dist/components/setup/SyncStep.js.map +1 -0
- package/dist/components/setup/VerificationStep.d.ts +7 -0
- package/dist/components/setup/VerificationStep.d.ts.map +1 -0
- package/dist/components/setup/VerificationStep.js +27 -0
- package/dist/components/setup/VerificationStep.js.map +1 -0
- package/dist/components/setup/WelcomeStep.d.ts +6 -0
- package/dist/components/setup/WelcomeStep.d.ts.map +1 -0
- package/dist/components/setup/WelcomeStep.js +17 -0
- package/dist/components/setup/WelcomeStep.js.map +1 -0
- package/dist/components/shared/ProgressLine.d.ts +10 -0
- package/dist/components/shared/ProgressLine.d.ts.map +1 -0
- package/dist/components/shared/ProgressLine.js +18 -0
- package/dist/components/shared/ProgressLine.js.map +1 -0
- package/dist/components/shared/ProjectLine.d.ts +10 -0
- package/dist/components/shared/ProjectLine.d.ts.map +1 -0
- package/dist/components/shared/ProjectLine.js +19 -0
- package/dist/components/shared/ProjectLine.js.map +1 -0
- package/dist/components/shared/ScanningIndicator.d.ts +9 -0
- package/dist/components/shared/ScanningIndicator.d.ts.map +1 -0
- package/dist/components/shared/ScanningIndicator.js +22 -0
- package/dist/components/shared/ScanningIndicator.js.map +1 -0
- package/dist/components/shared/StatusLine.d.ts +13 -0
- package/dist/components/shared/StatusLine.d.ts.map +1 -0
- package/dist/components/shared/StatusLine.js +24 -0
- package/dist/components/shared/StatusLine.js.map +1 -0
- package/dist/components/shared/StatusLine.test.d.ts +8 -0
- package/dist/components/shared/StatusLine.test.d.ts.map +1 -0
- package/dist/components/shared/StatusLine.test.js +50 -0
- package/dist/components/shared/StatusLine.test.js.map +1 -0
- package/dist/components/shared/index.d.ts +4 -0
- package/dist/components/shared/index.d.ts.map +1 -0
- package/dist/components/shared/index.js +4 -0
- package/dist/components/shared/index.js.map +1 -0
- package/dist/handoff/catalog.test.d.ts +5 -0
- package/dist/handoff/catalog.test.d.ts.map +1 -0
- package/dist/handoff/catalog.test.js +172 -0
- package/dist/handoff/catalog.test.js.map +1 -0
- package/dist/handoff/subagents.test.d.ts +8 -0
- package/dist/handoff/subagents.test.d.ts.map +1 -0
- package/dist/handoff/subagents.test.js +139 -0
- package/dist/handoff/subagents.test.js.map +1 -0
- package/dist/hooks/useAddContextFlow.d.ts +29 -0
- package/dist/hooks/useAddContextFlow.d.ts.map +1 -0
- package/dist/hooks/useAddContextFlow.js +83 -0
- package/dist/hooks/useAddContextFlow.js.map +1 -0
- package/dist/hooks/useArchiveBrowser.d.ts +37 -0
- package/dist/hooks/useArchiveBrowser.d.ts.map +1 -0
- package/dist/hooks/useArchiveBrowser.js +175 -0
- package/dist/hooks/useArchiveBrowser.js.map +1 -0
- package/dist/hooks/useClaudeToken.d.ts +29 -0
- package/dist/hooks/useClaudeToken.d.ts.map +1 -0
- package/dist/hooks/useClaudeToken.js +166 -0
- package/dist/hooks/useClaudeToken.js.map +1 -0
- package/dist/hooks/useGoogleDocsBrowser.d.ts +29 -0
- package/dist/hooks/useGoogleDocsBrowser.d.ts.map +1 -0
- package/dist/hooks/useGoogleDocsBrowser.js +146 -0
- package/dist/hooks/useGoogleDocsBrowser.js.map +1 -0
- package/dist/hooks/useHandoffBrowser.d.ts +27 -0
- package/dist/hooks/useHandoffBrowser.d.ts.map +1 -0
- package/dist/hooks/useHandoffBrowser.js +92 -0
- package/dist/hooks/useHandoffBrowser.js.map +1 -0
- package/dist/hooks/useJacquesClient.d.ts +69 -0
- package/dist/hooks/useJacquesClient.d.ts.map +1 -0
- package/dist/hooks/useJacquesClient.js +248 -0
- package/dist/hooks/useJacquesClient.js.map +1 -0
- package/dist/hooks/useLlmWorking.d.ts +30 -0
- package/dist/hooks/useLlmWorking.d.ts.map +1 -0
- package/dist/hooks/useLlmWorking.js +127 -0
- package/dist/hooks/useLlmWorking.js.map +1 -0
- package/dist/hooks/useLoadContext.d.ts +27 -0
- package/dist/hooks/useLoadContext.d.ts.map +1 -0
- package/dist/hooks/useLoadContext.js +102 -0
- package/dist/hooks/useLoadContext.js.map +1 -0
- package/dist/hooks/useNotification.d.ts +36 -0
- package/dist/hooks/useNotification.d.ts.map +1 -0
- package/dist/hooks/useNotification.js +89 -0
- package/dist/hooks/useNotification.js.map +1 -0
- package/dist/hooks/useNotification.test.d.ts +9 -0
- package/dist/hooks/useNotification.test.d.ts.map +1 -0
- package/dist/hooks/useNotification.test.js +144 -0
- package/dist/hooks/useNotification.test.js.map +1 -0
- package/dist/hooks/useNotionBrowser.d.ts +30 -0
- package/dist/hooks/useNotionBrowser.d.ts.map +1 -0
- package/dist/hooks/useNotionBrowser.js +154 -0
- package/dist/hooks/useNotionBrowser.js.map +1 -0
- package/dist/hooks/useObsidianBrowser.d.ts +42 -0
- package/dist/hooks/useObsidianBrowser.d.ts.map +1 -0
- package/dist/hooks/useObsidianBrowser.js +63 -0
- package/dist/hooks/useObsidianBrowser.js.map +1 -0
- package/dist/hooks/useObsidianConfig.d.ts +28 -0
- package/dist/hooks/useObsidianConfig.d.ts.map +1 -0
- package/dist/hooks/useObsidianConfig.js +119 -0
- package/dist/hooks/useObsidianConfig.js.map +1 -0
- package/dist/hooks/useObsidianFileBrowser.d.ts +29 -0
- package/dist/hooks/useObsidianFileBrowser.d.ts.map +1 -0
- package/dist/hooks/useObsidianFileBrowser.js +114 -0
- package/dist/hooks/useObsidianFileBrowser.js.map +1 -0
- package/dist/hooks/useProjectDashboard.d.ts +38 -0
- package/dist/hooks/useProjectDashboard.d.ts.map +1 -0
- package/dist/hooks/useProjectDashboard.js +224 -0
- package/dist/hooks/useProjectDashboard.js.map +1 -0
- package/dist/hooks/useProjectSelector.d.ts +17 -0
- package/dist/hooks/useProjectSelector.d.ts.map +1 -0
- package/dist/hooks/useProjectSelector.js +43 -0
- package/dist/hooks/useProjectSelector.js.map +1 -0
- package/dist/hooks/useProjectSelector.test.d.ts +7 -0
- package/dist/hooks/useProjectSelector.test.d.ts.map +1 -0
- package/dist/hooks/useProjectSelector.test.js +117 -0
- package/dist/hooks/useProjectSelector.test.js.map +1 -0
- package/dist/hooks/useSaveFlow.d.ts +30 -0
- package/dist/hooks/useSaveFlow.d.ts.map +1 -0
- package/dist/hooks/useSaveFlow.js +195 -0
- package/dist/hooks/useSaveFlow.js.map +1 -0
- package/dist/hooks/useSessions.test.d.ts +7 -0
- package/dist/hooks/useSessions.test.d.ts.map +1 -0
- package/dist/hooks/useSessions.test.js +153 -0
- package/dist/hooks/useSessions.test.js.map +1 -0
- package/dist/hooks/useSessionsExperiment.d.ts +97 -0
- package/dist/hooks/useSessionsExperiment.d.ts.map +1 -0
- package/dist/hooks/useSessionsExperiment.js +321 -0
- package/dist/hooks/useSessionsExperiment.js.map +1 -0
- package/dist/hooks/useSettings.d.ts +47 -0
- package/dist/hooks/useSettings.d.ts.map +1 -0
- package/dist/hooks/useSettings.js +245 -0
- package/dist/hooks/useSettings.js.map +1 -0
- package/dist/hooks/useSetupWizard.d.ts +35 -0
- package/dist/hooks/useSetupWizard.d.ts.map +1 -0
- package/dist/hooks/useSetupWizard.js +438 -0
- package/dist/hooks/useSetupWizard.js.map +1 -0
- package/dist/hooks/useUsageLimits.d.ts +24 -0
- package/dist/hooks/useUsageLimits.d.ts.map +1 -0
- package/dist/hooks/useUsageLimits.js +58 -0
- package/dist/hooks/useUsageLimits.js.map +1 -0
- package/dist/hooks/useUsageLimits.test.d.ts +7 -0
- package/dist/hooks/useUsageLimits.test.d.ts.map +1 -0
- package/dist/hooks/useUsageLimits.test.js +136 -0
- package/dist/hooks/useUsageLimits.test.js.map +1 -0
- package/dist/hooks/useWorktrees.d.ts +28 -0
- package/dist/hooks/useWorktrees.d.ts.map +1 -0
- package/dist/hooks/useWorktrees.js +57 -0
- package/dist/hooks/useWorktrees.js.map +1 -0
- package/dist/hooks/useWorktrees.test.d.ts +7 -0
- package/dist/hooks/useWorktrees.test.d.ts.map +1 -0
- package/dist/hooks/useWorktrees.test.js +119 -0
- package/dist/hooks/useWorktrees.test.js.map +1 -0
- package/dist/templates/compact-prompt.d.ts +16 -0
- package/dist/templates/compact-prompt.d.ts.map +1 -0
- package/dist/templates/compact-prompt.js +47 -0
- package/dist/templates/compact-prompt.js.map +1 -0
- package/dist/templates/context-skill.d.ts +8 -0
- package/dist/templates/context-skill.d.ts.map +1 -0
- package/dist/templates/context-skill.js +42 -0
- package/dist/templates/context-skill.js.map +1 -0
- package/dist/types.d.ts +127 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/activity.d.ts +17 -0
- package/dist/utils/activity.d.ts.map +1 -0
- package/dist/utils/activity.js +78 -0
- package/dist/utils/activity.js.map +1 -0
- package/dist/utils/bottom-controls.d.ts +24 -0
- package/dist/utils/bottom-controls.d.ts.map +1 -0
- package/dist/utils/bottom-controls.js +29 -0
- package/dist/utils/bottom-controls.js.map +1 -0
- package/dist/utils/clipboard.d.ts +2 -0
- package/dist/utils/clipboard.d.ts.map +1 -0
- package/dist/utils/clipboard.js +20 -0
- package/dist/utils/clipboard.js.map +1 -0
- package/dist/utils/constants.d.ts +6 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +6 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/format.d.ts +17 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +31 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/session-mode.d.ts +14 -0
- package/dist/utils/session-mode.d.ts.map +1 -0
- package/dist/utils/session-mode.js +29 -0
- package/dist/utils/session-mode.js.map +1 -0
- package/dist/utils/session-mode.test.d.ts +7 -0
- package/dist/utils/session-mode.test.d.ts.map +1 -0
- package/dist/utils/session-mode.test.js +102 -0
- package/dist/utils/session-mode.test.js.map +1 -0
- package/dist/utils/sessions-items-builder.d.ts +29 -0
- package/dist/utils/sessions-items-builder.d.ts.map +1 -0
- package/dist/utils/sessions-items-builder.js +394 -0
- package/dist/utils/sessions-items-builder.js.map +1 -0
- package/dist/utils/settings.d.ts +100 -0
- package/dist/utils/settings.d.ts.map +1 -0
- package/dist/utils/settings.js +206 -0
- package/dist/utils/settings.js.map +1 -0
- package/dist/websocket-client.d.ts +70 -0
- package/dist/websocket-client.d.ts.map +1 -0
- package/dist/websocket-client.js +188 -0
- package/dist/websocket-client.js.map +1 -0
- package/hooks/adapters/__init__.py +17 -0
- package/hooks/adapters/__pycache__/__init__.cpython-311.pyc +0 -0
- package/hooks/adapters/__pycache__/__init__.cpython-313.pyc +0 -0
- package/hooks/adapters/__pycache__/__init__.cpython-314.pyc +0 -0
- package/hooks/adapters/__pycache__/base.cpython-311.pyc +0 -0
- package/hooks/adapters/__pycache__/base.cpython-313.pyc +0 -0
- package/hooks/adapters/__pycache__/base.cpython-314.pyc +0 -0
- package/hooks/adapters/__pycache__/calibration.cpython-311.pyc +0 -0
- package/hooks/adapters/__pycache__/calibration.cpython-313.pyc +0 -0
- package/hooks/adapters/__pycache__/calibration.cpython-314.pyc +0 -0
- package/hooks/adapters/__pycache__/claude_code.cpython-311.pyc +0 -0
- package/hooks/adapters/__pycache__/claude_code.cpython-313.pyc +0 -0
- package/hooks/adapters/__pycache__/claude_code.cpython-314.pyc +0 -0
- package/hooks/adapters/__pycache__/cursor.cpython-311.pyc +0 -0
- package/hooks/adapters/__pycache__/cursor.cpython-313.pyc +0 -0
- package/hooks/adapters/__pycache__/cursor.cpython-314.pyc +0 -0
- package/hooks/adapters/__pycache__/skills.cpython-311.pyc +0 -0
- package/hooks/adapters/__pycache__/skills.cpython-313.pyc +0 -0
- package/hooks/adapters/__pycache__/skills.cpython-314.pyc +0 -0
- package/hooks/adapters/__pycache__/test_adapters.cpython-311-pytest-9.0.2.pyc +0 -0
- package/hooks/adapters/__pycache__/test_adapters.cpython-313.pyc +0 -0
- package/hooks/adapters/__pycache__/test_calibration.cpython-311-pytest-9.0.2.pyc +0 -0
- package/hooks/adapters/__pycache__/test_skills.cpython-311-pytest-9.0.2.pyc +0 -0
- package/hooks/adapters/__pycache__/test_tokenizer.cpython-311-pytest-9.0.2.pyc +0 -0
- package/hooks/adapters/__pycache__/tokenizer.cpython-311.pyc +0 -0
- package/hooks/adapters/__pycache__/tokenizer.cpython-313.pyc +0 -0
- package/hooks/adapters/__pycache__/tokenizer.cpython-314.pyc +0 -0
- package/hooks/adapters/base.py +459 -0
- package/hooks/adapters/calibration.py +236 -0
- package/hooks/adapters/claude_code.py +316 -0
- package/hooks/adapters/context_parser.py +288 -0
- package/hooks/adapters/cursor.py +258 -0
- package/hooks/adapters/skills.py +160 -0
- package/hooks/adapters/template.py +281 -0
- package/hooks/adapters/test_adapters.py +516 -0
- package/hooks/adapters/test_calibration.py +235 -0
- package/hooks/adapters/test_skills.py +162 -0
- package/hooks/adapters/test_tokenizer.py +158 -0
- package/hooks/adapters/tokenizer.py +192 -0
- package/hooks/claude-code/pre-tool-use.py +36 -0
- package/hooks/claude-code/register-session.py +35 -0
- package/hooks/claude-code/report-activity.py +32 -0
- package/hooks/claude-code/session-idle.py +32 -0
- package/hooks/claude-code/statusline.sh +91 -0
- package/hooks/claude-code/unregister-session.py +32 -0
- package/hooks/cursor/README.md +61 -0
- package/hooks/cursor/after-agent-response.py +97 -0
- package/hooks/cursor/hooks.json.template +30 -0
- package/hooks/cursor/post-tool-use.py +32 -0
- package/hooks/cursor/pre-compact.py +61 -0
- package/hooks/cursor/session-end.py +32 -0
- package/hooks/cursor/session-start.py +66 -0
- package/hooks/git-detect.sh +47 -0
- package/hooks/install.py +441 -0
- package/hooks/jacques-register-session.py +286 -0
- package/hooks/jacques-report-activity.py +145 -0
- package/hooks/jacques-session-idle.py +57 -0
- package/hooks/jacques-unregister-session.py +57 -0
- package/hooks/requirements.txt +9 -0
- package/hooks/statusline.py +457 -0
- package/hooks/statusline.sh +212 -0
- package/package.json +63 -0
- package/skills/jacques-continue/SKILL.md +87 -0
- package/skills/jacques-handoff/SKILL.md +147 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
cursor.py - Cursor Native AI Adapter for Jacques
|
|
4
|
+
|
|
5
|
+
Handles events from Cursor's native AI (sidebar chat).
|
|
6
|
+
|
|
7
|
+
Field Mappings:
|
|
8
|
+
- session_id: conversation_id
|
|
9
|
+
- project_path: workspace_roots[0]
|
|
10
|
+
- context_metrics: from preCompact event
|
|
11
|
+
|
|
12
|
+
Hook Events (configured in .cursor/hooks.json):
|
|
13
|
+
- sessionStart → session_start
|
|
14
|
+
- sessionEnd → session_end
|
|
15
|
+
- postToolUse → activity
|
|
16
|
+
- preCompact → context_update (contains context metrics!)
|
|
17
|
+
|
|
18
|
+
Key Discovery:
|
|
19
|
+
Cursor's preCompact event provides context metrics that allow us to display
|
|
20
|
+
context usage percentage just like Claude Code CLI!
|
|
21
|
+
"""
|
|
22
|
+
import os
|
|
23
|
+
from typing import Optional
|
|
24
|
+
from .base import BaseAdapter
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class CursorAdapter(BaseAdapter):
|
|
28
|
+
"""
|
|
29
|
+
Adapter for Cursor Native AI sessions.
|
|
30
|
+
|
|
31
|
+
Cursor provides session data via hooks configured in
|
|
32
|
+
.cursor/hooks.json (per-project) or global Cursor settings.
|
|
33
|
+
|
|
34
|
+
Note: Cursor uses different field names than Claude Code:
|
|
35
|
+
- conversation_id instead of session_id
|
|
36
|
+
- workspace_roots[] instead of workspace.project_dir
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def source(self) -> str:
|
|
41
|
+
return 'cursor'
|
|
42
|
+
|
|
43
|
+
def get_session_id(self, input_data: dict) -> Optional[str]:
|
|
44
|
+
"""
|
|
45
|
+
Extract session ID from Cursor input.
|
|
46
|
+
|
|
47
|
+
Cursor uses 'conversation_id' as the session identifier.
|
|
48
|
+
"""
|
|
49
|
+
return input_data.get('conversation_id')
|
|
50
|
+
|
|
51
|
+
def get_project_path(self, input_data: dict) -> Optional[str]:
|
|
52
|
+
"""
|
|
53
|
+
Extract project path from Cursor input.
|
|
54
|
+
|
|
55
|
+
Cursor provides workspace_roots as an array of open workspace paths.
|
|
56
|
+
We use the first one as the primary project path.
|
|
57
|
+
"""
|
|
58
|
+
workspace_roots = input_data.get('workspace_roots', [])
|
|
59
|
+
if workspace_roots and isinstance(workspace_roots, list):
|
|
60
|
+
return workspace_roots[0]
|
|
61
|
+
return ''
|
|
62
|
+
|
|
63
|
+
def get_model(self, input_data: dict) -> Optional[str]:
|
|
64
|
+
"""Extract model name from Cursor input."""
|
|
65
|
+
# Cursor may provide model info in different fields
|
|
66
|
+
return input_data.get('model') or input_data.get('model_name')
|
|
67
|
+
|
|
68
|
+
# =========================================================================
|
|
69
|
+
# Session Start Payload
|
|
70
|
+
# =========================================================================
|
|
71
|
+
|
|
72
|
+
def build_session_start_payload(self, input_data: dict) -> Optional[dict]:
|
|
73
|
+
"""
|
|
74
|
+
Build payload for session_start event.
|
|
75
|
+
|
|
76
|
+
Called from sessionStart hook (session-start.py).
|
|
77
|
+
"""
|
|
78
|
+
session_id = self.validate_session_id(input_data)
|
|
79
|
+
if not session_id:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
# Extract project info
|
|
83
|
+
project_info = self.extract_project_info(input_data)
|
|
84
|
+
|
|
85
|
+
# Cursor doesn't have transcript files like Claude Code
|
|
86
|
+
# Generate title from project name
|
|
87
|
+
session_title = self.generate_fallback_title(project_info['project'])
|
|
88
|
+
|
|
89
|
+
# Get terminal identity (useful for identification)
|
|
90
|
+
terminal = self.get_terminal_identity()
|
|
91
|
+
terminal_key = self.build_terminal_key(terminal)
|
|
92
|
+
|
|
93
|
+
return self.build_base_payload(
|
|
94
|
+
event='session_start',
|
|
95
|
+
session_id=session_id,
|
|
96
|
+
session_title=session_title,
|
|
97
|
+
transcript_path=None, # Cursor doesn't have transcripts
|
|
98
|
+
cwd=project_info['cwd'],
|
|
99
|
+
project=project_info['project'],
|
|
100
|
+
project_dir=project_info['project_path'],
|
|
101
|
+
model=self.get_model(input_data),
|
|
102
|
+
hook_source='startup',
|
|
103
|
+
terminal=terminal,
|
|
104
|
+
terminal_key=terminal_key,
|
|
105
|
+
# Cursor-specific fields
|
|
106
|
+
workspace_roots=input_data.get('workspace_roots', []),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# =========================================================================
|
|
110
|
+
# Context Estimate Payload (from token estimation)
|
|
111
|
+
# =========================================================================
|
|
112
|
+
|
|
113
|
+
def build_context_estimate_payload(
|
|
114
|
+
self,
|
|
115
|
+
input_data: dict,
|
|
116
|
+
estimated_tokens: int,
|
|
117
|
+
model: str = None
|
|
118
|
+
) -> Optional[dict]:
|
|
119
|
+
"""
|
|
120
|
+
Build payload for context_update event from token estimation.
|
|
121
|
+
|
|
122
|
+
Used by afterAgentResponse hook to send estimated context metrics.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
input_data: Hook input data
|
|
126
|
+
estimated_tokens: Token count estimated from transcript
|
|
127
|
+
model: Model name (for context window lookup)
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
context_update payload with is_estimate=True flag.
|
|
131
|
+
"""
|
|
132
|
+
from . import tokenizer
|
|
133
|
+
|
|
134
|
+
session_id = self.validate_session_id(input_data)
|
|
135
|
+
if not session_id:
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
# Get model from input or use provided
|
|
139
|
+
if not model:
|
|
140
|
+
model = self.get_model(input_data)
|
|
141
|
+
|
|
142
|
+
# Calculate context metrics
|
|
143
|
+
metrics = tokenizer.calculate_context_metrics(estimated_tokens, model)
|
|
144
|
+
|
|
145
|
+
# Get project info
|
|
146
|
+
project_info = self.extract_project_info(input_data)
|
|
147
|
+
|
|
148
|
+
return self.build_base_payload(
|
|
149
|
+
event='context_update',
|
|
150
|
+
session_id=session_id,
|
|
151
|
+
used_percentage=metrics['used_percentage'],
|
|
152
|
+
remaining_percentage=metrics['remaining_percentage'],
|
|
153
|
+
context_window_size=metrics['context_window_size'],
|
|
154
|
+
total_input_tokens=estimated_tokens,
|
|
155
|
+
total_output_tokens=0,
|
|
156
|
+
is_estimate=True, # Flag to indicate this is an estimate
|
|
157
|
+
cwd=project_info['cwd'],
|
|
158
|
+
project_dir=project_info['project_path'],
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# =========================================================================
|
|
162
|
+
# Pre-Compact Payload (Context Metrics!)
|
|
163
|
+
# =========================================================================
|
|
164
|
+
|
|
165
|
+
def build_pre_compact_payload(self, input_data: dict) -> Optional[dict]:
|
|
166
|
+
"""
|
|
167
|
+
Build payload for context_update event from preCompact.
|
|
168
|
+
|
|
169
|
+
This is the KEY event for Cursor that provides context metrics!
|
|
170
|
+
|
|
171
|
+
Expected input fields from preCompact:
|
|
172
|
+
- context_usage_percent: Percentage of context used (0-100)
|
|
173
|
+
- context_tokens: Current token count
|
|
174
|
+
- context_window_size: Maximum context window
|
|
175
|
+
|
|
176
|
+
NOTE: The 'model' field in preCompact is the SUMMARIZATION model
|
|
177
|
+
(typically gemini-2.5-flash), NOT the user's selected chat model.
|
|
178
|
+
We don't update model here - it should come from sessionStart.
|
|
179
|
+
"""
|
|
180
|
+
session_id = self.validate_session_id(input_data)
|
|
181
|
+
if not session_id:
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
# Extract context metrics
|
|
185
|
+
used_percentage = input_data.get('context_usage_percent', 0)
|
|
186
|
+
context_tokens = input_data.get('context_tokens', 0)
|
|
187
|
+
context_window_size = input_data.get('context_window_size', 0)
|
|
188
|
+
|
|
189
|
+
# Calculate remaining percentage
|
|
190
|
+
remaining_percentage = 100 - used_percentage if used_percentage else 100
|
|
191
|
+
|
|
192
|
+
# Get project info for cwd
|
|
193
|
+
project_info = self.extract_project_info(input_data)
|
|
194
|
+
|
|
195
|
+
# NOTE: Don't use model from preCompact - it's the summarization model
|
|
196
|
+
# (gemini-2.5-flash), not the user's chat model. Leave model empty
|
|
197
|
+
# so it doesn't overwrite the correct model from sessionStart.
|
|
198
|
+
|
|
199
|
+
return self.build_base_payload(
|
|
200
|
+
event='context_update',
|
|
201
|
+
session_id=session_id,
|
|
202
|
+
used_percentage=used_percentage,
|
|
203
|
+
remaining_percentage=remaining_percentage,
|
|
204
|
+
context_window_size=context_window_size,
|
|
205
|
+
total_input_tokens=context_tokens,
|
|
206
|
+
total_output_tokens=0, # Cursor doesn't provide this
|
|
207
|
+
# Don't include model - let sessionStart model persist
|
|
208
|
+
cwd=project_info['cwd'],
|
|
209
|
+
project_dir=project_info['project_path'],
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# =========================================================================
|
|
213
|
+
# Activity Payload
|
|
214
|
+
# =========================================================================
|
|
215
|
+
|
|
216
|
+
def build_activity_payload(self, input_data: dict) -> Optional[dict]:
|
|
217
|
+
"""
|
|
218
|
+
Build payload for activity event.
|
|
219
|
+
|
|
220
|
+
Called from postToolUse hook (post-tool-use.py).
|
|
221
|
+
"""
|
|
222
|
+
session_id = self.validate_session_id(input_data)
|
|
223
|
+
if not session_id:
|
|
224
|
+
return None
|
|
225
|
+
|
|
226
|
+
# Extract project info for session title
|
|
227
|
+
project_info = self.extract_project_info(input_data)
|
|
228
|
+
session_title = self.generate_fallback_title(project_info['project'])
|
|
229
|
+
|
|
230
|
+
tool_name = input_data.get('tool_name', 'unknown')
|
|
231
|
+
|
|
232
|
+
return self.build_base_payload(
|
|
233
|
+
event='activity',
|
|
234
|
+
session_id=session_id,
|
|
235
|
+
session_title=session_title,
|
|
236
|
+
tool_name=tool_name,
|
|
237
|
+
terminal_pid=os.getppid(),
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# =========================================================================
|
|
241
|
+
# Session End Payload
|
|
242
|
+
# =========================================================================
|
|
243
|
+
|
|
244
|
+
def build_session_end_payload(self, input_data: dict) -> Optional[dict]:
|
|
245
|
+
"""
|
|
246
|
+
Build payload for session_end event.
|
|
247
|
+
|
|
248
|
+
Called from sessionEnd hook (session-end.py).
|
|
249
|
+
"""
|
|
250
|
+
session_id = self.validate_session_id(input_data)
|
|
251
|
+
if not session_id:
|
|
252
|
+
return None
|
|
253
|
+
|
|
254
|
+
return self.build_base_payload(
|
|
255
|
+
event='session_end',
|
|
256
|
+
session_id=session_id,
|
|
257
|
+
terminal_pid=os.getppid(),
|
|
258
|
+
)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
skills.py - Cursor Agent Skills Detection for Jacques
|
|
4
|
+
|
|
5
|
+
Scans for installed Cursor agent skills and estimates their token overhead.
|
|
6
|
+
|
|
7
|
+
IMPORTANT: Cursor does NOT inject full SKILL.md files into context!
|
|
8
|
+
It only injects skill METADATA (name, description, path) - about 150-200 tokens per skill.
|
|
9
|
+
|
|
10
|
+
Skill locations:
|
|
11
|
+
- ~/.cursor/skills-cursor/*/SKILL.md - User-installed Cursor skills
|
|
12
|
+
- ~/.claude/plugins/cache/**/SKILL.md - Claude plugins (superpowers, etc.)
|
|
13
|
+
|
|
14
|
+
Typical overhead (CORRECTED):
|
|
15
|
+
- 21 skills × ~200 tokens metadata = ~4,200 tokens
|
|
16
|
+
- System prompts: ~2,000 tokens
|
|
17
|
+
- Total: ~6,000-8,000 tokens (~3-4% on 176k context)
|
|
18
|
+
"""
|
|
19
|
+
import os
|
|
20
|
+
import re
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import List, Tuple
|
|
23
|
+
|
|
24
|
+
# Known skill directories
|
|
25
|
+
SKILL_DIRECTORIES = [
|
|
26
|
+
Path.home() / '.cursor' / 'skills-cursor',
|
|
27
|
+
Path.home() / '.claude' / 'plugins' / 'cache',
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
# Tokens per skill METADATA (not full content!)
|
|
31
|
+
# Cursor uses dynamic context discovery - only name + short description
|
|
32
|
+
# are included statically. Full skill content loaded on-demand.
|
|
33
|
+
# Estimated: ~5-10 tokens for name + ~30-50 tokens for description
|
|
34
|
+
TOKENS_PER_SKILL_METADATA = 50
|
|
35
|
+
|
|
36
|
+
# Base system prompt overhead (Cursor's internal prompts, tools, etc.)
|
|
37
|
+
# Includes: tool definitions, system instructions, user rules
|
|
38
|
+
SYSTEM_PROMPT_TOKENS = 2500
|
|
39
|
+
|
|
40
|
+
# Cache for skill data (computed once per process)
|
|
41
|
+
_skills_cache = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def find_skill_files() -> List[Path]:
|
|
45
|
+
"""
|
|
46
|
+
Find all SKILL.md files in known locations.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
List of paths to skill files.
|
|
50
|
+
"""
|
|
51
|
+
skill_files = []
|
|
52
|
+
|
|
53
|
+
for skill_dir in SKILL_DIRECTORIES:
|
|
54
|
+
if not skill_dir.exists():
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
# Recursively find all SKILL.md files
|
|
58
|
+
for skill_file in skill_dir.rglob('SKILL.md'):
|
|
59
|
+
skill_files.append(skill_file)
|
|
60
|
+
|
|
61
|
+
return skill_files
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def extract_skill_description(skill_file: Path) -> str:
|
|
65
|
+
"""
|
|
66
|
+
Extract the description from a SKILL.md file's frontmatter.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Description string, or empty if not found.
|
|
70
|
+
"""
|
|
71
|
+
try:
|
|
72
|
+
content = skill_file.read_text(encoding='utf-8')
|
|
73
|
+
# Look for description in YAML frontmatter
|
|
74
|
+
match = re.search(r'^---\s*\n.*?description:\s*(.+?)\n.*?^---', content, re.MULTILINE | re.DOTALL)
|
|
75
|
+
if match:
|
|
76
|
+
return match.group(1).strip()
|
|
77
|
+
except Exception:
|
|
78
|
+
pass
|
|
79
|
+
return ""
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def estimate_skill_tokens() -> Tuple[int, int]:
|
|
83
|
+
"""
|
|
84
|
+
Estimate total token overhead from installed skills.
|
|
85
|
+
|
|
86
|
+
IMPORTANT: Cursor only injects skill METADATA, not full content!
|
|
87
|
+
Each skill adds ~200 tokens of metadata (name, description, path).
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Tuple of (skill_count, estimated_tokens)
|
|
91
|
+
"""
|
|
92
|
+
global _skills_cache
|
|
93
|
+
|
|
94
|
+
if _skills_cache is not None:
|
|
95
|
+
return _skills_cache
|
|
96
|
+
|
|
97
|
+
skill_files = find_skill_files()
|
|
98
|
+
skill_count = len(skill_files)
|
|
99
|
+
|
|
100
|
+
# Cursor injects metadata only, not full skill content
|
|
101
|
+
# ~200 tokens per skill for the <agent_skill> tag with path and description
|
|
102
|
+
estimated_tokens = skill_count * TOKENS_PER_SKILL_METADATA
|
|
103
|
+
|
|
104
|
+
_skills_cache = (skill_count, estimated_tokens)
|
|
105
|
+
return _skills_cache
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_initial_context_estimate(model: str = None) -> dict:
|
|
109
|
+
"""
|
|
110
|
+
Get initial context estimate including skill metadata overhead.
|
|
111
|
+
|
|
112
|
+
This provides a more accurate starting point than 0%.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
model: Model name for context window lookup
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Dict with skill_count, estimated_tokens, and context metrics.
|
|
119
|
+
"""
|
|
120
|
+
from . import tokenizer
|
|
121
|
+
|
|
122
|
+
skill_count, skill_tokens = estimate_skill_tokens()
|
|
123
|
+
|
|
124
|
+
# Total = skill metadata + system prompts
|
|
125
|
+
total_initial_tokens = skill_tokens + SYSTEM_PROMPT_TOKENS
|
|
126
|
+
|
|
127
|
+
# Calculate context metrics
|
|
128
|
+
context_window = tokenizer.get_context_window(model)
|
|
129
|
+
used_percentage = tokenizer.calculate_context_percentage(total_initial_tokens, context_window)
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
'skill_count': skill_count,
|
|
133
|
+
'skill_tokens': skill_tokens,
|
|
134
|
+
'system_prompt_tokens': SYSTEM_PROMPT_TOKENS,
|
|
135
|
+
'total_initial_tokens': total_initial_tokens,
|
|
136
|
+
'used_percentage': round(used_percentage, 1),
|
|
137
|
+
'remaining_percentage': round(100 - used_percentage, 1),
|
|
138
|
+
'context_window_size': context_window,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def get_skills_summary() -> str:
|
|
143
|
+
"""
|
|
144
|
+
Get a human-readable summary of installed skills.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
Summary string for logging/debugging.
|
|
148
|
+
"""
|
|
149
|
+
skill_count, estimated_tokens = estimate_skill_tokens()
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
f"{skill_count} skills installed, "
|
|
153
|
+
f"~{estimated_tokens:,} tokens overhead"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def clear_cache() -> None:
|
|
158
|
+
"""Clear the skills cache (useful for testing or when skills change)."""
|
|
159
|
+
global _skills_cache
|
|
160
|
+
_skills_cache = None
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
template.py - Template Adapter for New Jacques Sources
|
|
4
|
+
|
|
5
|
+
=============================================================================
|
|
6
|
+
HOW TO ADD A NEW AI TOOL TO JACQUES
|
|
7
|
+
=============================================================================
|
|
8
|
+
|
|
9
|
+
This template shows how to create an adapter for a new AI tool.
|
|
10
|
+
Follow these steps to add support for a new source:
|
|
11
|
+
|
|
12
|
+
1. COPY this file and rename it (e.g., 'vscode.py')
|
|
13
|
+
2. UPDATE the class name and source property
|
|
14
|
+
3. IMPLEMENT the required methods:
|
|
15
|
+
- get_session_id(): Map your tool's session identifier field
|
|
16
|
+
- get_project_path(): Map your tool's project path field
|
|
17
|
+
4. CREATE hook scripts in hooks/{your-source}/
|
|
18
|
+
5. UPDATE hooks/adapters/__init__.py to export your adapter
|
|
19
|
+
6. ADD installation support in hooks/install.py
|
|
20
|
+
|
|
21
|
+
=============================================================================
|
|
22
|
+
FIELD MAPPING REFERENCE
|
|
23
|
+
=============================================================================
|
|
24
|
+
|
|
25
|
+
Different AI tools use different field names. Here's how existing tools map:
|
|
26
|
+
|
|
27
|
+
| Concept | Claude Code CLI | Cursor Native | Your Tool |
|
|
28
|
+
|-----------------|---------------------|----------------------|---------------|
|
|
29
|
+
| Session ID | session_id | conversation_id | ??? |
|
|
30
|
+
| Project Path | workspace.project_dir| workspace_roots[0] | ??? |
|
|
31
|
+
| Model Name | model | model_name | ??? |
|
|
32
|
+
| Transcript | transcript_path | (none) | ??? |
|
|
33
|
+
| Context % | statusLine event | preCompact event | ??? |
|
|
34
|
+
|
|
35
|
+
=============================================================================
|
|
36
|
+
"""
|
|
37
|
+
from typing import Optional
|
|
38
|
+
from .base import BaseAdapter
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TemplateAdapter(BaseAdapter):
|
|
42
|
+
"""
|
|
43
|
+
Template adapter for a new AI tool.
|
|
44
|
+
|
|
45
|
+
Replace 'template' with your tool name (e.g., 'vscode', 'windsurf').
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def source(self) -> str:
|
|
50
|
+
"""
|
|
51
|
+
REQUIRED: Unique identifier for this source.
|
|
52
|
+
|
|
53
|
+
This appears in the Jacques dashboard and is used for filtering.
|
|
54
|
+
Examples: 'claude_code', 'cursor', 'vscode', 'windsurf'
|
|
55
|
+
"""
|
|
56
|
+
return 'template' # TODO: Change this!
|
|
57
|
+
|
|
58
|
+
def get_session_id(self, input_data: dict) -> Optional[str]:
|
|
59
|
+
"""
|
|
60
|
+
REQUIRED: Extract session ID from your tool's input format.
|
|
61
|
+
|
|
62
|
+
Find out what field your tool uses for the session/conversation ID
|
|
63
|
+
and extract it here.
|
|
64
|
+
|
|
65
|
+
Examples:
|
|
66
|
+
- Claude Code: input_data.get('session_id')
|
|
67
|
+
- Cursor: input_data.get('conversation_id')
|
|
68
|
+
"""
|
|
69
|
+
# TODO: Implement for your tool
|
|
70
|
+
return input_data.get('session_id')
|
|
71
|
+
|
|
72
|
+
def get_project_path(self, input_data: dict) -> Optional[str]:
|
|
73
|
+
"""
|
|
74
|
+
REQUIRED: Extract project path from your tool's input format.
|
|
75
|
+
|
|
76
|
+
Find out what field your tool uses for the workspace/project path
|
|
77
|
+
and extract it here.
|
|
78
|
+
|
|
79
|
+
Examples:
|
|
80
|
+
- Claude Code: input_data.get('workspace', {}).get('project_dir')
|
|
81
|
+
- Cursor: input_data.get('workspace_roots', [])[0]
|
|
82
|
+
"""
|
|
83
|
+
# TODO: Implement for your tool
|
|
84
|
+
return input_data.get('project_path', '')
|
|
85
|
+
|
|
86
|
+
# =========================================================================
|
|
87
|
+
# HOOK METHODS - Implement based on your tool's available hooks
|
|
88
|
+
# =========================================================================
|
|
89
|
+
|
|
90
|
+
def build_session_start_payload(self, input_data: dict) -> Optional[dict]:
|
|
91
|
+
"""
|
|
92
|
+
Build payload for session_start event.
|
|
93
|
+
|
|
94
|
+
This is called when a new AI session begins.
|
|
95
|
+
|
|
96
|
+
Typical hook names:
|
|
97
|
+
- Claude Code: SessionStart
|
|
98
|
+
- Cursor: sessionStart
|
|
99
|
+
"""
|
|
100
|
+
session_id = self.validate_session_id(input_data)
|
|
101
|
+
if not session_id:
|
|
102
|
+
return None
|
|
103
|
+
|
|
104
|
+
project_info = self.extract_project_info(input_data)
|
|
105
|
+
|
|
106
|
+
# Try to extract session title (if your tool supports transcripts)
|
|
107
|
+
transcript_path = input_data.get('transcript_path')
|
|
108
|
+
session_title = self.extract_session_title(transcript_path)
|
|
109
|
+
if not session_title:
|
|
110
|
+
session_title = self.generate_fallback_title(project_info['project'])
|
|
111
|
+
|
|
112
|
+
terminal = self.get_terminal_identity()
|
|
113
|
+
terminal_key = self.build_terminal_key(terminal)
|
|
114
|
+
|
|
115
|
+
return self.build_base_payload(
|
|
116
|
+
event='session_start',
|
|
117
|
+
session_id=session_id,
|
|
118
|
+
session_title=session_title,
|
|
119
|
+
transcript_path=transcript_path,
|
|
120
|
+
cwd=project_info['cwd'],
|
|
121
|
+
project=project_info['project'],
|
|
122
|
+
project_dir=project_info['project_path'],
|
|
123
|
+
model=input_data.get('model'),
|
|
124
|
+
hook_source='startup',
|
|
125
|
+
terminal=terminal,
|
|
126
|
+
terminal_key=terminal_key,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def build_activity_payload(self, input_data: dict) -> Optional[dict]:
|
|
130
|
+
"""
|
|
131
|
+
Build payload for activity event.
|
|
132
|
+
|
|
133
|
+
This is called when the AI uses a tool or takes an action.
|
|
134
|
+
|
|
135
|
+
Typical hook names:
|
|
136
|
+
- Claude Code: PostToolUse
|
|
137
|
+
- Cursor: postToolUse
|
|
138
|
+
"""
|
|
139
|
+
session_id = self.validate_session_id(input_data)
|
|
140
|
+
if not session_id:
|
|
141
|
+
return None
|
|
142
|
+
|
|
143
|
+
project_info = self.extract_project_info(input_data)
|
|
144
|
+
session_title = self.generate_fallback_title(project_info['project'])
|
|
145
|
+
|
|
146
|
+
return self.build_base_payload(
|
|
147
|
+
event='activity',
|
|
148
|
+
session_id=session_id,
|
|
149
|
+
session_title=session_title,
|
|
150
|
+
tool_name=input_data.get('tool_name', 'unknown'),
|
|
151
|
+
terminal_pid=self.get_terminal_identity()['terminal_pid'],
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def build_idle_payload(self, input_data: dict) -> Optional[dict]:
|
|
155
|
+
"""
|
|
156
|
+
Build payload for idle event.
|
|
157
|
+
|
|
158
|
+
This is called when the AI is waiting for user input.
|
|
159
|
+
|
|
160
|
+
Typical hook names:
|
|
161
|
+
- Claude Code: Stop
|
|
162
|
+
- Cursor: (may not have equivalent)
|
|
163
|
+
"""
|
|
164
|
+
session_id = self.validate_session_id(input_data)
|
|
165
|
+
if not session_id:
|
|
166
|
+
return None
|
|
167
|
+
|
|
168
|
+
return self.build_base_payload(
|
|
169
|
+
event='idle',
|
|
170
|
+
session_id=session_id,
|
|
171
|
+
terminal_pid=self.get_terminal_identity()['terminal_pid'],
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
def build_session_end_payload(self, input_data: dict) -> Optional[dict]:
|
|
175
|
+
"""
|
|
176
|
+
Build payload for session_end event.
|
|
177
|
+
|
|
178
|
+
This is called when an AI session ends.
|
|
179
|
+
|
|
180
|
+
Typical hook names:
|
|
181
|
+
- Claude Code: SessionEnd
|
|
182
|
+
- Cursor: sessionEnd
|
|
183
|
+
"""
|
|
184
|
+
session_id = self.validate_session_id(input_data)
|
|
185
|
+
if not session_id:
|
|
186
|
+
return None
|
|
187
|
+
|
|
188
|
+
return self.build_base_payload(
|
|
189
|
+
event='session_end',
|
|
190
|
+
session_id=session_id,
|
|
191
|
+
terminal_pid=self.get_terminal_identity()['terminal_pid'],
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
def build_context_update_payload(self, input_data: dict) -> Optional[dict]:
|
|
195
|
+
"""
|
|
196
|
+
Build payload for context_update event.
|
|
197
|
+
|
|
198
|
+
OPTIONAL: Only implement if your tool provides context metrics.
|
|
199
|
+
|
|
200
|
+
This provides real-time context window usage data.
|
|
201
|
+
|
|
202
|
+
Typical sources:
|
|
203
|
+
- Claude Code: statusLine (shell script, not Python hook)
|
|
204
|
+
- Cursor: preCompact event
|
|
205
|
+
|
|
206
|
+
If your tool doesn't provide context metrics, Jacques will show
|
|
207
|
+
"N/A" for context percentage, which is fine.
|
|
208
|
+
"""
|
|
209
|
+
session_id = self.validate_session_id(input_data)
|
|
210
|
+
if not session_id:
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
# TODO: Map your tool's context metric fields
|
|
214
|
+
# Example fields you might find:
|
|
215
|
+
# - context_usage_percent / used_percentage
|
|
216
|
+
# - context_tokens / total_tokens
|
|
217
|
+
# - context_window_size / max_tokens
|
|
218
|
+
|
|
219
|
+
used_percentage = input_data.get('used_percentage', 0)
|
|
220
|
+
remaining_percentage = 100 - used_percentage
|
|
221
|
+
|
|
222
|
+
project_info = self.extract_project_info(input_data)
|
|
223
|
+
|
|
224
|
+
return self.build_base_payload(
|
|
225
|
+
event='context_update',
|
|
226
|
+
session_id=session_id,
|
|
227
|
+
used_percentage=used_percentage,
|
|
228
|
+
remaining_percentage=remaining_percentage,
|
|
229
|
+
context_window_size=input_data.get('context_window_size', 0),
|
|
230
|
+
total_input_tokens=input_data.get('total_input_tokens', 0),
|
|
231
|
+
total_output_tokens=input_data.get('total_output_tokens', 0),
|
|
232
|
+
model=input_data.get('model', 'unknown'),
|
|
233
|
+
model_display_name=input_data.get('model_display_name', 'Unknown'),
|
|
234
|
+
cwd=project_info['cwd'],
|
|
235
|
+
project_dir=project_info['project_path'],
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
# =============================================================================
|
|
240
|
+
# EXAMPLE HOOK SCRIPT
|
|
241
|
+
# =============================================================================
|
|
242
|
+
#
|
|
243
|
+
# Create a file in hooks/{your-source}/session-start.py:
|
|
244
|
+
#
|
|
245
|
+
# #!/usr/bin/env python3
|
|
246
|
+
# """Session start hook for {YourTool}."""
|
|
247
|
+
# import sys
|
|
248
|
+
# sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
249
|
+
# from adapters.template import TemplateAdapter # Change to your adapter
|
|
250
|
+
#
|
|
251
|
+
# def main():
|
|
252
|
+
# adapter = TemplateAdapter() # Change to your adapter
|
|
253
|
+
# input_data = adapter.parse_input()
|
|
254
|
+
# if not input_data:
|
|
255
|
+
# sys.exit(0)
|
|
256
|
+
#
|
|
257
|
+
# adapter.log_debug(input_data, 'session-start')
|
|
258
|
+
# payload = adapter.build_session_start_payload(input_data)
|
|
259
|
+
# if payload:
|
|
260
|
+
# adapter.send_event(payload, use_fallback=True)
|
|
261
|
+
#
|
|
262
|
+
# if __name__ == '__main__':
|
|
263
|
+
# main()
|
|
264
|
+
#
|
|
265
|
+
# =============================================================================
|
|
266
|
+
# TESTING YOUR ADAPTER
|
|
267
|
+
# =============================================================================
|
|
268
|
+
#
|
|
269
|
+
# 1. Start Jacques server:
|
|
270
|
+
# cd server && npm run start
|
|
271
|
+
#
|
|
272
|
+
# 2. Test with sample input:
|
|
273
|
+
# echo '{"session_id": "test-123", "project_path": "/my/project"}' | \
|
|
274
|
+
# python3 hooks/{your-source}/session-start.py
|
|
275
|
+
#
|
|
276
|
+
# 3. Check server logs or dashboard for the session
|
|
277
|
+
#
|
|
278
|
+
# 4. Run unit tests:
|
|
279
|
+
# python3 -m pytest hooks/adapters/test_adapters.py -v
|
|
280
|
+
#
|
|
281
|
+
# =============================================================================
|