@geminilight/mindos 0.6.56 → 0.6.57
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 +23 -21
- 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 +8 -8
- 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 +2 -6
- 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_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/detect/route.js +1 -0
- package/_standalone/.next/server/app/api/agents/custom/detect/route.js.nft.json +1 -0
- package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -0
- package/_standalone/.next/server/app/api/agents/custom/route.js +1 -0
- package/_standalone/.next/server/app/api/agents/custom/route.js.nft.json +1 -0
- package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -0
- package/_standalone/.next/server/app/api/ask/route.js +3 -3
- 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.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_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/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 +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 +1 -1
- package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/trash/page.js +3 -3
- package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/view/[...path]/page.js +3 -3
- package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/wiki/page.js +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 -21
- package/_standalone/.next/server/chunks/2159.js +52 -0
- package/_standalone/.next/server/chunks/{2190.js → 3484.js} +1 -1
- package/_standalone/.next/server/chunks/530.js +29 -29
- 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 +2 -2
- 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/1053-5cb008a24930e271.js +29 -0
- package/_standalone/.next/static/chunks/1477.33df3cce509578c2.js +1 -0
- package/_standalone/.next/static/chunks/{1814.b08e9fb85dd3b13c.js → 1814.a7c127b2c73d1f70.js} +1 -1
- package/_standalone/.next/static/chunks/2549-e63cf57fa927a41d.js +1 -0
- package/_standalone/.next/static/chunks/{1007.c11404e50b39d165.js → 2647.e0b67d0c432ad7e7.js} +10 -10
- package/_standalone/.next/static/chunks/{2872.c8c8593be1ba4735.js → 2872.045858d00bd8307f.js} +2 -2
- package/_standalone/.next/static/chunks/362.3978790a2e636c3c.js +2 -0
- package/_standalone/.next/static/chunks/3637.38c4f28d8f698e0e.js +1 -0
- package/_standalone/.next/static/chunks/54a60aa6.7a74f547ec1bdd5a.js +79 -0
- package/_standalone/.next/static/chunks/6087.4b6102dc0bcd07a7.js +1 -0
- package/_standalone/.next/static/chunks/6878-e2c5459e1c608f89.js +1 -0
- package/_standalone/.next/static/chunks/7249-8cd568ad23656622.js +11 -0
- package/_standalone/.next/static/chunks/8252-e5ae7ced3a41e0ed.js +1 -0
- package/_standalone/.next/static/chunks/{8753-ea9db680b0f70f25.js → 8658-16ff58b75ae37fbb.js} +1 -1
- package/_standalone/.next/static/chunks/{7322-d67d05067544864c.js → 9274-296ab35f9f09e42e.js} +1 -1
- package/_standalone/.next/static/chunks/app/.well-known/agent-card.json/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/_global-error/page-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-7bdeab5af8e4f5f2.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/page-5d1446665ddb3801.js +1 -0
- package/_standalone/.next/static/chunks/app/api/a2a/agents/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/a2a/delegations/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/a2a/discover/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/a2a/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/config/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/detect/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/install/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/registry/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/acp/session/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/agent-activity/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/agents/custom/detect/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/agents/custom/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/ask/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/ask-sessions/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/auth/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/backlinks/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/bootstrap/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/changes/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/export/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/extract-pdf/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/file/import/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/file/raw/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/file/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/files/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/git/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/graph/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/health/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/inbox/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/init/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/agents/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/install/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/restart/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/status/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/mcp/uninstall/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/monitoring/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/recent-files/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/restart/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/search/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/settings/list-models/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/settings/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/settings/test-key/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/check-path/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/check-port/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/ls/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/setup/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/skills/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/sync/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/tree-version/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/uninstall/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/update/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/update-check/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/update-status/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/api/workflows/route-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/echo/[segment]/{page-6710da1f581b2854.js → page-b0103509ce34444b.js} +4 -4
- package/_standalone/.next/static/chunks/app/echo/page-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/{layout-d5f28933c5e14d74.js → layout-b3919384ec2eb979.js} +11 -11
- package/_standalone/.next/static/chunks/app/loading-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/{page-45140253e07a135a.js → page-6436a99cda35132b.js} +1 -1
- package/_standalone/.next/static/chunks/app/setup/{page-9a81fa4d82c6351b.js → page-99fcfc460fa29733.js} +1 -1
- package/_standalone/.next/static/chunks/app/trash/page-8dc388695344fdd4.js +1 -0
- package/_standalone/.next/static/chunks/app/view/[...path]/loading-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/app/view/[...path]/{page-62cfae628e31d411.js → page-b292b55305ecc021.js} +2 -2
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-2f4705aa66819b86.js +1 -0
- package/_standalone/.next/static/chunks/webpack-2c19436659aa657b.js +1 -0
- package/_standalone/.next/static/css/fd84c8316ead16eb.css +1 -0
- package/_standalone/.next/static/zOaEtgJbdRMncnCBucULp/_buildManifest.js +1 -0
- package/_standalone/.next/trace +64 -64
- package/_standalone/.next/types/routes.d.ts +3 -1
- package/_standalone/.next/types/validator.ts +18 -0
- package/_standalone/components/Editor.tsx +124 -6
- package/_standalone/components/MarkdownView.tsx +3 -1
- package/_standalone/components/WysiwygEditor.tsx +90 -0
- package/_standalone/components/agents/AgentsOverviewSection.tsx +100 -8
- package/_standalone/components/agents/CustomAgentModal.tsx +613 -0
- package/_standalone/components/settings/types.ts +4 -0
- package/_standalone/hooks/useEditorImageUpload.ts +113 -0
- package/_standalone/lib/image.ts +47 -0
- package/_standalone/tsconfig.tsbuildinfo +1 -1
- package/app/app/api/agents/custom/detect/route.ts +31 -0
- package/app/app/api/agents/custom/route.ts +150 -0
- package/app/app/api/file/import/route.ts +42 -0
- package/app/app/api/mcp/agents/route.ts +59 -7
- package/app/app/api/settings/list-models/route.ts +16 -2
- package/app/components/Editor.tsx +124 -6
- package/app/components/MarkdownView.tsx +3 -1
- package/app/components/WysiwygEditor.tsx +90 -0
- package/app/components/agents/AgentDetailContent.tsx +74 -1
- package/app/components/agents/AgentsContentPage.tsx +76 -1
- package/app/components/agents/AgentsOverviewSection.tsx +100 -8
- package/app/components/agents/CustomAgentModal.tsx +613 -0
- package/app/components/settings/types.ts +4 -0
- package/app/hooks/useEditorImageUpload.ts +113 -0
- package/app/lib/agent/model.ts +7 -1
- package/app/lib/agent/providers.ts +31 -6
- package/app/lib/core/organize.ts +1 -1
- package/app/lib/core/tree.ts +1 -1
- package/app/lib/custom-agents.ts +279 -0
- package/app/lib/fs.ts +1 -1
- package/app/lib/i18n/modules/panels.ts +96 -0
- package/app/lib/image.ts +47 -0
- package/app/lib/settings.ts +4 -0
- package/bin/commands/start.js +5 -4
- package/bin/commands/update.js +6 -2
- package/bin/lib/gateway.js +6 -2
- package/mcp/dist/index.cjs +1 -1
- package/mcp/src/index.ts +6 -1
- package/package.json +1 -1
- package/_standalone/.next/server/chunks/7543.js +0 -52
- package/_standalone/.next/static/3gMJ8EaZfDgHmB0NR0Q4T/_buildManifest.js +0 -1
- package/_standalone/.next/static/chunks/1053-2874859f7caefa0f.js +0 -29
- package/_standalone/.next/static/chunks/1880-7abf971bcfd2389b.js +0 -11
- package/_standalone/.next/static/chunks/254-32719a9bea2e74f0.js +0 -1
- package/_standalone/.next/static/chunks/362.a77be2f206db7b19.js +0 -1
- package/_standalone/.next/static/chunks/3637.0541ac2d0ea7de1f.js +0 -1
- package/_standalone/.next/static/chunks/54a60aa6.b97ba5e6900c089b.js +0 -79
- package/_standalone/.next/static/chunks/6087.0c32d26d0262c8e7.js +0 -1
- package/_standalone/.next/static/chunks/7035-2af69391c7b1ad95.js +0 -1
- package/_standalone/.next/static/chunks/8131.5e0bdb36bb91f212.js +0 -1
- package/_standalone/.next/static/chunks/app/.well-known/agent-card.json/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/_global-error/page-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-f006a70f6889eb56.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/page-bd522e428e3acb78.js +0 -5
- package/_standalone/.next/static/chunks/app/api/a2a/agents/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/a2a/delegations/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/a2a/discover/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/a2a/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/config/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/detect/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/install/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/registry/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/acp/session/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/agent-activity/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/ask/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/ask-sessions/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/auth/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/backlinks/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/bootstrap/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/changes/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/export/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/extract-pdf/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/file/import/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/file/raw/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/file/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/files/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/git/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/graph/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/health/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/inbox/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/init/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/agents/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/install/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/install-skill/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/restart/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/status/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/mcp/uninstall/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/monitoring/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/recent-files/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/restart/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/search/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/settings/list-models/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/settings/reset-token/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/settings/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/settings/test-key/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/check-path/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/check-port/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/generate-token/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/ls/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/setup/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/skills/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/sync/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/tree-version/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/uninstall/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/update/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/update-check/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/update-status/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/api/workflows/route-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/echo/page-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/loading-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/app/trash/page-c7f14311f040009e.js +0 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/loading-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-e240db6d5049d336.js +0 -1
- package/_standalone/.next/static/chunks/webpack-521ae5a2ddf0e396.js +0 -1
- package/_standalone/.next/static/css/66f8a81e4eda06d4.css +0 -1
- /package/_standalone/.next/static/{3gMJ8EaZfDgHmB0NR0Q4T → zOaEtgJbdRMncnCBucULp}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for uploading images to the .media/ directory in the editor.
|
|
3
|
+
*
|
|
4
|
+
* Unlike useImageUpload (for chat image attachments), this hook uploads
|
|
5
|
+
* images to the knowledge base's .media/ directory and returns file paths
|
|
6
|
+
* suitable for use in markdown `` syntax.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* const { uploadToMedia, isUploading } = useEditorImageUpload();
|
|
10
|
+
* const paths = await uploadToMedia([file1, file2]);
|
|
11
|
+
* // paths = ['/.media/2026-04-07_abc123.png', ...]
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { useState, useCallback } from 'react';
|
|
15
|
+
|
|
16
|
+
const MAX_IMAGE_SIZE = 10 * 1024 * 1024; // 10 MB per image
|
|
17
|
+
const ALLOWED_IMAGE_TYPES = new Set([
|
|
18
|
+
'image/png',
|
|
19
|
+
'image/jpeg',
|
|
20
|
+
'image/gif',
|
|
21
|
+
'image/webp',
|
|
22
|
+
'image/svg+xml',
|
|
23
|
+
'image/bmp',
|
|
24
|
+
'image/x-icon',
|
|
25
|
+
'image/vnd.microsoft.icon',
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Generates a unique filename: YYYY-MM-DD_randomhash.ext
|
|
30
|
+
*/
|
|
31
|
+
function generateImageFileName(originalName: string): string {
|
|
32
|
+
const ext = originalName.split('.').pop()?.toLowerCase() || 'png';
|
|
33
|
+
const timestamp = new Date().toISOString().split('T')[0];
|
|
34
|
+
const randomHash = Math.random().toString(36).slice(2, 10);
|
|
35
|
+
return `${timestamp}_${randomHash}.${ext}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Converts a File to base64 string (without data URL prefix). */
|
|
39
|
+
async function fileToBase64(file: File): Promise<string> {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const reader = new FileReader();
|
|
42
|
+
reader.onload = () => {
|
|
43
|
+
const result = reader.result as string;
|
|
44
|
+
resolve(result.split(',')[1]); // Strip "data:image/...;base64," prefix
|
|
45
|
+
};
|
|
46
|
+
reader.onerror = reject;
|
|
47
|
+
reader.readAsDataURL(file);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function useEditorImageUpload() {
|
|
52
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
53
|
+
|
|
54
|
+
const uploadToMedia = useCallback(async (files: File[]): Promise<string[]> => {
|
|
55
|
+
setIsUploading(true);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// Filter valid images
|
|
59
|
+
const validFiles: Array<{ base64: string; newName: string }> = [];
|
|
60
|
+
const skippedReasons: string[] = [];
|
|
61
|
+
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
if (!ALLOWED_IMAGE_TYPES.has(file.type)) {
|
|
64
|
+
skippedReasons.push(`${file.name}: unsupported format`);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (file.size > MAX_IMAGE_SIZE) {
|
|
68
|
+
skippedReasons.push(`${file.name}: exceeds 10MB limit`);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const base64 = await fileToBase64(file);
|
|
73
|
+
const newName = generateImageFileName(file.name);
|
|
74
|
+
validFiles.push({ base64, newName });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (validFiles.length === 0) {
|
|
78
|
+
throw new Error(skippedReasons.length > 0
|
|
79
|
+
? skippedReasons.join('; ')
|
|
80
|
+
: 'No valid images to upload');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const response = await fetch('/api/file/import', {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers: { 'Content-Type': 'application/json' },
|
|
86
|
+
body: JSON.stringify({
|
|
87
|
+
files: validFiles.map((img) => ({
|
|
88
|
+
name: img.newName,
|
|
89
|
+
content: img.base64,
|
|
90
|
+
encoding: 'base64',
|
|
91
|
+
})),
|
|
92
|
+
targetSpace: '.media',
|
|
93
|
+
organize: false, // Don't trigger AI organize for media files
|
|
94
|
+
conflict: 'rename',
|
|
95
|
+
}),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
const data = await response.json().catch(() => ({}));
|
|
100
|
+
throw new Error(data.error || `Upload failed: ${response.statusText}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const result = await response.json();
|
|
104
|
+
return (result.created ?? []).map(
|
|
105
|
+
(item: { path: string }) => `/${item.path}`,
|
|
106
|
+
);
|
|
107
|
+
} finally {
|
|
108
|
+
setIsUploading(false);
|
|
109
|
+
}
|
|
110
|
+
}, []);
|
|
111
|
+
|
|
112
|
+
return { uploadToMedia, isUploading };
|
|
113
|
+
}
|
package/app/lib/agent/model.ts
CHANGED
|
@@ -84,6 +84,12 @@ function resolveModel(providerId: ProviderId, modelName: string, baseUrl: string
|
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// 2.5. Apply preset fixedBaseUrl when registry lookup succeeded but needs endpoint override
|
|
88
|
+
// (zai-cn: domestic endpoint, deepseek: fixed baseUrl, ollama: localhost)
|
|
89
|
+
if (preset.fixedBaseUrl && !hasCustomBase) {
|
|
90
|
+
model = { ...model, baseUrl: preset.fixedBaseUrl };
|
|
91
|
+
}
|
|
92
|
+
|
|
87
93
|
// 3. Apply user's custom baseUrl
|
|
88
94
|
if (hasCustomBase) {
|
|
89
95
|
model = { ...model, baseUrl };
|
|
@@ -93,7 +99,7 @@ function resolveModel(providerId: ProviderId, modelName: string, baseUrl: string
|
|
|
93
99
|
}
|
|
94
100
|
}
|
|
95
101
|
|
|
96
|
-
// 4. For deepseek or any custom endpoint, apply conservative compat
|
|
102
|
+
// 4. For deepseek/zai-cn/ollama or any custom endpoint, apply conservative compat
|
|
97
103
|
if (hasCustomBase || preset.fixedBaseUrl) {
|
|
98
104
|
model = {
|
|
99
105
|
...model,
|
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
export type ProviderId =
|
|
17
17
|
| 'anthropic' | 'openai' | 'google' | 'groq'
|
|
18
18
|
| 'xai' | 'openrouter' | 'mistral' | 'deepseek'
|
|
19
|
-
| 'zai' | 'kimi-coding'
|
|
20
|
-
| 'cerebras' | 'minimax' | 'huggingface'
|
|
19
|
+
| 'zai' | 'zai-cn' | 'kimi-coding'
|
|
20
|
+
| 'cerebras' | 'minimax' | 'minimax-cn' | 'huggingface'
|
|
21
21
|
| 'ollama';
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -135,13 +135,26 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
|
|
|
135
135
|
zai: {
|
|
136
136
|
id: 'zai',
|
|
137
137
|
name: 'ZhipuAI (GLM)',
|
|
138
|
-
nameZh: '智谱 AI (GLM)',
|
|
138
|
+
nameZh: '智谱 AI (GLM 国际版)',
|
|
139
139
|
defaultModel: 'glm-4-plus',
|
|
140
140
|
supportsBaseUrl: false,
|
|
141
141
|
supportsThinking: true,
|
|
142
142
|
supportsListModels: false,
|
|
143
143
|
category: 'more',
|
|
144
144
|
},
|
|
145
|
+
'zai-cn': {
|
|
146
|
+
id: 'zai-cn',
|
|
147
|
+
name: 'ZhipuAI (GLM China)',
|
|
148
|
+
nameZh: '智谱 AI (GLM 国内版)',
|
|
149
|
+
defaultModel: 'glm-4-plus',
|
|
150
|
+
piProviderOverride: 'zai' as KnownProvider,
|
|
151
|
+
fixedBaseUrl: 'https://open.bigmodel.cn/api/coding/paas/v4',
|
|
152
|
+
supportsBaseUrl: false,
|
|
153
|
+
supportsThinking: true,
|
|
154
|
+
supportsListModels: false,
|
|
155
|
+
signupUrl: 'https://open.bigmodel.cn/',
|
|
156
|
+
category: 'more',
|
|
157
|
+
},
|
|
145
158
|
'kimi-coding': {
|
|
146
159
|
id: 'kimi-coding',
|
|
147
160
|
name: 'Kimi Coding',
|
|
@@ -165,10 +178,20 @@ export const PROVIDER_PRESETS: Record<ProviderId, ProviderPreset> = {
|
|
|
165
178
|
minimax: {
|
|
166
179
|
id: 'minimax',
|
|
167
180
|
name: 'MiniMax',
|
|
168
|
-
nameZh: 'MiniMax',
|
|
169
|
-
defaultModel: 'MiniMax-
|
|
181
|
+
nameZh: 'MiniMax (国际版)',
|
|
182
|
+
defaultModel: 'MiniMax-M2.5',
|
|
170
183
|
supportsBaseUrl: false,
|
|
171
|
-
supportsThinking:
|
|
184
|
+
supportsThinking: true,
|
|
185
|
+
supportsListModels: false,
|
|
186
|
+
category: 'more',
|
|
187
|
+
},
|
|
188
|
+
'minimax-cn': {
|
|
189
|
+
id: 'minimax-cn',
|
|
190
|
+
name: 'MiniMax (China)',
|
|
191
|
+
nameZh: 'MiniMax (国内版)',
|
|
192
|
+
defaultModel: 'MiniMax-M2.5',
|
|
193
|
+
supportsBaseUrl: false,
|
|
194
|
+
supportsThinking: true,
|
|
172
195
|
supportsListModels: false,
|
|
173
196
|
category: 'more',
|
|
174
197
|
},
|
|
@@ -288,8 +311,10 @@ const PI_ENV_MAP: Record<string, string> = {
|
|
|
288
311
|
xai: 'XAI_API_KEY',
|
|
289
312
|
openrouter: 'OPENROUTER_API_KEY',
|
|
290
313
|
zai: 'ZAI_API_KEY',
|
|
314
|
+
'zai-cn': 'ZAI_API_KEY',
|
|
291
315
|
mistral: 'MISTRAL_API_KEY',
|
|
292
316
|
minimax: 'MINIMAX_API_KEY',
|
|
317
|
+
'minimax-cn': 'MINIMAX_API_KEY',
|
|
293
318
|
huggingface: 'HF_TOKEN',
|
|
294
319
|
'kimi-coding': 'KIMI_API_KEY',
|
|
295
320
|
};
|
package/app/lib/core/organize.ts
CHANGED
|
@@ -14,7 +14,7 @@ const STOP_WORDS = new Set([
|
|
|
14
14
|
'readme', 'instruction', 'md',
|
|
15
15
|
]);
|
|
16
16
|
|
|
17
|
-
const SKIP_DIRS = new Set(['.git', 'node_modules', '.next', '.DS_Store']);
|
|
17
|
+
const SKIP_DIRS = new Set(['.git', 'node_modules', '.next', '.DS_Store', '.media', 'mcp']);
|
|
18
18
|
|
|
19
19
|
function extractKeywords(filePath: string): string[] {
|
|
20
20
|
const stem = path.basename(filePath, path.extname(filePath));
|
package/app/lib/core/tree.ts
CHANGED
|
@@ -3,7 +3,7 @@ import fsp from 'fs/promises';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import type { FileNode } from './types';
|
|
5
5
|
|
|
6
|
-
const DEFAULT_IGNORED_DIRS = new Set(['.git', 'node_modules', 'app', '.next', '.DS_Store', 'mcp']);
|
|
6
|
+
const DEFAULT_IGNORED_DIRS = new Set(['.git', 'node_modules', 'app', '.next', '.DS_Store', 'mcp', '.media']);
|
|
7
7
|
const DEFAULT_ALLOWED_EXTENSIONS = new Set([
|
|
8
8
|
'.md', '.csv', '.pdf',
|
|
9
9
|
'.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.ico',
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Agent registration: types, slugify, defaults inference, and persistence.
|
|
3
|
+
*
|
|
4
|
+
* CustomAgentDef is stored in config.json.customAgents[].
|
|
5
|
+
* At runtime, toAgentDef() converts it into the standard AgentDef that all
|
|
6
|
+
* downstream detection / snippet / UI code already understands.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { expandHome, MCP_AGENTS } from './mcp-agents';
|
|
12
|
+
import type { AgentDef } from './mcp-agents';
|
|
13
|
+
import { readSettings, writeSettings } from './settings';
|
|
14
|
+
|
|
15
|
+
/* ─── Types ─── */
|
|
16
|
+
|
|
17
|
+
export interface CustomAgentDef {
|
|
18
|
+
name: string;
|
|
19
|
+
key: string;
|
|
20
|
+
baseDir: string;
|
|
21
|
+
global: string;
|
|
22
|
+
project?: string | null;
|
|
23
|
+
configKey: string;
|
|
24
|
+
format: 'json' | 'toml';
|
|
25
|
+
preferredTransport: 'stdio' | 'http';
|
|
26
|
+
presenceDirs: string[];
|
|
27
|
+
presenceCli?: string;
|
|
28
|
+
globalNestedKey?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface DetectResult {
|
|
32
|
+
exists: boolean;
|
|
33
|
+
detectedConfig?: string;
|
|
34
|
+
detectedFormat?: 'json' | 'toml';
|
|
35
|
+
detectedConfigKey?: string;
|
|
36
|
+
hasSkillsDir: boolean;
|
|
37
|
+
suggestedName?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* ─── Slugify ─── */
|
|
41
|
+
|
|
42
|
+
export function slugify(name: string): string {
|
|
43
|
+
const slug = name
|
|
44
|
+
.toLowerCase()
|
|
45
|
+
.replace(/[^\x20-\x7E]/g, '')
|
|
46
|
+
.replace(/[_\s]+/g, '-')
|
|
47
|
+
.replace(/[^a-z0-9-]/g, '')
|
|
48
|
+
.replace(/-{2,}/g, '-')
|
|
49
|
+
.replace(/^-|-$/g, '');
|
|
50
|
+
|
|
51
|
+
return slug || '';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Generate a unique key from a name, avoiding collisions with built-in
|
|
56
|
+
* and existing custom agents.
|
|
57
|
+
*/
|
|
58
|
+
export function generateUniqueKey(
|
|
59
|
+
name: string,
|
|
60
|
+
existingKeys: Set<string>,
|
|
61
|
+
): string {
|
|
62
|
+
let base = slugify(name);
|
|
63
|
+
|
|
64
|
+
if (!base) {
|
|
65
|
+
let n = 1;
|
|
66
|
+
while (existingKeys.has(`custom-${n}`)) n++;
|
|
67
|
+
return `custom-${n}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!existingKeys.has(base)) return base;
|
|
71
|
+
|
|
72
|
+
let n = 2;
|
|
73
|
+
while (existingKeys.has(`${base}-${n}`)) n++;
|
|
74
|
+
return `${base}-${n}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* ─── Defaults Inference ─── */
|
|
78
|
+
|
|
79
|
+
export function inferDefaults(name: string, baseDir: string): Omit<CustomAgentDef, 'key'> {
|
|
80
|
+
const dir = baseDir.endsWith('/') ? baseDir : baseDir + '/';
|
|
81
|
+
return {
|
|
82
|
+
name,
|
|
83
|
+
baseDir: dir,
|
|
84
|
+
global: dir + 'mcp.json',
|
|
85
|
+
project: null,
|
|
86
|
+
configKey: 'mcpServers',
|
|
87
|
+
format: 'json',
|
|
88
|
+
preferredTransport: 'stdio',
|
|
89
|
+
presenceDirs: [dir],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* ─── Auto-detection ─── */
|
|
94
|
+
|
|
95
|
+
export function detectBaseDir(baseDir: string): DetectResult {
|
|
96
|
+
const expanded = expandHome(baseDir);
|
|
97
|
+
|
|
98
|
+
if (!fs.existsSync(expanded)) {
|
|
99
|
+
const dirName = path.basename(expanded.replace(/\/$/, ''));
|
|
100
|
+
return {
|
|
101
|
+
exists: false,
|
|
102
|
+
hasSkillsDir: false,
|
|
103
|
+
suggestedName: dirName.charAt(0).toUpperCase() + dirName.slice(1),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const result: DetectResult = {
|
|
108
|
+
exists: true,
|
|
109
|
+
hasSkillsDir: false,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const dirName = path.basename(expanded.replace(/\/$/, ''));
|
|
113
|
+
result.suggestedName = dirName.charAt(0).toUpperCase() + dirName.slice(1);
|
|
114
|
+
|
|
115
|
+
// Check for skills/ subdirectory
|
|
116
|
+
result.hasSkillsDir = fs.existsSync(path.join(expanded, 'skills'));
|
|
117
|
+
|
|
118
|
+
// Scan top-level files (max 20)
|
|
119
|
+
let entries: string[];
|
|
120
|
+
try {
|
|
121
|
+
entries = fs.readdirSync(expanded).slice(0, 20);
|
|
122
|
+
} catch {
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Try JSON files first
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
if (!entry.endsWith('.json')) continue;
|
|
129
|
+
const filePath = path.join(expanded, entry);
|
|
130
|
+
try {
|
|
131
|
+
const stat = fs.statSync(filePath);
|
|
132
|
+
if (!stat.isFile() || stat.size > 1_000_000) continue;
|
|
133
|
+
const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
134
|
+
if (raw && typeof raw === 'object') {
|
|
135
|
+
if ('mcpServers' in raw) {
|
|
136
|
+
result.detectedConfig = baseDir.endsWith('/') ? baseDir + entry : baseDir + '/' + entry;
|
|
137
|
+
result.detectedFormat = 'json';
|
|
138
|
+
result.detectedConfigKey = 'mcpServers';
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
if ('servers' in raw) {
|
|
142
|
+
result.detectedConfig = baseDir.endsWith('/') ? baseDir + entry : baseDir + '/' + entry;
|
|
143
|
+
result.detectedFormat = 'json';
|
|
144
|
+
result.detectedConfigKey = 'servers';
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} catch { /* skip unparseable files */ }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Try TOML files
|
|
152
|
+
for (const entry of entries) {
|
|
153
|
+
if (!entry.endsWith('.toml')) continue;
|
|
154
|
+
const filePath = path.join(expanded, entry);
|
|
155
|
+
try {
|
|
156
|
+
const stat = fs.statSync(filePath);
|
|
157
|
+
if (!stat.isFile() || stat.size > 1_000_000) continue;
|
|
158
|
+
const lines = fs.readFileSync(filePath, 'utf-8').split('\n').slice(0, 50);
|
|
159
|
+
for (const line of lines) {
|
|
160
|
+
if (/^\s*\[mcp_servers/i.test(line) || /^\s*\[mcpServers/i.test(line)) {
|
|
161
|
+
const lower = line.toLowerCase();
|
|
162
|
+
const key = lower.includes('mcp_servers') ? 'mcp_servers' : 'mcpServers';
|
|
163
|
+
result.detectedConfig = baseDir.endsWith('/') ? baseDir + entry : baseDir + '/' + entry;
|
|
164
|
+
result.detectedFormat = 'toml';
|
|
165
|
+
result.detectedConfigKey = key;
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} catch { /* skip */ }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* ─── AgentDef Conversion ─── */
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Convert a CustomAgentDef into the standard AgentDef that all downstream
|
|
179
|
+
* code (detectInstalled, generateSnippet, etc.) expects.
|
|
180
|
+
*
|
|
181
|
+
* Note: AgentDef.key is the *config key* (e.g. "mcpServers"), not the agent identifier.
|
|
182
|
+
* The agent identifier is the key in the MCP_AGENTS record, which comes from CustomAgentDef.key.
|
|
183
|
+
*/
|
|
184
|
+
export function toAgentDef(custom: CustomAgentDef): AgentDef {
|
|
185
|
+
return {
|
|
186
|
+
name: custom.name,
|
|
187
|
+
project: custom.project ?? null,
|
|
188
|
+
global: custom.global,
|
|
189
|
+
key: custom.configKey,
|
|
190
|
+
preferredTransport: custom.preferredTransport,
|
|
191
|
+
format: custom.format,
|
|
192
|
+
globalNestedKey: custom.globalNestedKey,
|
|
193
|
+
presenceCli: custom.presenceCli,
|
|
194
|
+
presenceDirs: custom.presenceDirs,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* ─── Persistence ─── */
|
|
199
|
+
|
|
200
|
+
export function loadCustomAgents(): CustomAgentDef[] {
|
|
201
|
+
try {
|
|
202
|
+
const settings = readSettings();
|
|
203
|
+
const raw = settings.customAgents;
|
|
204
|
+
if (!Array.isArray(raw)) return [];
|
|
205
|
+
return raw.filter(
|
|
206
|
+
(item): item is CustomAgentDef => {
|
|
207
|
+
if (item == null || typeof item !== 'object') return false;
|
|
208
|
+
const obj = item as unknown as Record<string, unknown>;
|
|
209
|
+
return typeof obj.name === 'string' && typeof obj.key === 'string' && typeof obj.baseDir === 'string';
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
} catch {
|
|
213
|
+
console.warn('[custom-agents] Failed to parse, using empty list');
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function saveCustomAgents(agents: CustomAgentDef[]): void {
|
|
219
|
+
const settings = readSettings();
|
|
220
|
+
settings.customAgents = agents;
|
|
221
|
+
writeSettings(settings);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* ─── Merged Registry ─── */
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Returns all agents (built-in + custom) as a Record<agentId, AgentDef>.
|
|
228
|
+
* Built-in agents take priority on key collision.
|
|
229
|
+
*/
|
|
230
|
+
export function getAllAgents(): Record<string, AgentDef> {
|
|
231
|
+
const result: Record<string, AgentDef> = { ...MCP_AGENTS };
|
|
232
|
+
const customs = loadCustomAgents();
|
|
233
|
+
|
|
234
|
+
for (const custom of customs) {
|
|
235
|
+
if (custom.key in result) continue; // built-in priority
|
|
236
|
+
result[custom.key] = toAgentDef(custom);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/* ─── Validation ─── */
|
|
243
|
+
|
|
244
|
+
export function validateCustomAgentInput(input: {
|
|
245
|
+
name?: string;
|
|
246
|
+
baseDir?: string;
|
|
247
|
+
key?: string;
|
|
248
|
+
}, existingKeys: Set<string>, isEdit = false): string | null {
|
|
249
|
+
if (!input.name || !input.name.trim()) {
|
|
250
|
+
return 'Agent name is required';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (!input.baseDir || !input.baseDir.trim()) {
|
|
254
|
+
return 'Config directory is required';
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const dir = input.baseDir.trim();
|
|
258
|
+
if (!dir.startsWith('~/') && !dir.startsWith('/')) {
|
|
259
|
+
if (process.platform === 'win32' && /^[A-Z]:\\/i.test(dir)) {
|
|
260
|
+
// Windows absolute path — OK
|
|
261
|
+
} else {
|
|
262
|
+
return 'Must be an absolute path (e.g. ~/.qclaw/)';
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (!isEdit) {
|
|
267
|
+
const key = input.key || slugify(input.name.trim());
|
|
268
|
+
if (!key) return 'Cannot generate a valid key from this name';
|
|
269
|
+
if (key in MCP_AGENTS) {
|
|
270
|
+
const builtIn = MCP_AGENTS[key];
|
|
271
|
+
return `Conflicts with built-in agent "${builtIn.name}"`;
|
|
272
|
+
}
|
|
273
|
+
if (existingKeys.has(key)) {
|
|
274
|
+
return `An agent with key "${key}" already exists`;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return null;
|
|
279
|
+
}
|
package/app/lib/fs.ts
CHANGED
|
@@ -49,7 +49,7 @@ export function getMindRoot(): string {
|
|
|
49
49
|
return effectiveSopRoot();
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const IGNORED_DIRS = new Set(['.git', 'node_modules', 'app', '.next', '.DS_Store']);
|
|
52
|
+
const IGNORED_DIRS = new Set(['.git', 'node_modules', 'app', '.next', '.DS_Store', '.media', 'mcp']);
|
|
53
53
|
const ALLOWED_EXTENSIONS = new Set([
|
|
54
54
|
'.md', '.csv', '.json', '.pdf',
|
|
55
55
|
'.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.ico',
|
|
@@ -313,6 +313,54 @@ export const panelsEn = {
|
|
|
313
313
|
recentActivity: 'Recent Activity',
|
|
314
314
|
viewAll: 'View all',
|
|
315
315
|
showLess: 'Show less',
|
|
316
|
+
addCustomAgent: 'Add your own agent',
|
|
317
|
+
addCustomAgentTitle: 'Add Custom Agent',
|
|
318
|
+
editCustomAgentTitle: (name: string) => `Edit ${name}`,
|
|
319
|
+
customAgentName: 'Agent Name',
|
|
320
|
+
customAgentNamePlaceholder: 'e.g. QCLaw, WorkBuddy',
|
|
321
|
+
customAgentDir: 'Config Directory',
|
|
322
|
+
customAgentDirPlaceholder: '~/.qclaw/',
|
|
323
|
+
customAgentDirHint: 'Common: ~/.xxx/ or ~/Library/Application Support/',
|
|
324
|
+
customAgentKeyPreview: (key: string) => `Key: ${key}`,
|
|
325
|
+
customAgentContinue: 'Continue',
|
|
326
|
+
customAgentDetecting: 'Detecting...',
|
|
327
|
+
customAgentDirFound: 'Directory found',
|
|
328
|
+
customAgentDirNotFound: 'Not found yet — agent will appear when installed',
|
|
329
|
+
customAgentDetectTimeout: 'Detection timed out, using defaults',
|
|
330
|
+
customAgentDetectedTitle: 'Detected Configuration',
|
|
331
|
+
customAgentDefaultTitle: 'Default Configuration',
|
|
332
|
+
customAgentConfigLabel: 'MCP Config',
|
|
333
|
+
customAgentFormatLabel: 'Format',
|
|
334
|
+
customAgentTransportLabel: 'Transport',
|
|
335
|
+
customAgentSkillsLabel: 'Skills',
|
|
336
|
+
customAgentSkillsFound: (n: number) => `${n} found`,
|
|
337
|
+
customAgentCustomize: 'Customize these settings',
|
|
338
|
+
customAgentAdd: 'Add Agent',
|
|
339
|
+
customAgentAdding: 'Adding...',
|
|
340
|
+
customAgentSave: 'Save Changes',
|
|
341
|
+
customAgentSaving: 'Saving...',
|
|
342
|
+
customAgentRetry: 'Retry',
|
|
343
|
+
customAgentAdded: (name: string) => `${name} added`,
|
|
344
|
+
customAgentUpdated: (name: string) => `${name} updated`,
|
|
345
|
+
customAgentRemoved: (name: string) => `${name} removed`,
|
|
346
|
+
customAgentRemoveTitle: (name: string) => `Remove "${name}"?`,
|
|
347
|
+
customAgentRemoveMessage: 'This removes the agent from MindOS. No files will be deleted on disk.',
|
|
348
|
+
customAgentRemoveConfirm: 'Remove',
|
|
349
|
+
customAgentConfigPath: 'MCP Config File Path',
|
|
350
|
+
customAgentConfigKey: 'Config Key',
|
|
351
|
+
customAgentFormat: 'Format',
|
|
352
|
+
customAgentTransport: 'Transport',
|
|
353
|
+
customAgentProjectConfig: 'Project Config (optional)',
|
|
354
|
+
customAgentCliBinary: 'CLI Binary (optional)',
|
|
355
|
+
customAgentCliBinaryPlaceholder: 'e.g. qclaw',
|
|
356
|
+
customAgentEdit: 'Edit',
|
|
357
|
+
customAgentRemove: 'Remove',
|
|
358
|
+
customAgentCancel: 'Cancel',
|
|
359
|
+
customAgentNetworkError: 'Network error. Please try again.',
|
|
360
|
+
customAgentFailedSave: 'Failed to save',
|
|
361
|
+
customAgentFailedRemove: 'Failed to remove',
|
|
362
|
+
customAgentKeyConflict: (key: string) => `An agent with key "${key}" already exists`,
|
|
363
|
+
customAgentBuiltinConflict: (name: string) => `Conflicts with built-in agent "${name}"`,
|
|
316
364
|
},
|
|
317
365
|
mcp: {
|
|
318
366
|
title: 'MCP Connections',
|
|
@@ -949,6 +997,54 @@ export const panelsZh = {
|
|
|
949
997
|
recentActivity: '最近活动',
|
|
950
998
|
viewAll: '查看全部',
|
|
951
999
|
showLess: '收起',
|
|
1000
|
+
addCustomAgent: '添加自定义 Agent',
|
|
1001
|
+
addCustomAgentTitle: '添加自定义 Agent',
|
|
1002
|
+
editCustomAgentTitle: (name: string) => `编辑 ${name}`,
|
|
1003
|
+
customAgentName: 'Agent 名称',
|
|
1004
|
+
customAgentNamePlaceholder: '例如 QCLaw、WorkBuddy',
|
|
1005
|
+
customAgentDir: '配置目录',
|
|
1006
|
+
customAgentDirPlaceholder: '~/.qclaw/',
|
|
1007
|
+
customAgentDirHint: '常见路径:~/.xxx/ 或 ~/Library/Application Support/',
|
|
1008
|
+
customAgentKeyPreview: (key: string) => `标识符:${key}`,
|
|
1009
|
+
customAgentContinue: '继续',
|
|
1010
|
+
customAgentDetecting: '检测中...',
|
|
1011
|
+
customAgentDirFound: '目录已找到',
|
|
1012
|
+
customAgentDirNotFound: '目录尚未创建,安装后将自动检测',
|
|
1013
|
+
customAgentDetectTimeout: '检测超时,使用默认配置',
|
|
1014
|
+
customAgentDetectedTitle: '检测到的配置',
|
|
1015
|
+
customAgentDefaultTitle: '默认配置',
|
|
1016
|
+
customAgentConfigLabel: 'MCP 配置',
|
|
1017
|
+
customAgentFormatLabel: '格式',
|
|
1018
|
+
customAgentTransportLabel: '传输协议',
|
|
1019
|
+
customAgentSkillsLabel: '技能',
|
|
1020
|
+
customAgentSkillsFound: (n: number) => `发现 ${n} 个`,
|
|
1021
|
+
customAgentCustomize: '自定义配置',
|
|
1022
|
+
customAgentAdd: '添加 Agent',
|
|
1023
|
+
customAgentAdding: '添加中...',
|
|
1024
|
+
customAgentSave: '保存更改',
|
|
1025
|
+
customAgentSaving: '保存中...',
|
|
1026
|
+
customAgentRetry: '重试',
|
|
1027
|
+
customAgentAdded: (name: string) => `${name} 已添加`,
|
|
1028
|
+
customAgentUpdated: (name: string) => `${name} 已更新`,
|
|
1029
|
+
customAgentRemoved: (name: string) => `${name} 已移除`,
|
|
1030
|
+
customAgentRemoveTitle: (name: string) => `移除「${name}」?`,
|
|
1031
|
+
customAgentRemoveMessage: '这将从 MindOS 中移除该 Agent,不会删除磁盘上的任何文件。',
|
|
1032
|
+
customAgentRemoveConfirm: '移除',
|
|
1033
|
+
customAgentConfigPath: 'MCP 配置文件路径',
|
|
1034
|
+
customAgentConfigKey: '配置键名',
|
|
1035
|
+
customAgentFormat: '格式',
|
|
1036
|
+
customAgentTransport: '传输协议',
|
|
1037
|
+
customAgentProjectConfig: '项目配置路径(可选)',
|
|
1038
|
+
customAgentCliBinary: 'CLI 命令名(可选)',
|
|
1039
|
+
customAgentCliBinaryPlaceholder: '例如 qclaw',
|
|
1040
|
+
customAgentEdit: '编辑',
|
|
1041
|
+
customAgentRemove: '移除',
|
|
1042
|
+
customAgentCancel: '取消',
|
|
1043
|
+
customAgentNetworkError: '网络错误,请重试。',
|
|
1044
|
+
customAgentFailedSave: '保存失败',
|
|
1045
|
+
customAgentFailedRemove: '移除失败',
|
|
1046
|
+
customAgentKeyConflict: (key: string) => `已存在标识为 "${key}" 的 Agent`,
|
|
1047
|
+
customAgentBuiltinConflict: (name: string) => `与内置 Agent "${name}" 冲突`,
|
|
952
1048
|
},
|
|
953
1049
|
mcp: {
|
|
954
1050
|
title: 'MCP 连接',
|
package/app/lib/image.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image path resolution utilities for Markdown.
|
|
3
|
+
*
|
|
4
|
+
* Converts markdown image paths (e.g., ``) to API URLs
|
|
5
|
+
* that can be served by `/api/file/raw?path=...`
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Checks if a path is an absolute path (starts with `/`).
|
|
10
|
+
*/
|
|
11
|
+
function isAbsolutePath(path: string): boolean {
|
|
12
|
+
return path.startsWith('/');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks if a path is a URL (starts with protocol like http://, https://, file://).
|
|
17
|
+
*/
|
|
18
|
+
function isUrl(path: string): boolean {
|
|
19
|
+
return /^(https?|file):\/\//.test(path);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolves an image path to a URL for the API endpoint.
|
|
24
|
+
*
|
|
25
|
+
* Rules:
|
|
26
|
+
* - Absolute paths (start with `/`) → `/api/file/raw?path=...` (strip leading slash)
|
|
27
|
+
* - URLs (http/https/file) → return as-is
|
|
28
|
+
* - Relative paths → return as-is (browser handles relative URLs)
|
|
29
|
+
*
|
|
30
|
+
* @param imagePath - The image path from markdown syntax
|
|
31
|
+
* @returns The resolved URL or path
|
|
32
|
+
*/
|
|
33
|
+
export function resolveImagePath(imagePath: string): string {
|
|
34
|
+
// Already a URL
|
|
35
|
+
if (isUrl(imagePath)) {
|
|
36
|
+
return imagePath;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Absolute path like `/.media/image.png` or `/path/to/image.png`
|
|
40
|
+
if (isAbsolutePath(imagePath)) {
|
|
41
|
+
const cleanPath = imagePath.slice(1); // Remove leading `/`
|
|
42
|
+
return `/api/file/raw?path=${encodeURIComponent(cleanPath)}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Relative path — return as-is for browser to resolve
|
|
46
|
+
return imagePath;
|
|
47
|
+
}
|