@geminilight/mindos 0.6.57 → 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.
- package/_standalone/.mindos-build-version +1 -1
- package/_standalone/.next/BUILD_ID +1 -1
- package/_standalone/.next/app-path-routes-manifest.json +24 -24
- package/_standalone/.next/build-manifest.json +3 -3
- package/_standalone/.next/cache/.previewinfo +1 -1
- package/_standalone/.next/cache/.rscinfo +1 -1
- package/_standalone/.next/cache/config.json +3 -3
- package/_standalone/.next/prerender-manifest.json +3 -3
- package/_standalone/.next/react-loadable-manifest.json +1 -1
- package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error.html +2 -2
- package/_standalone/.next/server/app/_global-error.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/_standalone/.next/server/app/_not-found/page.js +1 -1
- package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page.js +2 -2
- package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/agents/page.js +2 -2
- package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/config/route.js +1 -1
- package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/detect/route.js +1 -1
- package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/detect/route.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/route.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask/route.js +5 -5
- package/_standalone/.next/server/app/api/ask/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/backlinks/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/bootstrap/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/changes/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/export/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/import/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/raw/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/graph/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/inbox/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/init/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route.js +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install/route.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/status/route.js +1 -1
- package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/reset-token/route.js +1 -1
- package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/route.js +1 -1
- package/_standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/test-key/route.js +1 -1
- package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/route.js +1 -1
- package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/skills/route.js +1 -1
- package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/tree-version/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/workflows/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/changes/page.js +2 -2
- package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/echo/[segment]/page.js +3 -3
- package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/echo/page.js +1 -1
- package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/explore/page.js +3 -3
- package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/help/page.js +2 -2
- package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/inbox/history/page.js +1 -1
- package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/login/page.js +2 -2
- package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/page.js +2 -8
- package/_standalone/.next/server/app/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/setup/page.js +2 -2
- package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/trash/page.js +3 -3
- package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/view/[...path]/page.js +3 -3
- package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/wiki/page.js +2 -2
- package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app-paths-manifest.json +24 -24
- package/_standalone/.next/server/chunks/1550.js +1 -1
- package/_standalone/.next/server/chunks/1750.js +1 -1
- package/_standalone/.next/server/chunks/3484.js +1 -1
- package/_standalone/.next/server/chunks/530.js +61 -62
- package/_standalone/.next/server/chunks/6539.js +1 -1
- package/_standalone/.next/server/chunks/{2159.js → 8343.js} +2 -2
- package/_standalone/.next/server/chunks/9787.js +2 -0
- package/_standalone/.next/server/middleware-build-manifest.js +1 -1
- package/_standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/_standalone/.next/server/pages/500.html +2 -2
- package/_standalone/.next/server/server-reference-manifest.js +1 -1
- package/_standalone/.next/server/server-reference-manifest.json +1 -1
- package/_standalone/.next/static/chunks/{1814.a7c127b2c73d1f70.js → 1814.a79b84d37df75c43.js} +1 -1
- package/_standalone/.next/static/chunks/3427-2e61a5df1f5e55fb.js +1 -0
- package/_standalone/.next/static/chunks/5581-dac72e9f16e5ea29.js +29 -0
- package/_standalone/.next/static/chunks/6297-085daa21037d5f81.js +1 -0
- package/_standalone/.next/static/chunks/7249-6cf8f2b78718c59e.js +11 -0
- package/_standalone/.next/static/chunks/8520-56ec9ff087c15204.js +22 -0
- package/_standalone/.next/static/chunks/9905-a19d379cb225246e.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/{page-7bdeab5af8e4f5f2.js → page-35ea6de1af2be3b5.js} +1 -1
- package/_standalone/.next/static/chunks/app/agents/page-b172ea3743adb047.js +1 -0
- package/_standalone/.next/static/chunks/app/changes/{page-5a72144d1080a699.js → page-6d2f49651c0061f7.js} +1 -1
- package/_standalone/.next/static/chunks/app/echo/[segment]/page-84b95256f6e38aae.js +11 -0
- package/_standalone/.next/static/chunks/app/explore/{page-d3d99308146c2240.js → page-d9f58000bc445360.js} +2 -2
- package/_standalone/.next/static/chunks/app/help/{page-222df603080b5fab.js → page-f8cb806371b3175f.js} +1 -1
- package/_standalone/.next/static/chunks/app/inbox/history/{page-07819cf95cb0805f.js → page-26e71fb6f716a4c4.js} +1 -1
- package/_standalone/.next/static/chunks/app/layout-b89b0d955f39a753.js +164 -0
- package/_standalone/.next/static/chunks/app/login/{page-0eeef685052869a6.js → page-18fb00d568cd1f0e.js} +1 -1
- package/_standalone/.next/static/chunks/app/page-a8e6f085f38388bf.js +1 -0
- package/_standalone/.next/static/chunks/app/setup/{page-99fcfc460fa29733.js → page-821714e7477be46c.js} +1 -1
- package/_standalone/.next/static/chunks/app/trash/page-f92b728b78ac0f7e.js +1 -0
- package/_standalone/.next/static/chunks/app/view/[...path]/{not-found-fc04c2bd4f35bc6f.js → not-found-6e0c75ad26ce8572.js} +1 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/page-f87f4901b5e1a88f.js +12 -0
- package/_standalone/.next/static/chunks/app/wiki/page-641edb1f3cff2f93.js +1 -0
- package/_standalone/.next/static/chunks/{webpack-2c19436659aa657b.js → webpack-72e8d9e9073fd1f9.js} +1 -1
- package/_standalone/.next/static/css/6c104b118d3bc9b7.css +1 -0
- package/_standalone/.next/trace +64 -64
- package/_standalone/__tests__/api/mcp-install.test.ts +3 -2
- package/_standalone/__tests__/ask/non-streaming-api.test.ts +281 -0
- package/_standalone/__tests__/core/skill-install-logic.test.ts +1 -0
- package/_standalone/app/globals.css +2 -1
- package/_standalone/components/AskFab.tsx +4 -4
- package/_standalone/components/AskModal.tsx +1 -1
- package/_standalone/components/GuideCard.tsx +101 -152
- package/_standalone/components/RightAskPanel.tsx +2 -2
- package/_standalone/components/agents/CustomAgentModal.tsx +32 -8
- package/_standalone/components/ask/AskContent.tsx +90 -51
- package/_standalone/components/ask/AskHeader.tsx +218 -18
- package/_standalone/components/ask/MessageList.tsx +66 -47
- package/_standalone/components/ask/SessionHistory.tsx +86 -60
- package/_standalone/components/ask/SessionTabBar.tsx +29 -21
- package/_standalone/components/ask/ThinkingBlock.tsx +6 -5
- package/_standalone/components/ask/ToolCallBlock.tsx +10 -9
- package/_standalone/components/settings/SettingsContent.tsx +1 -1
- package/_standalone/data/skills/mindos/SKILL.md +72 -15
- package/_standalone/data/skills/mindos-zh/SKILL.md +73 -8
- package/_standalone/hooks/useAskSession.ts +23 -1
- package/_standalone/lib/stores/locale-store.ts +20 -6
- package/_standalone/tsconfig.tsbuildinfo +1 -1
- package/app/app/api/agents/custom/route.ts +8 -0
- package/app/app/api/ask/route.ts +171 -10
- package/app/app/api/mcp/agents/route.ts +5 -3
- package/app/app/api/settings/route.ts +9 -0
- package/app/app/api/settings/test-key/route.ts +13 -1
- package/app/app/globals.css +2 -1
- package/app/app/layout.tsx +16 -4
- package/app/components/AskFab.tsx +4 -4
- package/app/components/AskModal.tsx +1 -1
- package/app/components/GuideCard.tsx +101 -152
- package/app/components/HomeContent.tsx +116 -575
- package/app/components/RightAskPanel.tsx +2 -2
- package/app/components/WikiHomeContent.tsx +151 -3
- package/app/components/agents/CustomAgentModal.tsx +32 -8
- package/app/components/ask/AskContent.tsx +90 -51
- package/app/components/ask/AskHeader.tsx +218 -18
- package/app/components/ask/MessageList.tsx +66 -47
- package/app/components/ask/SessionHistory.tsx +86 -60
- package/app/components/ask/SessionTabBar.tsx +29 -21
- package/app/components/ask/ThinkingBlock.tsx +6 -5
- package/app/components/ask/ToolCallBlock.tsx +10 -9
- package/app/components/settings/SettingsContent.tsx +1 -1
- package/app/data/skills/mindos/SKILL.md +72 -15
- package/app/data/skills/mindos-zh/SKILL.md +73 -8
- package/app/hooks/useAskSession.ts +23 -1
- package/app/lib/custom-agents.ts +45 -2
- package/app/lib/i18n/modules/ai-chat.ts +97 -10
- package/app/lib/i18n/modules/onboarding.ts +12 -12
- package/app/lib/i18n/modules/panels.ts +10 -2
- package/app/lib/mcp-agents.ts +10 -0
- package/app/lib/stores/LocaleStoreInit.tsx +24 -1
- package/app/lib/stores/locale-store.ts +20 -6
- package/app/lib/types.ts +1 -0
- package/bin/lib/mcp-agents.js +10 -0
- package/package.json +1 -1
- package/skills/mindos/SKILL.md +69 -11
- package/skills/mindos/references/knowledge-health.md +120 -0
- package/skills/mindos-max/SKILL.md +238 -0
- package/skills/mindos-max-workspace/evals/evals.json +23 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/eval_metadata.json +11 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/old_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/old_skill/outputs/transcript.md +203 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/with_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/with_skill/outputs/transcript.md +271 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/eval_metadata.json +11 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/old_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/old_skill/outputs/transcript.md +121 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/with_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/with_skill/outputs/transcript.md +168 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/eval_metadata.json +11 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/old_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/old_skill/outputs/transcript.md +143 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/with_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/with_skill/outputs/transcript.md +233 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/SKILL.md +165 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/README.md +12 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/post-task-hooks.md +27 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/preference-capture.md +41 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/sop-template.md +74 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/write-supplement.md +119 -0
- package/skills/mindos-max-zh/SKILL.md +241 -0
- package/skills/mindos-zh/SKILL.md +72 -8
- package/_standalone/.next/server/chunks/2364.js +0 -2
- package/_standalone/.next/server/chunks/357.js +0 -1
- package/_standalone/.next/static/chunks/1053-5cb008a24930e271.js +0 -29
- package/_standalone/.next/static/chunks/178-105779afb62d36d9.js +0 -1
- package/_standalone/.next/static/chunks/2218-d54538000574ffef.js +0 -1
- package/_standalone/.next/static/chunks/2549-e63cf57fa927a41d.js +0 -1
- package/_standalone/.next/static/chunks/7249-8cd568ad23656622.js +0 -11
- package/_standalone/.next/static/chunks/9274-296ab35f9f09e42e.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/page-5d1446665ddb3801.js +0 -1
- package/_standalone/.next/static/chunks/app/echo/[segment]/page-b0103509ce34444b.js +0 -11
- package/_standalone/.next/static/chunks/app/layout-b3919384ec2eb979.js +0 -186
- package/_standalone/.next/static/chunks/app/page-6436a99cda35132b.js +0 -7
- package/_standalone/.next/static/chunks/app/trash/page-8dc388695344fdd4.js +0 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/page-b292b55305ecc021.js +0 -12
- package/_standalone/.next/static/chunks/app/wiki/page-d492256a93f0b8bc.js +0 -1
- package/_standalone/.next/static/css/fd84c8316ead16eb.css +0 -1
- /package/_standalone/.next/static/{zOaEtgJbdRMncnCBucULp → u8p6oIRTcr_ns-ElNZ9rl}/_buildManifest.js +0 -0
- /package/_standalone/.next/static/{zOaEtgJbdRMncnCBucULp → u8p6oIRTcr_ns-ElNZ9rl}/_ssgManifest.js +0 -0
|
@@ -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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
655
|
-
<div className="flex items-center
|
|
656
|
-
<
|
|
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>
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { memo } from 'react';
|
|
2
|
-
import {
|
|
1
|
+
import { memo, useState, useRef, useEffect, useCallback } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import { Sparkles, SquarePen, History, X, Maximize2, Minimize2, PanelRight, AppWindow, ChevronDown, Check, Trash2, Pencil, Pin, PinOff } from 'lucide-react';
|
|
3
4
|
import { useLocale } from '@/lib/stores/locale-store';
|
|
5
|
+
import type { ChatSession } from '@/lib/types';
|
|
6
|
+
import { sessionTitle } from '@/hooks/useAskSession';
|
|
4
7
|
|
|
5
8
|
interface AskHeaderProps {
|
|
6
9
|
isPanel: boolean;
|
|
@@ -13,49 +16,246 @@ interface AskHeaderProps {
|
|
|
13
16
|
askMode?: 'panel' | 'popup';
|
|
14
17
|
onModeSwitch?: () => void;
|
|
15
18
|
onClose?: () => void;
|
|
19
|
+
hideTitle?: boolean;
|
|
20
|
+
/** Session switching — inline in header when >=2 sessions */
|
|
21
|
+
sessions?: ChatSession[];
|
|
22
|
+
activeSessionId?: string | null;
|
|
23
|
+
onLoadSession?: (id: string) => void;
|
|
24
|
+
onDeleteSession?: (id: string) => void;
|
|
25
|
+
onRenameSession?: (id: string, name: string) => void;
|
|
26
|
+
onTogglePinSession?: (id: string) => void;
|
|
16
27
|
}
|
|
17
28
|
|
|
18
29
|
export default memo(function AskHeader({
|
|
19
30
|
isPanel, showHistory, onToggleHistory, onReset, isLoading,
|
|
20
|
-
maximized, onMaximize, askMode, onModeSwitch, onClose,
|
|
31
|
+
maximized, onMaximize, askMode, onModeSwitch, onClose, hideTitle,
|
|
32
|
+
sessions, activeSessionId, onLoadSession, onDeleteSession, onRenameSession, onTogglePinSession,
|
|
21
33
|
}: AskHeaderProps) {
|
|
22
34
|
const { t } = useLocale();
|
|
23
|
-
const iconSize =
|
|
35
|
+
const iconSize = 14;
|
|
36
|
+
const hasMultipleSessions = sessions && sessions.length >= 1;
|
|
37
|
+
const activeSession = sessions?.find(s => s.id === activeSessionId);
|
|
38
|
+
const activeTitle = activeSession ? sessionTitle(activeSession) : null;
|
|
39
|
+
|
|
40
|
+
// Session switcher dropdown state
|
|
41
|
+
const [switcherOpen, setSwitcherOpen] = useState(false);
|
|
42
|
+
const switcherRef = useRef<HTMLButtonElement>(null);
|
|
43
|
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
44
|
+
|
|
45
|
+
// Inline rename state
|
|
46
|
+
const [renamingId, setRenamingId] = useState<string | null>(null);
|
|
47
|
+
const [renameValue, setRenameValue] = useState('');
|
|
48
|
+
const renameInputRef = useRef<HTMLInputElement>(null);
|
|
49
|
+
|
|
50
|
+
// Close on outside click
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!switcherOpen) return;
|
|
53
|
+
const handler = (e: MouseEvent) => {
|
|
54
|
+
const target = e.target as Node;
|
|
55
|
+
if (
|
|
56
|
+
switcherRef.current && !switcherRef.current.contains(target) &&
|
|
57
|
+
dropdownRef.current && !dropdownRef.current.contains(target)
|
|
58
|
+
) {
|
|
59
|
+
setSwitcherOpen(false);
|
|
60
|
+
setRenamingId(null);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
document.addEventListener('mousedown', handler);
|
|
64
|
+
return () => document.removeEventListener('mousedown', handler);
|
|
65
|
+
}, [switcherOpen]);
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!switcherOpen) return;
|
|
69
|
+
const handler = (e: KeyboardEvent) => {
|
|
70
|
+
if (e.key === 'Escape') {
|
|
71
|
+
if (renamingId) { setRenamingId(null); } else { setSwitcherOpen(false); }
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
document.addEventListener('keydown', handler);
|
|
75
|
+
return () => document.removeEventListener('keydown', handler);
|
|
76
|
+
}, [switcherOpen, renamingId]);
|
|
77
|
+
|
|
78
|
+
// Focus rename input when it appears
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (renamingId) setTimeout(() => renameInputRef.current?.focus(), 0);
|
|
81
|
+
}, [renamingId]);
|
|
82
|
+
|
|
83
|
+
const handleSelectSession = useCallback((id: string) => {
|
|
84
|
+
onLoadSession?.(id);
|
|
85
|
+
setSwitcherOpen(false);
|
|
86
|
+
}, [onLoadSession]);
|
|
87
|
+
|
|
88
|
+
const handleStartRename = useCallback((id: string, currentTitle: string) => {
|
|
89
|
+
setRenamingId(id);
|
|
90
|
+
setRenameValue(currentTitle === '(empty session)' ? '' : currentTitle);
|
|
91
|
+
}, []);
|
|
92
|
+
|
|
93
|
+
const handleCommitRename = useCallback(() => {
|
|
94
|
+
if (renamingId && onRenameSession && renameValue.trim()) {
|
|
95
|
+
onRenameSession(renamingId, renameValue.trim());
|
|
96
|
+
}
|
|
97
|
+
setRenamingId(null);
|
|
98
|
+
}, [renamingId, renameValue, onRenameSession]);
|
|
99
|
+
|
|
100
|
+
// Position dropdown below trigger
|
|
101
|
+
const [dropPos, setDropPos] = useState<{ top: number; left: number; width: number } | null>(null);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (!switcherOpen || !switcherRef.current) return;
|
|
104
|
+
const rect = switcherRef.current.getBoundingClientRect();
|
|
105
|
+
setDropPos({ top: rect.bottom + 4, left: rect.left, width: Math.max(rect.width, 240) });
|
|
106
|
+
}, [switcherOpen]);
|
|
107
|
+
|
|
108
|
+
const switcherDropdown = switcherOpen && dropPos && sessions ? createPortal(
|
|
109
|
+
<div
|
|
110
|
+
ref={dropdownRef}
|
|
111
|
+
className="fixed z-50 rounded-xl border border-border/50 bg-card shadow-lg py-1 animate-in fade-in-0 slide-in-from-top-1 duration-100"
|
|
112
|
+
style={{ top: dropPos.top, left: dropPos.left, minWidth: dropPos.width, maxWidth: 320 }}
|
|
113
|
+
role="listbox"
|
|
114
|
+
>
|
|
115
|
+
{sessions.map((s) => {
|
|
116
|
+
const isActive = s.id === activeSessionId;
|
|
117
|
+
const title = sessionTitle(s);
|
|
118
|
+
const displayTitle = title === '(empty session)' ? (t.hints?.newChat ?? 'New chat') : title;
|
|
119
|
+
|
|
120
|
+
if (renamingId === s.id) {
|
|
121
|
+
return (
|
|
122
|
+
<div key={s.id} className="flex items-center gap-1 px-2 py-1.5">
|
|
123
|
+
<input
|
|
124
|
+
ref={renameInputRef}
|
|
125
|
+
type="text"
|
|
126
|
+
value={renameValue}
|
|
127
|
+
onChange={(e) => setRenameValue(e.target.value)}
|
|
128
|
+
onKeyDown={(e) => {
|
|
129
|
+
if (e.key === 'Enter') handleCommitRename();
|
|
130
|
+
if (e.key === 'Escape') setRenamingId(null);
|
|
131
|
+
}}
|
|
132
|
+
onBlur={handleCommitRename}
|
|
133
|
+
className="flex-1 min-w-0 px-2 py-1 text-xs rounded-md border border-border bg-background text-foreground outline-none focus:border-[var(--amber)]/50"
|
|
134
|
+
placeholder="Session name..."
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div key={s.id} className="group/item flex items-center">
|
|
142
|
+
<button
|
|
143
|
+
type="button"
|
|
144
|
+
role="option"
|
|
145
|
+
aria-selected={isActive}
|
|
146
|
+
onClick={() => handleSelectSession(s.id)}
|
|
147
|
+
className={`flex-1 min-w-0 flex items-center gap-2 px-3 py-2 text-xs text-left transition-colors ${
|
|
148
|
+
isActive ? 'text-foreground font-medium' : 'text-muted-foreground hover:text-foreground hover:bg-muted/50'
|
|
149
|
+
}`}
|
|
150
|
+
>
|
|
151
|
+
{s.pinned && <Pin size={10} className="shrink-0 text-[var(--amber)]/60 -rotate-45" />}
|
|
152
|
+
{isActive && !s.pinned && <Check size={11} className="shrink-0 text-[var(--amber)]" />}
|
|
153
|
+
<span className="truncate">{displayTitle}</span>
|
|
154
|
+
</button>
|
|
155
|
+
<div className="shrink-0 flex items-center gap-0.5 mr-1 opacity-0 group-hover/item:opacity-100 transition-opacity">
|
|
156
|
+
{onTogglePinSession && (
|
|
157
|
+
<button
|
|
158
|
+
type="button"
|
|
159
|
+
onClick={(e) => { e.stopPropagation(); onTogglePinSession(s.id); }}
|
|
160
|
+
className={`p-1.5 rounded-md transition-colors ${s.pinned ? 'text-[var(--amber)] hover:text-muted-foreground hover:bg-muted/60' : 'text-muted-foreground/40 hover:text-[var(--amber)] hover:bg-[var(--amber)]/5'}`}
|
|
161
|
+
aria-label={s.pinned ? 'Unpin' : 'Pin'}
|
|
162
|
+
>
|
|
163
|
+
{s.pinned ? <PinOff size={10} /> : <Pin size={10} />}
|
|
164
|
+
</button>
|
|
165
|
+
)}
|
|
166
|
+
{onRenameSession && (
|
|
167
|
+
<button
|
|
168
|
+
type="button"
|
|
169
|
+
onClick={(e) => { e.stopPropagation(); handleStartRename(s.id, title); }}
|
|
170
|
+
className="p-1.5 rounded-md text-muted-foreground/40 hover:text-foreground hover:bg-muted/60"
|
|
171
|
+
aria-label={`Rename: ${displayTitle}`}
|
|
172
|
+
>
|
|
173
|
+
<Pencil size={10} />
|
|
174
|
+
</button>
|
|
175
|
+
)}
|
|
176
|
+
{sessions.length > 1 && onDeleteSession && (
|
|
177
|
+
<button
|
|
178
|
+
type="button"
|
|
179
|
+
onClick={(e) => { e.stopPropagation(); onDeleteSession(s.id); }}
|
|
180
|
+
className="p-1.5 rounded-md text-muted-foreground/40 hover:text-error hover:bg-error/5"
|
|
181
|
+
aria-label={`Delete: ${displayTitle}`}
|
|
182
|
+
>
|
|
183
|
+
<Trash2 size={10} />
|
|
184
|
+
</button>
|
|
185
|
+
)}
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
})}
|
|
190
|
+
</div>,
|
|
191
|
+
document.body,
|
|
192
|
+
) : null;
|
|
24
193
|
|
|
25
194
|
return (
|
|
26
|
-
<div className="flex items-center justify-between px-4 py-
|
|
195
|
+
<div className="flex items-center justify-between px-4 py-2.5 shrink-0">
|
|
27
196
|
{!isPanel && (
|
|
28
197
|
<div className="absolute top-2 left-1/2 -translate-x-1/2 w-8 h-1 rounded-full bg-muted-foreground/20 md:hidden" />
|
|
29
198
|
)}
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
199
|
+
{!hideTitle && (
|
|
200
|
+
<div className="flex items-center gap-2 min-w-0">
|
|
201
|
+
<div className="w-6 h-6 rounded-lg bg-[var(--amber)]/10 flex items-center justify-center shrink-0">
|
|
202
|
+
<Sparkles size={13} className="text-[var(--amber)]" />
|
|
203
|
+
</div>
|
|
204
|
+
{hasMultipleSessions && activeTitle ? (
|
|
205
|
+
<button
|
|
206
|
+
ref={switcherRef}
|
|
207
|
+
type="button"
|
|
208
|
+
onClick={() => {
|
|
209
|
+
if (sessions && sessions.length >= 2) {
|
|
210
|
+
setSwitcherOpen(v => !v);
|
|
211
|
+
} else {
|
|
212
|
+
onToggleHistory();
|
|
213
|
+
}
|
|
214
|
+
}}
|
|
215
|
+
className="flex items-center gap-1 min-w-0 text-sm font-medium text-[var(--amber)] hover:text-[var(--amber)]/80 transition-colors"
|
|
216
|
+
aria-expanded={switcherOpen}
|
|
217
|
+
aria-haspopup="listbox"
|
|
218
|
+
>
|
|
219
|
+
<span className="truncate max-w-[180px]">{activeTitle === '(empty session)' ? (t.hints?.newChat ?? 'New chat') : activeTitle}</span>
|
|
220
|
+
<ChevronDown size={12} className={`shrink-0 text-muted-foreground transition-transform duration-150 ${switcherOpen ? 'rotate-180' : ''}`} />
|
|
221
|
+
</button>
|
|
222
|
+
) : activeTitle ? (
|
|
223
|
+
<span className="text-sm font-medium text-muted-foreground/60 truncate max-w-[180px]">
|
|
224
|
+
{activeTitle === '(empty session)' ? (t.hints?.newChat ?? 'New chat') : activeTitle}
|
|
225
|
+
</span>
|
|
226
|
+
) : (
|
|
227
|
+
/* Placeholder while sessions load — avoids flash of "MindOS Agent" text */
|
|
228
|
+
<span className="text-sm font-medium text-muted-foreground/40">
|
|
229
|
+
{t.hints?.newChat ?? 'New chat'}
|
|
230
|
+
</span>
|
|
231
|
+
)}
|
|
232
|
+
</div>
|
|
233
|
+
)}
|
|
234
|
+
{hideTitle && <div />}
|
|
36
235
|
<div className="flex items-center gap-1 shrink-0">
|
|
37
|
-
<button type="button" onClick={(e) => { e.stopPropagation(); onToggleHistory(); }} aria-pressed={showHistory} className={`p-2 rounded transition-colors ${showHistory ? 'bg-
|
|
236
|
+
<button type="button" onClick={(e) => { e.stopPropagation(); onToggleHistory(); }} aria-pressed={showHistory} className={`p-2 rounded-lg transition-colors ${showHistory ? 'bg-[var(--amber)]/10 text-[var(--amber)]' : 'text-muted-foreground hover:text-foreground hover:bg-muted'}`} title={t.hints.sessionHistory}>
|
|
38
237
|
<History size={iconSize} />
|
|
39
238
|
</button>
|
|
40
|
-
<button type="button" onClick={(e) => { e.stopPropagation(); onReset(); }} disabled={isLoading} className="p-2 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-40" title={t.hints.newSession}>
|
|
239
|
+
<button type="button" onClick={(e) => { e.stopPropagation(); onReset(); }} disabled={isLoading} className="p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-40" title={t.hints.newSession}>
|
|
41
240
|
<SquarePen size={iconSize} />
|
|
42
241
|
</button>
|
|
43
|
-
{
|
|
44
|
-
<button type="button" onClick={(e) => { e.stopPropagation(); onMaximize(); }} className="p-2 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={maximized ? t.hints.restorePanel : t.hints.maximizePanel}>
|
|
242
|
+
{onMaximize && (
|
|
243
|
+
<button type="button" onClick={(e) => { e.stopPropagation(); onMaximize(); }} className="p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={maximized ? t.hints.restorePanel : t.hints.maximizePanel}>
|
|
45
244
|
{maximized ? <Minimize2 size={iconSize} /> : <Maximize2 size={iconSize} />}
|
|
46
245
|
</button>
|
|
47
246
|
)}
|
|
48
247
|
{onModeSwitch && (
|
|
49
|
-
<button type="button" onClick={(e) => { e.stopPropagation(); onModeSwitch(); }} className="p-2 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={askMode === 'popup' ? t.hints.dockToSide : t.hints.openAsPopup}>
|
|
248
|
+
<button type="button" onClick={(e) => { e.stopPropagation(); onModeSwitch(); }} className="p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={askMode === 'popup' ? t.hints.dockToSide : t.hints.openAsPopup}>
|
|
50
249
|
{askMode === 'popup' ? <PanelRight size={iconSize} /> : <AppWindow size={iconSize} />}
|
|
51
250
|
</button>
|
|
52
251
|
)}
|
|
53
252
|
{onClose && (
|
|
54
|
-
<button type="button" onClick={(e) => { e.stopPropagation(); onClose(); }} className="p-2 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={t.hints.closePanel} aria-label="Close">
|
|
55
|
-
<X size={
|
|
253
|
+
<button type="button" onClick={(e) => { e.stopPropagation(); onClose(); }} className="p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={t.hints.closePanel} aria-label="Close">
|
|
254
|
+
<X size={iconSize} />
|
|
56
255
|
</button>
|
|
57
256
|
)}
|
|
58
257
|
</div>
|
|
258
|
+
{typeof document !== 'undefined' && switcherDropdown}
|
|
59
259
|
</div>
|
|
60
260
|
);
|
|
61
261
|
});
|