@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.
Files changed (508) hide show
  1. package/dist/assets/mascot-ansi.d.ts +8 -0
  2. package/dist/assets/mascot-ansi.d.ts.map +1 -0
  3. package/dist/assets/mascot-ansi.js +15 -0
  4. package/dist/assets/mascot-ansi.js.map +1 -0
  5. package/dist/cli.d.ts +15 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +53 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/commands/client-helper.d.ts +14 -0
  10. package/dist/commands/client-helper.d.ts.map +1 -0
  11. package/dist/commands/client-helper.js +38 -0
  12. package/dist/commands/client-helper.js.map +1 -0
  13. package/dist/commands/dashboard.d.ts +8 -0
  14. package/dist/commands/dashboard.d.ts.map +1 -0
  15. package/dist/commands/dashboard.js +159 -0
  16. package/dist/commands/dashboard.js.map +1 -0
  17. package/dist/commands/index.d.ts +6 -0
  18. package/dist/commands/index.d.ts.map +1 -0
  19. package/dist/commands/index.js +6 -0
  20. package/dist/commands/index.js.map +1 -0
  21. package/dist/commands/list.d.ts +5 -0
  22. package/dist/commands/list.d.ts.map +1 -0
  23. package/dist/commands/list.js +13 -0
  24. package/dist/commands/list.js.map +1 -0
  25. package/dist/commands/search.d.ts +13 -0
  26. package/dist/commands/search.d.ts.map +1 -0
  27. package/dist/commands/search.js +79 -0
  28. package/dist/commands/search.js.map +1 -0
  29. package/dist/commands/setup.d.ts +8 -0
  30. package/dist/commands/setup.d.ts.map +1 -0
  31. package/dist/commands/setup.js +32 -0
  32. package/dist/commands/setup.js.map +1 -0
  33. package/dist/commands/status.d.ts +5 -0
  34. package/dist/commands/status.d.ts.map +1 -0
  35. package/dist/commands/status.js +27 -0
  36. package/dist/commands/status.js.map +1 -0
  37. package/dist/components/ActiveSessionsView.d.ts +18 -0
  38. package/dist/components/ActiveSessionsView.d.ts.map +1 -0
  39. package/dist/components/ActiveSessionsView.js +68 -0
  40. package/dist/components/ActiveSessionsView.js.map +1 -0
  41. package/dist/components/AddContextConfirmView.d.ts +21 -0
  42. package/dist/components/AddContextConfirmView.d.ts.map +1 -0
  43. package/dist/components/AddContextConfirmView.js +44 -0
  44. package/dist/components/AddContextConfirmView.js.map +1 -0
  45. package/dist/components/App.d.ts +11 -0
  46. package/dist/components/App.d.ts.map +1 -0
  47. package/dist/components/App.js +292 -0
  48. package/dist/components/App.js.map +1 -0
  49. package/dist/components/ArchiveBrowserView.d.ts +40 -0
  50. package/dist/components/ArchiveBrowserView.d.ts.map +1 -0
  51. package/dist/components/ArchiveBrowserView.js +161 -0
  52. package/dist/components/ArchiveBrowserView.js.map +1 -0
  53. package/dist/components/ArchiveInitProgressView.d.ts +16 -0
  54. package/dist/components/ArchiveInitProgressView.d.ts.map +1 -0
  55. package/dist/components/ArchiveInitProgressView.js +72 -0
  56. package/dist/components/ArchiveInitProgressView.js.map +1 -0
  57. package/dist/components/AutoCompactToggle.d.ts +16 -0
  58. package/dist/components/AutoCompactToggle.d.ts.map +1 -0
  59. package/dist/components/AutoCompactToggle.js +12 -0
  60. package/dist/components/AutoCompactToggle.js.map +1 -0
  61. package/dist/components/BottomControls.d.ts +12 -0
  62. package/dist/components/BottomControls.d.ts.map +1 -0
  63. package/dist/components/BottomControls.js +11 -0
  64. package/dist/components/BottomControls.js.map +1 -0
  65. package/dist/components/CompactHeader.d.ts +21 -0
  66. package/dist/components/CompactHeader.d.ts.map +1 -0
  67. package/dist/components/CompactHeader.js +63 -0
  68. package/dist/components/CompactHeader.js.map +1 -0
  69. package/dist/components/CompactPanel.d.ts +22 -0
  70. package/dist/components/CompactPanel.d.ts.map +1 -0
  71. package/dist/components/CompactPanel.js +31 -0
  72. package/dist/components/CompactPanel.js.map +1 -0
  73. package/dist/components/ContentBox.d.ts +14 -0
  74. package/dist/components/ContentBox.d.ts.map +1 -0
  75. package/dist/components/ContentBox.js +24 -0
  76. package/dist/components/ContentBox.js.map +1 -0
  77. package/dist/components/ContextProgress.d.ts +14 -0
  78. package/dist/components/ContextProgress.d.ts.map +1 -0
  79. package/dist/components/ContextProgress.js +36 -0
  80. package/dist/components/ContextProgress.js.map +1 -0
  81. package/dist/components/Dashboard.d.ts +46 -0
  82. package/dist/components/Dashboard.d.ts.map +1 -0
  83. package/dist/components/Dashboard.js +67 -0
  84. package/dist/components/Dashboard.js.map +1 -0
  85. package/dist/components/FilterSelectionView.d.ts +15 -0
  86. package/dist/components/FilterSelectionView.d.ts.map +1 -0
  87. package/dist/components/FilterSelectionView.js +27 -0
  88. package/dist/components/FilterSelectionView.js.map +1 -0
  89. package/dist/components/GoogleDocsBrowserView.d.ts +20 -0
  90. package/dist/components/GoogleDocsBrowserView.d.ts.map +1 -0
  91. package/dist/components/GoogleDocsBrowserView.js +72 -0
  92. package/dist/components/GoogleDocsBrowserView.js.map +1 -0
  93. package/dist/components/HandoffBrowserView.d.ts +20 -0
  94. package/dist/components/HandoffBrowserView.d.ts.map +1 -0
  95. package/dist/components/HandoffBrowserView.js +66 -0
  96. package/dist/components/HandoffBrowserView.js.map +1 -0
  97. package/dist/components/Header.d.ts +14 -0
  98. package/dist/components/Header.d.ts.map +1 -0
  99. package/dist/components/Header.js +16 -0
  100. package/dist/components/Header.js.map +1 -0
  101. package/dist/components/HorizontalMenu.d.ts +24 -0
  102. package/dist/components/HorizontalMenu.d.ts.map +1 -0
  103. package/dist/components/HorizontalMenu.js +20 -0
  104. package/dist/components/HorizontalMenu.js.map +1 -0
  105. package/dist/components/ImageMascot.d.ts +8 -0
  106. package/dist/components/ImageMascot.d.ts.map +1 -0
  107. package/dist/components/ImageMascot.js +7 -0
  108. package/dist/components/ImageMascot.js.map +1 -0
  109. package/dist/components/LLMWorkingView.d.ts +19 -0
  110. package/dist/components/LLMWorkingView.d.ts.map +1 -0
  111. package/dist/components/LLMWorkingView.js +72 -0
  112. package/dist/components/LLMWorkingView.js.map +1 -0
  113. package/dist/components/LoadContextView.d.ts +22 -0
  114. package/dist/components/LoadContextView.d.ts.map +1 -0
  115. package/dist/components/LoadContextView.js +83 -0
  116. package/dist/components/LoadContextView.js.map +1 -0
  117. package/dist/components/MainMenuView.d.ts +20 -0
  118. package/dist/components/MainMenuView.d.ts.map +1 -0
  119. package/dist/components/MainMenuView.js +49 -0
  120. package/dist/components/MainMenuView.js.map +1 -0
  121. package/dist/components/Mascot.d.ts +24 -0
  122. package/dist/components/Mascot.d.ts.map +1 -0
  123. package/dist/components/Mascot.js +32 -0
  124. package/dist/components/Mascot.js.map +1 -0
  125. package/dist/components/Menu.d.ts +22 -0
  126. package/dist/components/Menu.d.ts.map +1 -0
  127. package/dist/components/Menu.js +28 -0
  128. package/dist/components/Menu.js.map +1 -0
  129. package/dist/components/NotionBrowserView.d.ts +21 -0
  130. package/dist/components/NotionBrowserView.d.ts.map +1 -0
  131. package/dist/components/NotionBrowserView.js +75 -0
  132. package/dist/components/NotionBrowserView.js.map +1 -0
  133. package/dist/components/ObsidianBrowserView.d.ts +21 -0
  134. package/dist/components/ObsidianBrowserView.d.ts.map +1 -0
  135. package/dist/components/ObsidianBrowserView.js +74 -0
  136. package/dist/components/ObsidianBrowserView.js.map +1 -0
  137. package/dist/components/ObsidianConfigView.d.ts +19 -0
  138. package/dist/components/ObsidianConfigView.d.ts.map +1 -0
  139. package/dist/components/ObsidianConfigView.js +45 -0
  140. package/dist/components/ObsidianConfigView.js.map +1 -0
  141. package/dist/components/PlaceholderView.d.ts +15 -0
  142. package/dist/components/PlaceholderView.d.ts.map +1 -0
  143. package/dist/components/PlaceholderView.js +20 -0
  144. package/dist/components/PlaceholderView.js.map +1 -0
  145. package/dist/components/PlanViewerView.d.ts +26 -0
  146. package/dist/components/PlanViewerView.d.ts.map +1 -0
  147. package/dist/components/PlanViewerView.js +170 -0
  148. package/dist/components/PlanViewerView.js.map +1 -0
  149. package/dist/components/ProgressBar.d.ts +24 -0
  150. package/dist/components/ProgressBar.d.ts.map +1 -0
  151. package/dist/components/ProgressBar.js +23 -0
  152. package/dist/components/ProgressBar.js.map +1 -0
  153. package/dist/components/ProjectDashboardView.d.ts +38 -0
  154. package/dist/components/ProjectDashboardView.d.ts.map +1 -0
  155. package/dist/components/ProjectDashboardView.js +129 -0
  156. package/dist/components/ProjectDashboardView.js.map +1 -0
  157. package/dist/components/SaveContextView.d.ts +32 -0
  158. package/dist/components/SaveContextView.d.ts.map +1 -0
  159. package/dist/components/SaveContextView.js +41 -0
  160. package/dist/components/SaveContextView.js.map +1 -0
  161. package/dist/components/SessionDetails.d.ts +14 -0
  162. package/dist/components/SessionDetails.d.ts.map +1 -0
  163. package/dist/components/SessionDetails.js +87 -0
  164. package/dist/components/SessionDetails.js.map +1 -0
  165. package/dist/components/SessionsExperimentView.d.ts +35 -0
  166. package/dist/components/SessionsExperimentView.d.ts.map +1 -0
  167. package/dist/components/SessionsExperimentView.js +347 -0
  168. package/dist/components/SessionsExperimentView.js.map +1 -0
  169. package/dist/components/SessionsList.d.ts +20 -0
  170. package/dist/components/SessionsList.d.ts.map +1 -0
  171. package/dist/components/SessionsList.js +75 -0
  172. package/dist/components/SessionsList.js.map +1 -0
  173. package/dist/components/SettingsView.d.ts +48 -0
  174. package/dist/components/SettingsView.d.ts.map +1 -0
  175. package/dist/components/SettingsView.js +156 -0
  176. package/dist/components/SettingsView.js.map +1 -0
  177. package/dist/components/SourceSelectionView.d.ts +26 -0
  178. package/dist/components/SourceSelectionView.d.ts.map +1 -0
  179. package/dist/components/SourceSelectionView.js +109 -0
  180. package/dist/components/SourceSelectionView.js.map +1 -0
  181. package/dist/components/VerticalMenu.d.ts +18 -0
  182. package/dist/components/VerticalMenu.d.ts.map +1 -0
  183. package/dist/components/VerticalMenu.js +15 -0
  184. package/dist/components/VerticalMenu.js.map +1 -0
  185. package/dist/components/ascii-art/index.d.ts +6 -0
  186. package/dist/components/ascii-art/index.d.ts.map +1 -0
  187. package/dist/components/ascii-art/index.js +6 -0
  188. package/dist/components/ascii-art/index.js.map +1 -0
  189. package/dist/components/ascii-art/progress.d.ts +53 -0
  190. package/dist/components/ascii-art/progress.d.ts.map +1 -0
  191. package/dist/components/ascii-art/progress.js +102 -0
  192. package/dist/components/ascii-art/progress.js.map +1 -0
  193. package/dist/components/ascii-art/scene.d.ts +34 -0
  194. package/dist/components/ascii-art/scene.d.ts.map +1 -0
  195. package/dist/components/ascii-art/scene.js +72 -0
  196. package/dist/components/ascii-art/scene.js.map +1 -0
  197. package/dist/components/index.d.ts +27 -0
  198. package/dist/components/index.d.ts.map +1 -0
  199. package/dist/components/index.js +25 -0
  200. package/dist/components/index.js.map +1 -0
  201. package/dist/components/layout/HorizontalLayout.d.ts +19 -0
  202. package/dist/components/layout/HorizontalLayout.d.ts.map +1 -0
  203. package/dist/components/layout/HorizontalLayout.js +62 -0
  204. package/dist/components/layout/HorizontalLayout.js.map +1 -0
  205. package/dist/components/layout/VerticalLayout.d.ts +16 -0
  206. package/dist/components/layout/VerticalLayout.d.ts.map +1 -0
  207. package/dist/components/layout/VerticalLayout.js +32 -0
  208. package/dist/components/layout/VerticalLayout.js.map +1 -0
  209. package/dist/components/layout/index.d.ts +6 -0
  210. package/dist/components/layout/index.d.ts.map +1 -0
  211. package/dist/components/layout/index.js +4 -0
  212. package/dist/components/layout/index.js.map +1 -0
  213. package/dist/components/layout/theme.d.ts +20 -0
  214. package/dist/components/layout/theme.d.ts.map +1 -0
  215. package/dist/components/layout/theme.js +23 -0
  216. package/dist/components/layout/theme.js.map +1 -0
  217. package/dist/components/setup/DoneStep.d.ts +7 -0
  218. package/dist/components/setup/DoneStep.d.ts.map +1 -0
  219. package/dist/components/setup/DoneStep.js +31 -0
  220. package/dist/components/setup/DoneStep.js.map +1 -0
  221. package/dist/components/setup/InstallingStep.d.ts +11 -0
  222. package/dist/components/setup/InstallingStep.d.ts.map +1 -0
  223. package/dist/components/setup/InstallingStep.js +27 -0
  224. package/dist/components/setup/InstallingStep.js.map +1 -0
  225. package/dist/components/setup/OptionsStep.d.ts +9 -0
  226. package/dist/components/setup/OptionsStep.d.ts.map +1 -0
  227. package/dist/components/setup/OptionsStep.js +39 -0
  228. package/dist/components/setup/OptionsStep.js.map +1 -0
  229. package/dist/components/setup/PrerequisitesStep.d.ts +7 -0
  230. package/dist/components/setup/PrerequisitesStep.d.ts.map +1 -0
  231. package/dist/components/setup/PrerequisitesStep.js +31 -0
  232. package/dist/components/setup/PrerequisitesStep.js.map +1 -0
  233. package/dist/components/setup/SetupFrame.d.ts +17 -0
  234. package/dist/components/setup/SetupFrame.d.ts.map +1 -0
  235. package/dist/components/setup/SetupFrame.js +33 -0
  236. package/dist/components/setup/SetupFrame.js.map +1 -0
  237. package/dist/components/setup/SetupWizard.d.ts +9 -0
  238. package/dist/components/setup/SetupWizard.d.ts.map +1 -0
  239. package/dist/components/setup/SetupWizard.js +149 -0
  240. package/dist/components/setup/SetupWizard.js.map +1 -0
  241. package/dist/components/setup/Spinner.d.ts +10 -0
  242. package/dist/components/setup/Spinner.d.ts.map +1 -0
  243. package/dist/components/setup/Spinner.js +20 -0
  244. package/dist/components/setup/Spinner.js.map +1 -0
  245. package/dist/components/setup/SyncStep.d.ts +11 -0
  246. package/dist/components/setup/SyncStep.d.ts.map +1 -0
  247. package/dist/components/setup/SyncStep.js +47 -0
  248. package/dist/components/setup/SyncStep.js.map +1 -0
  249. package/dist/components/setup/VerificationStep.d.ts +7 -0
  250. package/dist/components/setup/VerificationStep.d.ts.map +1 -0
  251. package/dist/components/setup/VerificationStep.js +27 -0
  252. package/dist/components/setup/VerificationStep.js.map +1 -0
  253. package/dist/components/setup/WelcomeStep.d.ts +6 -0
  254. package/dist/components/setup/WelcomeStep.d.ts.map +1 -0
  255. package/dist/components/setup/WelcomeStep.js +17 -0
  256. package/dist/components/setup/WelcomeStep.js.map +1 -0
  257. package/dist/components/shared/ProgressLine.d.ts +10 -0
  258. package/dist/components/shared/ProgressLine.d.ts.map +1 -0
  259. package/dist/components/shared/ProgressLine.js +18 -0
  260. package/dist/components/shared/ProgressLine.js.map +1 -0
  261. package/dist/components/shared/ProjectLine.d.ts +10 -0
  262. package/dist/components/shared/ProjectLine.d.ts.map +1 -0
  263. package/dist/components/shared/ProjectLine.js +19 -0
  264. package/dist/components/shared/ProjectLine.js.map +1 -0
  265. package/dist/components/shared/ScanningIndicator.d.ts +9 -0
  266. package/dist/components/shared/ScanningIndicator.d.ts.map +1 -0
  267. package/dist/components/shared/ScanningIndicator.js +22 -0
  268. package/dist/components/shared/ScanningIndicator.js.map +1 -0
  269. package/dist/components/shared/StatusLine.d.ts +13 -0
  270. package/dist/components/shared/StatusLine.d.ts.map +1 -0
  271. package/dist/components/shared/StatusLine.js +24 -0
  272. package/dist/components/shared/StatusLine.js.map +1 -0
  273. package/dist/components/shared/StatusLine.test.d.ts +8 -0
  274. package/dist/components/shared/StatusLine.test.d.ts.map +1 -0
  275. package/dist/components/shared/StatusLine.test.js +50 -0
  276. package/dist/components/shared/StatusLine.test.js.map +1 -0
  277. package/dist/components/shared/index.d.ts +4 -0
  278. package/dist/components/shared/index.d.ts.map +1 -0
  279. package/dist/components/shared/index.js +4 -0
  280. package/dist/components/shared/index.js.map +1 -0
  281. package/dist/handoff/catalog.test.d.ts +5 -0
  282. package/dist/handoff/catalog.test.d.ts.map +1 -0
  283. package/dist/handoff/catalog.test.js +172 -0
  284. package/dist/handoff/catalog.test.js.map +1 -0
  285. package/dist/handoff/subagents.test.d.ts +8 -0
  286. package/dist/handoff/subagents.test.d.ts.map +1 -0
  287. package/dist/handoff/subagents.test.js +139 -0
  288. package/dist/handoff/subagents.test.js.map +1 -0
  289. package/dist/hooks/useAddContextFlow.d.ts +29 -0
  290. package/dist/hooks/useAddContextFlow.d.ts.map +1 -0
  291. package/dist/hooks/useAddContextFlow.js +83 -0
  292. package/dist/hooks/useAddContextFlow.js.map +1 -0
  293. package/dist/hooks/useArchiveBrowser.d.ts +37 -0
  294. package/dist/hooks/useArchiveBrowser.d.ts.map +1 -0
  295. package/dist/hooks/useArchiveBrowser.js +175 -0
  296. package/dist/hooks/useArchiveBrowser.js.map +1 -0
  297. package/dist/hooks/useClaudeToken.d.ts +29 -0
  298. package/dist/hooks/useClaudeToken.d.ts.map +1 -0
  299. package/dist/hooks/useClaudeToken.js +166 -0
  300. package/dist/hooks/useClaudeToken.js.map +1 -0
  301. package/dist/hooks/useGoogleDocsBrowser.d.ts +29 -0
  302. package/dist/hooks/useGoogleDocsBrowser.d.ts.map +1 -0
  303. package/dist/hooks/useGoogleDocsBrowser.js +146 -0
  304. package/dist/hooks/useGoogleDocsBrowser.js.map +1 -0
  305. package/dist/hooks/useHandoffBrowser.d.ts +27 -0
  306. package/dist/hooks/useHandoffBrowser.d.ts.map +1 -0
  307. package/dist/hooks/useHandoffBrowser.js +92 -0
  308. package/dist/hooks/useHandoffBrowser.js.map +1 -0
  309. package/dist/hooks/useJacquesClient.d.ts +69 -0
  310. package/dist/hooks/useJacquesClient.d.ts.map +1 -0
  311. package/dist/hooks/useJacquesClient.js +248 -0
  312. package/dist/hooks/useJacquesClient.js.map +1 -0
  313. package/dist/hooks/useLlmWorking.d.ts +30 -0
  314. package/dist/hooks/useLlmWorking.d.ts.map +1 -0
  315. package/dist/hooks/useLlmWorking.js +127 -0
  316. package/dist/hooks/useLlmWorking.js.map +1 -0
  317. package/dist/hooks/useLoadContext.d.ts +27 -0
  318. package/dist/hooks/useLoadContext.d.ts.map +1 -0
  319. package/dist/hooks/useLoadContext.js +102 -0
  320. package/dist/hooks/useLoadContext.js.map +1 -0
  321. package/dist/hooks/useNotification.d.ts +36 -0
  322. package/dist/hooks/useNotification.d.ts.map +1 -0
  323. package/dist/hooks/useNotification.js +89 -0
  324. package/dist/hooks/useNotification.js.map +1 -0
  325. package/dist/hooks/useNotification.test.d.ts +9 -0
  326. package/dist/hooks/useNotification.test.d.ts.map +1 -0
  327. package/dist/hooks/useNotification.test.js +144 -0
  328. package/dist/hooks/useNotification.test.js.map +1 -0
  329. package/dist/hooks/useNotionBrowser.d.ts +30 -0
  330. package/dist/hooks/useNotionBrowser.d.ts.map +1 -0
  331. package/dist/hooks/useNotionBrowser.js +154 -0
  332. package/dist/hooks/useNotionBrowser.js.map +1 -0
  333. package/dist/hooks/useObsidianBrowser.d.ts +42 -0
  334. package/dist/hooks/useObsidianBrowser.d.ts.map +1 -0
  335. package/dist/hooks/useObsidianBrowser.js +63 -0
  336. package/dist/hooks/useObsidianBrowser.js.map +1 -0
  337. package/dist/hooks/useObsidianConfig.d.ts +28 -0
  338. package/dist/hooks/useObsidianConfig.d.ts.map +1 -0
  339. package/dist/hooks/useObsidianConfig.js +119 -0
  340. package/dist/hooks/useObsidianConfig.js.map +1 -0
  341. package/dist/hooks/useObsidianFileBrowser.d.ts +29 -0
  342. package/dist/hooks/useObsidianFileBrowser.d.ts.map +1 -0
  343. package/dist/hooks/useObsidianFileBrowser.js +114 -0
  344. package/dist/hooks/useObsidianFileBrowser.js.map +1 -0
  345. package/dist/hooks/useProjectDashboard.d.ts +38 -0
  346. package/dist/hooks/useProjectDashboard.d.ts.map +1 -0
  347. package/dist/hooks/useProjectDashboard.js +224 -0
  348. package/dist/hooks/useProjectDashboard.js.map +1 -0
  349. package/dist/hooks/useProjectSelector.d.ts +17 -0
  350. package/dist/hooks/useProjectSelector.d.ts.map +1 -0
  351. package/dist/hooks/useProjectSelector.js +43 -0
  352. package/dist/hooks/useProjectSelector.js.map +1 -0
  353. package/dist/hooks/useProjectSelector.test.d.ts +7 -0
  354. package/dist/hooks/useProjectSelector.test.d.ts.map +1 -0
  355. package/dist/hooks/useProjectSelector.test.js +117 -0
  356. package/dist/hooks/useProjectSelector.test.js.map +1 -0
  357. package/dist/hooks/useSaveFlow.d.ts +30 -0
  358. package/dist/hooks/useSaveFlow.d.ts.map +1 -0
  359. package/dist/hooks/useSaveFlow.js +195 -0
  360. package/dist/hooks/useSaveFlow.js.map +1 -0
  361. package/dist/hooks/useSessions.test.d.ts +7 -0
  362. package/dist/hooks/useSessions.test.d.ts.map +1 -0
  363. package/dist/hooks/useSessions.test.js +153 -0
  364. package/dist/hooks/useSessions.test.js.map +1 -0
  365. package/dist/hooks/useSessionsExperiment.d.ts +97 -0
  366. package/dist/hooks/useSessionsExperiment.d.ts.map +1 -0
  367. package/dist/hooks/useSessionsExperiment.js +321 -0
  368. package/dist/hooks/useSessionsExperiment.js.map +1 -0
  369. package/dist/hooks/useSettings.d.ts +47 -0
  370. package/dist/hooks/useSettings.d.ts.map +1 -0
  371. package/dist/hooks/useSettings.js +245 -0
  372. package/dist/hooks/useSettings.js.map +1 -0
  373. package/dist/hooks/useSetupWizard.d.ts +35 -0
  374. package/dist/hooks/useSetupWizard.d.ts.map +1 -0
  375. package/dist/hooks/useSetupWizard.js +438 -0
  376. package/dist/hooks/useSetupWizard.js.map +1 -0
  377. package/dist/hooks/useUsageLimits.d.ts +24 -0
  378. package/dist/hooks/useUsageLimits.d.ts.map +1 -0
  379. package/dist/hooks/useUsageLimits.js +58 -0
  380. package/dist/hooks/useUsageLimits.js.map +1 -0
  381. package/dist/hooks/useUsageLimits.test.d.ts +7 -0
  382. package/dist/hooks/useUsageLimits.test.d.ts.map +1 -0
  383. package/dist/hooks/useUsageLimits.test.js +136 -0
  384. package/dist/hooks/useUsageLimits.test.js.map +1 -0
  385. package/dist/hooks/useWorktrees.d.ts +28 -0
  386. package/dist/hooks/useWorktrees.d.ts.map +1 -0
  387. package/dist/hooks/useWorktrees.js +57 -0
  388. package/dist/hooks/useWorktrees.js.map +1 -0
  389. package/dist/hooks/useWorktrees.test.d.ts +7 -0
  390. package/dist/hooks/useWorktrees.test.d.ts.map +1 -0
  391. package/dist/hooks/useWorktrees.test.js +119 -0
  392. package/dist/hooks/useWorktrees.test.js.map +1 -0
  393. package/dist/templates/compact-prompt.d.ts +16 -0
  394. package/dist/templates/compact-prompt.d.ts.map +1 -0
  395. package/dist/templates/compact-prompt.js +47 -0
  396. package/dist/templates/compact-prompt.js.map +1 -0
  397. package/dist/templates/context-skill.d.ts +8 -0
  398. package/dist/templates/context-skill.d.ts.map +1 -0
  399. package/dist/templates/context-skill.js +42 -0
  400. package/dist/templates/context-skill.js.map +1 -0
  401. package/dist/types.d.ts +127 -0
  402. package/dist/types.d.ts.map +1 -0
  403. package/dist/types.js +8 -0
  404. package/dist/types.js.map +1 -0
  405. package/dist/utils/activity.d.ts +17 -0
  406. package/dist/utils/activity.d.ts.map +1 -0
  407. package/dist/utils/activity.js +78 -0
  408. package/dist/utils/activity.js.map +1 -0
  409. package/dist/utils/bottom-controls.d.ts +24 -0
  410. package/dist/utils/bottom-controls.d.ts.map +1 -0
  411. package/dist/utils/bottom-controls.js +29 -0
  412. package/dist/utils/bottom-controls.js.map +1 -0
  413. package/dist/utils/clipboard.d.ts +2 -0
  414. package/dist/utils/clipboard.d.ts.map +1 -0
  415. package/dist/utils/clipboard.js +20 -0
  416. package/dist/utils/clipboard.js.map +1 -0
  417. package/dist/utils/constants.d.ts +6 -0
  418. package/dist/utils/constants.d.ts.map +1 -0
  419. package/dist/utils/constants.js +6 -0
  420. package/dist/utils/constants.js.map +1 -0
  421. package/dist/utils/format.d.ts +17 -0
  422. package/dist/utils/format.d.ts.map +1 -0
  423. package/dist/utils/format.js +31 -0
  424. package/dist/utils/format.js.map +1 -0
  425. package/dist/utils/session-mode.d.ts +14 -0
  426. package/dist/utils/session-mode.d.ts.map +1 -0
  427. package/dist/utils/session-mode.js +29 -0
  428. package/dist/utils/session-mode.js.map +1 -0
  429. package/dist/utils/session-mode.test.d.ts +7 -0
  430. package/dist/utils/session-mode.test.d.ts.map +1 -0
  431. package/dist/utils/session-mode.test.js +102 -0
  432. package/dist/utils/session-mode.test.js.map +1 -0
  433. package/dist/utils/sessions-items-builder.d.ts +29 -0
  434. package/dist/utils/sessions-items-builder.d.ts.map +1 -0
  435. package/dist/utils/sessions-items-builder.js +394 -0
  436. package/dist/utils/sessions-items-builder.js.map +1 -0
  437. package/dist/utils/settings.d.ts +100 -0
  438. package/dist/utils/settings.d.ts.map +1 -0
  439. package/dist/utils/settings.js +206 -0
  440. package/dist/utils/settings.js.map +1 -0
  441. package/dist/websocket-client.d.ts +70 -0
  442. package/dist/websocket-client.d.ts.map +1 -0
  443. package/dist/websocket-client.js +188 -0
  444. package/dist/websocket-client.js.map +1 -0
  445. package/hooks/adapters/__init__.py +17 -0
  446. package/hooks/adapters/__pycache__/__init__.cpython-311.pyc +0 -0
  447. package/hooks/adapters/__pycache__/__init__.cpython-313.pyc +0 -0
  448. package/hooks/adapters/__pycache__/__init__.cpython-314.pyc +0 -0
  449. package/hooks/adapters/__pycache__/base.cpython-311.pyc +0 -0
  450. package/hooks/adapters/__pycache__/base.cpython-313.pyc +0 -0
  451. package/hooks/adapters/__pycache__/base.cpython-314.pyc +0 -0
  452. package/hooks/adapters/__pycache__/calibration.cpython-311.pyc +0 -0
  453. package/hooks/adapters/__pycache__/calibration.cpython-313.pyc +0 -0
  454. package/hooks/adapters/__pycache__/calibration.cpython-314.pyc +0 -0
  455. package/hooks/adapters/__pycache__/claude_code.cpython-311.pyc +0 -0
  456. package/hooks/adapters/__pycache__/claude_code.cpython-313.pyc +0 -0
  457. package/hooks/adapters/__pycache__/claude_code.cpython-314.pyc +0 -0
  458. package/hooks/adapters/__pycache__/cursor.cpython-311.pyc +0 -0
  459. package/hooks/adapters/__pycache__/cursor.cpython-313.pyc +0 -0
  460. package/hooks/adapters/__pycache__/cursor.cpython-314.pyc +0 -0
  461. package/hooks/adapters/__pycache__/skills.cpython-311.pyc +0 -0
  462. package/hooks/adapters/__pycache__/skills.cpython-313.pyc +0 -0
  463. package/hooks/adapters/__pycache__/skills.cpython-314.pyc +0 -0
  464. package/hooks/adapters/__pycache__/test_adapters.cpython-311-pytest-9.0.2.pyc +0 -0
  465. package/hooks/adapters/__pycache__/test_adapters.cpython-313.pyc +0 -0
  466. package/hooks/adapters/__pycache__/test_calibration.cpython-311-pytest-9.0.2.pyc +0 -0
  467. package/hooks/adapters/__pycache__/test_skills.cpython-311-pytest-9.0.2.pyc +0 -0
  468. package/hooks/adapters/__pycache__/test_tokenizer.cpython-311-pytest-9.0.2.pyc +0 -0
  469. package/hooks/adapters/__pycache__/tokenizer.cpython-311.pyc +0 -0
  470. package/hooks/adapters/__pycache__/tokenizer.cpython-313.pyc +0 -0
  471. package/hooks/adapters/__pycache__/tokenizer.cpython-314.pyc +0 -0
  472. package/hooks/adapters/base.py +459 -0
  473. package/hooks/adapters/calibration.py +236 -0
  474. package/hooks/adapters/claude_code.py +316 -0
  475. package/hooks/adapters/context_parser.py +288 -0
  476. package/hooks/adapters/cursor.py +258 -0
  477. package/hooks/adapters/skills.py +160 -0
  478. package/hooks/adapters/template.py +281 -0
  479. package/hooks/adapters/test_adapters.py +516 -0
  480. package/hooks/adapters/test_calibration.py +235 -0
  481. package/hooks/adapters/test_skills.py +162 -0
  482. package/hooks/adapters/test_tokenizer.py +158 -0
  483. package/hooks/adapters/tokenizer.py +192 -0
  484. package/hooks/claude-code/pre-tool-use.py +36 -0
  485. package/hooks/claude-code/register-session.py +35 -0
  486. package/hooks/claude-code/report-activity.py +32 -0
  487. package/hooks/claude-code/session-idle.py +32 -0
  488. package/hooks/claude-code/statusline.sh +91 -0
  489. package/hooks/claude-code/unregister-session.py +32 -0
  490. package/hooks/cursor/README.md +61 -0
  491. package/hooks/cursor/after-agent-response.py +97 -0
  492. package/hooks/cursor/hooks.json.template +30 -0
  493. package/hooks/cursor/post-tool-use.py +32 -0
  494. package/hooks/cursor/pre-compact.py +61 -0
  495. package/hooks/cursor/session-end.py +32 -0
  496. package/hooks/cursor/session-start.py +66 -0
  497. package/hooks/git-detect.sh +47 -0
  498. package/hooks/install.py +441 -0
  499. package/hooks/jacques-register-session.py +286 -0
  500. package/hooks/jacques-report-activity.py +145 -0
  501. package/hooks/jacques-session-idle.py +57 -0
  502. package/hooks/jacques-unregister-session.py +57 -0
  503. package/hooks/requirements.txt +9 -0
  504. package/hooks/statusline.py +457 -0
  505. package/hooks/statusline.sh +212 -0
  506. package/package.json +63 -0
  507. package/skills/jacques-continue/SKILL.md +87 -0
  508. package/skills/jacques-handoff/SKILL.md +147 -0
