@geminilight/mindos 0.6.76 → 0.6.78
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 +25 -23
- 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 +4 -4
- package/_standalone/.next/required-server-files.json +2 -1
- package/_standalone/.next/routes-manifest.json +12 -0
- 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_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 +2 -2
- 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/channels/verify/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/connect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/embedding/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/im/activity/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/config/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/feishu/long-connection/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/im/feishu/long-connection/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/status/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/im/status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/test/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/webhook/feishu/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/im/webhook/feishu/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/webhook-status/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/im/webhook-status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/inbox/clip/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/inbox/clip/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/lint/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/lint/route_client-reference-manifest.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/direct-tools/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/tools/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/obsidian/compat-report/route.js +1 -0
- package/_standalone/.next/server/app/api/obsidian/compat-report/route.js.nft.json +1 -0
- package/_standalone/.next/server/app/api/obsidian/compat-report/route_client-reference-manifest.js +1 -0
- package/_standalone/.next/server/app/api/obsidian/import/route.js +1 -0
- package/_standalone/.next/server/app/api/obsidian/import/route.js.nft.json +1 -0
- package/_standalone/.next/server/app/api/obsidian/import/route_client-reference-manifest.js +1 -0
- 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_client-reference-manifest.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.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.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_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/space-overview/route.js +1 -1
- package/_standalone/.next/server/app/api/space-overview/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/space-overview/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/changelog/page.js +1 -1
- package/_standalone/.next/server/app/changelog/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/changelog/page_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 +1 -1
- 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-paths-manifest.json +25 -23
- package/_standalone/.next/server/chunks/1299.js +1 -1
- package/_standalone/.next/server/chunks/{7686.js → 2057.js} +3 -3
- package/_standalone/.next/server/chunks/4802.js +37 -37
- package/_standalone/.next/server/chunks/5299.js +1 -1
- package/_standalone/.next/server/chunks/6223.js +1 -1
- package/_standalone/.next/server/chunks/7531.js +1 -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/{5484.a70877a2667d0779.js → 1768.1e964db7834ecb4f.js} +1 -1
- package/_standalone/.next/static/chunks/{4878.ad1f431d34ff03fc.js → 1937.e178266395104aa3.js} +1 -1
- package/_standalone/.next/static/chunks/{5358-15ceeb8c1cd9889d.js → 5358-4d1ef32068d304de.js} +2 -2
- package/_standalone/.next/static/chunks/{5581-c3be891101a3e511.js → 5581-c29703cc06a6c8dc.js} +2 -2
- package/_standalone/.next/static/chunks/app/.well-known/agent-card.json/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/_global-error/page-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/a2a/agents/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/a2a/delegations/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/a2a/discover/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/a2a/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/config/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/detect/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/install/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/registry/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/session/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/agent-activity/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/agents/copy-skill/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/agents/custom/detect/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/agents/custom/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/ask/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/ask-sessions/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/auth/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/backlinks/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/bootstrap/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/changes/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/channels/verify/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/connect/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/embedding/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/export/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/extract-pdf/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/file/import/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/file/raw/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/file/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/files/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/git/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/graph/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/health/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/im/activity/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/im/config/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/im/feishu/long-connection/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/im/status/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/im/test/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/im/webhook/feishu/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/im/webhook-status/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/inbox/clip/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/inbox/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/init/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/lint/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/agents/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/direct-tools/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/install/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/restart/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/status/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/tools/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/uninstall/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/monitoring/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/obsidian/compat-report/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/obsidian/import/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/recent-files/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/restart/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/search/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/settings/list-models/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/settings/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/settings/test-key/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/check-path/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/check-port/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/ls/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/skills/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/space-overview/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/sync/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/tree-version/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/uninstall/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/update/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/update-check/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/update-status/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/api/workflows/route-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/changes/page-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/echo/page-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/{layout-55af7e1870f7d59b.js → layout-5832614ed6a78167.js} +65 -65
- package/_standalone/.next/static/chunks/app/loading-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/setup/page-6135642c48cbf4e8.js +1 -0
- package/_standalone/.next/static/chunks/app/trash/{page-77dfe3df94abafb4.js → page-21dc1c6b6490cae8.js} +1 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/loading-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/app/view/[...path]/{page-6791166d03535cb7.js → page-e5330470ce362641.js} +2 -2
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-6359573cc0d7ff3b.js +1 -0
- package/_standalone/.next/static/chunks/webpack-6a9916defe5b8b6d.js +1 -0
- package/_standalone/.next/static/yJdsYbp_76hvDnNeV7OCT/_buildManifest.js +1 -0
- package/_standalone/.next/trace +72 -72
- package/_standalone/.next/types/routes.d.ts +3 -1
- package/_standalone/.next/types/validator.ts +18 -0
- package/_standalone/__tests__/acp/subprocess.test.ts +80 -0
- package/_standalone/__tests__/agent/model-config.test.ts +90 -0
- package/_standalone/__tests__/api/acp-detect.test.ts +4 -3
- package/_standalone/__tests__/api/obsidian-compat-report.test.ts +62 -0
- package/_standalone/__tests__/api/obsidian-import.test.ts +89 -0
- package/_standalone/__tests__/api/setup-path-utils.test.ts +188 -0
- package/_standalone/__tests__/ask/agent-selector-capsule.test.tsx +34 -0
- package/_standalone/__tests__/ask/ask-content-agent-capsule-visibility.test.tsx +195 -0
- package/_standalone/__tests__/ask/ask-content-input-during-run.test.tsx +1 -1
- package/_standalone/__tests__/fixtures/obsidian-community-fixtures.ts +92 -0
- package/_standalone/__tests__/obsidian-compat/community-smoke.test.ts +62 -0
- package/_standalone/__tests__/obsidian-compat/obsidian-import.test.ts +126 -0
- package/_standalone/__tests__/obsidian-compat/plugin-manager.test.ts +28 -0
- package/_standalone/__tests__/scripts/extract-pdf-runtime.test.ts +139 -0
- package/_standalone/components/ask/AgentSelectorCapsule.tsx +5 -4
- package/_standalone/components/ask/AskContent.tsx +2 -2
- package/_standalone/components/setup/StepKB.tsx +66 -17
- package/_standalone/lib/obsidian-compat/index.ts +1 -0
- package/_standalone/lib/obsidian-compat/plugin-manager.ts +13 -0
- package/_standalone/next.config.ts +2 -0
- package/_standalone/package-lock.json +2 -2
- package/_standalone/package.json +1 -1
- package/_standalone/server.js +1 -1
- package/_standalone/tsconfig.tsbuildinfo +1 -1
- package/app/__tests__/acp/subprocess.test.ts +80 -0
- package/app/__tests__/agent/model-config.test.ts +90 -0
- package/app/__tests__/api/acp-detect.test.ts +4 -3
- package/app/__tests__/api/obsidian-compat-report.test.ts +62 -0
- package/app/__tests__/api/obsidian-import.test.ts +89 -0
- package/app/__tests__/api/setup-path-utils.test.ts +188 -0
- package/app/__tests__/ask/agent-selector-capsule.test.tsx +34 -0
- package/app/__tests__/ask/ask-content-agent-capsule-visibility.test.tsx +195 -0
- package/app/__tests__/ask/ask-content-input-during-run.test.tsx +1 -1
- package/app/__tests__/fixtures/obsidian-community-fixtures.ts +92 -0
- package/app/__tests__/obsidian-compat/community-smoke.test.ts +62 -0
- package/app/__tests__/obsidian-compat/obsidian-import.test.ts +126 -0
- package/app/__tests__/obsidian-compat/plugin-manager.test.ts +28 -0
- package/app/__tests__/scripts/extract-pdf-runtime.test.ts +139 -0
- package/app/app/api/obsidian/compat-report/route.ts +33 -0
- package/app/app/api/obsidian/import/route.ts +37 -0
- package/app/app/api/setup/check-path/route.ts +16 -2
- package/app/app/api/setup/path-utils.ts +123 -1
- package/app/app/api/setup/route.ts +11 -1
- package/app/components/ask/AgentSelectorCapsule.tsx +5 -4
- package/app/components/ask/AskContent.tsx +2 -2
- package/app/components/setup/StepKB.tsx +66 -17
- package/app/components/setup/index.tsx +19 -1
- package/app/lib/acp/detect-local.ts +105 -24
- package/app/lib/acp/subprocess.ts +2 -1
- package/app/lib/agent/model.ts +2 -1
- package/app/lib/i18n/modules/onboarding.ts +2 -0
- package/app/lib/obsidian-compat/index.ts +1 -0
- package/app/lib/obsidian-compat/obsidian-import.ts +118 -0
- package/app/lib/obsidian-compat/plugin-manager.ts +13 -0
- package/app/lib/settings.ts +17 -5
- package/app/next.config.ts +2 -0
- package/app/package.json +1 -1
- package/package.json +1 -1
- package/_standalone/.next/static/chunks/app/.well-known/agent-card.json/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/_global-error/page-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/a2a/agents/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/a2a/delegations/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/a2a/discover/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/a2a/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/config/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/detect/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/install/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/registry/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/session/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/agent-activity/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/agents/copy-skill/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/agents/custom/detect/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/agents/custom/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/ask/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/ask-sessions/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/auth/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/backlinks/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/bootstrap/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/changes/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/channels/verify/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/connect/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/embedding/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/export/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/extract-pdf/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/file/import/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/file/raw/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/file/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/files/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/git/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/graph/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/health/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/im/activity/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/im/config/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/im/feishu/long-connection/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/im/status/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/im/test/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/im/webhook/feishu/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/im/webhook-status/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/inbox/clip/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/inbox/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/init/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/lint/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/agents/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/direct-tools/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/install/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/restart/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/status/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/tools/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/uninstall/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/monitoring/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/recent-files/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/restart/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/search/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/settings/list-models/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/settings/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/settings/test-key/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/check-path/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/check-port/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/ls/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/skills/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/space-overview/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/sync/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/tree-version/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/uninstall/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/update/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/update-check/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/update-status/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/api/workflows/route-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/changes/page-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/echo/page-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/loading-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/app/setup/page-64d7fa097ef3f367.js +0 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/loading-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-6d0a0465c7af74d1.js +0 -1
- package/_standalone/.next/static/chunks/webpack-aeeb4e3ebba9ef3c.js +0 -1
- package/_standalone/.next/static/f4SL2Rxm_VRCg6oVg9EuX/_buildManifest.js +0 -1
- package/_standalone/lib/obsidian-compat/compatibility-report.ts +0 -131
- package/_standalone/lib/obsidian-compat/manifest.ts +0 -90
- /package/_standalone/.next/static/{f4SL2Rxm_VRCg6oVg9EuX → yJdsYbp_76hvDnNeV7OCT}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const dynamic = 'force-dynamic';
|
|
2
|
+
|
|
3
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
4
|
+
import { handleRouteErrorSimple } from '@/lib/errors';
|
|
5
|
+
import { importObsidianPlugin, scanObsidianVaultPlugins } from '@/lib/obsidian-compat/obsidian-import';
|
|
6
|
+
import { expandSetupPathHome } from '@/app/api/setup/path-utils';
|
|
7
|
+
|
|
8
|
+
export async function POST(req: NextRequest) {
|
|
9
|
+
try {
|
|
10
|
+
const body = await req.json() as { vaultRoot?: string; pluginId?: string; targetMindRoot?: string };
|
|
11
|
+
if (!body.vaultRoot || !body.pluginId) {
|
|
12
|
+
return NextResponse.json({ ok: false, error: 'Missing vaultRoot or pluginId' }, { status: 400 });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const vaultRoot = expandSetupPathHome(body.vaultRoot.trim());
|
|
16
|
+
const targetMindRoot = expandSetupPathHome((body.targetMindRoot ?? process.cwd()).trim());
|
|
17
|
+
const plugins = await scanObsidianVaultPlugins(vaultRoot);
|
|
18
|
+
const plugin = plugins.find((item) => item.id === body.pluginId);
|
|
19
|
+
if (!plugin) {
|
|
20
|
+
return NextResponse.json({ ok: false, error: 'Plugin not found in Obsidian vault' }, { status: 404 });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const imported = await importObsidianPlugin({
|
|
24
|
+
vaultRoot,
|
|
25
|
+
pluginId: body.pluginId,
|
|
26
|
+
targetMindRoot,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return NextResponse.json({
|
|
30
|
+
ok: true,
|
|
31
|
+
plugin,
|
|
32
|
+
imported,
|
|
33
|
+
});
|
|
34
|
+
} catch (err) {
|
|
35
|
+
return handleRouteErrorSimple(err);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const dynamic = 'force-dynamic';
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
3
|
import { existsSync, readdirSync } from 'node:fs';
|
|
4
|
-
import { expandSetupPathHome } from '../path-utils';
|
|
4
|
+
import { expandSetupPathHome, validateMindRootPath } from '../path-utils';
|
|
5
5
|
import { handleRouteErrorSimple } from '@/lib/errors';
|
|
6
6
|
|
|
7
7
|
export async function POST(req: NextRequest) {
|
|
@@ -11,6 +11,20 @@ export async function POST(req: NextRequest) {
|
|
|
11
11
|
return NextResponse.json({ error: 'Invalid path' }, { status: 400 });
|
|
12
12
|
}
|
|
13
13
|
const abs = expandSetupPathHome(path.trim());
|
|
14
|
+
|
|
15
|
+
// Validate path is not inside dangerous directories
|
|
16
|
+
const validation = validateMindRootPath(abs);
|
|
17
|
+
if (!validation.safe) {
|
|
18
|
+
return NextResponse.json({
|
|
19
|
+
exists: false,
|
|
20
|
+
empty: true,
|
|
21
|
+
count: 0,
|
|
22
|
+
unsafe: true,
|
|
23
|
+
reason: validation.reason,
|
|
24
|
+
reasonZh: validation.reasonZh,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
14
28
|
const exists = existsSync(abs);
|
|
15
29
|
let empty = true;
|
|
16
30
|
let count = 0;
|
|
@@ -24,7 +38,7 @@ export async function POST(req: NextRequest) {
|
|
|
24
38
|
empty = false;
|
|
25
39
|
}
|
|
26
40
|
}
|
|
27
|
-
return NextResponse.json({ exists, empty, count });
|
|
41
|
+
return NextResponse.json({ exists, empty, count, unsafe: false });
|
|
28
42
|
} catch (err) {
|
|
29
43
|
return handleRouteErrorSimple(err);
|
|
30
44
|
}
|
|
@@ -1,8 +1,130 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
2
|
+
import path, { resolve } from 'node:path';
|
|
3
3
|
|
|
4
4
|
export function expandSetupPathHome(p: string): string {
|
|
5
5
|
if (p === '~') return homedir();
|
|
6
6
|
if (p.startsWith('~/') || p.startsWith('~\\')) return resolve(homedir(), p.slice(2));
|
|
7
7
|
return p;
|
|
8
8
|
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* List of dangerous path prefixes where knowledge base should NEVER be placed.
|
|
12
|
+
* These paths get cleared during install/update/uninstall and would cause data loss.
|
|
13
|
+
*
|
|
14
|
+
* Windows:
|
|
15
|
+
* - %APPDATA%\MindOS (Electron userData, may be cleared on uninstall)
|
|
16
|
+
* - %LOCALAPPDATA%\MindOS
|
|
17
|
+
* - Program Files (install directories, cleared on reinstall)
|
|
18
|
+
* - ~/.mindos/runtime (updater-managed, cleared on core update)
|
|
19
|
+
*
|
|
20
|
+
* macOS/Linux:
|
|
21
|
+
* - ~/.mindos/runtime (updater-managed)
|
|
22
|
+
* - /Applications/MindOS.app (install directory)
|
|
23
|
+
* - /opt/MindOS (Linux install directory)
|
|
24
|
+
*/
|
|
25
|
+
export interface PathValidationResult {
|
|
26
|
+
safe: boolean;
|
|
27
|
+
reason?: string;
|
|
28
|
+
reasonZh?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function normalizeForPathCheck(p: string): string {
|
|
32
|
+
return path.normalize(p).toLowerCase().replace(/\\/g, '/');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isSameOrSubPath(candidate: string, parent: string): boolean {
|
|
36
|
+
return candidate === parent || candidate.startsWith(parent + '/');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if a knowledge base path is safe (not inside install/system directories).
|
|
41
|
+
* Returns { safe: true } if OK, or { safe: false, reason, reasonZh } if dangerous.
|
|
42
|
+
*/
|
|
43
|
+
export function validateMindRootPath(absPath: string): PathValidationResult {
|
|
44
|
+
const normalized = normalizeForPathCheck(absPath);
|
|
45
|
+
const home = homedir();
|
|
46
|
+
const homeNorm = normalizeForPathCheck(home);
|
|
47
|
+
|
|
48
|
+
// ── 1. ~/.mindos/ system directory (updater, config, cache) ──
|
|
49
|
+
const mindosDir = homeNorm + '/.mindos';
|
|
50
|
+
if (isSameOrSubPath(normalized, mindosDir)) {
|
|
51
|
+
return {
|
|
52
|
+
safe: false,
|
|
53
|
+
reason: 'Cannot use ~/.mindos/ — this is the MindOS system directory (config, cache, updater). It gets modified during updates.',
|
|
54
|
+
reasonZh: '不能使用 ~/.mindos/ 目录——这是 MindOS 系统目录(配置、缓存、更新器),更新时会被修改。',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── 2. Windows-specific dangerous paths ──
|
|
59
|
+
if (process.platform === 'win32') {
|
|
60
|
+
const appData = normalizeForPathCheck(process.env.APPDATA || path.join(home, 'AppData', 'Roaming'));
|
|
61
|
+
const localAppData = normalizeForPathCheck(process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local'));
|
|
62
|
+
|
|
63
|
+
// Electron userData: %APPDATA%\MindOS or %LOCALAPPDATA%\MindOS
|
|
64
|
+
const electronUserData = appData + '/mindos';
|
|
65
|
+
const electronLocalData = localAppData + '/mindos';
|
|
66
|
+
if (isSameOrSubPath(normalized, electronUserData) || isSameOrSubPath(normalized, electronLocalData)) {
|
|
67
|
+
return {
|
|
68
|
+
safe: false,
|
|
69
|
+
reason: 'Cannot use AppData\\MindOS — this is the Electron app data directory. It may be cleared when uninstalling.',
|
|
70
|
+
reasonZh: '不能使用 AppData\\MindOS 目录——这是 Electron 应用数据目录,卸载时可能被清除。',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Program Files (default and x86)
|
|
75
|
+
const programFiles = normalizeForPathCheck(process.env.ProgramFiles || 'C:\\Program Files');
|
|
76
|
+
const programFilesX86 = normalizeForPathCheck(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)');
|
|
77
|
+
if (isSameOrSubPath(normalized, programFiles) || isSameOrSubPath(normalized, programFilesX86)) {
|
|
78
|
+
return {
|
|
79
|
+
safe: false,
|
|
80
|
+
reason: 'Cannot use Program Files — this is the Windows application directory. It gets cleared when reinstalling apps.',
|
|
81
|
+
reasonZh: '不能使用 Program Files 目录——这是 Windows 应用程序目录,重装时会被清除。',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── 3. macOS .app bundle ──
|
|
87
|
+
if (process.platform === 'darwin') {
|
|
88
|
+
if (normalized.includes('.app/') || normalized.endsWith('.app')) {
|
|
89
|
+
return {
|
|
90
|
+
safe: false,
|
|
91
|
+
reason: 'Cannot use a path inside an .app bundle — it gets replaced when updating the app.',
|
|
92
|
+
reasonZh: '不能使用 .app 包内的路径——更新应用时会被替换。',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// /Applications/MindOS.app adjacent directory
|
|
96
|
+
if (normalized.startsWith('/applications/mindos')) {
|
|
97
|
+
return {
|
|
98
|
+
safe: false,
|
|
99
|
+
reason: 'Cannot use /Applications/MindOS — this is the app install location. Use ~/MindOS/mind or ~/Documents instead.',
|
|
100
|
+
reasonZh: '不能使用 /Applications/MindOS——这是应用安装位置。请使用 ~/MindOS/mind 或 ~/Documents。',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ── 4. Linux install directories ──
|
|
106
|
+
if (process.platform === 'linux') {
|
|
107
|
+
if (normalized.startsWith('/opt/mindos') || normalized.startsWith('/usr/share/mindos')) {
|
|
108
|
+
return {
|
|
109
|
+
safe: false,
|
|
110
|
+
reason: 'Cannot use /opt/MindOS or /usr/share/MindOS — these are system install directories. Use ~/MindOS/mind instead.',
|
|
111
|
+
reasonZh: '不能使用 /opt/MindOS 或 /usr/share/MindOS——这些是系统安装目录。请使用 ~/MindOS/mind。',
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── 5. Actual Desktop install directory (dynamic, covers custom install paths) ──
|
|
117
|
+
const installDir = process.env.MINDOS_INSTALL_DIR;
|
|
118
|
+
if (installDir) {
|
|
119
|
+
const installDirNorm = normalizeForPathCheck(installDir);
|
|
120
|
+
if (isSameOrSubPath(normalized, installDirNorm)) {
|
|
121
|
+
return {
|
|
122
|
+
safe: false,
|
|
123
|
+
reason: 'Cannot use a path inside the MindOS Desktop installation directory — it gets deleted when reinstalling or uninstalling the app.',
|
|
124
|
+
reasonZh: '不能使用 MindOS Desktop 安装目录内的路径——重装或卸载应用时会被删除。',
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return { safe: true };
|
|
130
|
+
}
|
|
@@ -4,7 +4,7 @@ import fs from 'fs';
|
|
|
4
4
|
import os from 'os';
|
|
5
5
|
import { readSettings, writeSettings, ServerSettings } from '@/lib/settings';
|
|
6
6
|
import { applyTemplate } from '@/lib/template';
|
|
7
|
-
import { expandSetupPathHome } from './path-utils';
|
|
7
|
+
import { expandSetupPathHome, validateMindRootPath } from './path-utils';
|
|
8
8
|
import { type ProviderId, isProviderId, PROVIDER_PRESETS } from '@/lib/agent/providers';
|
|
9
9
|
import { type Provider, generateProviderId, findProvider } from '@/lib/custom-endpoints';
|
|
10
10
|
import { handleRouteErrorSimple } from '@/lib/errors';
|
|
@@ -60,6 +60,16 @@ export async function POST(req: NextRequest) {
|
|
|
60
60
|
|
|
61
61
|
const resolvedRoot = expandSetupPathHome(mindRoot.trim());
|
|
62
62
|
|
|
63
|
+
// Validate path is not inside dangerous directories (install dirs, system dirs)
|
|
64
|
+
const pathValidation = validateMindRootPath(resolvedRoot);
|
|
65
|
+
if (!pathValidation.safe) {
|
|
66
|
+
return NextResponse.json({
|
|
67
|
+
error: pathValidation.reason,
|
|
68
|
+
errorZh: pathValidation.reasonZh,
|
|
69
|
+
unsafePath: true,
|
|
70
|
+
}, { status: 400 });
|
|
71
|
+
}
|
|
72
|
+
|
|
63
73
|
// Validate ports
|
|
64
74
|
const webPort = typeof port === 'number' ? port : 3456;
|
|
65
75
|
const mcpPortNum = typeof mcpPort === 'number' ? mcpPort : 8781;
|
|
@@ -27,7 +27,11 @@ export default function AgentSelectorCapsule({
|
|
|
27
27
|
loading = false,
|
|
28
28
|
}: AgentSelectorCapsuleProps) {
|
|
29
29
|
const { t } = useLocale();
|
|
30
|
-
const p = t.panels
|
|
30
|
+
const p = t.panels?.agents ?? {
|
|
31
|
+
acpDefaultAgent: 'MindOS',
|
|
32
|
+
acpSelectAgent: 'Select Agent',
|
|
33
|
+
acpChangeAgent: 'Change agent',
|
|
34
|
+
};
|
|
31
35
|
const [open, setOpen] = useState(false);
|
|
32
36
|
const [pos, setPos] = useState<DropdownPos | null>(null);
|
|
33
37
|
const triggerRef = useRef<HTMLButtonElement>(null);
|
|
@@ -117,9 +121,6 @@ export default function AgentSelectorCapsule({
|
|
|
117
121
|
const isDefault = !selectedAgent;
|
|
118
122
|
const displayName = selectedAgent?.name ?? p.acpDefaultAgent;
|
|
119
123
|
|
|
120
|
-
// Only show if there are installed agents to choose from
|
|
121
|
-
if (!loading && installedAgents.length === 0 && !selectedAgent) return null;
|
|
122
|
-
|
|
123
124
|
const dropdown = open && pos ? (
|
|
124
125
|
<div
|
|
125
126
|
ref={dropdownRef}
|
|
@@ -183,7 +183,7 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
|
|
|
183
183
|
session.setSessionDefaultAcpAgent(agent);
|
|
184
184
|
}, [session]);
|
|
185
185
|
const hasLoadingAttachments = upload.localAttachments.some((f) => f.status === 'loading');
|
|
186
|
-
const composerStatusMessage = upload.uploadError || imageUpload.imageError ||
|
|
186
|
+
const composerStatusMessage = upload.uploadError || imageUpload.imageError || '';
|
|
187
187
|
|
|
188
188
|
useEffect(() => {
|
|
189
189
|
const handler = (e: Event) => {
|
|
@@ -815,7 +815,7 @@ export default function AskContent({ visible, currentFile, initialMessage, initi
|
|
|
815
815
|
<div className={cn('flex items-center justify-between border-t border-border/10', isPanel ? 'px-2 pb-1.5 pt-1 gap-1' : 'px-3 pb-2 pt-1.5')}>
|
|
816
816
|
<div className={cn('flex items-center flex-wrap', isPanel ? 'gap-1' : 'gap-2')}>
|
|
817
817
|
<ModeCapsule mode={chatMode} onChange={setChatMode} disabled={isLoading} />
|
|
818
|
-
{mounted &&
|
|
818
|
+
{mounted && (
|
|
819
819
|
<AgentSelectorCapsule
|
|
820
820
|
selectedAgent={selectedAcpAgent}
|
|
821
821
|
onSelect={handleSelectAcpAgent}
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect, useRef } from 'react';
|
|
4
|
-
import { AlertCircle } from 'lucide-react';
|
|
4
|
+
import { AlertCircle, FolderOpen } from 'lucide-react';
|
|
5
5
|
import { Field } from '@/components/settings/Primitives';
|
|
6
6
|
import type { Messages } from '@/lib/i18n';
|
|
7
|
+
import { useLocale } from '@/lib/stores/locale-store';
|
|
7
8
|
import type { SetupState } from './types';
|
|
8
9
|
import { TEMPLATES } from './constants';
|
|
9
10
|
|
|
11
|
+
// Desktop bridge for folder picker (Electron only)
|
|
12
|
+
interface MindosDesktopBridge {
|
|
13
|
+
selectDirectory?: () => Promise<string | null>;
|
|
14
|
+
}
|
|
15
|
+
function getDesktopBridge(): MindosDesktopBridge | null {
|
|
16
|
+
if (typeof window === 'undefined') return null;
|
|
17
|
+
const w = window as unknown as { mindos?: MindosDesktopBridge };
|
|
18
|
+
return w.mindos ?? null;
|
|
19
|
+
}
|
|
20
|
+
|
|
10
21
|
// Derive parent dir from current input for ls — supports both / and \ separators
|
|
11
22
|
function getParentDir(p: string): string {
|
|
12
23
|
if (!p.trim()) return '';
|
|
@@ -26,13 +37,15 @@ export interface StepKBProps {
|
|
|
26
37
|
}
|
|
27
38
|
|
|
28
39
|
export default function StepKB({ state, update, t, homeDir }: StepKBProps) {
|
|
40
|
+
const { locale } = useLocale();
|
|
41
|
+
const isZh = locale === 'zh';
|
|
29
42
|
const s = t.setup;
|
|
30
43
|
const [passwordTouched, setPasswordTouched] = useState(false);
|
|
31
44
|
// Build platform-aware placeholder, e.g. /Users/alice/MindOS/mind or C:\Users\alice\MindOS\mind
|
|
32
45
|
// Windows homedir always contains \, e.g. C:\Users\Alice — safe to detect by separator
|
|
33
46
|
const sep = homeDir.includes('\\') ? '\\' : '/';
|
|
34
47
|
const placeholder = homeDir !== '~' ? [homeDir, 'MindOS', 'mind'].join(sep) : s.kbPathDefault;
|
|
35
|
-
const [pathInfo, setPathInfo] = useState<{ exists: boolean; empty: boolean; count: number } | null>(null);
|
|
48
|
+
const [pathInfo, setPathInfo] = useState<{ exists: boolean; empty: boolean; count: number; unsafe?: boolean; reason?: string; reasonZh?: string } | null>(null);
|
|
36
49
|
const [suggestions, setSuggestions] = useState<string[]>([]);
|
|
37
50
|
const [showSuggestions, setShowSuggestions] = useState(false);
|
|
38
51
|
const [activeSuggestion, setActiveSuggestion] = useState(-1);
|
|
@@ -126,21 +139,42 @@ export default function StepKB({ state, update, t, homeDir }: StepKBProps) {
|
|
|
126
139
|
<div className="space-y-6">
|
|
127
140
|
<Field label={s.kbPath} hint={s.kbPathHint}>
|
|
128
141
|
<div className="relative">
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
<div className="flex gap-2">
|
|
143
|
+
<input
|
|
144
|
+
ref={inputRef}
|
|
145
|
+
value={state.mindRoot}
|
|
146
|
+
onChange={e => { update('mindRoot', e.target.value); setShowSuggestions(true); }}
|
|
147
|
+
onKeyDown={handleKeyDown}
|
|
148
|
+
onBlur={() => setTimeout(() => hideSuggestions(), 150)}
|
|
149
|
+
onFocus={() => suggestions.length > 0 && setShowSuggestions(true)}
|
|
150
|
+
placeholder={placeholder}
|
|
151
|
+
className="flex-1 px-3 py-2 text-sm rounded-lg border outline-none transition-colors focus-visible:ring-1 focus-visible:ring-ring"
|
|
152
|
+
style={{
|
|
153
|
+
background: 'var(--input, var(--card))',
|
|
154
|
+
borderColor: 'var(--border)',
|
|
155
|
+
color: 'var(--foreground)',
|
|
156
|
+
}}
|
|
157
|
+
/>
|
|
158
|
+
{/* Folder picker button — Desktop (Electron) only */}
|
|
159
|
+
{getDesktopBridge()?.selectDirectory && (
|
|
160
|
+
<button
|
|
161
|
+
type="button"
|
|
162
|
+
onClick={async () => {
|
|
163
|
+
const selected = await getDesktopBridge()?.selectDirectory?.();
|
|
164
|
+
if (selected) {
|
|
165
|
+
justSelectedRef.current = true;
|
|
166
|
+
update('mindRoot', selected);
|
|
167
|
+
hideSuggestions();
|
|
168
|
+
}
|
|
169
|
+
}}
|
|
170
|
+
className="px-3 py-2 rounded-lg border transition-colors hover:bg-muted/50"
|
|
171
|
+
style={{ borderColor: 'var(--border)' }}
|
|
172
|
+
title={s.kbPathBrowse ?? 'Browse...'}
|
|
173
|
+
>
|
|
174
|
+
<FolderOpen size={16} style={{ color: 'var(--muted-foreground)' }} />
|
|
175
|
+
</button>
|
|
176
|
+
)}
|
|
177
|
+
</div>
|
|
144
178
|
{showSuggestions && suggestions.length > 0 && (
|
|
145
179
|
<div
|
|
146
180
|
role="listbox"
|
|
@@ -179,6 +213,21 @@ export default function StepKB({ state, update, t, homeDir }: StepKBProps) {
|
|
|
179
213
|
{s.kbPathUseDefault(placeholder)}
|
|
180
214
|
</button>
|
|
181
215
|
)}
|
|
216
|
+
{/* ⚠️ Unsafe path warning — blocks setup until user picks a safe path */}
|
|
217
|
+
{pathInfo?.unsafe && (
|
|
218
|
+
<div className="mt-3 rounded-lg border p-3 text-sm flex gap-2 items-start"
|
|
219
|
+
style={{ borderColor: 'var(--error)', background: 'color-mix(in srgb, var(--error) 8%, transparent)' }}>
|
|
220
|
+
<AlertCircle size={16} className="flex-shrink-0 mt-0.5" style={{ color: 'var(--error)' }} />
|
|
221
|
+
<div>
|
|
222
|
+
<p className="font-medium" style={{ color: 'var(--error)' }}>
|
|
223
|
+
{isZh ? '路径不安全' : 'Unsafe Path'}
|
|
224
|
+
</p>
|
|
225
|
+
<p className="mt-1" style={{ color: 'var(--muted-foreground)' }}>
|
|
226
|
+
{isZh ? pathInfo.reasonZh : pathInfo.reason}
|
|
227
|
+
</p>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
)}
|
|
182
231
|
</Field>
|
|
183
232
|
{/* Template selection — conditional on directory state */}
|
|
184
233
|
{pathInfo && pathInfo.exists && !pathInfo.empty && !showTemplatePickerAnyway ? (
|
|
@@ -157,6 +157,7 @@ export default function SetupWizard() {
|
|
|
157
157
|
|
|
158
158
|
const [webPortStatus, setWebPortStatus] = useState<PortStatus>({ checking: false, available: null, isSelf: false, suggestion: null });
|
|
159
159
|
const [mcpPortStatus, setMcpPortStatus] = useState<PortStatus>({ checking: false, available: null, isSelf: false, suggestion: null });
|
|
160
|
+
const [pathUnsafe, setPathUnsafe] = useState(false); // Track if mindRoot is in a dangerous location
|
|
160
161
|
|
|
161
162
|
const [agents, setAgents] = useState<AgentEntry[]>([]);
|
|
162
163
|
const [agentsLoading, setAgentsLoading] = useState(false);
|
|
@@ -251,6 +252,22 @@ export default function SetupWizard() {
|
|
|
251
252
|
}
|
|
252
253
|
}, [step, agentsLoaded, agentsLoading]);
|
|
253
254
|
|
|
255
|
+
// Check path safety when mindRoot changes
|
|
256
|
+
useEffect(() => {
|
|
257
|
+
if (!state.mindRoot.trim()) { setPathUnsafe(false); return; }
|
|
258
|
+
const timer = setTimeout(() => {
|
|
259
|
+
fetch('/api/setup/check-path', {
|
|
260
|
+
method: 'POST',
|
|
261
|
+
headers: { 'Content-Type': 'application/json' },
|
|
262
|
+
body: JSON.stringify({ path: state.mindRoot }),
|
|
263
|
+
})
|
|
264
|
+
.then(r => r.json())
|
|
265
|
+
.then(d => setPathUnsafe(!!d.unsafe))
|
|
266
|
+
.catch(() => setPathUnsafe(false));
|
|
267
|
+
}, 400);
|
|
268
|
+
return () => clearTimeout(timer);
|
|
269
|
+
}, [state.mindRoot]);
|
|
270
|
+
|
|
254
271
|
const update = useCallback(<K extends keyof SetupState>(key: K, val: SetupState[K]) => {
|
|
255
272
|
setState(prev => ({ ...prev, [key]: val }));
|
|
256
273
|
}, []);
|
|
@@ -305,7 +322,8 @@ export default function SetupWizard() {
|
|
|
305
322
|
|
|
306
323
|
const canNext = () => {
|
|
307
324
|
if (step === STEP_KB) {
|
|
308
|
-
// KB path required + password required
|
|
325
|
+
// KB path required + password required + path must be safe
|
|
326
|
+
if (pathUnsafe) return false;
|
|
309
327
|
return state.mindRoot.trim().length > 0 && state.webPassword.trim().length > 0;
|
|
310
328
|
}
|
|
311
329
|
if (step === STEP_AI) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import os from 'os';
|
|
3
|
-
import { execFile } from 'child_process';
|
|
3
|
+
import { execFile, execFileSync } from 'child_process';
|
|
4
4
|
import { findUserOverride, getDetectableAgents, resolveAgentCommand } from './agent-descriptors';
|
|
5
5
|
import { readSettings } from '@/lib/settings';
|
|
6
6
|
|
|
@@ -22,17 +22,17 @@ export interface NotInstalledAgent {
|
|
|
22
22
|
packageName?: string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
function expandHome(filePath: string): string {
|
|
25
|
+
export function expandHome(filePath: string): string {
|
|
26
26
|
if (filePath === '~') return os.homedir();
|
|
27
27
|
if (filePath.startsWith('~/')) return `${os.homedir()}/${filePath.slice(2)}`;
|
|
28
28
|
return filePath;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function isPathLikeCommand(command: string): boolean {
|
|
31
|
+
export function isPathLikeCommand(command: string): boolean {
|
|
32
32
|
return command.startsWith('~/') || command.startsWith('/') || command.startsWith('./') || command.startsWith('../') || command.includes('\\') || /^[A-Za-z]:[\\/]/.test(command);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function resolveDirectCommandPath(command: string | undefined): string | null {
|
|
35
|
+
export function resolveDirectCommandPath(command: string | undefined): string | null {
|
|
36
36
|
if (!command) return null;
|
|
37
37
|
const trimmed = command.trim();
|
|
38
38
|
if (!trimmed || !isPathLikeCommand(trimmed)) return null;
|
|
@@ -40,7 +40,7 @@ function resolveDirectCommandPath(command: string | undefined): string | null {
|
|
|
40
40
|
return fs.existsSync(expanded) ? expanded : null;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
function resolveExistingPresenceDir(paths: string[] | undefined): string | null {
|
|
43
|
+
export function resolveExistingPresenceDir(paths: string[] | undefined): string | null {
|
|
44
44
|
if (!paths || paths.length === 0) return null;
|
|
45
45
|
for (const candidate of paths) {
|
|
46
46
|
const expanded = expandHome(candidate);
|
|
@@ -49,28 +49,103 @@ function resolveExistingPresenceDir(paths: string[] | undefined): string | null
|
|
|
49
49
|
return null;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function
|
|
53
|
-
const
|
|
54
|
-
|
|
52
|
+
function parseResolvedPath(stdout: string): string | null {
|
|
53
|
+
const candidates = stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
54
|
+
for (const candidate of candidates) {
|
|
55
|
+
const expanded = expandHome(candidate);
|
|
56
|
+
if (isPathLikeCommand(expanded) && fs.existsSync(expanded)) return expanded;
|
|
57
|
+
}
|
|
58
|
+
for (const candidate of candidates) {
|
|
59
|
+
if (isPathLikeCommand(candidate)) return expandHome(candidate);
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function shellEscape(command: string): string {
|
|
65
|
+
return `'${command.replace(/'/g, `'\\''`)}'`;
|
|
66
|
+
}
|
|
55
67
|
|
|
68
|
+
function getLoginShells(): string[] {
|
|
69
|
+
if (process.platform === 'win32') return [];
|
|
70
|
+
return [...new Set([
|
|
71
|
+
process.env.SHELL,
|
|
72
|
+
process.platform === 'darwin' ? '/bin/zsh' : undefined,
|
|
73
|
+
'/bin/bash',
|
|
74
|
+
'/bin/sh',
|
|
75
|
+
].filter((shell): shell is string => Boolean(shell)))];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function execFileText(command: string, args: string[]): Promise<string | null> {
|
|
56
79
|
return new Promise((resolve) => {
|
|
57
|
-
execFile(
|
|
80
|
+
execFile(command, args, { encoding: 'utf-8', timeout: 3000 }, (err, stdout) => {
|
|
58
81
|
if (err) {
|
|
59
82
|
resolve(null);
|
|
60
83
|
return;
|
|
61
84
|
}
|
|
62
|
-
|
|
63
|
-
.split(/\r?\n/)
|
|
64
|
-
.map((line) => line.trim())
|
|
65
|
-
.find(Boolean);
|
|
66
|
-
resolve(firstMatch ?? null);
|
|
85
|
+
resolve(stdout);
|
|
67
86
|
});
|
|
68
87
|
});
|
|
69
88
|
}
|
|
70
89
|
|
|
90
|
+
function execFileTextSync(command: string, args: string[]): string | null {
|
|
91
|
+
try {
|
|
92
|
+
return execFileSync(command, args, { encoding: 'utf-8', timeout: 3000 });
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function lookupCommandPathCurrentEnv(command: string): Promise<string | null> {
|
|
99
|
+
const stdout = await execFileText(process.platform === 'win32' ? 'where' : 'which', [command]);
|
|
100
|
+
return stdout ? parseResolvedPath(stdout) : null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function lookupCommandPathCurrentEnvSync(command: string): string | null {
|
|
104
|
+
const stdout = execFileTextSync(process.platform === 'win32' ? 'where' : 'which', [command]);
|
|
105
|
+
return stdout ? parseResolvedPath(stdout) : null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function lookupCommandPathLoginShell(command: string): Promise<string | null> {
|
|
109
|
+
for (const shell of getLoginShells()) {
|
|
110
|
+
const stdout = await execFileText(shell, ['-lic', `command -v -- ${shellEscape(command)}`]);
|
|
111
|
+
if (!stdout) continue;
|
|
112
|
+
const resolved = parseResolvedPath(stdout);
|
|
113
|
+
if (resolved) return resolved;
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function lookupCommandPathLoginShellSync(command: string): string | null {
|
|
119
|
+
for (const shell of getLoginShells()) {
|
|
120
|
+
const stdout = execFileTextSync(shell, ['-lic', `command -v -- ${shellEscape(command)}`]);
|
|
121
|
+
if (!stdout) continue;
|
|
122
|
+
const resolved = parseResolvedPath(stdout);
|
|
123
|
+
if (resolved) return resolved;
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export async function resolveCommandPath(command: string | undefined): Promise<string | null> {
|
|
129
|
+
if (!command) return null;
|
|
130
|
+
const direct = resolveDirectCommandPath(command);
|
|
131
|
+
if (direct) return direct;
|
|
132
|
+
const trimmed = command.trim();
|
|
133
|
+
if (!trimmed || isPathLikeCommand(trimmed)) return null;
|
|
134
|
+
return await lookupCommandPathCurrentEnv(trimmed) ?? await lookupCommandPathLoginShell(trimmed);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function resolveCommandPathSync(command: string | undefined): string | null {
|
|
138
|
+
if (!command) return null;
|
|
139
|
+
const direct = resolveDirectCommandPath(command);
|
|
140
|
+
if (direct) return direct;
|
|
141
|
+
const trimmed = command.trim();
|
|
142
|
+
if (!trimmed || isPathLikeCommand(trimmed)) return null;
|
|
143
|
+
return lookupCommandPathCurrentEnvSync(trimmed) ?? lookupCommandPathLoginShellSync(trimmed);
|
|
144
|
+
}
|
|
145
|
+
|
|
71
146
|
async function lookupCommandPaths(commands: string[]): Promise<Map<string, string | null>> {
|
|
72
147
|
const unique = [...new Set(commands.map((command) => command.trim()).filter(Boolean))];
|
|
73
|
-
const entries = await Promise.all(unique.map(async (command) => [command, await
|
|
148
|
+
const entries = await Promise.all(unique.map(async (command) => [command, await resolveCommandPath(command)] as const));
|
|
74
149
|
return new Map(entries);
|
|
75
150
|
}
|
|
76
151
|
|
|
@@ -80,29 +155,35 @@ export async function detectLocalAcpAgents(settings = readSettings()): Promise<{
|
|
|
80
155
|
const plans = agents.map((agent) => {
|
|
81
156
|
const userOverride = findUserOverride(agent.id, settings.acpAgents);
|
|
82
157
|
const resolved = resolveAgentCommand(agent.id, undefined, userOverride);
|
|
83
|
-
const
|
|
84
|
-
const
|
|
158
|
+
const directOverridePath = resolveDirectCommandPath(userOverride?.command);
|
|
159
|
+
const presenceCommands = [...new Set([
|
|
85
160
|
...(agent.detectCommands ?? [agent.binary]),
|
|
86
161
|
...(userOverride?.command && !isPathLikeCommand(userOverride.command) ? [userOverride.command] : []),
|
|
87
162
|
])];
|
|
88
|
-
return { agent, resolved,
|
|
163
|
+
return { agent, resolved, directOverridePath, presenceCommands };
|
|
89
164
|
});
|
|
90
165
|
|
|
91
|
-
const
|
|
166
|
+
const presenceLookup = await lookupCommandPaths(plans.flatMap((plan) => plan.presenceCommands));
|
|
167
|
+
const launchLookup = await lookupCommandPaths(plans.map((plan) => plan.resolved.cmd));
|
|
92
168
|
|
|
93
169
|
const installed: InstalledAgent[] = [];
|
|
94
170
|
const notInstalled: NotInstalledAgent[] = [];
|
|
95
171
|
|
|
96
|
-
for (const { agent, resolved,
|
|
97
|
-
const
|
|
98
|
-
|
|
172
|
+
for (const { agent, resolved, directOverridePath, presenceCommands } of plans) {
|
|
173
|
+
const detectedCommandPath = presenceCommands.map((command) => presenceLookup.get(command) ?? null).find(Boolean);
|
|
174
|
+
const presencePath = directOverridePath
|
|
175
|
+
?? detectedCommandPath
|
|
99
176
|
?? resolveExistingPresenceDir(agent.presenceDirs);
|
|
177
|
+
const launchPath = directOverridePath
|
|
178
|
+
?? launchLookup.get(resolved.cmd)
|
|
179
|
+
?? (presenceCommands.includes(resolved.cmd) ? detectedCommandPath : null)
|
|
180
|
+
?? null;
|
|
100
181
|
|
|
101
|
-
if (
|
|
182
|
+
if (presencePath && launchPath) {
|
|
102
183
|
installed.push({
|
|
103
184
|
id: agent.id,
|
|
104
185
|
name: agent.name,
|
|
105
|
-
binaryPath,
|
|
186
|
+
binaryPath: launchPath,
|
|
106
187
|
resolvedCommand: { cmd: resolved.cmd, args: resolved.args, source: resolved.source },
|
|
107
188
|
});
|
|
108
189
|
} else {
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
} from '@agentclientprotocol/sdk';
|
|
35
35
|
import type { AcpRegistryEntry } from './types';
|
|
36
36
|
import { resolveAgentCommand, findUserOverride } from './agent-descriptors';
|
|
37
|
+
import { resolveCommandPathSync } from './detect-local';
|
|
37
38
|
import { readSettings } from '../settings';
|
|
38
39
|
|
|
39
40
|
/* ── Types ─────────────────────────────────────────────────────────────── */
|
|
@@ -106,7 +107,7 @@ export function spawnAcpAgent(
|
|
|
106
107
|
const settings = readSettings();
|
|
107
108
|
const userOverride = findUserOverride(entry.id, settings.acpAgents);
|
|
108
109
|
const resolved = resolveAgentCommand(entry.id, entry, userOverride);
|
|
109
|
-
const { cmd, args } = { cmd: resolved.cmd, args: resolved.args };
|
|
110
|
+
const { cmd, args } = { cmd: resolveCommandPathSync(resolved.cmd) ?? resolved.cmd, args: resolved.args };
|
|
110
111
|
|
|
111
112
|
const mergedEnv = {
|
|
112
113
|
...process.env,
|
package/app/lib/agent/model.ts
CHANGED
|
@@ -47,9 +47,10 @@ export function getModelConfig(options?: ModelConfigOverrides): {
|
|
|
47
47
|
baseUrl: string;
|
|
48
48
|
} {
|
|
49
49
|
const saved = effectiveAiConfig(options?.provider);
|
|
50
|
+
const provider = options?.provider ?? saved.provider;
|
|
50
51
|
|
|
51
52
|
const cfg = {
|
|
52
|
-
provider
|
|
53
|
+
provider,
|
|
53
54
|
apiKey: options?.apiKey ?? saved.apiKey,
|
|
54
55
|
model: options?.model ?? saved.model,
|
|
55
56
|
baseUrl: options?.baseUrl ?? saved.baseUrl,
|