@geminilight/mindos 0.6.61 → 0.6.65
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/.antigravity/mcp_config.json +14 -0
- package/_standalone/.mindos-build-version +1 -1
- package/_standalone/.next/BUILD_ID +1 -1
- package/_standalone/.next/app-path-routes-manifest.json +23 -23
- package/_standalone/.next/build-manifest.json +2 -2
- 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/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 +1 -1
- 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 +1 -1
- 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_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.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/copy-skill/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/agents/copy-skill/route_client-reference-manifest.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_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask/route.js +53 -47
- 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 +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_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_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.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_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 +1 -1
- 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 +2 -2
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +2 -2
- 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 +1 -1
- 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 +23 -23
- package/_standalone/.next/server/chunks/122.js +222 -0
- package/_standalone/.next/server/chunks/1550.js +1 -1
- package/_standalone/.next/server/chunks/1750.js +1 -1
- package/_standalone/.next/server/chunks/3113.js +52 -0
- package/_standalone/.next/server/chunks/6539.js +1 -1
- package/_standalone/.next/server/chunks/8388.js +3 -3
- package/_standalone/.next/server/chunks/953.js +3 -3
- 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/1001-99da82ec8d8c136f.js +1 -0
- package/_standalone/.next/static/chunks/1088-77544af0a50cb7a4.js +1 -0
- package/_standalone/.next/static/chunks/1467-87dde7eed498806f.js +1 -0
- package/_standalone/.next/static/chunks/5149-4d828886dda479fa.js +1 -0
- package/_standalone/.next/static/chunks/5581-c671163a2fe1b312.js +29 -0
- package/_standalone/.next/static/chunks/{7266-bb7be1128eccd48e.js → 5718-3837c3210a0e175f.js} +2 -2
- package/_standalone/.next/static/chunks/6636-53238eff89503f03.js +6 -0
- package/_standalone/.next/static/chunks/6757-1c1a89720fdda8f0.js +1 -0
- package/_standalone/.next/static/chunks/7129-20e9d2463a9da646.js +1 -0
- package/_standalone/.next/static/chunks/7294-cac25d97869afadc.js +1 -0
- package/_standalone/.next/static/chunks/8225-21e5cebc3731ddf0.js +1 -0
- package/_standalone/.next/static/chunks/8520-b51810e66293ceb8.js +22 -0
- package/_standalone/.next/static/chunks/9207-dc9c31b351a2ed78.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-2f5cf97e03dc1cc9.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/page-50eac58d511dcc6e.js +1 -0
- package/_standalone/.next/static/chunks/app/echo/[segment]/page-2a00f4686adf3885.js +11 -0
- package/_standalone/.next/static/chunks/app/layout-2cb7a6602d2e5d5f.js +168 -0
- package/_standalone/.next/static/chunks/app/{page-6a1f8d21c12b829e.js → page-5ab911b2226f6ff7.js} +1 -1
- package/_standalone/.next/static/chunks/app/setup/page-907b7c57fad2292b.js +1 -0
- package/_standalone/.next/static/chunks/app/trash/page-11a511b065ea84c2.js +1 -0
- package/_standalone/.next/static/chunks/app/view/[...path]/page-26e47dd4c533a58c.js +12 -0
- package/_standalone/.next/static/chunks/app/wiki/page-dce495b9048022fb.js +1 -0
- package/_standalone/.next/static/css/67e7918f5ed7d147.css +1 -0
- package/_standalone/.next/trace +65 -65
- package/_standalone/__tests__/acp/registry.test.ts +30 -20
- package/_standalone/__tests__/api/ask-attachments.test.ts +194 -0
- package/_standalone/__tests__/api/mcp-install.test.ts +49 -2
- package/_standalone/__tests__/api/settings.test.ts +16 -12
- package/_standalone/__tests__/api/setup.test.ts +11 -9
- package/_standalone/__tests__/api/test-key.test.ts +0 -10
- package/_standalone/__tests__/components/UpdateToast.test.ts +344 -0
- package/_standalone/__tests__/core/context.test.ts +48 -426
- package/_standalone/__tests__/lib/pi-skills.test.ts +4 -4
- package/_standalone/__tests__/lib/settings-ai-client.test.ts +32 -12
- package/_standalone/__tests__/setup.ts +5 -5
- package/_standalone/app/globals.css +4 -4
- package/_standalone/components/ActivityBar.tsx +17 -6
- package/_standalone/components/Panel.tsx +24 -6
- package/_standalone/components/SidebarLayout.tsx +36 -8
- package/_standalone/components/agents/AgentsMcpSection.tsx +2 -2
- package/_standalone/components/agents/AgentsOverviewSection.tsx +5 -1
- package/_standalone/components/agents/AgentsPanelA2aTab.tsx +173 -113
- package/_standalone/components/agents/AgentsSkillsSection.tsx +2 -2
- package/_standalone/components/ask/AskContent.tsx +83 -44
- package/_standalone/components/ask/AskHeader.tsx +8 -1
- package/_standalone/components/ask/MessageList.tsx +37 -3
- package/_standalone/components/ask/ProviderModelCapsule.tsx +444 -174
- package/_standalone/components/home/InboxSection.tsx +25 -25
- package/_standalone/components/settings/AiTab.tsx +353 -298
- package/_standalone/components/settings/CustomProviderFields.tsx +121 -0
- package/_standalone/components/settings/CustomProvidersCard.tsx +154 -0
- package/_standalone/components/settings/KnowledgeTab.tsx +6 -20
- package/_standalone/components/settings/McpAgentInstall.tsx +7 -2
- package/_standalone/components/settings/Primitives.tsx +48 -104
- package/_standalone/components/settings/ProviderModal.tsx +87 -0
- package/_standalone/components/settings/SettingsContent.tsx +2 -5
- package/_standalone/components/settings/TestButton.tsx +64 -0
- package/_standalone/components/settings/types.ts +3 -9
- package/_standalone/components/settings/useCustomProviderForm.ts +132 -0
- package/_standalone/components/setup/StepAI.tsx +12 -5
- package/_standalone/components/shared/ModelInput.tsx +220 -0
- package/_standalone/components/shared/ProviderSelect.tsx +126 -36
- package/_standalone/hooks/useAskChat.ts +100 -13
- package/_standalone/hooks/useAskPanel.ts +17 -1
- package/_standalone/lib/settings-ai-client.ts +17 -8
- package/_standalone/tsconfig.tsbuildinfo +1 -1
- package/app/.antigravity/mcp_config.json +14 -0
- package/app/app/api/ask/route.ts +154 -45
- package/app/app/api/mcp/agents/route.ts +3 -3
- package/app/app/api/settings/list-models/route.ts +36 -9
- package/app/app/api/settings/route.ts +14 -42
- package/app/app/api/settings/test-key/route.ts +78 -2
- package/app/app/api/setup/route.ts +36 -18
- package/app/app/api/skills/route.ts +1 -1
- package/app/app/globals.css +4 -4
- package/app/app/layout.tsx +5 -3
- package/app/app/view/[...path]/page.tsx +5 -0
- package/app/components/ActivityBar.tsx +17 -6
- package/app/components/HomeContent.tsx +11 -0
- package/app/components/InboxView.tsx +656 -0
- package/app/components/Panel.tsx +24 -6
- package/app/components/SidebarLayout.tsx +36 -8
- package/app/components/UpdateToast.tsx +255 -0
- package/app/components/agents/AgentDetailContent.tsx +8 -8
- package/app/components/agents/AgentsMcpSection.tsx +2 -2
- package/app/components/agents/AgentsOverviewSection.tsx +5 -1
- package/app/components/agents/AgentsPanelA2aTab.tsx +173 -113
- package/app/components/agents/AgentsSkillsSection.tsx +2 -2
- package/app/components/ask/AskContent.tsx +83 -44
- package/app/components/ask/AskHeader.tsx +8 -1
- package/app/components/ask/MessageList.tsx +37 -3
- package/app/components/ask/ProviderModelCapsule.tsx +444 -174
- package/app/components/home/InboxSection.tsx +25 -25
- package/app/components/settings/AiTab.tsx +353 -298
- package/app/components/settings/CustomProviderFields.tsx +121 -0
- package/app/components/settings/CustomProvidersCard.tsx +154 -0
- package/app/components/settings/KnowledgeTab.tsx +6 -20
- package/app/components/settings/McpAgentInstall.tsx +7 -2
- package/app/components/settings/Primitives.tsx +48 -104
- package/app/components/settings/ProviderModal.tsx +87 -0
- package/app/components/settings/SettingsContent.tsx +2 -5
- package/app/components/settings/TestButton.tsx +64 -0
- package/app/components/settings/types.ts +3 -9
- package/app/components/settings/useCustomProviderForm.ts +132 -0
- package/app/components/setup/StepAI.tsx +12 -5
- package/app/components/shared/ModelInput.tsx +220 -0
- package/app/components/shared/ProviderSelect.tsx +126 -36
- package/app/hooks/useAskChat.ts +100 -13
- package/app/hooks/useAskPanel.ts +17 -1
- package/app/lib/acp/registry.ts +92 -10
- package/app/lib/agent/context.ts +65 -0
- package/app/lib/agent/providers.ts +25 -0
- package/app/lib/agent/tools.ts +1 -1
- package/app/lib/custom-endpoints.ts +160 -0
- package/app/lib/fs.ts +8 -1
- package/app/lib/i18n/modules/ai-chat.ts +6 -0
- package/app/lib/i18n/modules/knowledge.ts +16 -0
- package/app/lib/i18n/modules/onboarding.ts +4 -0
- package/app/lib/i18n/modules/settings.ts +88 -2
- package/app/lib/mcp-agents.ts +11 -0
- package/app/lib/pi-integration/skills.ts +16 -4
- package/app/lib/settings-ai-client.ts +17 -8
- package/app/lib/settings.ts +68 -72
- package/app/lib/types.ts +4 -0
- package/bin/lib/mcp-agents.js +11 -0
- package/bin/lib/mcp-install.js +71 -7
- package/package.json +1 -1
- package/_standalone/.next/server/chunks/530.js +0 -218
- package/_standalone/.next/server/chunks/8955.js +0 -52
- package/_standalone/.next/static/chunks/1369-7d0ac5d1564eed1e.js +0 -1
- package/_standalone/.next/static/chunks/3427-2e61a5df1f5e55fb.js +0 -1
- package/_standalone/.next/static/chunks/5581-0c700c20718bd916.js +0 -29
- package/_standalone/.next/static/chunks/6297-085daa21037d5f81.js +0 -1
- package/_standalone/.next/static/chunks/6636-9bbc90fb3b8731fe.js +0 -6
- package/_standalone/.next/static/chunks/7637-904b0a381dc3ec02.js +0 -1
- package/_standalone/.next/static/chunks/8520-76d1b05072178b43.js +0 -22
- package/_standalone/.next/static/chunks/8658-16ff58b75ae37fbb.js +0 -1
- package/_standalone/.next/static/chunks/9905-a19d379cb225246e.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-0ea3571c8fbae823.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/page-66858acbcd1d4bf8.js +0 -1
- package/_standalone/.next/static/chunks/app/echo/[segment]/page-bf5c290fa3ccff09.js +0 -11
- package/_standalone/.next/static/chunks/app/layout-a5d5925b47e87cc3.js +0 -164
- package/_standalone/.next/static/chunks/app/setup/page-821714e7477be46c.js +0 -1
- package/_standalone/.next/static/chunks/app/trash/page-40bc7316806acd62.js +0 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/page-6fbb14b8f322d0f0.js +0 -12
- package/_standalone/.next/static/chunks/app/wiki/page-ba36eccf4fe62cfe.js +0 -1
- package/_standalone/.next/static/css/b57c4eb3cc88308b.css +0 -1
- package/_standalone/lib/agent/context.ts +0 -403
- /package/_standalone/.next/static/{5GmVArEG8OX03azKICsGq → eIlwbGas1iRGonlPyEwj7}/_buildManifest.js +0 -0
- /package/_standalone/.next/static/{5GmVArEG8OX03azKICsGq → eIlwbGas1iRGonlPyEwj7}/_ssgManifest.js +0 -0
|
@@ -33,14 +33,16 @@ describe('ACP Registry', () => {
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
describe('fetchAcpRegistry', () => {
|
|
36
|
-
it('fetches and
|
|
36
|
+
it('fetches and merges with built-in registry', async () => {
|
|
37
37
|
mockFetch.mockResolvedValueOnce({ ok: true, json: async () => MOCK_REGISTRY });
|
|
38
38
|
|
|
39
39
|
const registry = await fetchAcpRegistry();
|
|
40
40
|
expect(registry).not.toBeNull();
|
|
41
|
-
|
|
42
|
-
expect(registry
|
|
43
|
-
|
|
41
|
+
// CDN agents are merged with built-in agents
|
|
42
|
+
expect(registry.agents.length).toBeGreaterThanOrEqual(2);
|
|
43
|
+
const gemini = registry.agents.find(a => a.id === 'gemini-cli');
|
|
44
|
+
expect(gemini).toBeDefined();
|
|
45
|
+
expect(gemini!.transport).toBe('npx');
|
|
44
46
|
});
|
|
45
47
|
|
|
46
48
|
it('caches the registry for subsequent calls', async () => {
|
|
@@ -53,11 +55,14 @@ describe('ACP Registry', () => {
|
|
|
53
55
|
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
54
56
|
});
|
|
55
57
|
|
|
56
|
-
it('returns
|
|
58
|
+
it('returns built-in registry on fetch failure with no cache', async () => {
|
|
57
59
|
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
58
60
|
|
|
59
61
|
const registry = await fetchAcpRegistry();
|
|
60
|
-
|
|
62
|
+
// Should fall back to built-in registry, never null
|
|
63
|
+
expect(registry).not.toBeNull();
|
|
64
|
+
expect(registry.agents.length).toBeGreaterThan(0);
|
|
65
|
+
expect(registry.version).toBe('builtin');
|
|
61
66
|
});
|
|
62
67
|
|
|
63
68
|
it('returns stale cache on fetch failure', async () => {
|
|
@@ -68,22 +73,26 @@ describe('ACP Registry', () => {
|
|
|
68
73
|
// (we can't easily expire cache in test, so just test that cache works)
|
|
69
74
|
const cached = await fetchAcpRegistry();
|
|
70
75
|
expect(cached).not.toBeNull();
|
|
71
|
-
expect(cached!.agents).
|
|
76
|
+
expect(cached!.agents.length).toBeGreaterThanOrEqual(2);
|
|
72
77
|
});
|
|
73
78
|
|
|
74
|
-
it('returns
|
|
79
|
+
it('returns built-in registry for non-ok HTTP response with no cache', async () => {
|
|
75
80
|
mockFetch.mockResolvedValueOnce({ ok: false, status: 500 });
|
|
76
81
|
|
|
77
82
|
const registry = await fetchAcpRegistry();
|
|
78
|
-
|
|
83
|
+
// Should fall back to built-in registry, never null
|
|
84
|
+
expect(registry).not.toBeNull();
|
|
85
|
+
expect(registry.agents.length).toBeGreaterThan(0);
|
|
86
|
+
expect(registry.version).toBe('builtin');
|
|
79
87
|
});
|
|
80
88
|
|
|
81
|
-
it('
|
|
89
|
+
it('merges empty CDN registry with built-in agents', async () => {
|
|
82
90
|
mockFetch.mockResolvedValueOnce({ ok: true, json: async () => ({ version: '1', agents: [] }) });
|
|
83
91
|
|
|
84
92
|
const registry = await fetchAcpRegistry();
|
|
85
93
|
expect(registry).not.toBeNull();
|
|
86
|
-
|
|
94
|
+
// Even with empty CDN, built-in agents should be present
|
|
95
|
+
expect(registry.agents.length).toBeGreaterThan(0);
|
|
87
96
|
});
|
|
88
97
|
|
|
89
98
|
it('handles object-keyed registry format', async () => {
|
|
@@ -95,8 +104,8 @@ describe('ACP Registry', () => {
|
|
|
95
104
|
|
|
96
105
|
const registry = await fetchAcpRegistry();
|
|
97
106
|
expect(registry).not.toBeNull();
|
|
98
|
-
expect(registry
|
|
99
|
-
expect(registry
|
|
107
|
+
expect(registry.agents.length).toBeGreaterThanOrEqual(1);
|
|
108
|
+
expect(registry.agents.find(a => a.id === 'my-agent')).toBeDefined();
|
|
100
109
|
});
|
|
101
110
|
|
|
102
111
|
it('handles malformed entries gracefully', async () => {
|
|
@@ -113,25 +122,26 @@ describe('ACP Registry', () => {
|
|
|
113
122
|
|
|
114
123
|
const registry = await fetchAcpRegistry();
|
|
115
124
|
expect(registry).not.toBeNull();
|
|
116
|
-
//
|
|
117
|
-
expect(registry
|
|
118
|
-
|
|
125
|
+
// Valid CDN entry should be present (merged with built-in)
|
|
126
|
+
expect(registry.agents.find(a => a.id === 'good')).toBeDefined();
|
|
127
|
+
// Malformed entries should not be present
|
|
128
|
+
expect(registry.agents.find(a => a.id === '')).toBeUndefined();
|
|
119
129
|
});
|
|
120
130
|
});
|
|
121
131
|
|
|
122
132
|
describe('getAcpAgents', () => {
|
|
123
|
-
it('returns agents from registry', async () => {
|
|
133
|
+
it('returns agents from registry merged with built-in', async () => {
|
|
124
134
|
mockFetch.mockResolvedValueOnce({ ok: true, json: async () => MOCK_REGISTRY });
|
|
125
135
|
|
|
126
136
|
const agents = await getAcpAgents();
|
|
127
|
-
expect(agents).
|
|
137
|
+
expect(agents.length).toBeGreaterThanOrEqual(2);
|
|
128
138
|
});
|
|
129
139
|
|
|
130
|
-
it('returns
|
|
140
|
+
it('returns built-in agents on failure', async () => {
|
|
131
141
|
mockFetch.mockRejectedValueOnce(new Error('down'));
|
|
132
142
|
|
|
133
143
|
const agents = await getAcpAgents();
|
|
134
|
-
expect(agents).
|
|
144
|
+
expect(agents.length).toBeGreaterThan(0);
|
|
135
145
|
});
|
|
136
146
|
});
|
|
137
147
|
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { seedFile, testMindRoot } from '../setup';
|
|
3
|
+
import { getFileContent, invalidateCache } from '../../lib/fs';
|
|
4
|
+
import { truncate } from '../../lib/agent/tools';
|
|
5
|
+
|
|
6
|
+
describe('Ask attached files', () => {
|
|
7
|
+
describe('getFileContent reads KB files', () => {
|
|
8
|
+
it('reads a seeded markdown file', () => {
|
|
9
|
+
seedFile('notes/test.md', '# Test\nHello world');
|
|
10
|
+
invalidateCache();
|
|
11
|
+
const content = getFileContent('notes/test.md');
|
|
12
|
+
expect(content).toBe('# Test\nHello world');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('reads a nested file', () => {
|
|
16
|
+
seedFile('deep/nested/dir/file.md', 'nested content');
|
|
17
|
+
invalidateCache();
|
|
18
|
+
const content = getFileContent('deep/nested/dir/file.md');
|
|
19
|
+
expect(content).toBe('nested content');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('throws for non-existent file', () => {
|
|
23
|
+
invalidateCache();
|
|
24
|
+
expect(() => getFileContent('does-not-exist.md')).toThrow();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('reads CSV files', () => {
|
|
28
|
+
seedFile('data.csv', 'a,b,c\n1,2,3');
|
|
29
|
+
invalidateCache();
|
|
30
|
+
const content = getFileContent('data.csv');
|
|
31
|
+
expect(content).toBe('a,b,c\n1,2,3');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('truncate limits content length', () => {
|
|
36
|
+
it('passes through short content unchanged', () => {
|
|
37
|
+
const short = 'Hello world';
|
|
38
|
+
expect(truncate(short)).toBe(short);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('truncates very long content', () => {
|
|
42
|
+
const long = 'x'.repeat(50_000);
|
|
43
|
+
const result = truncate(long);
|
|
44
|
+
expect(result.length).toBeLessThan(long.length);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('attachment pattern builds correct context', () => {
|
|
49
|
+
it('builds context parts for multiple attached files', () => {
|
|
50
|
+
seedFile('file-a.md', '# File A\nContent A');
|
|
51
|
+
seedFile('file-b.md', '# File B\nContent B');
|
|
52
|
+
invalidateCache();
|
|
53
|
+
|
|
54
|
+
const attachedFiles = ['file-a.md', 'file-b.md'];
|
|
55
|
+
const contextParts: string[] = [];
|
|
56
|
+
const seen = new Set<string>();
|
|
57
|
+
|
|
58
|
+
for (const filePath of attachedFiles) {
|
|
59
|
+
if (seen.has(filePath)) continue;
|
|
60
|
+
seen.add(filePath);
|
|
61
|
+
try {
|
|
62
|
+
const content = truncate(getFileContent(filePath));
|
|
63
|
+
contextParts.push(`## Attached: ${filePath}\n\n${content}`);
|
|
64
|
+
} catch { /* simulate route.ts pattern */ }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
expect(contextParts).toHaveLength(2);
|
|
68
|
+
expect(contextParts[0]).toContain('## Attached: file-a.md');
|
|
69
|
+
expect(contextParts[0]).toContain('Content A');
|
|
70
|
+
expect(contextParts[1]).toContain('## Attached: file-b.md');
|
|
71
|
+
expect(contextParts[1]).toContain('Content B');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('deduplicates attached files', () => {
|
|
75
|
+
seedFile('dup.md', 'content');
|
|
76
|
+
invalidateCache();
|
|
77
|
+
|
|
78
|
+
const attachedFiles = ['dup.md', 'dup.md', 'dup.md'];
|
|
79
|
+
const contextParts: string[] = [];
|
|
80
|
+
const seen = new Set<string>();
|
|
81
|
+
|
|
82
|
+
for (const filePath of attachedFiles) {
|
|
83
|
+
if (seen.has(filePath)) continue;
|
|
84
|
+
seen.add(filePath);
|
|
85
|
+
try {
|
|
86
|
+
const content = truncate(getFileContent(filePath));
|
|
87
|
+
contextParts.push(`## Attached: ${filePath}\n\n${content}`);
|
|
88
|
+
} catch { /* */ }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
expect(contextParts).toHaveLength(1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('skips missing files without crashing', () => {
|
|
95
|
+
seedFile('exists.md', 'good');
|
|
96
|
+
invalidateCache();
|
|
97
|
+
|
|
98
|
+
const attachedFiles = ['exists.md', 'missing.md', 'also-missing.md'];
|
|
99
|
+
const contextParts: string[] = [];
|
|
100
|
+
const seen = new Set<string>();
|
|
101
|
+
|
|
102
|
+
for (const filePath of attachedFiles) {
|
|
103
|
+
if (seen.has(filePath)) continue;
|
|
104
|
+
seen.add(filePath);
|
|
105
|
+
try {
|
|
106
|
+
const content = truncate(getFileContent(filePath));
|
|
107
|
+
contextParts.push(`## Attached: ${filePath}\n\n${content}`);
|
|
108
|
+
} catch { /* silently skip */ }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
expect(contextParts).toHaveLength(1);
|
|
112
|
+
expect(contextParts[0]).toContain('exists.md');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('handles empty attachedFiles array', () => {
|
|
116
|
+
const attachedFiles: string[] = [];
|
|
117
|
+
const contextParts: string[] = [];
|
|
118
|
+
const seen = new Set<string>();
|
|
119
|
+
|
|
120
|
+
for (const filePath of attachedFiles) {
|
|
121
|
+
if (seen.has(filePath)) continue;
|
|
122
|
+
seen.add(filePath);
|
|
123
|
+
try {
|
|
124
|
+
const content = truncate(getFileContent(filePath));
|
|
125
|
+
contextParts.push(`## Attached: ${filePath}\n\n${content}`);
|
|
126
|
+
} catch { /* */ }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
expect(contextParts).toHaveLength(0);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('currentFile is included when not in attachedFiles', () => {
|
|
133
|
+
seedFile('attached.md', 'attached content');
|
|
134
|
+
seedFile('current.md', 'current content');
|
|
135
|
+
invalidateCache();
|
|
136
|
+
|
|
137
|
+
const attachedFiles = ['attached.md'];
|
|
138
|
+
const currentFile = 'current.md';
|
|
139
|
+
const contextParts: string[] = [];
|
|
140
|
+
const seen = new Set<string>();
|
|
141
|
+
|
|
142
|
+
for (const filePath of attachedFiles) {
|
|
143
|
+
if (seen.has(filePath)) continue;
|
|
144
|
+
seen.add(filePath);
|
|
145
|
+
try {
|
|
146
|
+
const content = truncate(getFileContent(filePath));
|
|
147
|
+
contextParts.push(`## Attached: ${filePath}\n\n${content}`);
|
|
148
|
+
} catch { /* */ }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (currentFile && !seen.has(currentFile)) {
|
|
152
|
+
seen.add(currentFile);
|
|
153
|
+
try {
|
|
154
|
+
const content = truncate(getFileContent(currentFile));
|
|
155
|
+
contextParts.push(`## Current file: ${currentFile}\n\n${content}`);
|
|
156
|
+
} catch { /* */ }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
expect(contextParts).toHaveLength(2);
|
|
160
|
+
expect(contextParts[0]).toContain('## Attached: attached.md');
|
|
161
|
+
expect(contextParts[1]).toContain('## Current file: current.md');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('currentFile is not duplicated when already in attachedFiles', () => {
|
|
165
|
+
seedFile('same.md', 'same content');
|
|
166
|
+
invalidateCache();
|
|
167
|
+
|
|
168
|
+
const attachedFiles = ['same.md'];
|
|
169
|
+
const currentFile = 'same.md';
|
|
170
|
+
const contextParts: string[] = [];
|
|
171
|
+
const seen = new Set<string>();
|
|
172
|
+
|
|
173
|
+
for (const filePath of attachedFiles) {
|
|
174
|
+
if (seen.has(filePath)) continue;
|
|
175
|
+
seen.add(filePath);
|
|
176
|
+
try {
|
|
177
|
+
const content = truncate(getFileContent(filePath));
|
|
178
|
+
contextParts.push(`## Attached: ${filePath}\n\n${content}`);
|
|
179
|
+
} catch { /* */ }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (currentFile && !seen.has(currentFile)) {
|
|
183
|
+
seen.add(currentFile);
|
|
184
|
+
try {
|
|
185
|
+
const content = truncate(getFileContent(currentFile));
|
|
186
|
+
contextParts.push(`## Current file: ${currentFile}\n\n${content}`);
|
|
187
|
+
} catch { /* */ }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
expect(contextParts).toHaveLength(1);
|
|
191
|
+
expect(contextParts[0]).toContain('## Attached: same.md');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
});
|
|
@@ -251,14 +251,60 @@ describe('POST /api/mcp/install', () => {
|
|
|
251
251
|
fs.rmSync(absPath);
|
|
252
252
|
}
|
|
253
253
|
});
|
|
254
|
+
|
|
255
|
+
it('installs copaw agent with nested mcp.clients structure', async () => {
|
|
256
|
+
const { POST } = await importInstallRoute();
|
|
257
|
+
|
|
258
|
+
// Pre-seed CoPaw config with existing data (like the user's example)
|
|
259
|
+
const copawDir = path.join(tempHome, '.copaw');
|
|
260
|
+
fs.mkdirSync(copawDir, { recursive: true });
|
|
261
|
+
fs.writeFileSync(path.join(copawDir, 'config.json'), JSON.stringify({
|
|
262
|
+
mcp: {
|
|
263
|
+
clients: {
|
|
264
|
+
tavily_search: {
|
|
265
|
+
name: 'tavily_mcp',
|
|
266
|
+
enabled: false,
|
|
267
|
+
transport: 'stdio',
|
|
268
|
+
command: 'npx',
|
|
269
|
+
args: ['-y', 'tavily-mcp@latest'],
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
}, null, 2), 'utf-8');
|
|
274
|
+
|
|
275
|
+
const req = new NextRequest('http://localhost/api/mcp/install', {
|
|
276
|
+
method: 'POST',
|
|
277
|
+
body: JSON.stringify({
|
|
278
|
+
agents: [{ key: 'copaw', scope: 'global' }],
|
|
279
|
+
transport: 'stdio',
|
|
280
|
+
}),
|
|
281
|
+
headers: { 'content-type': 'application/json' },
|
|
282
|
+
});
|
|
283
|
+
const res = await POST(req);
|
|
284
|
+
const body = await res.json();
|
|
285
|
+
expect(body.results[0].status).toBe('ok');
|
|
286
|
+
|
|
287
|
+
// Verify config uses nested mcp.clients structure
|
|
288
|
+
const configPath = path.join(copawDir, 'config.json');
|
|
289
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
290
|
+
// mindos should be under mcp.clients, NOT under a flat "mcp" key
|
|
291
|
+
expect(config.mcp).toBeDefined();
|
|
292
|
+
expect(config.mcp.clients).toBeDefined();
|
|
293
|
+
expect(config.mcp.clients.mindos).toBeDefined();
|
|
294
|
+
expect(config.mcp.clients.mindos.type).toBe('stdio');
|
|
295
|
+
expect(config.mcp.clients.mindos.command).toBe('mindos');
|
|
296
|
+
// Existing entry should be preserved
|
|
297
|
+
expect(config.mcp.clients.tavily_search).toBeDefined();
|
|
298
|
+
expect(config.mcp.clients.tavily_search.command).toBe('npx');
|
|
299
|
+
});
|
|
254
300
|
});
|
|
255
301
|
|
|
256
302
|
describe('GET /api/mcp/agents', () => {
|
|
257
|
-
it('returns all
|
|
303
|
+
it('returns all 25 agents (1 builtin + 24 registry)', async () => {
|
|
258
304
|
const { GET } = await importAgentsRoute();
|
|
259
305
|
const res = await GET();
|
|
260
306
|
const body = await res.json();
|
|
261
|
-
expect(body.agents).toHaveLength(
|
|
307
|
+
expect(body.agents).toHaveLength(25);
|
|
262
308
|
const keys = body.agents.map((a: { key: string }) => a.key);
|
|
263
309
|
expect(keys).toContain('mindos');
|
|
264
310
|
expect(keys).toContain('claude-code');
|
|
@@ -279,6 +325,7 @@ describe('GET /api/mcp/agents', () => {
|
|
|
279
325
|
expect(keys).toContain('qclaw');
|
|
280
326
|
expect(keys).toContain('workbuddy');
|
|
281
327
|
expect(keys).toContain('lingma');
|
|
328
|
+
expect(keys).toContain('copaw');
|
|
282
329
|
});
|
|
283
330
|
|
|
284
331
|
it('detects installed agent from config file', async () => {
|
|
@@ -12,15 +12,19 @@ describe('GET /api/settings', () => {
|
|
|
12
12
|
const body = await res.json();
|
|
13
13
|
|
|
14
14
|
expect(body).toHaveProperty('ai');
|
|
15
|
-
expect(body.ai).toHaveProperty('
|
|
15
|
+
expect(body.ai).toHaveProperty('activeProvider');
|
|
16
16
|
expect(body.ai).toHaveProperty('providers');
|
|
17
|
-
expect(body.ai.providers).
|
|
18
|
-
expect(body.ai.providers).
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
expect(
|
|
22
|
-
expect(
|
|
23
|
-
expect(
|
|
17
|
+
expect(Array.isArray(body.ai.providers)).toBe(true);
|
|
18
|
+
expect(body.ai.providers.length).toBeGreaterThanOrEqual(1);
|
|
19
|
+
const anthropic = body.ai.providers.find((p: any) => p.protocol === 'anthropic');
|
|
20
|
+
const openai = body.ai.providers.find((p: any) => p.protocol === 'openai');
|
|
21
|
+
expect(anthropic).toBeDefined();
|
|
22
|
+
expect(anthropic).toHaveProperty('apiKey');
|
|
23
|
+
expect(anthropic).toHaveProperty('model');
|
|
24
|
+
expect(openai).toBeDefined();
|
|
25
|
+
expect(openai).toHaveProperty('apiKey');
|
|
26
|
+
expect(openai).toHaveProperty('model');
|
|
27
|
+
expect(openai).toHaveProperty('baseUrl');
|
|
24
28
|
expect(body).toHaveProperty('mindRoot');
|
|
25
29
|
expect(body).toHaveProperty('envOverrides');
|
|
26
30
|
expect(body).toHaveProperty('envValues');
|
|
@@ -33,10 +37,10 @@ describe('POST /api/settings', () => {
|
|
|
33
37
|
method: 'POST',
|
|
34
38
|
body: JSON.stringify({
|
|
35
39
|
ai: {
|
|
36
|
-
|
|
37
|
-
providers:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
activeProvider: 'p_openai01',
|
|
41
|
+
providers: [
|
|
42
|
+
{ id: 'p_openai01', name: 'OpenAI', protocol: 'openai', apiKey: 'sk-test', model: 'gpt-5.4', baseUrl: '' },
|
|
43
|
+
],
|
|
40
44
|
},
|
|
41
45
|
}),
|
|
42
46
|
headers: { 'content-type': 'application/json' },
|
|
@@ -7,11 +7,11 @@ import path from 'path';
|
|
|
7
7
|
// We need to mock settings + template modules for the setup API
|
|
8
8
|
const mockSettings = {
|
|
9
9
|
ai: {
|
|
10
|
-
|
|
11
|
-
providers:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
activeProvider: 'p_anthro01',
|
|
11
|
+
providers: [
|
|
12
|
+
{ id: 'p_anthro01', name: 'Anthropic', protocol: 'anthropic' as const, apiKey: '', model: 'claude-sonnet-4-6', baseUrl: '' },
|
|
13
|
+
{ id: 'p_openai01', name: 'OpenAI', protocol: 'openai' as const, apiKey: '', model: 'gpt-5.4', baseUrl: '' },
|
|
14
|
+
],
|
|
15
15
|
},
|
|
16
16
|
mindRoot: '',
|
|
17
17
|
port: 3456,
|
|
@@ -76,12 +76,13 @@ describe('GET /api/setup', () => {
|
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
it('masks API keys in providerConfigs', async () => {
|
|
79
|
-
mockSettings.ai.providers.
|
|
79
|
+
mockSettings.ai.providers[0].apiKey = 'sk-ant-1234567890abcdef';
|
|
80
80
|
const { GET } = await importSetupRoute();
|
|
81
81
|
const res = await GET();
|
|
82
82
|
const body = await res.json();
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
const anthropicConfig = body.providerConfigs.find((p: any) => p.protocol === 'anthropic');
|
|
84
|
+
expect(anthropicConfig.apiKeyMask).toBe('sk-ant***');
|
|
85
|
+
mockSettings.ai.providers[0].apiKey = '';
|
|
85
86
|
});
|
|
86
87
|
});
|
|
87
88
|
|
|
@@ -315,7 +316,8 @@ describe('POST /api/setup — LLM skip', () => {
|
|
|
315
316
|
expect(res.status).toBe(200);
|
|
316
317
|
const config = writtenConfig as Record<string, unknown>;
|
|
317
318
|
const ai = config.ai as Record<string, unknown>;
|
|
318
|
-
|
|
319
|
+
// The route merges incoming ai into the existing format
|
|
320
|
+
expect(ai).toBeDefined();
|
|
319
321
|
});
|
|
320
322
|
});
|
|
321
323
|
|
|
@@ -148,16 +148,6 @@ describe('POST /api/settings/test-key', () => {
|
|
|
148
148
|
expect(body.error).toBe('Request timed out');
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
-
it('treats ***set*** as masked and falls back to config', async () => {
|
|
152
|
-
const res = await POST(makeReq({ provider: 'anthropic', apiKey: '***set***' }));
|
|
153
|
-
const body = await res.json();
|
|
154
|
-
|
|
155
|
-
// effectiveAiConfig returns empty apiKey → auth_error
|
|
156
|
-
expect(body.ok).toBe(false);
|
|
157
|
-
expect(body.code).toBe('auth_error');
|
|
158
|
-
expect(body.error).toBe('No API key configured');
|
|
159
|
-
});
|
|
160
|
-
|
|
161
151
|
it('accepts new providers like google and deepseek', async () => {
|
|
162
152
|
(complete as ReturnType<typeof vi.fn>).mockResolvedValueOnce({ text: 'ok' });
|
|
163
153
|
|