@@ -0,0 +1,457 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Jacques statusLine Script (Cross-Platform)
4
+
5
+ Receives JSON from Claude Code's statusLine feature via stdin.
6
+ Extracts session_id and context_window data.
7
+ Sends context update to Jacques server via IPC.
8
+ Displays abbreviated status for Claude Code's status bar.
9
+
10
+ Replaces statusline.sh — works on macOS, Linux, and Windows.
11
+ """
12
+ import json
13
+ import os
14
+ import re
15
+ import sys
16
+ import time
17
+ import platform
18
+ import tempfile
19
+ import subprocess
20
+
21
+ # Add adapters directory to path for base.py imports
22
+ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
23
+ sys.path.insert(0, SCRIPT_DIR)
24
+
25
+ from adapters.base import BaseAdapter
26
+
27
+
28
+ # ============================================================
29
+ # Cache Utilities
30
+ # ============================================================
31
+
32
+ TMPDIR = tempfile.gettempdir()
33
+
34
+
35
+ def cache_path(prefix: str, key: str) -> str:
36
+ """Build a cache file path in the temp directory."""
37
+ safe_key = key.replace('/', '-').replace('\\', '-').replace(':', '-')
38
+ return os.path.join(TMPDIR, f'jacques-{prefix}-{safe_key}.cache')
39
+
40
+
41
+ def read_cache(path: str, max_age_seconds: float) -> str | None:
42
+ """Read a cache file if it exists and is fresh enough."""
43
+ try:
44
+ if not os.path.isfile(path):
45
+ return None
46
+ mtime = os.path.getmtime(path)
47
+ age = time.time() - mtime
48
+ if age > max_age_seconds:
49
+ return None
50
+ with open(path, 'r') as f:
51
+ return f.read()
52
+ except Exception:
53
+ return None
54
+
55
+
56
+ def write_cache(path: str, content: str) -> None:
57
+ """Write content to a cache file."""
58
+ try:
59
+ with open(path, 'w') as f:
60
+ f.write(content)
61
+ except Exception:
62
+ pass
63
+
64
+
65
+ # ============================================================
66
+ # Git Detection (with 60s cache)
67
+ # ============================================================
68
+
69
+ def detect_git_info(project_dir: str) -> dict:
70
+ """
71
+ Detect git branch, worktree name, and repo root.
72
+ Uses git-detect.sh if available, falls back to inline git commands.
73
+ Results cached for 60 seconds.
74
+ """
75
+ result = {'git_branch': '', 'git_worktree': '', 'git_repo_root': ''}
76
+
77
+ if not project_dir or not os.path.isdir(project_dir):
78
+ return result
79
+
80
+ # Check cache
81
+ cp = cache_path('git', project_dir)
82
+ cached = read_cache(cp, 60)
83
+ if cached is not None:
84
+ lines = cached.split('\n')
85
+ result['git_branch'] = lines[0] if len(lines) > 0 else ''
86
+ result['git_worktree'] = lines[1] if len(lines) > 1 else ''
87
+ result['git_repo_root'] = lines[2] if len(lines) > 2 else ''
88
+ return result
89
+
90
+ # Try git-detect.sh first (Unix only)
91
+ if platform.system() != 'Windows':
92
+ script_path = os.path.join(SCRIPT_DIR, 'git-detect.sh')
93
+ if os.path.isfile(script_path) and os.access(script_path, os.X_OK):
94
+ try:
95
+ proc = subprocess.run(
96
+ [script_path, project_dir],
97
+ capture_output=True, text=True, timeout=5
98
+ )
99
+ if proc.returncode == 0:
100
+ lines = proc.stdout.split('\n')
101
+ result['git_branch'] = lines[0] if len(lines) > 0 else ''
102
+ result['git_worktree'] = lines[1] if len(lines) > 1 else ''
103
+ result['git_repo_root'] = lines[2] if len(lines) > 2 else ''
104
+ write_cache(cp, f"{result['git_branch']}\n{result['git_worktree']}\n{result['git_repo_root']}")
105
+ return result
106
+ except Exception:
107
+ pass
108
+
109
+ # Fallback: inline git detection (cross-platform)
110
+ try:
111
+ proc = subprocess.run(
112
+ ['git', '-C', project_dir, 'rev-parse', '--abbrev-ref', 'HEAD', '--git-common-dir'],
113
+ capture_output=True, text=True, timeout=5
114
+ )
115
+ if proc.returncode == 0:
116
+ lines = proc.stdout.strip().split('\n')
117
+ if len(lines) >= 2:
118
+ result['git_branch'] = lines[0]
119
+ common = lines[1]
120
+ if common == '.git':
121
+ result['git_repo_root'] = os.path.realpath(project_dir)
122
+ elif common:
123
+ result['git_repo_root'] = os.path.dirname(os.path.realpath(
124
+ os.path.join(project_dir, common)
125
+ ))
126
+ result['git_worktree'] = os.path.basename(project_dir)
127
+ except Exception:
128
+ pass
129
+
130
+ write_cache(cp, f"{result['git_branch']}\n{result['git_worktree']}\n{result['git_repo_root']}")
131
+ return result
132
+
133
+
134
+ # ============================================================
135
+ # Session Title Extraction (with 5-min cache)
136
+ # ============================================================
137
+
138
+ def _extract_first_user_message(transcript_path: str) -> str:
139
+ """Read first real user message from transcript (up to 200 chars, preserving newlines)."""
140
+ if not transcript_path or not os.path.isfile(transcript_path):
141
+ return ''
142
+ try:
143
+ with open(transcript_path, 'r') as f:
144
+ for line in f:
145
+ line = line.strip()
146
+ if '"type":"user"' not in line and '"type": "user"' not in line:
147
+ continue
148
+ try:
149
+ entry = json.loads(line)
150
+ msg = entry.get('message', {})
151
+ content = msg.get('content', '') if isinstance(msg, dict) else ''
152
+ if not content or not isinstance(content, str):
153
+ continue
154
+ first_char = content.strip()[:1]
155
+ if first_char in ('<', '['):
156
+ continue
157
+ text = content.strip()[:200]
158
+ return text if len(content.strip()) <= 200 else text + '...'
159
+ except json.JSONDecodeError:
160
+ continue
161
+ except Exception:
162
+ pass
163
+ return ''
164
+
165
+
166
+ # Plan trigger patterns (match core/src/archive/plan-extractor.ts)
167
+ _PLAN_TRIGGERS = [
168
+ re.compile(r'^implement the following plan[:\s]', re.IGNORECASE),
169
+ re.compile(r'^here is the plan[:\s]', re.IGNORECASE),
170
+ re.compile(r'^follow this plan[:\s]', re.IGNORECASE),
171
+ ]
172
+
173
+
174
+ def extract_session_title(session_id: str, transcript_path: str) -> str:
175
+ """
176
+ Extract session title from transcript.
177
+ Sources (in priority order):
178
+ 1. First user message — if it's a plan trigger (need full text for heading extraction)
179
+ 2. sessions-index.json (Claude's resume list title)
180
+ 3. Last summary entry in transcript
181
+ 4. First real user message (fallback)
182
+ Cached for 5 minutes.
183
+ """
184
+ if not session_id:
185
+ return ''
186
+
187
+ # Check cache
188
+ cp = cache_path('title', session_id)
189
+ cached = read_cache(cp, 300)
190
+ if cached is not None:
191
+ return cached
192
+
193
+ title = ''
194
+
195
+ # Always extract first user message — needed for plan trigger check
196
+ first_msg = _extract_first_user_message(transcript_path)
197
+
198
+ # Source 1: If first message is a plan trigger, use it (display code needs the trigger + heading)
199
+ if first_msg:
200
+ for pattern in _PLAN_TRIGGERS:
201
+ if pattern.search(first_msg):
202
+ title = first_msg
203
+ break
204
+
205
+ # Source 2: sessions-index.json
206
+ if not title and transcript_path and session_id:
207
+ transcript_dir = os.path.dirname(transcript_path)
208
+ index_path = os.path.join(transcript_dir, 'sessions-index.json')
209
+ if os.path.isfile(index_path):
210
+ try:
211
+ with open(index_path, 'r') as f:
212
+ index_data = json.load(f)
213
+ for entry in index_data.get('entries', []):
214
+ if entry.get('sessionId') == session_id:
215
+ title = entry.get('summary', '')
216
+ break
217
+ except Exception:
218
+ pass
219
+
220
+ # Source 3: Last summary entry in transcript
221
+ if not title and transcript_path and os.path.isfile(transcript_path):
222
+ try:
223
+ with open(transcript_path, 'r') as f:
224
+ for line in f:
225
+ line = line.strip()
226
+ if '"type":"summary"' in line or '"type": "summary"' in line:
227
+ try:
228
+ entry = json.loads(line)
229
+ s = entry.get('summary', '')
230
+ if s:
231
+ title = s
232
+ except json.JSONDecodeError:
233
+ pass
234
+ except Exception:
235
+ pass
236
+
237
+ # Source 4: First real user message (fallback)
238
+ if not title:
239
+ title = first_msg
240
+
241
+ # Cache the result
242
+ if title:
243
+ write_cache(cp, title)
244
+
245
+ return title
246
+
247
+
248
+ # ============================================================
249
+ # Auto-Compact Settings (with 5-min cache)
250
+ # ============================================================
251
+
252
+ def read_autocompact_settings() -> dict:
253
+ """
254
+ Read auto-compact settings from Claude's settings.json.
255
+ Cached for 5 minutes.
256
+ """
257
+ settings = {
258
+ 'enabled': True,
259
+ 'threshold': int(os.environ.get('CLAUDE_AUTOCOMPACT_PCT_OVERRIDE', '95')),
260
+ 'bug_threshold': None,
261
+ }
262
+
263
+ cp = os.path.join(TMPDIR, 'jacques-settings.cache')
264
+ cached = read_cache(cp, 300)
265
+ if cached is not None:
266
+ parts = cached.split('|')
267
+ if len(parts) >= 3:
268
+ settings['enabled'] = parts[0] == 'true'
269
+ try:
270
+ settings['threshold'] = int(parts[1])
271
+ except ValueError:
272
+ pass
273
+ settings['bug_threshold'] = int(parts[2]) if parts[2] != 'null' else None
274
+ return settings
275
+
276
+ # Read from Claude settings.json
277
+ # Try CLAUDE_CONFIG_DIR first, then default ~/.claude
278
+ claude_dir = os.environ.get('CLAUDE_CONFIG_DIR', os.path.join(os.path.expanduser('~'), '.claude'))
279
+ settings_path = os.path.join(claude_dir, 'settings.json')
280
+
281
+ if os.path.isfile(settings_path):
282
+ try:
283
+ with open(settings_path, 'r') as f:
284
+ data = json.load(f)
285
+ ac = data.get('autoCompact')
286
+ if ac is False:
287
+ settings['enabled'] = False
288
+ settings['bug_threshold'] = 78
289
+ except Exception:
290
+ pass
291
+
292
+ # Cache
293
+ enabled_str = 'true' if settings['enabled'] else 'false'
294
+ bug_str = str(settings['bug_threshold']) if settings['bug_threshold'] is not None else 'null'
295
+ write_cache(cp, f"{enabled_str}|{settings['threshold']}|{bug_str}")
296
+
297
+ return settings
298
+
299
+
300
+ # ============================================================
301
+ # Terminal Key
302
+ # ============================================================
303
+
304
+ def build_terminal_key() -> str:
305
+ """Build a terminal key from environment variables."""
306
+ iterm = os.environ.get('ITERM_SESSION_ID', '')
307
+ kitty = os.environ.get('KITTY_WINDOW_ID', '')
308
+ wezterm = os.environ.get('WEZTERM_PANE', '')
309
+ wt = os.environ.get('WT_SESSION', '')
310
+ term_session = os.environ.get('TERM_SESSION_ID', '')
311
+
312
+ if iterm:
313
+ return f'ITERM:{iterm}'
314
+ if kitty:
315
+ return f'KITTY:{kitty}'
316
+ if wezterm:
317
+ return f'WEZTERM:{wezterm}'
318
+ if wt:
319
+ return f'WT:{wt}'
320
+ if term_session:
321
+ return f'TERM:{term_session}'
322
+ return ''
323
+
324
+
325
+ # ============================================================
326
+ # IPC Send
327
+ # ============================================================
328
+
329
+ def send_to_server(payload: dict) -> bool:
330
+ """Send payload to Jacques server via IPC (Unix socket or Windows Named Pipe)."""
331
+ import socket as sock_mod
332
+
333
+ is_windows = platform.system() == 'Windows'
334
+ socket_path = os.environ.get('JACQUES_SOCKET_PATH',
335
+ r'\\.\pipe\jacques' if is_windows else '/tmp/jacques.sock')
336
+
337
+ try:
338
+ data = json.dumps(payload).encode() + b'\n'
339
+ if is_windows:
340
+ with open(socket_path, 'wb') as pipe:
341
+ pipe.write(data)
342
+ else:
343
+ # Check if socket exists before connecting
344
+ if not os.path.exists(socket_path):
345
+ return False
346
+ s = sock_mod.socket(sock_mod.AF_UNIX, sock_mod.SOCK_STREAM)
347
+ s.settimeout(1.0)
348
+ s.connect(socket_path)
349
+ s.sendall(data)
350
+ s.close()
351
+ return True
352
+ except Exception:
353
+ return False
354
+
355
+
356
+ # ============================================================
357
+ # Main
358
+ # ============================================================
359
+
360
+ def main():
361
+ # Skip if running as subprocess or JACQUES_SKIP=1
362
+ if os.environ.get('JACQUES_SUBPROCESS') == '1':
363
+ return
364
+ if os.environ.get('JACQUES_SKIP') == '1':
365
+ return
366
+ skip_file = os.path.join(os.path.expanduser('~'), '.jacques', 'skip')
367
+ if os.path.isfile(skip_file):
368
+ return
369
+
370
+ # Read JSON from stdin
371
+ try:
372
+ input_data = json.load(sys.stdin)
373
+ except (json.JSONDecodeError, Exception):
374
+ return
375
+
376
+ if not input_data:
377
+ return
378
+
379
+ # Timestamp in milliseconds
380
+ now = int(time.time() * 1000)
381
+
382
+ # Extract fields
383
+ session_id = input_data.get('session_id', '')
384
+ ctx = input_data.get('context_window', {})
385
+ used_pct = ctx.get('used_percentage', 0)
386
+ remaining_pct = ctx.get('remaining_percentage', 100)
387
+ ctx_size = ctx.get('context_window_size', 0)
388
+ total_input = ctx.get('total_input_tokens', 0)
389
+ total_output = ctx.get('total_output_tokens', 0)
390
+
391
+ model_data = input_data.get('model', {})
392
+ model = model_data.get('id', 'unknown') if isinstance(model_data, dict) else 'unknown'
393
+ model_display = model_data.get('display_name', 'Unknown') if isinstance(model_data, dict) else 'Unknown'
394
+
395
+ workspace = input_data.get('workspace', {})
396
+ cwd = workspace.get('current_dir', '') or input_data.get('cwd', '') if isinstance(workspace, dict) else input_data.get('cwd', '')
397
+ project_dir = workspace.get('project_dir', '') if isinstance(workspace, dict) else ''
398
+ transcript_path = input_data.get('transcript_path', '')
399
+
400
+ # Git detection
401
+ git_dir = project_dir or cwd
402
+ git_info = detect_git_info(git_dir) if git_dir else {'git_branch': '', 'git_worktree': '', 'git_repo_root': ''}
403
+
404
+ # Session title
405
+ session_title = extract_session_title(session_id, transcript_path)
406
+
407
+ # Auto-compact settings
408
+ ac = read_autocompact_settings()
409
+
410
+ # If no session_id, just output a placeholder
411
+ if not session_id:
412
+ sys.stdout.write('ctx:?%')
413
+ return
414
+
415
+ # Terminal key
416
+ terminal_key = build_terminal_key()
417
+
418
+ # Build payload
419
+ payload = {
420
+ 'event': 'context_update',
421
+ 'session_id': session_id,
422
+ 'used_percentage': used_pct,
423
+ 'remaining_percentage': remaining_pct,
424
+ 'context_window_size': ctx_size,
425
+ 'total_input_tokens': total_input,
426
+ 'total_output_tokens': total_output,
427
+ 'model': model,
428
+ 'model_display_name': model_display,
429
+ 'cwd': cwd,
430
+ 'project_dir': project_dir,
431
+ 'timestamp': now,
432
+ 'autocompact': {
433
+ 'enabled': ac['enabled'],
434
+ 'threshold': ac['threshold'],
435
+ 'bug_threshold': ac['bug_threshold'],
436
+ },
437
+ 'terminal_key': terminal_key,
438
+ 'session_title': session_title,
439
+ 'transcript_path': transcript_path,
440
+ 'git_branch': git_info['git_branch'],
441
+ 'git_worktree': git_info['git_worktree'],
442
+ 'git_repo_root': git_info['git_repo_root'],
443
+ }
444
+
445
+ # Send to server (non-blocking — don't block Claude Code)
446
+ send_to_server(payload)
447
+
448
+ # Output status line
449
+ used_int = int(used_pct) if used_pct else 0
450
+
451
+ git_part = f' @{git_info["git_branch"]}' if git_info['git_branch'] else ''
452
+
453
+ sys.stdout.write(f'[{model_display}] ctx:{used_int}%{git_part}')
454
+
455
+
456
+ if __name__ == '__main__':
457
+ main()
@@ -0,0 +1,212 @@
1
+ #!/bin/bash
2
+ #
3
+ # Jacques statusLine Script
4
+ #
5
+ # Receives JSON from Claude Code's statusLine feature via stdin.
6
+ # Extracts session_id and context_window data.
7
+ # Sends context update to Jacques server via Unix socket.
8
+ # Displays abbreviated status for Claude Code's status bar.
9
+ #
10
+
11
+ # Skip if running as subprocess, JACQUES_SKIP=1, or ~/.jacques/skip exists
12
+ if [ "$JACQUES_SUBPROCESS" = "1" ] || [ "$JACQUES_SKIP" = "1" ] || [ -f "$HOME/.jacques/skip" ]; then
13
+ exit 0
14
+ fi
15
+
16
+ # Read all input from stdin
17
+ input=$(cat)
18
+
19
+ # Exit if no input
20
+ if [ -z "$input" ]; then
21
+ exit 0
22
+ fi
23
+
24
+ # Capture timestamp once, reuse everywhere (milliseconds to match Date.now())
25
+ now=$(( $(date +%s) * 1000 ))
26
+
27
+ # Extract all fields in a single jq invocation (saves ~20 forks)
28
+ IFS='§' read -r session_id used_pct remaining_pct ctx_size total_input total_output \
29
+ model model_display cwd project_dir transcript_path <<< \
30
+ "$(jq -r '[
31
+ .session_id // "",
32
+ (.context_window.used_percentage // 0 | tostring),
33
+ (.context_window.remaining_percentage // 100 | tostring),
34
+ (.context_window.context_window_size // 0 | tostring),
35
+ (.context_window.total_input_tokens // 0 | tostring),
36
+ (.context_window.total_output_tokens // 0 | tostring),
37
+ .model.id // "unknown",
38
+ .model.display_name // "Unknown",
39
+ .workspace.current_dir // .cwd // "",
40
+ .workspace.project_dir // "",
41
+ .transcript_path // ""
42
+ ] | join("§")' <<< "$input")"
43
+
44
+ # Detect git branch, worktree, and repo root from project directory (cached for 60s)
45
+ # Try cwd first (always a real filesystem path), then project_dir as fallback
46
+ git_branch=""
47
+ git_worktree=""
48
+ git_repo_root=""
49
+ git_dir="${project_dir:-$cwd}"
50
+ if [ -n "$git_dir" ] && [ -d "$git_dir" ]; then
51
+ git_cache="/tmp/jacques-git-$(echo "$git_dir" | tr '/' '-').cache"
52
+ cache_stale=1
53
+ if [ -f "$git_cache" ]; then
54
+ cache_age=$(( now - $(stat -f %m "$git_cache" 2>/dev/null || echo 0) ))
55
+ [ "$cache_age" -lt 60 ] && cache_stale=0
56
+ fi
57
+ if [ "$cache_stale" = "1" ]; then
58
+ # Use git-detect.sh as single source of truth
59
+ script_dir="$(cd "$(dirname "$0")" && pwd)"
60
+ if [ -x "$script_dir/git-detect.sh" ]; then
61
+ git_output=$("$script_dir/git-detect.sh" "$git_dir")
62
+ git_branch=$(echo "$git_output" | sed -n '1p')
63
+ git_worktree=$(echo "$git_output" | sed -n '2p')
64
+ git_repo_root=$(echo "$git_output" | sed -n '3p')
65
+ fi
66
+ printf '%s\n%s\n%s' "$git_branch" "$git_worktree" "$git_repo_root" > "$git_cache" 2>/dev/null
67
+ else
68
+ git_branch=$(sed -n '1p' "$git_cache" 2>/dev/null)
69
+ git_worktree=$(sed -n '2p' "$git_cache" 2>/dev/null)
70
+ git_repo_root=$(sed -n '3p' "$git_cache" 2>/dev/null)
71
+ fi
72
+ fi
73
+
74
+ # Extract session title with 5-min cache
75
+ session_title=""
76
+ title_cache="/tmp/jacques-title-${session_id}.cache"
77
+ if [ -n "$session_id" ] && [ -f "$title_cache" ]; then
78
+ cache_age=$(( now - $(stat -f %m "$title_cache" 2>/dev/null || echo 0) ))
79
+ if [ "$cache_age" -lt 300 ]; then
80
+ session_title=$(cat "$title_cache" 2>/dev/null)
81
+ fi
82
+ fi
83
+
84
+ if [ -z "$session_title" ]; then
85
+ # Source 1: Try sessions-index.json (has the dynamic title Claude shows in resume list)
86
+ if [ -n "$transcript_path" ] && [ -n "$session_id" ]; then
87
+ transcript_dir=$(dirname "$transcript_path")
88
+ sessions_index="$transcript_dir/sessions-index.json"
89
+ if [ -f "$sessions_index" ]; then
90
+ session_title=$(jq -r --arg sid "$session_id" '.entries[] | select(.sessionId == $sid) | .summary // empty' "$sessions_index" 2>/dev/null)
91
+ fi
92
+ fi
93
+
94
+ # Source 2: Try transcript summary entries (written during conversation)
95
+ if [ -z "$session_title" ] && [ -n "$transcript_path" ] && [ -f "$transcript_path" ]; then
96
+ session_title=$(grep '"type":"summary"' "$transcript_path" 2>/dev/null | tail -1 | jq -r '.summary // empty' 2>/dev/null)
97
+ fi
98
+
99
+ # Source 3: First REAL user message (skip internal Claude Code messages)
100
+ # Always extract first user message — needed for plan trigger check even if Source 1/2 found a title
101
+ first_user_msg=""
102
+ if [ -n "$transcript_path" ] && [ -f "$transcript_path" ]; then
103
+ first_user_msg=$(grep '"type":"user"' "$transcript_path" 2>/dev/null | while read -r line; do
104
+ content=$(echo "$line" | jq -r '.message.content // empty' 2>/dev/null)
105
+ [ -z "$content" ] && continue
106
+ first_char="${content:0:1}"
107
+ if [ "$first_char" = "<" ] || [ "$first_char" = "[" ]; then
108
+ continue
109
+ fi
110
+ echo "$content" | head -c 200
111
+ break
112
+ done)
113
+ fi
114
+
115
+ # If first message is a plan trigger, prefer it over sessions-index summary
116
+ # (display code needs the trigger + heading to extract plan title)
117
+ if [ -n "$first_user_msg" ]; then
118
+ is_plan=$(echo "$first_user_msg" | head -1 | grep -iE '^(implement the following plan|here is the plan|follow this plan)[: ]' 2>/dev/null)
119
+ if [ -n "$is_plan" ]; then
120
+ session_title="$first_user_msg"
121
+ fi
122
+ fi
123
+
124
+ # Fallback: use first user message if no title found
125
+ if [ -z "$session_title" ] && [ -n "$first_user_msg" ]; then
126
+ session_title="$first_user_msg"
127
+ fi
128
+
129
+ # Cache the extracted title
130
+ if [ -n "$session_id" ] && [ -n "$session_title" ]; then
131
+ printf '%s' "$session_title" > "$title_cache" 2>/dev/null
132
+ fi
133
+ fi
134
+
135
+
136
+ # Read auto-compact settings with 5-min cache
137
+ autocompact_enabled="true"
138
+ autocompact_threshold="${CLAUDE_AUTOCOMPACT_PCT_OVERRIDE:-95}"
139
+ autocompact_bug_threshold="null"
140
+
141
+ settings_cache="/tmp/jacques-settings.cache"
142
+ settings_valid=0
143
+ if [ -f "$settings_cache" ]; then
144
+ cache_age=$(( now - $(stat -f %m "$settings_cache" 2>/dev/null || echo 0) ))
145
+ if [ "$cache_age" -lt 300 ]; then
146
+ IFS='|' read -r autocompact_enabled autocompact_threshold autocompact_bug_threshold < "$settings_cache"
147
+ settings_valid=1
148
+ fi
149
+ fi
150
+
151
+ if [ "$settings_valid" = "0" ] && [ -f "$HOME/.claude/settings.json" ]; then
152
+ ac_setting=$(jq -r '.autoCompact // "null"' "$HOME/.claude/settings.json" 2>/dev/null)
153
+ if [ "$ac_setting" = "false" ]; then
154
+ autocompact_enabled="false"
155
+ autocompact_bug_threshold="78"
156
+ fi
157
+ printf '%s|%s|%s' "$autocompact_enabled" "$autocompact_threshold" "$autocompact_bug_threshold" > "$settings_cache" 2>/dev/null
158
+ fi
159
+
160
+ # Only proceed if we have a session_id
161
+ if [ -z "$session_id" ]; then
162
+ printf "ctx:?%%"
163
+ exit 0
164
+ fi
165
+
166
+ # Capture terminal identity for focus detection
167
+ iterm_session_id="${ITERM_SESSION_ID:-}"
168
+ term_session_id="${TERM_SESSION_ID:-}"
169
+ kitty_window_id="${KITTY_WINDOW_ID:-}"
170
+ terminal_pid="$PPID"
171
+
172
+ # Build terminal_key (same logic as jacques-register-session.py)
173
+ if [ -n "$iterm_session_id" ]; then
174
+ terminal_key="ITERM:$iterm_session_id"
175
+ elif [ -n "$kitty_window_id" ]; then
176
+ terminal_key="KITTY:$kitty_window_id"
177
+ elif [ -n "$term_session_id" ]; then
178
+ terminal_key="TERM:$term_session_id"
179
+ else
180
+ terminal_key=""
181
+ fi
182
+
183
+ # Send to Jacques server (if socket exists and server is running)
184
+ if [ -S /tmp/jacques.sock ]; then
185
+ # Escape special characters in session_title using bash builtins (saves 1 fork)
186
+ escaped_title="${session_title//\\/\\\\}"
187
+ escaped_title="${escaped_title//\"/\\\"}"
188
+ escaped_title="${escaped_title//$'\t'/\\t}"
189
+ escaped_title="${escaped_title//$'\n'/ }"
190
+ payload=$(cat <<EOF
191
+ {"event":"context_update","session_id":"$session_id","used_percentage":$used_pct,"remaining_percentage":$remaining_pct,"context_window_size":$ctx_size,"total_input_tokens":$total_input,"total_output_tokens":$total_output,"model":"$model","model_display_name":"$model_display","cwd":"$cwd","project_dir":"$project_dir","timestamp":$now,"autocompact":{"enabled":$autocompact_enabled,"threshold":$autocompact_threshold,"bug_threshold":$autocompact_bug_threshold},"terminal_key":"$terminal_key","terminal_pid":$terminal_pid,"session_title":"$escaped_title","transcript_path":"$transcript_path","git_branch":"$git_branch","git_worktree":"$git_worktree","git_repo_root":"$git_repo_root"}
192
+ EOF
193
+ )
194
+
195
+ # Send to socket (non-blocking, ignore errors)
196
+ echo "$payload" | nc -U /tmp/jacques.sock 2>/dev/null &
197
+ fi
198
+
199
+ # Display status line
200
+ # Format: [Model] ctx:XX% @branch [AC:ON@95%]
201
+ used_int=${used_pct%.*}
202
+ if [ -z "$used_int" ]; then
203
+ used_int="0"
204
+ fi
205
+
206
+ # Git branch indicator
207
+ git_part=""
208
+ if [ -n "$git_branch" ]; then
209
+ git_part=" @${git_branch}"
210
+ fi
211
+
212
+ printf "[%s] ctx:%s%%%s" "$model_display" "$used_int" "$git_part"