larkup 0.1.39 → 0.1.40

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 (238) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/diagnostics/route-bundle-stats.json +22 -21
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/required-server-files.js +1 -1
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/server/app/_global-error.html +1 -1
  8. package/.next/server/app/_global-error.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/server/app/_not-found.html +1 -1
  17. package/.next/server/app/_not-found.rsc +18 -18
  18. package/.next/server/app/_not-found.segments/_full.segment.rsc +18 -18
  19. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  20. package/.next/server/app/_not-found.segments/_index.segment.rsc +12 -12
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  22. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  23. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  24. package/.next/server/app/analytics/page.js.nft.json +1 -1
  25. package/.next/server/app/analytics/page_client-reference-manifest.js +1 -1
  26. package/.next/server/app/analytics.html +1 -1
  27. package/.next/server/app/analytics.rsc +19 -19
  28. package/.next/server/app/analytics.segments/_full.segment.rsc +19 -19
  29. package/.next/server/app/analytics.segments/_head.segment.rsc +4 -4
  30. package/.next/server/app/analytics.segments/_index.segment.rsc +12 -12
  31. package/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
  32. package/.next/server/app/analytics.segments/analytics/__PAGE__.segment.rsc +3 -3
  33. package/.next/server/app/analytics.segments/analytics.segment.rsc +3 -3
  34. package/.next/server/app/chat/page.js.nft.json +1 -1
  35. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  36. package/.next/server/app/chat.html +1 -1
  37. package/.next/server/app/chat.rsc +19 -19
  38. package/.next/server/app/chat.segments/_full.segment.rsc +19 -19
  39. package/.next/server/app/chat.segments/_head.segment.rsc +4 -4
  40. package/.next/server/app/chat.segments/_index.segment.rsc +12 -12
  41. package/.next/server/app/chat.segments/_tree.segment.rsc +2 -2
  42. package/.next/server/app/chat.segments/chat/__PAGE__.segment.rsc +3 -3
  43. package/.next/server/app/chat.segments/chat.segment.rsc +3 -3
  44. package/.next/server/app/data/page.js.nft.json +1 -1
  45. package/.next/server/app/data/page_client-reference-manifest.js +1 -1
  46. package/.next/server/app/data.html +1 -1
  47. package/.next/server/app/data.rsc +25 -26
  48. package/.next/server/app/data.segments/_full.segment.rsc +25 -26
  49. package/.next/server/app/data.segments/_head.segment.rsc +4 -4
  50. package/.next/server/app/data.segments/_index.segment.rsc +12 -12
  51. package/.next/server/app/data.segments/_tree.segment.rsc +2 -2
  52. package/.next/server/app/data.segments/data/__PAGE__.segment.rsc +3 -3
  53. package/.next/server/app/data.segments/data.segment.rsc +3 -3
  54. package/.next/server/app/index.html +1 -1
  55. package/.next/server/app/index.rsc +17 -17
  56. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  57. package/.next/server/app/index.segments/_full.segment.rsc +17 -17
  58. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  59. package/.next/server/app/index.segments/_index.segment.rsc +12 -12
  60. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  61. package/.next/server/app/page.js.nft.json +1 -1
  62. package/.next/server/app/page_client-reference-manifest.js +1 -1
  63. package/.next/server/app/settings/page.js.nft.json +1 -1
  64. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  65. package/.next/server/app/settings.html +1 -1
  66. package/.next/server/app/settings.rsc +19 -19
  67. package/.next/server/app/settings.segments/_full.segment.rsc +19 -19
  68. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  69. package/.next/server/app/settings.segments/_index.segment.rsc +12 -12
  70. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  71. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  72. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  73. package/.next/server/chunks/0598_next_dist_esm_build_templates_app-route_0kbcuk-.js +6 -6
  74. package/.next/server/chunks/0598_next_dist_esm_build_templates_app-route_0sbf4ny.js +2 -2
  75. package/.next/server/chunks/ssr/{[root-of-the-server]__0m21fli._.js → [root-of-the-server]__0pgotbk._.js} +2 -2
  76. package/.next/server/chunks/ssr/[root-of-the-server]__1k1mxo2._.js +3 -0
  77. package/.next/server/chunks/ssr/_169pdlf._.js +4 -4
  78. package/.next/server/chunks/ssr/_18jagqc._.js +2 -2
  79. package/.next/server/chunks/ssr/_1hetwwu._.js +2 -2
  80. package/.next/{standalone/apps/web/.next/server/chunks/ssr/_0s8403d._.js → server/chunks/ssr/_1p6lb7s._.js} +2 -2
  81. package/.next/server/chunks/ssr/_1yqlx1m._.js +1 -1
  82. package/.next/server/chunks/ssr/apps_web_components_analytics_analytics-dashboard_tsx_1056-z3._.js +1 -1
  83. package/.next/server/middleware-build-manifest.js +3 -3
  84. package/.next/server/pages/404.html +1 -1
  85. package/.next/server/pages/500.html +1 -1
  86. package/.next/standalone/apps/web/.next/BUILD_ID +1 -1
  87. package/.next/standalone/apps/web/.next/build-manifest.json +3 -3
  88. package/.next/standalone/apps/web/.next/required-server-files.json +1 -1
  89. package/.next/standalone/apps/web/.next/server/app/_global-error.html +1 -1
  90. package/.next/standalone/apps/web/.next/server/app/_global-error.rsc +1 -1
  91. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  92. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  94. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  95. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  96. package/.next/standalone/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  97. package/.next/standalone/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  98. package/.next/standalone/apps/web/.next/server/app/_not-found.html +1 -1
  99. package/.next/standalone/apps/web/.next/server/app/_not-found.rsc +18 -18
  100. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_full.segment.rsc +18 -18
  101. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  102. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_index.segment.rsc +12 -12
  103. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  104. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  105. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  106. package/.next/standalone/apps/web/.next/server/app/analytics/page.js.nft.json +1 -1
  107. package/.next/standalone/apps/web/.next/server/app/analytics/page_client-reference-manifest.js +1 -1
  108. package/.next/standalone/apps/web/.next/server/app/analytics.html +1 -1
  109. package/.next/standalone/apps/web/.next/server/app/analytics.rsc +19 -19
  110. package/.next/standalone/apps/web/.next/server/app/analytics.segments/_full.segment.rsc +19 -19
  111. package/.next/standalone/apps/web/.next/server/app/analytics.segments/_head.segment.rsc +4 -4
  112. package/.next/standalone/apps/web/.next/server/app/analytics.segments/_index.segment.rsc +12 -12
  113. package/.next/standalone/apps/web/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
  114. package/.next/standalone/apps/web/.next/server/app/analytics.segments/analytics/__PAGE__.segment.rsc +3 -3
  115. package/.next/standalone/apps/web/.next/server/app/analytics.segments/analytics.segment.rsc +3 -3
  116. package/.next/standalone/apps/web/.next/server/app/chat/page.js.nft.json +1 -1
  117. package/.next/standalone/apps/web/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  118. package/.next/standalone/apps/web/.next/server/app/chat.html +1 -1
  119. package/.next/standalone/apps/web/.next/server/app/chat.rsc +19 -19
  120. package/.next/standalone/apps/web/.next/server/app/chat.segments/_full.segment.rsc +19 -19
  121. package/.next/standalone/apps/web/.next/server/app/chat.segments/_head.segment.rsc +4 -4
  122. package/.next/standalone/apps/web/.next/server/app/chat.segments/_index.segment.rsc +12 -12
  123. package/.next/standalone/apps/web/.next/server/app/chat.segments/_tree.segment.rsc +2 -2
  124. package/.next/standalone/apps/web/.next/server/app/chat.segments/chat/__PAGE__.segment.rsc +3 -3
  125. package/.next/standalone/apps/web/.next/server/app/chat.segments/chat.segment.rsc +3 -3
  126. package/.next/standalone/apps/web/.next/server/app/data/page.js.nft.json +1 -1
  127. package/.next/standalone/apps/web/.next/server/app/data/page_client-reference-manifest.js +1 -1
  128. package/.next/standalone/apps/web/.next/server/app/data.html +1 -1
  129. package/.next/standalone/apps/web/.next/server/app/data.rsc +25 -26
  130. package/.next/standalone/apps/web/.next/server/app/data.segments/_full.segment.rsc +25 -26
  131. package/.next/standalone/apps/web/.next/server/app/data.segments/_head.segment.rsc +4 -4
  132. package/.next/standalone/apps/web/.next/server/app/data.segments/_index.segment.rsc +12 -12
  133. package/.next/standalone/apps/web/.next/server/app/data.segments/_tree.segment.rsc +2 -2
  134. package/.next/standalone/apps/web/.next/server/app/data.segments/data/__PAGE__.segment.rsc +3 -3
  135. package/.next/standalone/apps/web/.next/server/app/data.segments/data.segment.rsc +3 -3
  136. package/.next/standalone/apps/web/.next/server/app/index.html +1 -1
  137. package/.next/standalone/apps/web/.next/server/app/index.rsc +17 -17
  138. package/.next/standalone/apps/web/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  139. package/.next/standalone/apps/web/.next/server/app/index.segments/_full.segment.rsc +17 -17
  140. package/.next/standalone/apps/web/.next/server/app/index.segments/_head.segment.rsc +4 -4
  141. package/.next/standalone/apps/web/.next/server/app/index.segments/_index.segment.rsc +12 -12
  142. package/.next/standalone/apps/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  143. package/.next/standalone/apps/web/.next/server/app/page.js.nft.json +1 -1
  144. package/.next/standalone/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  145. package/.next/standalone/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  146. package/.next/standalone/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  147. package/.next/standalone/apps/web/.next/server/app/settings.html +1 -1
  148. package/.next/standalone/apps/web/.next/server/app/settings.rsc +19 -19
  149. package/.next/standalone/apps/web/.next/server/app/settings.segments/_full.segment.rsc +19 -19
  150. package/.next/standalone/apps/web/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  151. package/.next/standalone/apps/web/.next/server/app/settings.segments/_index.segment.rsc +12 -12
  152. package/.next/standalone/apps/web/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  153. package/.next/standalone/apps/web/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  154. package/.next/standalone/apps/web/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  155. package/.next/standalone/apps/web/.next/server/chunks/0598_next_dist_esm_build_templates_app-route_0kbcuk-.js +6 -6
  156. package/.next/standalone/apps/web/.next/server/chunks/0598_next_dist_esm_build_templates_app-route_0sbf4ny.js +2 -2
  157. package/.next/standalone/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__0m21fli._.js → [root-of-the-server]__0pgotbk._.js} +2 -2
  158. package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__1k1mxo2._.js +3 -0
  159. package/.next/standalone/apps/web/.next/server/chunks/ssr/_169pdlf._.js +4 -4
  160. package/.next/standalone/apps/web/.next/server/chunks/ssr/_18jagqc._.js +2 -2
  161. package/.next/standalone/apps/web/.next/server/chunks/ssr/_1hetwwu._.js +2 -2
  162. package/.next/{server/chunks/ssr/_0s8403d._.js → standalone/apps/web/.next/server/chunks/ssr/_1p6lb7s._.js} +2 -2
  163. package/.next/standalone/apps/web/.next/server/chunks/ssr/_1yqlx1m._.js +1 -1
  164. package/.next/standalone/apps/web/.next/server/chunks/ssr/apps_web_components_analytics_analytics-dashboard_tsx_1056-z3._.js +1 -1
  165. package/.next/standalone/apps/web/.next/server/middleware-build-manifest.js +3 -3
  166. package/.next/standalone/apps/web/.next/server/pages/404.html +1 -1
  167. package/.next/standalone/apps/web/.next/server/pages/500.html +1 -1
  168. package/.next/standalone/apps/web/.next/static/chunks/0f_k7h1yraes3.js +1 -0
  169. package/.next/{static/chunks/1ov69q-i9ybqi.js → standalone/apps/web/.next/static/chunks/1b9srvyupwcjz.js} +1 -1
  170. package/.next/standalone/apps/web/.next/static/chunks/1j_-mc43_9-b3.js +121 -0
  171. package/.next/standalone/apps/web/.next/static/chunks/23efo4rpc31kr.js +1 -0
  172. package/.next/standalone/apps/web/.next/static/chunks/2_qbhu4zxkm7j.js +11 -0
  173. package/.next/standalone/apps/web/.next/static/chunks/{2ljwki2xxnblc.js → 2h-80z3n8mi3d.js} +7 -7
  174. package/.next/standalone/apps/web/.next/static/chunks/37j20in7beze4.js +1 -0
  175. package/.next/standalone/apps/web/.next/static/chunks/{1cxabi5yzqz57.js → 38f3p67a1uufx.js} +1 -1
  176. package/.next/standalone/apps/web/.next/static/chunks/3fe06cefiv690.css +1 -0
  177. package/.next/standalone/apps/web/CHANGELOG.md +12 -0
  178. package/.next/standalone/apps/web/app/api/chat/route.ts +25 -11
  179. package/.next/standalone/apps/web/app/api/media/process/route.ts +34 -1
  180. package/.next/standalone/apps/web/app/settings/page.tsx +16 -5
  181. package/.next/standalone/apps/web/bin/larkup.js +12 -1
  182. package/.next/standalone/apps/web/components/chat/message-item.tsx +68 -3
  183. package/.next/standalone/apps/web/components/data/data-workspace.tsx +53 -120
  184. package/.next/standalone/apps/web/components/data/firecrawl-notice.tsx +1 -11
  185. package/.next/standalone/apps/web/components/data/media-panel.tsx +187 -25
  186. package/.next/standalone/apps/web/components/data/scrape-panel.tsx +1 -1
  187. package/.next/standalone/apps/web/components/data/upload-panel.tsx +0 -1
  188. package/.next/standalone/apps/web/components/index/index-workspace.tsx +48 -25
  189. package/.next/standalone/apps/web/components/settings/marketplace-section.tsx +1 -1
  190. package/.next/standalone/apps/web/components/settings/settings-layout.tsx +1 -2
  191. package/.next/standalone/apps/web/package.json +1 -1
  192. package/.next/standalone/apps/web/server.js +1 -1
  193. package/.next/standalone/packages/tools/doc-editor/CHANGELOG.md +7 -0
  194. package/.next/standalone/packages/tools/doc-editor/dist/editor.js +1 -15
  195. package/.next/standalone/packages/tools/doc-editor/package.json +1 -1
  196. package/.next/standalone/packages/tools/doc-editor/src/editor.ts +1 -15
  197. package/.next/static/chunks/0f_k7h1yraes3.js +1 -0
  198. package/.next/{standalone/apps/web/.next/static/chunks/1ov69q-i9ybqi.js → static/chunks/1b9srvyupwcjz.js} +1 -1
  199. package/.next/static/chunks/1j_-mc43_9-b3.js +121 -0
  200. package/.next/static/chunks/23efo4rpc31kr.js +1 -0
  201. package/.next/static/chunks/2_qbhu4zxkm7j.js +11 -0
  202. package/.next/static/chunks/{2ljwki2xxnblc.js → 2h-80z3n8mi3d.js} +7 -7
  203. package/.next/static/chunks/37j20in7beze4.js +1 -0
  204. package/.next/static/chunks/{1cxabi5yzqz57.js → 38f3p67a1uufx.js} +1 -1
  205. package/.next/static/chunks/3fe06cefiv690.css +1 -0
  206. package/CHANGELOG.md +12 -0
  207. package/app/api/chat/route.ts +25 -11
  208. package/app/api/media/process/route.ts +34 -1
  209. package/app/settings/page.tsx +16 -5
  210. package/bin/larkup.js +12 -1
  211. package/components/chat/message-item.tsx +68 -3
  212. package/components/data/data-workspace.tsx +53 -120
  213. package/components/data/firecrawl-notice.tsx +1 -11
  214. package/components/data/media-panel.tsx +187 -25
  215. package/components/data/scrape-panel.tsx +1 -1
  216. package/components/data/upload-panel.tsx +0 -1
  217. package/components/index/index-workspace.tsx +48 -25
  218. package/components/settings/marketplace-section.tsx +1 -1
  219. package/components/settings/settings-layout.tsx +1 -2
  220. package/package.json +6 -6
  221. package/.next/server/chunks/ssr/[root-of-the-server]__0t8ud_u._.js +0 -3
  222. package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0t8ud_u._.js +0 -3
  223. package/.next/standalone/apps/web/.next/static/chunks/03ju_837pa9ul.js +0 -11
  224. package/.next/standalone/apps/web/.next/static/chunks/0ge3nirnmx_np.js +0 -1
  225. package/.next/standalone/apps/web/.next/static/chunks/19krxv-ou9c8c.js +0 -121
  226. package/.next/standalone/apps/web/.next/static/chunks/1_nk3imchwn8a.css +0 -1
  227. package/.next/standalone/apps/web/.next/static/chunks/25rt2v27sz0io.js +0 -1
  228. package/.next/static/chunks/03ju_837pa9ul.js +0 -11
  229. package/.next/static/chunks/0ge3nirnmx_np.js +0 -1
  230. package/.next/static/chunks/19krxv-ou9c8c.js +0 -121
  231. package/.next/static/chunks/1_nk3imchwn8a.css +0 -1
  232. package/.next/static/chunks/25rt2v27sz0io.js +0 -1
  233. /package/.next/standalone/apps/web/.next/static/{iCALZzxFfElF4z3wYZwsC → 7yuxi3XYqMr4kxUl6T-qk}/_buildManifest.js +0 -0
  234. /package/.next/standalone/apps/web/.next/static/{iCALZzxFfElF4z3wYZwsC → 7yuxi3XYqMr4kxUl6T-qk}/_clientMiddlewareManifest.js +0 -0
  235. /package/.next/standalone/apps/web/.next/static/{iCALZzxFfElF4z3wYZwsC → 7yuxi3XYqMr4kxUl6T-qk}/_ssgManifest.js +0 -0
  236. /package/.next/static/{iCALZzxFfElF4z3wYZwsC → 7yuxi3XYqMr4kxUl6T-qk}/_buildManifest.js +0 -0
  237. /package/.next/static/{iCALZzxFfElF4z3wYZwsC → 7yuxi3XYqMr4kxUl6T-qk}/_clientMiddlewareManifest.js +0 -0
  238. /package/.next/static/{iCALZzxFfElF4z3wYZwsC → 7yuxi3XYqMr4kxUl6T-qk}/_ssgManifest.js +0 -0
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useEffect, Suspense } from 'react';
3
+ import { useEffect, useState, Suspense } from 'react';
4
4
  import { useSearchParams, useRouter, usePathname } from 'next/navigation';
