@geminilight/mindos 0.6.58 → 0.6.59

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 (219) hide show
  1. package/_standalone/.mindos-build-version +1 -1
  2. package/_standalone/.next/BUILD_ID +1 -1
  3. package/_standalone/.next/app-path-routes-manifest.json +24 -24
  4. package/_standalone/.next/build-manifest.json +3 -3
  5. package/_standalone/.next/cache/.previewinfo +1 -1
  6. package/_standalone/.next/cache/.rscinfo +1 -1
  7. package/_standalone/.next/cache/config.json +3 -3
  8. package/_standalone/.next/prerender-manifest.json +3 -3
  9. package/_standalone/.next/react-loadable-manifest.json +1 -1
  10. package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
  11. package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  12. package/_standalone/.next/server/app/_global-error.html +2 -2
  13. package/_standalone/.next/server/app/_global-error.rsc +1 -1
  14. package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  15. package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  16. package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  17. package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  18. package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  19. package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  20. package/_standalone/.next/server/app/_not-found/page.js +1 -1
  21. package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  22. package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  23. package/_standalone/.next/server/app/agents/[agentKey]/page.js +1 -1
  24. package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
  25. package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
  26. package/_standalone/.next/server/app/agents/page.js +2 -2
  27. package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
  28. package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  29. package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
  30. package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
  31. package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
  32. package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
  33. package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
  34. package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
  35. package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
  36. package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
  37. package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
  38. package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
  39. package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
  40. package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
  41. package/_standalone/.next/server/app/api/ask/route.js +3 -3
  42. package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
  43. package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
  44. package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
  45. package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
  46. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  47. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  48. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  49. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  50. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  51. package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
  52. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  53. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  54. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  55. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  56. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  57. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  58. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  59. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  60. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  61. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  62. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  63. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  64. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
  65. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  66. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  67. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  68. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  69. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  70. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  71. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  72. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  73. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  74. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  75. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  76. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  77. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  78. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  79. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  80. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  81. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  82. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  83. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  84. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  85. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  86. package/_standalone/.next/server/app/changes/page.js +2 -2
  87. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  88. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  89. package/_standalone/.next/server/app/echo/[segment]/page.js +3 -3
  90. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  91. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  92. package/_standalone/.next/server/app/echo/page.js +1 -1
  93. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  94. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  95. package/_standalone/.next/server/app/explore/page.js +2 -2
  96. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  97. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  98. package/_standalone/.next/server/app/help/page.js +2 -2
  99. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  100. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  101. package/_standalone/.next/server/app/inbox/history/page.js +1 -1
  102. package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
  103. package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
  104. package/_standalone/.next/server/app/login/page.js +2 -2
  105. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  106. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  107. package/_standalone/.next/server/app/page.js +2 -8
  108. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  109. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  110. package/_standalone/.next/server/app/setup/page.js +2 -2
  111. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  112. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  113. package/_standalone/.next/server/app/trash/page.js +3 -3
  114. package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
  115. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  116. package/_standalone/.next/server/app/view/[...path]/page.js +3 -3
  117. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  118. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  119. package/_standalone/.next/server/app/wiki/page.js +2 -2
  120. package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
  121. package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
  122. package/_standalone/.next/server/app-paths-manifest.json +24 -24
  123. package/_standalone/.next/server/chunks/3484.js +1 -1
  124. package/_standalone/.next/server/chunks/530.js +65 -66
  125. package/_standalone/.next/server/chunks/{6793.js → 8343.js} +2 -2
  126. package/_standalone/.next/server/chunks/9787.js +2 -0
  127. package/_standalone/.next/server/middleware-build-manifest.js +1 -1
  128. package/_standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  129. package/_standalone/.next/server/pages/500.html +2 -2
  130. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  131. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  132. package/_standalone/.next/static/chunks/{1814.a7c127b2c73d1f70.js → 1814.a79b84d37df75c43.js} +1 -1
  133. package/_standalone/.next/static/chunks/3427-2e61a5df1f5e55fb.js +1 -0
  134. package/_standalone/.next/static/chunks/{1053-fe009233cff06e72.js → 5581-dac72e9f16e5ea29.js} +3 -3
  135. package/_standalone/.next/static/chunks/6297-085daa21037d5f81.js +1 -0
  136. package/_standalone/.next/static/chunks/{7249-fa98ca10e9a10f39.js → 7249-6cf8f2b78718c59e.js} +1 -1
  137. package/_standalone/.next/static/chunks/8520-56ec9ff087c15204.js +22 -0
  138. package/_standalone/.next/static/chunks/9905-a19d379cb225246e.js +1 -0
  139. package/_standalone/.next/static/chunks/app/agents/[agentKey]/{page-7bdeab5af8e4f5f2.js → page-35ea6de1af2be3b5.js} +1 -1
  140. package/_standalone/.next/static/chunks/app/agents/page-b172ea3743adb047.js +1 -0
  141. package/_standalone/.next/static/chunks/app/changes/{page-5a72144d1080a699.js → page-6d2f49651c0061f7.js} +1 -1
  142. package/_standalone/.next/static/chunks/app/echo/[segment]/page-84b95256f6e38aae.js +11 -0
  143. package/_standalone/.next/static/chunks/app/explore/{page-d3d99308146c2240.js → page-d9f58000bc445360.js} +2 -2
  144. package/_standalone/.next/static/chunks/app/help/{page-222df603080b5fab.js → page-f8cb806371b3175f.js} +1 -1
  145. package/_standalone/.next/static/chunks/app/inbox/history/{page-07819cf95cb0805f.js → page-26e71fb6f716a4c4.js} +1 -1
  146. package/_standalone/.next/static/chunks/app/layout-b89b0d955f39a753.js +164 -0
  147. package/_standalone/.next/static/chunks/app/login/{page-0eeef685052869a6.js → page-18fb00d568cd1f0e.js} +1 -1
  148. package/_standalone/.next/static/chunks/app/page-a8e6f085f38388bf.js +1 -0
  149. package/_standalone/.next/static/chunks/app/setup/{page-99fcfc460fa29733.js → page-821714e7477be46c.js} +1 -1
  150. package/_standalone/.next/static/chunks/app/trash/{page-54cbd5c98d9de69b.js → page-f92b728b78ac0f7e.js} +1 -1
  151. package/_standalone/.next/static/chunks/app/view/[...path]/{not-found-fc04c2bd4f35bc6f.js → not-found-6e0c75ad26ce8572.js} +1 -1
  152. package/_standalone/.next/static/chunks/app/view/[...path]/page-f87f4901b5e1a88f.js +12 -0
  153. package/_standalone/.next/static/chunks/app/wiki/page-641edb1f3cff2f93.js +1 -0
  154. package/_standalone/.next/static/chunks/{webpack-2c19436659aa657b.js → webpack-72e8d9e9073fd1f9.js} +1 -1
  155. package/_standalone/.next/static/css/6c104b118d3bc9b7.css +1 -0
  156. package/_standalone/.next/trace +64 -64
  157. package/_standalone/app/globals.css +2 -1
  158. package/_standalone/components/AskFab.tsx +4 -4
  159. package/_standalone/components/AskModal.tsx +1 -1
  160. package/_standalone/components/GuideCard.tsx +101 -152
  161. package/_standalone/components/RightAskPanel.tsx +2 -2
  162. package/_standalone/components/ask/AskContent.tsx +90 -51
  163. package/_standalone/components/ask/AskHeader.tsx +218 -18
  164. package/_standalone/components/ask/MessageList.tsx +66 -47
  165. package/_standalone/components/ask/SessionHistory.tsx +86 -60
  166. package/_standalone/components/ask/SessionTabBar.tsx +29 -21
  167. package/_standalone/components/ask/ThinkingBlock.tsx +6 -5
  168. package/_standalone/components/ask/ToolCallBlock.tsx +10 -9
  169. package/_standalone/components/settings/SettingsContent.tsx +1 -1
  170. package/_standalone/data/skills/mindos/SKILL.md +67 -15
  171. package/_standalone/data/skills/mindos-zh/SKILL.md +67 -11
  172. package/_standalone/hooks/useAskSession.ts +23 -1
  173. package/_standalone/lib/stores/locale-store.ts +20 -6
  174. package/_standalone/tsconfig.tsbuildinfo +1 -1
  175. package/app/app/globals.css +2 -1
  176. package/app/app/layout.tsx +16 -4
  177. package/app/components/AskFab.tsx +4 -4
  178. package/app/components/AskModal.tsx +1 -1
  179. package/app/components/GuideCard.tsx +101 -152
  180. package/app/components/HomeContent.tsx +116 -575
  181. package/app/components/RightAskPanel.tsx +2 -2
  182. package/app/components/WikiHomeContent.tsx +151 -3
  183. package/app/components/ask/AskContent.tsx +90 -51
  184. package/app/components/ask/AskHeader.tsx +218 -18
  185. package/app/components/ask/MessageList.tsx +66 -47
  186. package/app/components/ask/SessionHistory.tsx +86 -60
  187. package/app/components/ask/SessionTabBar.tsx +29 -21
  188. package/app/components/ask/ThinkingBlock.tsx +6 -5
  189. package/app/components/ask/ToolCallBlock.tsx +10 -9
  190. package/app/components/settings/SettingsContent.tsx +1 -1
  191. package/app/data/skills/mindos/SKILL.md +67 -15
  192. package/app/data/skills/mindos-zh/SKILL.md +67 -11
  193. package/app/hooks/useAskSession.ts +23 -1
  194. package/app/lib/i18n/modules/ai-chat.ts +97 -10
  195. package/app/lib/i18n/modules/onboarding.ts +12 -12
  196. package/app/lib/stores/LocaleStoreInit.tsx +24 -1
  197. package/app/lib/stores/locale-store.ts +20 -6
  198. package/app/lib/types.ts +1 -0
  199. package/package.json +1 -1
  200. package/skills/mindos/SKILL.md +67 -15
  201. package/skills/mindos/references/knowledge-health.md +120 -0
  202. package/skills/mindos-max/SKILL.md +52 -5
  203. package/skills/mindos-max-zh/SKILL.md +55 -6
  204. package/skills/mindos-zh/SKILL.md +67 -11
  205. package/_standalone/.next/server/chunks/2364.js +0 -2
  206. package/_standalone/.next/server/chunks/357.js +0 -1
  207. package/_standalone/.next/static/chunks/178-105779afb62d36d9.js +0 -1
  208. package/_standalone/.next/static/chunks/2218-d54538000574ffef.js +0 -1
  209. package/_standalone/.next/static/chunks/2549-e63cf57fa927a41d.js +0 -1
  210. package/_standalone/.next/static/chunks/9274-296ab35f9f09e42e.js +0 -1
  211. package/_standalone/.next/static/chunks/app/agents/page-5d1446665ddb3801.js +0 -1
  212. package/_standalone/.next/static/chunks/app/echo/[segment]/page-b0103509ce34444b.js +0 -11
  213. package/_standalone/.next/static/chunks/app/layout-7e02ddf4144b01f1.js +0 -186
  214. package/_standalone/.next/static/chunks/app/page-6a6a12bd6d6812d0.js +0 -7
  215. package/_standalone/.next/static/chunks/app/view/[...path]/page-ca7bdcbf27f88a46.js +0 -12
  216. package/_standalone/.next/static/chunks/app/wiki/page-d492256a93f0b8bc.js +0 -1
  217. package/_standalone/.next/static/css/fd84c8316ead16eb.css +0 -1
  218. /package/_standalone/.next/static/{2ksXveDzEcnCMRIElDkLq → u8p6oIRTcr_ns-ElNZ9rl}/_buildManifest.js +0 -0
  219. /package/_standalone/.next/static/{2ksXveDzEcnCMRIElDkLq → u8p6oIRTcr_ns-ElNZ9rl}/_ssgManifest.js +0 -0