5
5
  import { SettingsLayout, type SettingsSection } from '@/components/settings/settings-layout';
6
6
  import { GeneralSection } from '@/components/settings/general-section';
@@ -27,9 +27,14 @@ function SettingsContent() {
27
27
  return 'general';
28
28
  };
29
29
 
30
- // Always derive the active section from the URL this ensures navigating
31
- // away and back never leaves the sidebar stuck on a stale section.
32
- const activeSection = resolveSection();
30
+ // Keep an immediate local selection as well as the URL. A slow Installed
31
+ // Tools request must never make the rest of the settings navigation feel
32
+ // frozen while Next finishes a route transition.
33
+ const [activeSection, setActiveSection] = useState<SettingsSection>(resolveSection);
34
+
35
+ useEffect(() => {
36
+ setActiveSection(resolveSection());
37
+ }, [searchParams]);
33
38
 
34
39
  useEffect(() => {
35
40
  // Normalize legacy `?ai-models` param to `?section=models`
@@ -42,7 +47,13 @@ function SettingsContent() {
42
47
  }, [searchParams, pathname, router]);
43
48
 
44
49
  const handleSectionChange = (newSection: SettingsSection) => {
45
- router.replace(`${pathname}?section=${newSection}`, { scroll: false });
50
+ setActiveSection(newSection);
51
+ const nextUrl = `${pathname}?section=${newSection}`;
52
+ window.history.replaceState(null, '', nextUrl);
53
+ // Keep Next's route state in sync in the background. The local state above
54
+ // is intentionally updated first so this remains responsive if a section
55
+ // has a slow request in flight.
56
+ router.replace(nextUrl, { scroll: false });
46
57
  };
47
58
 
48
59
  return (
@@ -35,8 +35,19 @@ if (command === '--version' || command === '-v') {
35
35
  child.once('exit', (code) => process.exit(code ?? 0));
36
36
 
37
37
  void openWhenReady(url);
38
+ } else if (command === 'update') {
39
+ console.log('\x1b[38;2;223;156;32mUpdating Larkup…\x1b[0m');
40
+ const child = spawn('npm', ['install', '-g', 'larkup@latest'], { stdio: 'inherit' });
41
+ child.once('error', (error) => {
42
+ console.error('Failed to update Larkup:', error.message);
43
+ process.exit(1);
44
+ });
45
+ child.once('exit', (code) => {
46
+ if (code === 0) console.log('Larkup is up to date. Restart it to use the new version.');
47
+ process.exit(code ?? 0);
48
+ });
38
49
  } else {
39
- console.error('Usage: larkup dev');
50
+ console.error('Usage: larkup <dev|start|update>');
40
51
  process.exit(1);
41
52
  }
42
53
 
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useEffect, useMemo, useRef } from 'react';
3
+ import { useEffect, useMemo, useRef, useState } from 'react';
4
4
  import type { UIMessage } from 'ai';
5
5
  import { KnowledgeBaseResult } from '@/components/chat/tools/knowledge-base-result';
6
6
  import { ChatChart, type ChartConfig } from '@/components/chat/tools/chat-chart';
@@ -15,7 +15,7 @@ import {
15
15
  type CorpusDataConfig,
16
16
  } from '@/components/chat/tools/corpus-data-result';
17
17
  import { ChatSignatureRequest } from '@/components/chat/tools/chat-signature-request';
18
- import { Sparkles, FileEdit, CheckCircle2, Globe } from 'lucide-react';
18
+ import { Sparkles, FileEdit, CheckCircle2, Globe, ChevronDown } from 'lucide-react';
19
19
  import { ChatMediaPreview, parseMediaRefs } from '@/components/chat/tools/chat-media-preview';
20
20
  import { useDocEditor } from '@/components/chat/canvas/doc-editor-provider';
21
21
 
@@ -455,6 +455,64 @@ function renderToolPart(
455
455
  return null;
456
456
  }
457
457
 
458
+ function WebSearchSummary({ parts }: { parts: any[] }) {
459
+ const [open, setOpen] = useState(false);
460
+ const searches = parts.map((part) => {
461
+ const info = getToolInfo(part);
462
+ const results = Array.isArray(info.output?.results) ? info.output.results : [];
463
+ return { query: info.input?.query as string | undefined, results, running: info.isExecuting };
464
+ });
465
+ const resultCount = searches.reduce((count, search) => count + search.results.length, 0);
466
+ const running = searches.some((search) => search.running);
467
+
468
+ return (
469
+ <div className="mb-2 w-full">
470
+ <button
471
+ type="button"
472
+ onClick={() => (resultCount > 0 || searches.length > 1) && setOpen((value) => !value)}
473
+ className="inline-flex items-center gap-2 rounded-md border border-border/50 bg-muted/30 px-2 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-muted/50"
474
+ >
475
+ <Globe className="size-3.5 shrink-0" />
476
+ <span>{running ? 'Searching the web…' : 'Searched the web'}</span>
477
+ {!running && resultCount > 0 ? (
478
+ <span className="rounded-full bg-secondary px-1.5 py-0.5 text-[10px] font-medium text-foreground">
479
+ {resultCount} result{resultCount === 1 ? '' : 's'}
480
+ </span>
481
+ ) : null}
482
+ {!running && (resultCount > 0 || searches.length > 1) ? (
483
+ <ChevronDown className={`size-3 transition-transform ${open ? 'rotate-180' : ''}`} />
484
+ ) : null}
485
+ </button>
486
+
487
+ {open ? (
488
+ <div className="mt-2 max-w-xl overflow-hidden rounded-lg border border-border/60 bg-background text-xs">
489
+ {searches
490
+ .flatMap((search) => search.results)
491
+ .slice(0, 5)
492
+ .map((result: any, index) => (
493
+ <a
494
+ key={`${result.url ?? result.title ?? index}-${index}`}
495
+ href={result.url}
496
+ target="_blank"
497
+ rel="noreferrer"
498
+ className="block border-b border-border/50 px-3 py-2.5 last:border-0 hover:bg-muted/40"
499
+ >
500
+ <span className="block truncate font-medium text-foreground">
501
+ {result.title || result.url}
502
+ </span>
503
+ {result.snippet ? (
504
+ <span className="mt-0.5 block line-clamp-2 text-muted-foreground">
505
+ {result.snippet}
506
+ </span>
507
+ ) : null}
508
+ </a>
509
+ ))}
510
+ </div>
511
+ ) : null}
512
+ </div>
513
+ );
514
+ }
515
+
458
516
  /* ------------------------------------------------------------------ */
459
517
  /* Main message component */
460
518
  /* ------------------------------------------------------------------ */
@@ -777,8 +835,12 @@ export function MessageItem({
777
835
 
778
836
  const vizParts = toolParts.filter(isVizPart);
779
837
  const mediaToolParts = toolParts.filter((p: any) => getToolInfo(p).toolName === 'presentMedia');
838
+ const webSearchParts = toolParts.filter((p: any) => getToolInfo(p).toolName === 'webSearch');
780
839
  const nonVizToolParts = toolParts.filter(
781
- (p: any) => !isVizPart(p) && getToolInfo(p).toolName !== 'presentMedia',
840
+ (p: any) =>
841
+ !isVizPart(p) &&
842
+ getToolInfo(p).toolName !== 'presentMedia' &&
843
+ getToolInfo(p).toolName !== 'webSearch',
782
844
  );
783
845
 
784
846
  // Build tabs if we have multiple visualizations
@@ -808,6 +870,9 @@ export function MessageItem({
808
870
  {/* Knowledge base results */}
809
871
  {kbParts.length > 0 && <KnowledgeBaseResult parts={kbParts} isShimmering={isShimmering} />}
810
872
 
873
+ {/* All search attempts are intentionally one compact disclosure. */}
874
+ {webSearchParts.length > 0 && <WebSearchSummary parts={webSearchParts} />}
875
+
811
876
  {/* Non-visualization tool outputs (data tables, sandbox results) */}
812
877
  {nonVizToolParts
813
878
  .filter((p: any) => getToolInfo(p).isCompleted)
@@ -1,23 +1,13 @@
1
1
  'use client';
2
2
 
3
3
  import { useState, useEffect, useRef, useCallback } from 'react';
4
- import { useSearchParams, useRouter, usePathname } from 'next/navigation';
4
+ import { useSearchParams, usePathname } from 'next/navigation';
5
5
  import useSWR, { useSWRConfig } from 'swr';
6
6
  import { toast } from 'sonner';
7
7
  import { motion } from 'framer-motion';
8
8
  import { cn } from '@/lib/utils';
9
9
  import type { CrawlJob, SourceDocument, IndexRun } from '@larkup/core/types';
10
- import {
11
- Globe,
12
- FileUp,
13
- Type,
14
- Image,
15
- Plug,
16
- Briefcase,
17
- ChevronDown,
18
- Zap,
19
- RotateCcw,
20
- } from 'lucide-react';
10
+ import { Globe, FileUp, Type, Image, Plug, Briefcase, ChevronDown } from 'lucide-react';
21
11
  import { ScrapePanel } from '@/components/data/scrape-panel';
22
12
  import { PastePanel } from '@/components/data/paste-panel';
23
13
  import { UploadPanel } from '@/components/data/upload-panel';
@@ -33,20 +23,7 @@ import {
33
23
  DialogHeader,
34
24
  DialogTitle,
35
25
  DialogDescription,
36
- DialogTrigger,
37
26
  } from '@/components/ui/dialog';
38
- import {
39
- AlertDialog,
40
- AlertDialogAction,
41
- AlertDialogCancel,
42
- AlertDialogContent,
43
- AlertDialogDescription,
44
- AlertDialogFooter,
45
- AlertDialogHeader,
46
- AlertDialogTitle,
47
- AlertDialogTrigger,
48
- } from '@/components/ui/alert-dialog';
49
- import { Button } from '@/components/ui/button';
50
27
 
51
28
  const fetcher = (url: string) => fetch(url).then((r) => r.json());
52
29
 
@@ -102,7 +79,6 @@ type SubTabId = (typeof SUB_TABS)[number]['id'];
102
79
 
103
80
  export function DataWorkspace() {
104
81
  const searchParams = useSearchParams();
105
- const router = useRouter();
106
82
  const pathname = usePathname();
107
83
 
108
84
  const getInitialTab = (): TopTabId => {
@@ -165,30 +141,6 @@ export function DataWorkspace() {
165
141
  });
166
142
  const { mutate: mutateDocuments } = docsQuery;
167
143
  const documents = docsQuery.data?.documents ?? [];
168
- const stats = docsQuery.data?.stats;
169
- const docCount = stats?.docCount ?? 0;
170
-
171
- useEffect(() => {
172
- const prevJobs = prevJobsRef.current;
173
- if (prevJobs.length > 0 && jobs.length > 0) {
174
- const justCompleted = jobs.filter(
175
- (j) =>
176
- j.status === 'completed' &&
177
- prevJobs.some(
178
- (pj) => pj.id === j.id && (pj.status === 'running' || pj.status === 'queued'),
179
- ),
180
- );
181
-
182
- if (justCompleted.length > 0) {
183
- toast.success('Scraping completed.');
184
- // Refresh the corpus immediately so new documents appear.
185
- mutateDocuments();
186
- // Documents may still be flushing — re-fetch after a short delay.
187
- setTimeout(() => mutateDocuments(), 2500);
188
- }
189
- }
190
- prevJobsRef.current = jobs;
191
- }, [jobs, mutateDocuments]);
192
144
 
193
145
  const indexQuery = useSWR<{
194
146
  unindexedCount: number;
@@ -197,9 +149,7 @@ export function DataWorkspace() {
197
149
  }>('/api/index', fetcher, {
198
150
  refreshInterval: (d) => (d?.running ? 2000 : 0),
199
151
  });
200
- const unindexedCount = indexQuery.data?.unindexedCount ?? 0;
201
152
  const indexRunning = indexQuery.data?.running ?? false;
202
- const hasCompletedIndex = indexQuery.data?.run?.status === 'completed';
203
153
  const { mutate: mutateIndex } = indexQuery;
204
154
 
205
155
  const prevIndexRunning = useRef(indexRunning);
@@ -219,9 +169,54 @@ export function DataWorkspace() {
219
169
  mutateGlobal('/api/index');
220
170
  };
221
171
 
172
+ const startAutomaticIndex = useCallback(async () => {
173
+ try {
174
+ const res = await fetch('/api/index', {
175
+ method: 'POST',
176
+ headers: { 'Content-Type': 'application/json' },
177
+ body: JSON.stringify({ incremental: indexQuery.data?.run?.status === 'completed' }),
178
+ });
179
+ const body = await res.json();
180
+ if (res.status === 409) return;
181
+ if (!res.ok) {
182
+ toast.error(body.error || 'Your data was added, but indexing could not start.');
183
+ return;
184
+ }
185
+ toast.success('Making your data searchable', {
186
+ description: 'This continues in the background. You can safely leave this page.',
187
+ duration: 7_000,
188
+ });
189
+ setIndexDialogOpen(true);
190
+ void indexQuery.mutate();
191
+ } catch {
192
+ toast.error('Your data was added, but indexing could not start.');
193
+ }
194
+ }, [indexQuery]);
195
+
196
+ useEffect(() => {
197
+ const prevJobs = prevJobsRef.current;
198
+ if (prevJobs.length > 0 && jobs.length > 0) {
199
+ const justCompleted = jobs.filter(
200
+ (j) =>
201
+ j.status === 'completed' &&
202
+ prevJobs.some(
203
+ (pj) => pj.id === j.id && (pj.status === 'running' || pj.status === 'queued'),
204
+ ),
205
+ );
206
+
207
+ if (justCompleted.length > 0) {
208
+ toast.success('Scraping completed. Making the new pages searchable…');
209
+ void mutateDocuments();
210
+ setTimeout(() => void mutateDocuments(), 2500);
211
+ void startAutomaticIndex();
212
+ }
213
+ }
214
+ prevJobsRef.current = jobs;
215
+ }, [jobs, mutateDocuments, startAutomaticIndex]);
216
+
222
217
  const handleDataAdded = () => {
223
218
  refreshAll();
224
- setActiveTab('corpus');
219
+ void startAutomaticIndex();
225
220
  };
226
221
 
227
222
  const handleScrapeStarted = useCallback(
@@ -330,79 +325,17 @@ export function DataWorkspace() {
330
325
  </button>
331
326
  )}
332
327
 
333
- {hasCompletedIndex && !indexRunning && (
334
- <AlertDialog>
335
- <AlertDialogTrigger
336
- render={
337
- <Button variant="outline" className="h-10 bg-white px-4 text-sm gap-1.5">
338
- <RotateCcw className="size-3.5" />
339
- Re-Index
340
- </Button>
341
- }
342
- />
343
- <AlertDialogContent>
344
- <AlertDialogHeader>
345
- <AlertDialogTitle>Are you sure you want to re-index data?</AlertDialogTitle>
346
- <AlertDialogDescription>
347
- This will rebuild the entire index from scratch. All documents will be
348
- re-processed.
349
- </AlertDialogDescription>
350
- </AlertDialogHeader>
351
- <AlertDialogFooter>
352
- <AlertDialogCancel>Cancel</AlertDialogCancel>
353
- <AlertDialogAction
354
- onClick={() => {
355
- fetch('/api/index', {
356
- method: 'POST',
357
- body: JSON.stringify({ incremental: false }),
358
- headers: { 'Content-Type': 'application/json' },
359
- }).then(() => {
360
- toast.success('Indexing started.');
361
- setIndexDialogOpen(true);
362
- indexQuery.mutate();
363
- });
364
- }}
365
- >
366
- Continue
367
- </AlertDialogAction>
368
- </AlertDialogFooter>
369
- </AlertDialogContent>
370
- </AlertDialog>
371
- )}
372
-
328
+ {/* Indexing begins automatically after data is added. */}
373
329
  <Dialog open={indexDialogOpen} onOpenChange={setIndexDialogOpen}>
374
- <DialogTrigger
375
- render={
376
- <Button
377
- variant={indexRunning ? 'success' : 'default'}
378
- disabled={(docCount === 0 || unindexedCount === 0) && !indexRunning}
379
- className="h-10 rounded-md px-4 gap-1.5 text-sm"
380
- >
381
- {indexRunning ? (
382
- <>
383
- <span className="relative flex size-2">
384
- <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-white opacity-75" />
385
- <span className="relative inline-flex size-2 rounded-full bg-white" />
386
- </span>
387
- Indexing…
388
- </>
389
- ) : (
390
- <>
391
- <Zap className="size-3.5" />
392
- {unindexedCount > 0 ? `Start Indexing (${unindexedCount})` : 'Start Indexing'}
393
- </>
394
- )}
395
- </Button>
396
- }
397
- />
398
- <DialogContent className="max-w-2xl max-h-[85vh] overflow-y-auto ">
330
+ <DialogContent className="max-w-lg overflow-y-auto">
399
331
  <DialogHeader>
400
- <DialogTitle>Build Index</DialogTitle>
332
+ <DialogTitle>Making your data searchable</DialogTitle>
401
333
  <DialogDescription>
402
- Embed your documents into a vector index for semantic search.
334
+ This runs safely in the background. You can close this and come back anytime.
403
335
  </DialogDescription>
404
336
  </DialogHeader>
405
337
  <IndexWorkspace
338
+ automatic
406
339
  onDone={() => {
407
340
  indexQuery.mutate();
408
341
  setResetKey((k) => k + 1);
@@ -29,16 +29,6 @@ interface LocalResponse {
29
29
 
30
30
  const fetcher = (url: string) => fetch(url).then((r) => r.json());
31
31
 
32
- /**
33
- * Web-crawler launcher notice.
34
- *
35
- * Adapts to the runtime environment:
36
- * - **Web / Desktop**: starts Larkup's built-in crawler (no Docker required).
37
- * - **Docker**: detects a sibling crawler service on the Docker network.
38
- *
39
- * The API key (cloud) option is managed in Settings — this component only
40
- * handles the local/Docker launcher.
41
- */
42
32
  export function FirecrawlNotice({
43
33
  cloudConfigured = false,
44
34
  onChange,
@@ -76,7 +66,7 @@ export function FirecrawlNotice({
76
66
  description:
77
67
  runtimeEnv === 'docker'
78
68
  ? 'Checking if the crawler service is available on the network.'
79
- : 'Starting Larkup’s built-in crawler. No Docker setup is required.',
69
+ : 'Starting Larkup’s built-in crawler. ',
80
70
  },
81
71
  );
82
72
  }