@@ -119,7 +119,7 @@ export default function RightAskPanel({
119
119
  <aside
120
120
  className={`
121
121
  hidden md:flex fixed top-0 right-0 h-screen z-40
122
- flex-col bg-card border-l border-border
122
+ flex-col bg-background border-l border-border/40 shadow-[-4px_0_16px_rgba(0,0,0,0.04)]
123
123
  transition-[width,transform] duration-200 ease-out
124
124
  ${open ? 'translate-x-0' : 'translate-x-full pointer-events-none'}
125
125
  `}
@@ -161,7 +161,7 @@ export default function RightAskPanel({
161
161
  className="absolute top-0 -left-[3px] w-[6px] h-full cursor-col-resize z-40 group hidden md:block"
162
162
  onMouseDown={handleMouseDown}
163
163
  >
164
- <div className="absolute left-[2px] top-0 w-[2px] h-full opacity-0 group-hover:opacity-100 bg-[var(--amber)]/60 transition-opacity" />
164
+ <div className="absolute left-[2px] top-0 w-[1px] h-full opacity-0 group-hover:opacity-100 bg-[var(--amber)]/50 transition-opacity duration-150" />
165
165
  </div>
166
166
  </aside>
167
167
  );
@@ -2,7 +2,8 @@
2
2
 
3
3
  import { useState, useEffect, useMemo } from 'react';
4
4
  import Link from 'next/link';
5
- import { Brain, ChevronDown, FolderOpen, Plus, Sparkles, Search, FilePlus, ArrowRight } from 'lucide-react';
5
+ import { Brain, ChevronDown, FolderOpen, Plus, Sparkles, Search, FilePlus, ArrowRight, Clock, FileText, Table, Star, X, History } from 'lucide-react';
6
+ import { usePinnedFiles } from '@/lib/hooks/usePinnedFiles';
6
7
  import { useLocale } from '@/lib/stores/locale-store';
7
8
  import { encodePath, relativeTime, extractEmoji, stripEmoji } from '@/lib/utils';
8
9
  import { InboxSection } from '@/components/home/InboxSection';
@@ -39,7 +40,7 @@ function getSpaceLatestMtime(spaceName: string, recentFiles: RecentFile[]): numb
39
40
  return maxMtime;
40
41
  }
41
42
 
42
- const SPACES_COLLAPSED = 9;
43
+ const SPACES_COLLAPSED = 6;
43
44
 
44
45
  export default function WikiHomeContent({ spaces, recent }: WikiHomeContentProps) {
45
46
  const { t } = useLocale();
@@ -107,7 +108,7 @@ export default function WikiHomeContent({ spaces, recent }: WikiHomeContentProps
107
108
  key={suggestionIdx}
108
109
  className="text-sm text-left text-muted-foreground animate-in fade-in duration-300"
109
110
  >
110
- {suggestions[suggestionIdx]}
111
+ {suggestions[suggestionIdx].label}
111
112
  </span>
112
113
  </div>
113
114
  <kbd className="hidden sm:inline-flex items-center gap-0.5 px-2 py-0.5 rounded text-xs font-mono font-medium bg-[var(--amber-dim)] text-[var(--amber-text)]">
@@ -263,6 +264,17 @@ export default function WikiHomeContent({ spaces, recent }: WikiHomeContentProps
263
264
  {/* ══════════ Inbox ══════════ */}
264
265
  <InboxSection />
265
266
 
267
+ {/* ══════════ Pinned Files ══════════ */}
268
+ <PinnedFilesSection formatTime={formatTime} />
269
+
270
+ {/* ── Visual divider ── */}
271
+ <div className="border-t border-border/30 mb-8" />
272
+
273
+ {/* ══════════ Recently Edited (flat list) ══════════ */}
274
+ {recent.length > 0 && (
275
+ <RecentlyEditedSection recent={recent} formatTime={formatTime} />
276
+ )}
277
+
266
278
  {/* Footer */}
267
279
  <div className="py-6 border-t border-border/20 flex items-center gap-1.5 text-xs font-display text-muted-foreground/30">
268
280
  <Sparkles size={10} className="text-[var(--amber)]/40" />
@@ -271,3 +283,139 @@ export default function WikiHomeContent({ spaces, recent }: WikiHomeContentProps
271
283
  </div>
272
284
  );
273
285
  }
286
+
287
+ /* ── Section Title ── */
288
+ function SectionTitle({ icon, children, count, action }: {
289
+ icon: React.ReactNode;
290
+ children: React.ReactNode;
291
+ count?: number;
292
+ action?: React.ReactNode;
293
+ }) {
294
+ return (
295
+ <div className="flex items-center gap-2.5 mb-4">
296
+ <div className="flex items-center justify-center w-6 h-6 rounded-md bg-[var(--amber-subtle)] text-[var(--amber)]">
297
+ {icon}
298
+ </div>
299
+ <h2 className="text-[13px] font-semibold text-foreground tracking-wide">
300
+ {children}
301
+ </h2>
302
+ {count != null && count > 0 && (
303
+ <span className="inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 text-[10px] font-semibold rounded-full bg-muted text-muted-foreground tabular-nums">{count}</span>
304
+ )}
305
+ {action ? <div className="ml-auto">{action}</div> : null}
306
+ </div>
307
+ );
308
+ }
309
+
310
+ /* ── Pinned Files Section ── */
311
+ function PinnedFilesSection({ formatTime }: { formatTime: (t: number) => string }) {
312
+ const { t } = useLocale();
313
+ const { pinnedFiles, removePin } = usePinnedFiles();
314
+
315
+ if (pinnedFiles.length === 0) return null;
316
+
317
+ return (
318
+ <section className="mb-8">
319
+ <SectionTitle icon={<Star size={14} />} count={pinnedFiles.length}>
320
+ {t.pinnedFiles.title}
321
+ </SectionTitle>
322
+ <div className="flex flex-col gap-0.5">
323
+ {pinnedFiles.map((filePath) => {
324
+ const name = filePath.split('/').pop() || filePath;
325
+ const dir = filePath.split('/').slice(0, -1).join('/');
326
+ const isCSV = filePath.endsWith('.csv');
327
+ return (
328
+ <div key={filePath} className="group/pin relative">
329
+ <Link
330
+ href={`/view/${encodePath(filePath)}`}
331
+ className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted overflow-hidden"
332
+ >
333
+ <Star size={12} className="shrink-0 fill-[var(--amber)] text-[var(--amber)]" />
334
+ {isCSV
335
+ ? <Table size={12} className="shrink-0 text-success" />
336
+ : <FileText size={12} className="shrink-0 text-muted-foreground" />
337
+ }
338
+ <div className="flex-1 min-w-0">
339
+ <span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
340
+ {dir && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{dir}</span>}
341
+ </div>
342
+ </Link>
343
+ <button
344
+ onClick={(e) => { e.preventDefault(); e.stopPropagation(); removePin(filePath); }}
345
+ className="absolute right-2 top-1/2 -translate-y-1/2 hidden group-hover/pin:flex p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
346
+ title={t.pinnedFiles.removedToast}
347
+ >
348
+ <X size={12} />
349
+ </button>
350
+ </div>
351
+ );
352
+ })}
353
+ </div>
354
+ </section>
355
+ );
356
+ }
357
+
358
+ /* ── Recently Edited Section ── */
359
+ const RECENT_FILES_LIMIT = 8;
360
+
361
+ function RecentlyEditedSection({ recent, formatTime }: { recent: RecentFile[]; formatTime: (t: number) => string }) {
362
+ const { t } = useLocale();
363
+ const [showAll, setShowAll] = useState(false);
364
+
365
+ return (
366
+ <section className="mb-8">
367
+ <SectionTitle
368
+ icon={<Clock size={14} />}
369
+ count={recent.length}
370
+ action={
371
+ <Link
372
+ href="/changes"
373
+ className="flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80"
374
+ >
375
+ <History size={12} />
376
+ <span>{t.home.changeHistory}</span>
377
+ </Link>
378
+ }
379
+ >
380
+ {t.home.recentlyEdited}
381
+ </SectionTitle>
382
+
383
+ <div className="flex flex-col gap-0.5">
384
+ {(showAll ? recent : recent.slice(0, RECENT_FILES_LIMIT)).map(({ path: filePath, mtime }) => {
385
+ const name = filePath.split('/').pop() || filePath;
386
+ const dir = filePath.split('/').slice(0, -1).join('/');
387
+ const isCSV = filePath.endsWith('.csv');
388
+ return (
389
+ <Link
390
+ key={filePath}
391
+ href={`/view/${encodePath(filePath)}`}
392
+ className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted group overflow-hidden"
393
+ >
394
+ {isCSV
395
+ ? <Table size={12} className="shrink-0 text-success" />
396
+ : <FileText size={12} className="shrink-0 text-muted-foreground" />
397
+ }
398
+ <div className="flex-1 min-w-0">
399
+ <span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
400
+ {dir && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{dir}</span>}
401
+ </div>
402
+ <span className="text-xs shrink-0 tabular-nums text-muted-foreground/40" suppressHydrationWarning>
403
+ {formatTime(mtime)}
404
+ </span>
405
+ </Link>
406
+ );
407
+ })}
408
+ </div>
409
+ {recent.length > RECENT_FILES_LIMIT && (
410
+ <button
411
+ onClick={() => setShowAll(v => !v)}
412
+ aria-expanded={showAll}
413
+ className="flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer mt-2 ml-1"
414
+ >
415
+ <ChevronDown size={12} className={`transition-transform duration-200 ${showAll ? 'rotate-180' : ''}`} />
416
+ <span>{showAll ? t.home.showLess : t.home.showMore}</span>
417
+ </button>
418
+ )}
419
+ </section>
420
+ );
421
+ }
@@ -15,7 +15,6 @@ import MessageList from '@/components/ask/MessageList';
15
15
  import MentionPopover from '@/components/ask/MentionPopover';
16
16
  import SlashCommandPopover from '@/components/ask/SlashCommandPopover';
17
17
  import SessionHistory from '@/components/ask/SessionHistory';
18
- import SessionTabBar from '@/components/ask/SessionTabBar';
19
18
  import AskHeader from '@/components/ask/AskHeader';
20
19
  import FileChip from '@/components/ask/FileChip';
21
20
  import AgentSelectorCapsule from '@/components/ask/AgentSelectorCapsule';
@@ -65,8 +64,8 @@ interface AskContentProps {
65
64
  /** ACP agent pre-selected via "Use" button from A2A tab */
66
65
  initialAcpAgent?: AcpAgentSelection | null;
67
66
  onFirstMessage?: () => void;
68
- /** 'modal' renders close button + ESC handler; 'panel' renders compact header */
69
- variant: 'modal' | 'panel';
67
+ /** 'modal' renders close button + ESC handler; 'panel' renders compact header; 'home' renders embedded on homepage */
68
+ variant: 'modal' | 'panel' | 'home';
70
69
  /** Required for modal variant — called on close button / ESC / backdrop click */
71
70
  onClose?: () => void;
72
71
  maximized?: boolean;
@@ -79,6 +78,7 @@ interface AskContentProps {
79
78
 
80
79
  export default function AskContent({ visible, currentFile, initialMessage, initialAcpAgent, onFirstMessage, variant, onClose, maximized, onMaximize, askMode, onModeSwitch }: AskContentProps) {
81
80
  const isPanel = variant === 'panel';
81
+ const isHome = variant === 'home';
82
82
 
83
83
  const inputRef = useRef<HTMLTextAreaElement>(null);
84
84
  const imageInputRef = useRef<HTMLInputElement>(null);
@@ -160,12 +160,26 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
160
160
  return () => window.removeEventListener('mindos:inject-ask-files', handler);
161
161
  }, []);
162
162
 
163
+ // Home suggestion chip click — inject text into input
164
+ useEffect(() => {
165
+ if (!isHome) return;
166
+ const handler = (e: Event) => {
167
+ const text = (e as CustomEvent).detail?.text;
168
+ if (typeof text === 'string') {
169
+ setInput(text);
170
+ setTimeout(() => inputRef.current?.focus(), 50);
171
+ }
172
+ };
173
+ window.addEventListener('mindos:home-suggestion', handler);
174
+ return () => window.removeEventListener('mindos:home-suggestion', handler);
175
+ }, [isHome]);
176
+
163
177
  // Focus and init session when becoming visible (edge-triggered for panel, level-triggered for modal)
164
178
  const prevVisibleRef = useRef(false);
165
179
  const prevFileRef = useRef(currentFile);
166
180
  useEffect(() => {
167
- const justOpened = variant === 'panel'
168
- ? (visible && !prevVisibleRef.current) // panel: edge detection
181
+ const justOpened = variant === 'panel' || variant === 'home'
182
+ ? (visible && !prevVisibleRef.current) // panel/home: edge detection
169
183
  : visible; // modal: level detection (reset every open)
170
184
 
171
185
  // Detect file change while panel is already open
@@ -173,14 +187,15 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
173
187
 
174
188
  if (justOpened) {
175
189
  setTimeout(() => inputRef.current?.focus(), 50);
190
+ // Home variant: also load sessions so user can switch
176
191
  void session.initSessions();
177
192
  setInput(initialMessage || '');
178
193
  chat.firstMessageFired.current = false;
179
194
  setAttachedFiles(currentFile ? [currentFile] : []);
180
- upload.clearAttachments();
181
- imageUpload.clearImages();
182
- mention.resetMention();
183
- slash.resetSlash();
195
+ upload.clearAttachments();
196
+ imageUpload.clearImages();
197
+ mention.resetMention();
198
+ slash.resetSlash();
184
199
  setSelectedSkill(null);
185
200
  setSelectedAcpAgent(initialAcpAgent ?? null);
186
201
  setShowHistory(false);
@@ -191,6 +206,10 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
191
206
  // Modal: abort streaming on close
192
207
  chat.abortRef.current?.abort();
193
208
  }
209
+ // Home variant: auto-focus on mount
210
+ if (variant === 'home' && visible && !prevVisibleRef.current) {
211
+ setTimeout(() => inputRef.current?.focus(), 150);
212
+ }
194
213
  prevVisibleRef.current = visible;
195
214
  prevFileRef.current = currentFile;
196
215
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -209,9 +228,9 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
209
228
  // eslint-disable-next-line react-hooks/exhaustive-deps
210
229
  }, [visible, session.messages, session.activeSessionId, chat.isLoading]);
211
230
 
212
- // Esc to close modal or exit focus mode
231
+ // Esc to close modal or exit focus mode (skip for home variant)
213
232
  useEffect(() => {
214
- if (!visible) return;
233
+ if (!visible || variant === 'home') return;
215
234
  const isModal = variant === 'modal';
216
235
  const isFocused = variant === 'panel' && maximized;
217
236
  if (!isModal && !isFocused) return;
@@ -376,6 +395,7 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
376
395
  setSelectedSkill(null);
377
396
  setSelectedAcpAgent(null);
378
397
  setShowHistory(false);
398
+ chat.firstMessageFired.current = false;
379
399
  setTimeout(() => inputRef.current?.focus(), 0);
380
400
  }, [currentFile]);
381
401
 
@@ -438,34 +458,31 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
438
458
  thinking: t.ask.thinking,
439
459
  generating: t.ask.generating,
440
460
  reconnecting: reconnectAttempt > 0 ? t.ask.reconnecting(reconnectAttempt, reconnectMaxRef.current) : undefined,
461
+ copyMessage: t.ask.copyMessage,
441
462
  }), [t, reconnectAttempt]);
442
463
 
443
464
  return (
444
465
  <>
466
+ {/* Header — home variant shows session switcher + new/history/fullscreen buttons */}
445
467
  <AskHeader
446
- isPanel={isPanel}
468
+ isPanel={isPanel || isHome}
447
469
  showHistory={showHistory}
448
470
  onToggleHistory={toggleHistory}
449
471
  onReset={handleResetSession}
450
472
  isLoading={isLoading}
451
473
  maximized={maximized}
452
- onMaximize={onMaximize}
453
- askMode={askMode}
454
- onModeSwitch={onModeSwitch}
455
- onClose={onClose}
474
+ onMaximize={isHome ? onMaximize : onMaximize}
475
+ askMode={isHome ? undefined : askMode}
476
+ onModeSwitch={isHome ? undefined : onModeSwitch}
477
+ onClose={isHome ? undefined : onClose}
478
+ sessions={session.sessions}
479
+ activeSessionId={session.activeSessionId}
480
+ onLoadSession={handleLoadSession}
481
+ onDeleteSession={session.deleteSession}
482
+ onRenameSession={session.renameSession}
483
+ onTogglePinSession={session.togglePinSession}
456
484
  />
457
485
 
458
- {/* Session tabs — panel variant only */}
459
- {isPanel && session.sessions.length > 0 && (
460
- <SessionTabBar
461
- sessions={session.sessions}
462
- activeSessionId={session.activeSessionId}
463
- onLoad={handleLoadSession}
464
- onDelete={session.deleteSession}
465
- onNew={handleResetSession}
466
- />
467
- )}
468
-
469
486
  {showHistory && (
470
487
  <SessionHistory
471
488
  sessions={session.sessions}
@@ -473,6 +490,7 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
473
490
  onLoad={handleLoadSession}
474
491
  onDelete={session.deleteSession}
475
492
  onRename={session.renameSession}
493
+ onTogglePin={session.togglePinSession}
476
494
  onClearAll={session.clearAllSessions}
477
495
  labels={{
478
496
  title: t.ask.sessionHistory ?? 'Session History',
@@ -485,16 +503,31 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
485
503
  )}
486
504
 
487
505
  {/* Messages */}
488
- <MessageList
489
- messages={session.messages}
490
- isLoading={isLoading}
491
- loadingPhase={loadingPhase}
492
- emptyPrompt={t.ask.emptyPrompt}
493
- emptyHint={t.ask.emptyHint}
494
- suggestions={t.ask.suggestions}
495
- onSuggestionClick={setInput}
496
- labels={messageLabels}
497
- />
506
+ {/* Messages — home variant hides empty state (suggestions rendered externally) */}
507
+ {!isHome && (
508
+ <MessageList
509
+ messages={session.messages}
510
+ isLoading={isLoading}
511
+ loadingPhase={loadingPhase}
512
+ emptyPrompt={t.ask.emptyPrompt}
513
+ emptyHint={t.ask.emptyHint}
514
+ suggestions={t.ask.suggestions}
515
+ onSuggestionClick={setInput}
516
+ labels={messageLabels}
517
+ />
518
+ )}
519
+ {isHome && session.messages.length > 0 && (
520
+ <MessageList
521
+ messages={session.messages}
522
+ isLoading={isLoading}
523
+ loadingPhase={loadingPhase}
524
+ emptyPrompt={t.ask.emptyPrompt}
525
+ emptyHint={t.ask.emptyHint}
526
+ suggestions={[]}
527
+ onSuggestionClick={setInput}
528
+ labels={messageLabels}
529
+ />
530
+ )}
498
531
 
499
532
  {/* Popovers — flex children so they stay within overflow boundary (absolute positioning would be clipped by RightAskPanel's overflow-hidden) */}
500
533
  {mention.mentionQuery !== null && mention.mentionResults.length > 0 && (
@@ -519,11 +552,11 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
519
552
  </div>
520
553
  )}
521
554
 
522
- {/* Composer card — unified input area with rounded container */}
523
- <div className="shrink-0 px-3 pb-2 pt-1">
555
+ {/* Composer card — unified input area */}
556
+ <div className="shrink-0 px-3 pb-2.5 pt-1">
524
557
  <div
525
558
  className={cn(
526
- 'rounded-xl border border-border/60 bg-card shadow-sm transition-shadow',
559
+ 'rounded-xl bg-muted/40 transition-all focus-within:bg-muted/60',
527
560
  isDragOver && 'ring-2 ring-[var(--amber)] bg-[var(--amber-dim)]',
528
561
  )}
529
562
  onDragOver={handleDragOver}
@@ -568,23 +601,23 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
568
601
  <form
569
602
  ref={formRef}
570
603
  onSubmit={handleSubmit}
571
- className="flex items-end gap-1 px-1.5 py-1.5"
604
+ className="flex items-end gap-1.5 px-3 py-2"
572
605
  >
573
606
  {/* + attach button with mini menu */}
574
607
  <div className="relative shrink-0">
575
608
  <button
576
609
  type="button"
577
610
  onClick={() => setShowAttachMenu(v => !v)}
578
- className="p-1.5 rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted/60 transition-colors"
611
+ className="p-2 rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted/60 transition-colors"
579
612
  title={t.hints.attachFile}
580
613
  >
581
614
  <Plus size={inputIconSize} />
582
615
  </button>
583
616
  {showAttachMenu && (
584
- <div className="absolute bottom-full left-0 mb-1 py-1 rounded-lg border border-border bg-card shadow-lg z-50 min-w-[140px]">
617
+ <div className="absolute bottom-full left-0 mb-1.5 py-1 rounded-xl border border-border/60 bg-card shadow-lg z-50 min-w-[150px] animate-in fade-in-0 slide-in-from-bottom-2 duration-150">
585
618
  <button
586
619
  type="button"
587
- className="flex w-full items-center gap-2 px-3 py-1.5 text-xs hover:bg-muted transition-colors text-left"
620
+ className="flex w-full items-center gap-2.5 px-3 py-2 text-xs hover:bg-muted transition-colors text-left rounded-lg"
588
621
  onClick={() => { setShowAttachMenu(false); upload.uploadInputRef.current?.click(); }}
589
622
  >
590
623
  <FileText size={12} className="shrink-0 text-muted-foreground" />
@@ -592,7 +625,7 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
592
625
  </button>
593
626
  <button
594
627
  type="button"
595
- className="flex w-full items-center gap-2 px-3 py-1.5 text-xs hover:bg-muted transition-colors text-left"
628
+ className="flex w-full items-center gap-2.5 px-3 py-2 text-xs hover:bg-muted transition-colors text-left rounded-lg"
596
629
  onClick={() => { setShowAttachMenu(false); imageInputRef.current?.click(); }}
597
630
  >
598
631
  <ImageIcon size={12} className="shrink-0 text-muted-foreground" />
@@ -637,23 +670,24 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
637
670
  onPaste={handlePaste}
638
671
  placeholder={t.ask.placeholder}
639
672
  rows={1}
640
- className="min-w-0 flex-1 resize-none overflow-y-hidden bg-transparent py-1.5 text-sm leading-snug text-foreground placeholder:text-muted-foreground outline-none focus-visible:ring-0"
673
+ className="min-w-0 flex-1 resize-none overflow-y-hidden bg-transparent py-2 text-sm leading-relaxed text-foreground placeholder:text-muted-foreground/50 outline-none focus-visible:ring-0"
641
674
  />
642
675
 
643
676
  {isLoading ? (
644
- <button type="button" onClick={handleStop} className="p-1.5 rounded-lg transition-colors shrink-0 text-muted-foreground hover:text-foreground hover:bg-muted/60" title={loadingPhase === 'reconnecting' ? t.ask.cancelReconnect : t.ask.stopTitle}>
677
+ <button type="button" onClick={handleStop} className="p-2 rounded-xl transition-colors shrink-0 text-foreground bg-muted hover:bg-muted/80" title={loadingPhase === 'reconnecting' ? t.ask.cancelReconnect : t.ask.stopTitle}>
645
678
  {loadingPhase === 'reconnecting' ? <X size={inputIconSize} /> : <StopCircle size={inputIconSize} />}
646
679
  </button>
647
680
  ) : (
648
- <button type="submit" disabled={!input.trim() && imageUpload.images.length === 0} className="p-1.5 rounded-lg disabled:opacity-40 disabled:cursor-not-allowed transition-opacity shrink-0 bg-[var(--amber)] text-[var(--amber-foreground)]">
681
+ <button type="submit" disabled={!input.trim() && imageUpload.images.length === 0} className="p-2 rounded-xl disabled:opacity-20 disabled:scale-95 disabled:cursor-not-allowed transition-all duration-150 shrink-0 bg-[var(--amber)] text-[var(--amber-foreground)] shadow-sm shadow-[var(--amber)]/15 hover:shadow-md hover:shadow-[var(--amber)]/20 active:scale-95">
649
682
  <Send size={14} />
650
683
  </button>
651
684
  )}
652
685
  </form>
653
686
 
654
- {/* Mode + Agent + Provider selector row inside card bottom */}
655
- <div className="flex items-center gap-1.5 px-3 pb-2 pt-0.5 border-t border-border/30">
656
- <ModeCapsule mode={chatMode} onChange={setChatMode} disabled={isLoading} />
687
+ {/* Mode + Agent + Provider selector row + keyboard hint */}
688
+ <div className="flex items-center justify-between px-3 pb-2 pt-1.5 border-t border-border/10">
689
+ <div className="flex items-center gap-2">
690
+ <ModeCapsule mode={chatMode} onChange={setChatMode} disabled={isLoading} />
657
691
  {mounted && acpDetection.installedAgents.length > 0 && (
658
692
  <AgentSelectorCapsule
659
693
  selectedAgent={selectedAcpAgent}
@@ -669,6 +703,11 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
669
703
  disabled={isLoading}
670
704
  />
671
705
  )}
706
+ </div>
707
+ {/* Keyboard hint */}
708
+ <span className="hidden md:inline text-2xs text-muted-foreground/40 select-none">
709
+ <kbd className="font-mono">Enter</kbd> {t.ask.send} · <kbd className="font-mono">Shift+Enter</kbd> {t.ask.newlineHint}
710
+ </span>
672
711
  </div>
673
712
  </div>
674
713
  </div>