@geminilight/mindos 0.6.40 → 0.6.41
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 +18 -18
- 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 +5 -1
- package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error.html +2 -2
- package/_standalone/.next/server/app/_global-error.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/_standalone/.next/server/app/_not-found/page.js +1 -1
- package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page.js +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 -2
- package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/config/route_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/ask/route.js +1 -1
- package/_standalone/.next/server/app/api/ask/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/backlinks/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/bootstrap/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/changes/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/export/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/import/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/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.nft.json +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install/route.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install-skill/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/status/route.js +1 -1
- package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/reset-token/route_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_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 +2 -2
- package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/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 +2 -2
- package/_standalone/.next/server/app/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/setup/page.js +2 -2
- package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/trash/page.js +3 -3
- package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/view/[...path]/page.js +3 -3
- package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app-paths-manifest.json +18 -18
- package/_standalone/.next/server/chunks/1550.js +1 -1
- package/_standalone/.next/server/chunks/2190.js +11 -0
- package/_standalone/.next/server/chunks/{6365.js → 2536.js} +2 -2
- package/_standalone/.next/server/chunks/5648.js +2 -0
- package/_standalone/.next/server/chunks/8388.js +1 -1
- package/_standalone/.next/server/chunks/953.js +1 -1
- package/_standalone/.next/server/chunks/9539.js +219 -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/next-font-manifest.js +1 -1
- package/_standalone/.next/server/next-font-manifest.json +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-b70535785cc5aaee.js +29 -0
- package/_standalone/.next/static/chunks/{8663-de911d2d395622be.js → 1880-c2a9e76201841c86.js} +1 -1
- package/_standalone/.next/static/chunks/3637.0541ac2d0ea7de1f.js +1 -0
- package/_standalone/.next/static/chunks/4563-b2a2ce80aff845af.js +6 -0
- package/_standalone/.next/static/chunks/6981-3d7dcac2d12a5670.js +1 -0
- package/_standalone/.next/static/chunks/7144-5febf62f1a79fe64.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-773071a99c4daac2.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/page-6102a884b2cb3cfe.js +5 -0
- package/_standalone/.next/static/chunks/app/help/page-2325d25b6846ca07.js +1 -0
- package/_standalone/.next/static/chunks/app/{layout-9378c1c8d3e5761b.js → layout-42cdbce19f404567.js} +34 -34
- package/_standalone/.next/static/chunks/app/{page-9bae420fbbdc5fff.js → page-8c9643b649e01735.js} +1 -1
- package/_standalone/.next/static/chunks/app/setup/page-d158b8cb533feb1e.js +1 -0
- package/_standalone/.next/static/chunks/app/trash/{page-b61ef2d5cd4f8d73.js → page-e9ab74ffeb96af41.js} +1 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/page-764a69a1c8bd4eef.js +12 -0
- package/_standalone/.next/static/chunks/{webpack-c28c55d0a6021a6b.js → webpack-7b276daaa930d480.js} +1 -1
- package/_standalone/.next/static/css/bc9179074eaf65ae.css +1 -0
- package/_standalone/.next/trace +63 -63
- package/_standalone/__tests__/api/mcp-install.test.ts +23 -0
- package/_standalone/__tests__/cli/agent-routing.test.ts +232 -0
- package/_standalone/__tests__/cli/file-subcommands.test.ts +379 -0
- package/_standalone/__tests__/core/tools.test.ts +3 -6
- package/_standalone/components/FileTree.tsx +3 -2
- package/_standalone/components/MarkdownView.tsx +30 -15
- package/_standalone/components/RightAskPanel.tsx +36 -6
- package/_standalone/components/Sidebar.tsx +3 -3
- package/_standalone/components/agents/AgentsMcpSection.tsx +3 -0
- package/_standalone/components/settings/McpAgentInstall.tsx +94 -27
- package/_standalone/components/settings/McpSkillsSection.tsx +1 -1
- package/_standalone/components/settings/McpTab.tsx +484 -340
- package/_standalone/components/settings/SettingsContent.tsx +12 -6
- package/_standalone/components/settings/types.ts +3 -0
- package/_standalone/components/setup/StepAgents.tsx +113 -47
- package/_standalone/components/setup/StepReview.tsx +14 -27
- package/_standalone/components/setup/types.ts +6 -0
- package/_standalone/data/skills/mindos/SKILL.md +92 -92
- package/_standalone/data/skills/mindos/references/write-supplement.md +119 -0
- package/_standalone/data/skills/mindos-zh/SKILL.md +100 -104
- package/_standalone/data/skills/mindos-zh/references/write-supplement.md +119 -0
- package/_standalone/lib/i18n/modules/features.ts +4 -4
- package/_standalone/lib/i18n/modules/knowledge.ts +4 -0
- package/_standalone/lib/i18n/modules/onboarding.ts +40 -30
- package/_standalone/lib/i18n/modules/settings.ts +78 -6
- package/_standalone/lib/mcp-snippets.ts +5 -1
- package/_standalone/tsconfig.tsbuildinfo +1 -1
- package/app/app/api/ask/route.ts +3 -2
- package/app/app/api/mcp/install/route.ts +2 -1
- package/app/app/api/mcp/status/route.ts +14 -6
- package/app/app/view/[...path]/ViewPageClient.tsx +12 -27
- package/app/components/FileTree.tsx +3 -2
- package/app/components/MarkdownView.tsx +30 -15
- package/app/components/RightAskPanel.tsx +36 -6
- package/app/components/Sidebar.tsx +3 -3
- package/app/components/agents/AgentsMcpSection.tsx +3 -0
- package/app/components/help/HelpContent.tsx +1 -0
- package/app/components/settings/McpAgentInstall.tsx +94 -27
- package/app/components/settings/McpSkillsSection.tsx +1 -1
- package/app/components/settings/McpTab.tsx +484 -340
- package/app/components/settings/SettingsContent.tsx +12 -6
- package/app/components/settings/types.ts +3 -0
- package/app/components/setup/StepAgents.tsx +113 -47
- package/app/components/setup/StepReview.tsx +14 -27
- package/app/components/setup/index.tsx +12 -11
- package/app/components/setup/types.ts +6 -0
- package/app/data/skills/mindos/SKILL.md +92 -92
- package/app/data/skills/mindos/references/write-supplement.md +119 -0
- package/app/data/skills/mindos-zh/SKILL.md +100 -104
- package/app/data/skills/mindos-zh/references/write-supplement.md +119 -0
- package/app/lib/fs.ts +0 -6
- package/app/lib/i18n/modules/features.ts +4 -4
- package/app/lib/i18n/modules/knowledge.ts +4 -0
- package/app/lib/i18n/modules/onboarding.ts +40 -30
- package/app/lib/i18n/modules/settings.ts +78 -6
- package/app/lib/mcp-agents.ts +1 -2
- package/app/lib/mcp-snippets.ts +5 -1
- package/app/lib/renderers/index.ts +2 -1
- package/bin/cli.js +168 -1404
- package/bin/commands/agent.js +156 -20
- package/bin/commands/api.js +14 -11
- package/bin/commands/ask.js +79 -68
- package/bin/commands/build.js +26 -0
- package/bin/commands/config.js +170 -0
- package/bin/commands/dev.js +58 -0
- package/bin/commands/doctor.js +205 -0
- package/bin/commands/file.js +551 -36
- package/bin/commands/gateway.js +42 -0
- package/bin/commands/init-skills.js +56 -0
- package/bin/commands/logs.js +32 -0
- package/bin/commands/mcp-cmd.js +57 -0
- package/bin/commands/onboard.js +25 -0
- package/bin/commands/open.js +41 -0
- package/bin/commands/restart.js +48 -0
- package/bin/commands/search.js +16 -14
- package/bin/commands/space.js +96 -25
- package/bin/commands/start.js +262 -0
- package/bin/commands/status.js +2 -2
- package/bin/commands/stop.js +14 -0
- package/bin/commands/sync-cmd.js +134 -0
- package/bin/commands/token.js +98 -0
- package/bin/commands/uninstall.js +154 -0
- package/bin/commands/update.js +286 -0
- package/bin/lib/build.js +1 -1
- package/bin/lib/colors.js +8 -7
- package/bin/lib/command.js +37 -96
- package/bin/lib/config.js +5 -0
- package/bin/lib/csv.js +19 -0
- package/bin/lib/jsonc.js +12 -0
- package/bin/lib/markdown.js +69 -0
- package/bin/lib/mcp-agents.js +1 -6
- package/bin/lib/mcp-build.js +1 -1
- package/bin/lib/mcp-install.js +2 -1
- package/bin/lib/one-shot.js +88 -0
- package/bin/lib/path-expand.js +9 -0
- package/bin/lib/remote.js +65 -0
- package/bin/lib/repl.js +167 -0
- package/bin/lib/{utils.js → shell.js} +10 -26
- package/bin/lib/skill-check.js +1 -1
- package/bin/lib/sse-stream.js +167 -0
- package/package.json +2 -2
- package/scripts/setup.js +182 -120
- package/skills/mindos/SKILL.md +92 -92
- package/skills/mindos-zh/SKILL.md +100 -104
- package/_standalone/.next/server/chunks/1955.js +0 -11
- package/_standalone/.next/server/chunks/3680.js +0 -1
- package/_standalone/.next/server/chunks/4497.js +0 -219
- package/_standalone/.next/server/chunks/5560.js +0 -2
- package/_standalone/.next/static/chunks/1053-0adaccc98a752a58.js +0 -29
- package/_standalone/.next/static/chunks/3637.f9a42cca59fd5bb5.js +0 -1
- package/_standalone/.next/static/chunks/4563-c2afaeacb241d1d0.js +0 -6
- package/_standalone/.next/static/chunks/6090-c98268ca726a68d3.js +0 -1
- package/_standalone/.next/static/chunks/9371-575600301da5d6bb.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-3e08abb495ecd5fd.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/page-e7e0f87ad3d765ac.js +0 -5
- package/_standalone/.next/static/chunks/app/help/page-3d0e1ceaa4abc243.js +0 -1
- package/_standalone/.next/static/chunks/app/setup/page-99ed3d1bb6b8f4ef.js +0 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/page-44fa78cbea613a78.js +0 -12
- package/_standalone/.next/static/css/d300701f384db50d.css +0 -1
- package/_standalone/components/renderers/agent-inspector/manifest.ts +0 -16
- /package/_standalone/.next/static/{rZLs1krFuduixvcVNe6q3 → Ij3PFh-a0zi5K_ANoSAW0}/_buildManifest.js +0 -0
- /package/_standalone/.next/static/{rZLs1krFuduixvcVNe6q3 → Ij3PFh-a0zi5K_ANoSAW0}/_ssgManifest.js +0 -0
package/app/app/api/ask/route.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type ToolDefinition,
|
|
14
14
|
SessionManager,
|
|
15
15
|
SettingsManager,
|
|
16
|
+
bashTool,
|
|
16
17
|
} from '@mariozechner/pi-coding-agent';
|
|
17
18
|
import { NextRequest, NextResponse } from 'next/server';
|
|
18
19
|
import fs from 'fs';
|
|
@@ -316,7 +317,7 @@ function toPiCustomToolDefinitions(tools: AgentTool<any>[]): ToolDefinition<any,
|
|
|
316
317
|
params: args,
|
|
317
318
|
result: outputText.startsWith('Error:') ? 'error' : 'ok',
|
|
318
319
|
message: outputText.slice(0, 200),
|
|
319
|
-
agentName: 'MindOS
|
|
320
|
+
agentName: 'MindOS',
|
|
320
321
|
});
|
|
321
322
|
} catch {
|
|
322
323
|
// logging must never kill the stream
|
|
@@ -669,7 +670,7 @@ export async function POST(req: NextRequest) {
|
|
|
669
670
|
resourceLoader,
|
|
670
671
|
sessionManager: SessionManager.inMemory(),
|
|
671
672
|
settingsManager,
|
|
672
|
-
tools: [],
|
|
673
|
+
tools: askMode === 'agent' ? [bashTool] : [],
|
|
673
674
|
customTools,
|
|
674
675
|
});
|
|
675
676
|
|
|
@@ -5,10 +5,11 @@ import path from 'path';
|
|
|
5
5
|
import { MCP_AGENTS, expandHome } from '@/lib/mcp-agents';
|
|
6
6
|
import { readSettings } from '@/lib/settings';
|
|
7
7
|
|
|
8
|
-
/** Parse JSONC — strips
|
|
8
|
+
/** Parse JSONC — strips comments before JSON.parse. Returns {} for empty/whitespace-only input. */
|
|
9
9
|
function parseJsonc(text: string): Record<string, unknown> {
|
|
10
10
|
let stripped = text.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*$)/gm, (m, g) => g ? '' : m);
|
|
11
11
|
stripped = stripped.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
12
|
+
if (!stripped.trim()) return {};
|
|
12
13
|
return JSON.parse(stripped);
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -2,18 +2,29 @@ export const dynamic = 'force-dynamic';
|
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
3
|
import { readSettings } from '@/lib/settings';
|
|
4
4
|
import { maskToken } from '@/lib/format';
|
|
5
|
+
import { networkInterfaces } from 'os';
|
|
5
6
|
|
|
6
7
|
/** Parse hostname from Host header, handling IPv6 brackets */
|
|
7
8
|
function parseHostname(host: string): string {
|
|
8
|
-
// IPv6: [::1]:3003 → [::1]
|
|
9
9
|
if (host.includes(']')) {
|
|
10
10
|
return host.slice(0, host.lastIndexOf(']') + 1);
|
|
11
11
|
}
|
|
12
|
-
// IPv4/hostname: 192.168.1.1:3003 → 192.168.1.1
|
|
13
12
|
const colonIdx = host.lastIndexOf(':');
|
|
14
13
|
return colonIdx > 0 ? host.slice(0, colonIdx) : host;
|
|
15
14
|
}
|
|
16
15
|
|
|
16
|
+
/** Get first non-internal IPv4 address */
|
|
17
|
+
function getLocalIP(): string | null {
|
|
18
|
+
try {
|
|
19
|
+
for (const ifaces of Object.values(networkInterfaces())) {
|
|
20
|
+
for (const iface of ifaces ?? []) {
|
|
21
|
+
if (iface.family === 'IPv4' && !iface.internal) return iface.address;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
} catch { /* ignore */ }
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
17
28
|
export async function GET(req: NextRequest) {
|
|
18
29
|
try {
|
|
19
30
|
const settings = readSettings();
|
|
@@ -52,12 +63,9 @@ export async function GET(req: NextRequest) {
|
|
|
52
63
|
port,
|
|
53
64
|
toolCount: running ? 24 : 0,
|
|
54
65
|
authConfigured,
|
|
55
|
-
// Masked for display; full token only used server-side in snippet generation
|
|
56
66
|
maskedToken: authConfigured ? maskToken(token) : undefined,
|
|
57
|
-
// Full token for config snippet copy — this API is protected by proxy.ts middleware
|
|
58
|
-
// (same-origin or bearer token required). Consistent with /api/settings which also
|
|
59
|
-
// exposes the token to authenticated users.
|
|
60
67
|
authToken: authConfigured ? token : undefined,
|
|
68
|
+
localIP: getLocalIP(),
|
|
61
69
|
});
|
|
62
70
|
} catch (err) {
|
|
63
71
|
return NextResponse.json({ error: String(err) }, { status: 500 });
|
|
@@ -58,8 +58,8 @@ export default function ViewPageClient({
|
|
|
58
58
|
);
|
|
59
59
|
|
|
60
60
|
const [useRaw, setUseRaw] = useRendererState<boolean>('_raw', filePath, false);
|
|
61
|
-
//
|
|
62
|
-
const [graphMode, setGraphMode] =
|
|
61
|
+
// Graph mode — per-view, resets when navigating to a different file
|
|
62
|
+
const [graphMode, setGraphMode] = useState(false);
|
|
63
63
|
const router = useRouter();
|
|
64
64
|
const [editing, setEditing] = useState(initialEditing || content === '');
|
|
65
65
|
const [editContent, setEditContent] = useState(content);
|
|
@@ -167,7 +167,7 @@ export default function ViewPageClient({
|
|
|
167
167
|
setGraphMode(prev => !prev);
|
|
168
168
|
}, [setGraphMode]);
|
|
169
169
|
|
|
170
|
-
const effectiveGraphMode =
|
|
170
|
+
const effectiveGraphMode = graphMode;
|
|
171
171
|
|
|
172
172
|
// Resolve renderer: for md files, graph mode overrides normal resolution
|
|
173
173
|
const registryRenderer = resolveRenderer(filePath, extension);
|
|
@@ -383,22 +383,6 @@ export default function ViewPageClient({
|
|
|
383
383
|
<span className="text-xs text-error hidden sm:inline">{saveError}</span>
|
|
384
384
|
)}
|
|
385
385
|
|
|
386
|
-
{/* Graph toggle — only for md files, hidden when graph plugin is disabled */}
|
|
387
|
-
{extension === 'md' && !editing && !isDraft && isRendererEnabled('graph') && (
|
|
388
|
-
<button
|
|
389
|
-
onClick={handleToggleGraph}
|
|
390
|
-
className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium transition-colors font-display"
|
|
391
|
-
style={{
|
|
392
|
-
background: effectiveGraphMode ? `${'var(--amber)'}22` : 'var(--muted)',
|
|
393
|
-
color: effectiveGraphMode ? 'var(--amber)' : 'var(--muted-foreground)',
|
|
394
|
-
}}
|
|
395
|
-
title={effectiveGraphMode ? 'Switch to document view' : 'Switch to Wiki Graph'}
|
|
396
|
-
>
|
|
397
|
-
{effectiveGraphMode ? <FileText size={13} /> : <Share2 size={13} />}
|
|
398
|
-
<span className="hidden sm:inline">{effectiveGraphMode ? 'Doc' : 'Graph'}</span>
|
|
399
|
-
</button>
|
|
400
|
-
)}
|
|
401
|
-
|
|
402
386
|
{/* Renderer toggle — only shown when a custom renderer exists (excludes graph-mode override) */}
|
|
403
387
|
{registryRenderer && !editing && !isDraft && !graphRenderer && (
|
|
404
388
|
<button
|
|
@@ -463,14 +447,6 @@ export default function ViewPageClient({
|
|
|
463
447
|
>
|
|
464
448
|
<Star size={16} className={pinned ? 'fill-[var(--amber)] text-[var(--amber)]' : ''} />
|
|
465
449
|
</button>
|
|
466
|
-
<button
|
|
467
|
-
type="button"
|
|
468
|
-
onClick={() => setExportOpen(true)}
|
|
469
|
-
className="p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
|
|
470
|
-
title={t.fileTree.export}
|
|
471
|
-
>
|
|
472
|
-
<Download size={16} />
|
|
473
|
-
</button>
|
|
474
450
|
<button
|
|
475
451
|
ref={moreRef}
|
|
476
452
|
type="button"
|
|
@@ -485,6 +461,15 @@ export default function ViewPageClient({
|
|
|
485
461
|
ref={moreMenuRef}
|
|
486
462
|
className="absolute right-0 top-full mt-1 z-50 min-w-[160px] rounded-lg border border-border bg-card shadow-lg py-1"
|
|
487
463
|
>
|
|
464
|
+
{extension === 'md' && !editing && !isDraft && isRendererEnabled('graph') && (
|
|
465
|
+
<button className="w-full flex items-center gap-2 px-3 py-2 text-sm text-foreground hover:bg-muted transition-colors text-left" onClick={() => { setMoreOpen(false); handleToggleGraph(); }}>
|
|
466
|
+
{effectiveGraphMode ? <FileText size={14} className="shrink-0" /> : <Share2 size={14} className="shrink-0" />}
|
|
467
|
+
{effectiveGraphMode ? (t.view?.switchToDoc ?? 'Document view') : (t.view?.switchToGraph ?? 'Wiki Graph')}
|
|
468
|
+
</button>
|
|
469
|
+
)}
|
|
470
|
+
<button className="w-full flex items-center gap-2 px-3 py-2 text-sm text-foreground hover:bg-muted transition-colors text-left" onClick={() => { setMoreOpen(false); setExportOpen(true); }}>
|
|
471
|
+
<Download size={14} className="shrink-0" /> {t.fileTree?.export ?? 'Export'}
|
|
472
|
+
</button>
|
|
488
473
|
<button className="w-full flex items-center gap-2 px-3 py-2 text-sm text-foreground hover:bg-muted transition-colors text-left" onClick={handleCopyPath}>
|
|
489
474
|
<Copy size={14} className="shrink-0" /> {t.view?.copyPath ?? t.fileTree?.copyPath ?? 'Copy Path'}
|
|
490
475
|
</button>
|
|
@@ -77,11 +77,12 @@ function countContentFiles(node: FileNode): number {
|
|
|
77
77
|
return (node.children ?? []).reduce((sum, c) => sum + countContentFiles(c), 0);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
/** Filter out
|
|
80
|
+
/** Filter out hidden entries (dot-files at root, system files) when show-hidden is off. */
|
|
81
81
|
function filterHiddenNodes(nodes: FileNode[], isRoot: boolean): FileNode[] {
|
|
82
82
|
return nodes.filter(node => {
|
|
83
83
|
if (isRoot && node.name.startsWith('.')) return false;
|
|
84
84
|
if (node.type === 'file' && SYSTEM_FILES.has(node.name)) return false;
|
|
85
|
+
if (node.type === 'directory' && node.name.startsWith('.')) return false;
|
|
85
86
|
return true;
|
|
86
87
|
});
|
|
87
88
|
}
|
|
@@ -426,7 +427,7 @@ function DirectoryNode({ node, depth, currentPath, onNavigate, maxOpenDepth, onI
|
|
|
426
427
|
onClick={toggle}
|
|
427
428
|
className="shrink-0 p-1 rounded hover:bg-muted text-muted-foreground transition-colors"
|
|
428
429
|
style={{ marginLeft: `${depth * 12 + 4}px` }}
|
|
429
|
-
aria-label={open ?
|
|
430
|
+
aria-label={open ? `Collapse ${node.name}` : `Expand ${node.name}`}
|
|
430
431
|
>
|
|
431
432
|
<span className="block transition-transform duration-150" style={{ transform: open ? 'rotate(0deg)' : 'rotate(-90deg)' }}>
|
|
432
433
|
<ChevronDown size={13} />
|
|
@@ -51,11 +51,18 @@ function CopyButton({ code }: { code: string }) {
|
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
//
|
|
55
|
-
//
|
|
54
|
+
// react-markdown passes an AST `node` prop to custom components;
|
|
55
|
+
// strip it (and any other non-DOM keys) before forwarding to the real element.
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
function stripNonDom(props: Record<string, any>): Record<string, any> {
|
|
58
|
+
const { node, inline, ordered, depth, isHeader, ...domProps } = props;
|
|
59
|
+
return domProps;
|
|
60
|
+
}
|
|
61
|
+
|
|
56
62
|
function makeHeading(Tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6') {
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
const HeadingComponent = ({ children, ...props }: any) => (
|
|
65
|
+
<Tag {...stripNonDom(props)} suppressHydrationWarning>{children}</Tag>
|
|
59
66
|
);
|
|
60
67
|
HeadingComponent.displayName = Tag;
|
|
61
68
|
return HeadingComponent;
|
|
@@ -68,11 +75,12 @@ const components: Components = {
|
|
|
68
75
|
h4: makeHeading('h4'),
|
|
69
76
|
h5: makeHeading('h5'),
|
|
70
77
|
h6: makeHeading('h6'),
|
|
71
|
-
code({ children, ...
|
|
72
|
-
|
|
78
|
+
code({ children, node, ...rest }) {
|
|
79
|
+
void node;
|
|
80
|
+
return <code {...stripNonDom(rest)} suppressHydrationWarning>{children}</code>;
|
|
73
81
|
},
|
|
74
|
-
pre({ children, ...
|
|
75
|
-
|
|
82
|
+
pre({ children, node, ...rest }) {
|
|
83
|
+
void node;
|
|
76
84
|
let codeString = '';
|
|
77
85
|
if (children && typeof children === 'object' && 'props' in children) {
|
|
78
86
|
const codeEl = children as React.ReactElement<{ children?: React.ReactNode }>;
|
|
@@ -80,31 +88,38 @@ const components: Components = {
|
|
|
80
88
|
}
|
|
81
89
|
return (
|
|
82
90
|
<div className="relative group">
|
|
83
|
-
<pre {...
|
|
91
|
+
<pre {...stripNonDom(rest)} suppressHydrationWarning>{children}</pre>
|
|
84
92
|
<CopyButton code={codeString} />
|
|
85
93
|
</div>
|
|
86
94
|
);
|
|
87
95
|
},
|
|
88
|
-
li({ children, ...
|
|
89
|
-
|
|
96
|
+
li({ children, node, ...rest }) {
|
|
97
|
+
void node;
|
|
98
|
+
return <li {...stripNonDom(rest)} suppressHydrationWarning>{children}</li>;
|
|
99
|
+
},
|
|
100
|
+
p({ children, node, ...rest }) {
|
|
101
|
+
void node;
|
|
102
|
+
return <p {...stripNonDom(rest)} suppressHydrationWarning>{children}</p>;
|
|
90
103
|
},
|
|
91
|
-
a({ href, children, ...
|
|
104
|
+
a({ href, children, node, ...rest }) {
|
|
105
|
+
void node;
|
|
92
106
|
const isExternal = href?.startsWith('http');
|
|
93
107
|
return (
|
|
94
108
|
<a
|
|
95
109
|
href={href}
|
|
96
110
|
target={isExternal ? '_blank' : undefined}
|
|
97
111
|
rel={isExternal ? 'noopener noreferrer' : undefined}
|
|
98
|
-
{...
|
|
112
|
+
{...stripNonDom(rest)}
|
|
99
113
|
>
|
|
100
114
|
{children}
|
|
101
115
|
</a>
|
|
102
116
|
);
|
|
103
117
|
},
|
|
104
|
-
img({ src, alt, ...
|
|
118
|
+
img({ src, alt, node, ...rest }) {
|
|
119
|
+
void node;
|
|
105
120
|
if (!src) return null;
|
|
106
121
|
// eslint-disable-next-line @next/next/no-img-element
|
|
107
|
-
return <img src={src} alt={alt ?? ''} {...
|
|
122
|
+
return <img src={src} alt={alt ?? ''} {...stripNonDom(rest)} />;
|
|
108
123
|
},
|
|
109
124
|
};
|
|
110
125
|
|
|
@@ -9,7 +9,9 @@ import { useResizeDrag } from '@/hooks/useResizeDrag';
|
|
|
9
9
|
const DEFAULT_WIDTH = 420;
|
|
10
10
|
const MIN_WIDTH = 400;
|
|
11
11
|
const MAX_WIDTH_ABS = 4000;
|
|
12
|
-
const
|
|
12
|
+
const ENTER_SNAP_THRESHOLD = 80;
|
|
13
|
+
const EXIT_SNAP_THRESHOLD = 16;
|
|
14
|
+
const MIN_CONTENT_WIDTH = 360;
|
|
13
15
|
|
|
14
16
|
import type { AcpAgentSelection } from '@/hooks/useAskModal';
|
|
15
17
|
|
|
@@ -37,6 +39,7 @@ export default function RightAskPanel({
|
|
|
37
39
|
maximized = false, onMaximize, sidebarOffset = 0,
|
|
38
40
|
}: RightAskPanelProps) {
|
|
39
41
|
const snapFiredRef = useRef(false);
|
|
42
|
+
const justExitedMaxRef = useRef(false);
|
|
40
43
|
|
|
41
44
|
const maxAvailable = typeof window !== 'undefined'
|
|
42
45
|
? window.innerWidth - sidebarOffset
|
|
@@ -45,12 +48,28 @@ export default function RightAskPanel({
|
|
|
45
48
|
const handleResize = useCallback((w: number) => {
|
|
46
49
|
if (snapFiredRef.current) return;
|
|
47
50
|
const clamped = Math.min(w, maxAvailable);
|
|
48
|
-
|
|
51
|
+
|
|
52
|
+
// Exit maximized: user drags right even a little (16px) → exit immediately
|
|
53
|
+
if (maximized && clamped < maxAvailable - EXIT_SNAP_THRESHOLD && onMaximize) {
|
|
54
|
+
justExitedMaxRef.current = true;
|
|
49
55
|
onMaximize();
|
|
50
|
-
|
|
56
|
+
const maxPanelForContent = typeof window !== 'undefined'
|
|
57
|
+
? window.innerWidth - sidebarOffset - MIN_CONTENT_WIDTH
|
|
58
|
+
: clamped;
|
|
59
|
+
onWidthChange(Math.min(clamped, maxPanelForContent));
|
|
51
60
|
return;
|
|
52
61
|
}
|
|
53
|
-
|
|
62
|
+
|
|
63
|
+
// Snap to fullscreen: panel near max edge OR content squeezed below minimum.
|
|
64
|
+
// Suppress content-based snap while justExitedMaxRef is true (user recently
|
|
65
|
+
// exited fullscreen and panel is still wide); only re-enable once the panel
|
|
66
|
+
// has been shrunk enough that content is comfortable (reset in handleMouseDown).
|
|
67
|
+
const contentRemaining = typeof window !== 'undefined'
|
|
68
|
+
? window.innerWidth - sidebarOffset - clamped
|
|
69
|
+
: Infinity;
|
|
70
|
+
const shouldSnap = clamped >= maxAvailable - ENTER_SNAP_THRESHOLD
|
|
71
|
+
|| (!justExitedMaxRef.current && contentRemaining < MIN_CONTENT_WIDTH);
|
|
72
|
+
if (!maximized && shouldSnap && onMaximize) {
|
|
54
73
|
snapFiredRef.current = true;
|
|
55
74
|
onMaximize();
|
|
56
75
|
return;
|
|
@@ -58,7 +77,7 @@ export default function RightAskPanel({
|
|
|
58
77
|
if (!maximized) {
|
|
59
78
|
onWidthChange(clamped);
|
|
60
79
|
}
|
|
61
|
-
}, [maxAvailable, onMaximize, maximized, onWidthChange]);
|
|
80
|
+
}, [maxAvailable, sidebarOffset, onMaximize, maximized, onWidthChange]);
|
|
62
81
|
|
|
63
82
|
const handleResizeEnd = useCallback((w: number) => {
|
|
64
83
|
if (snapFiredRef.current) return;
|
|
@@ -77,8 +96,19 @@ export default function RightAskPanel({
|
|
|
77
96
|
|
|
78
97
|
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
|
79
98
|
snapFiredRef.current = false;
|
|
99
|
+
// Only re-enable content-based snap once the panel has been shrunk enough
|
|
100
|
+
// that content is comfortably above minimum. This prevents the bounce:
|
|
101
|
+
// exit fullscreen → new drag → immediately re-snap because panel still wide.
|
|
102
|
+
if (justExitedMaxRef.current) {
|
|
103
|
+
const currentContent = typeof window !== 'undefined'
|
|
104
|
+
? window.innerWidth - sidebarOffset - width
|
|
105
|
+
: Infinity;
|
|
106
|
+
if (currentContent >= MIN_CONTENT_WIDTH) {
|
|
107
|
+
justExitedMaxRef.current = false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
80
110
|
rawMouseDown(e);
|
|
81
|
-
}, [rawMouseDown]);
|
|
111
|
+
}, [rawMouseDown, sidebarOffset, width]);
|
|
82
112
|
|
|
83
113
|
const effectiveWidth = maximized
|
|
84
114
|
? `calc(100vw - ${sidebarOffset}px)`
|
|
@@ -102,13 +102,13 @@ export default function Sidebar({ fileTree, collapsed = false, onCollapse, onExp
|
|
|
102
102
|
</button>
|
|
103
103
|
{/* Desktop action buttons — trimmed to 4 */}
|
|
104
104
|
<div className="hidden md:flex items-center gap-1">
|
|
105
|
-
<button onClick={() => setSearchOpen(true)} className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={t.sidebar.searchTitle} aria-
|
|
105
|
+
<button onClick={() => setSearchOpen(true)} className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={t.sidebar.searchTitle} aria-hidden="true" tabIndex={-1}>
|
|
106
106
|
<Search size={15} />
|
|
107
107
|
</button>
|
|
108
|
-
<button onClick={() => setSettingsOpen(true)} className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={t.sidebar.settingsTitle} aria-
|
|
108
|
+
<button onClick={() => setSettingsOpen(true)} className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={t.sidebar.settingsTitle} aria-hidden="true" tabIndex={-1}>
|
|
109
109
|
<Settings size={15} />
|
|
110
110
|
</button>
|
|
111
|
-
<button onClick={onCollapse} className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={t.sidebar.collapseTitle} aria-
|
|
111
|
+
<button onClick={onCollapse} className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors" title={t.sidebar.collapseTitle} aria-hidden="true" tabIndex={-1}>
|
|
112
112
|
<PanelLeftClose size={15} />
|
|
113
113
|
</button>
|
|
114
114
|
</div>
|
|
@@ -18,6 +18,7 @@ function Section({ id, icon, title, defaultOpen = false, children }: {
|
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
20
|
<div id={id} className="bg-card border border-border rounded-lg overflow-hidden scroll-mt-4">
|
|
21
|
+
<h2 className="sr-only">{title}</h2>
|
|
21
22
|
<button
|
|
22
23
|
onClick={() => setOpen(v => !v)}
|
|
23
24
|
className="w-full flex items-center gap-3 px-5 py-4 text-left hover:bg-muted/50 transition-colors focus-visible:ring-2 focus-visible:ring-ring"
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { CheckCircle2, AlertCircle, Loader2 } from 'lucide-react';
|
|
4
|
+
import { CheckCircle2, AlertCircle, Loader2, Copy } from 'lucide-react';
|
|
5
5
|
import CustomSelect from '@/components/CustomSelect';
|
|
6
6
|
import { apiFetch } from '@/lib/api';
|
|
7
|
+
import { copyToClipboard } from '@/lib/clipboard';
|
|
8
|
+
import { toast } from '@/lib/toast';
|
|
7
9
|
import type { AgentInfo, McpAgentInstallProps } from './types';
|
|
8
10
|
|
|
9
11
|
/* ── Agent Install ─────────────────────────────────────────────── */
|
|
10
12
|
|
|
11
|
-
export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallProps) {
|
|
13
|
+
export default function AgentInstall({ agents, t, onRefresh, mode = 'mcp', activeSkillName = 'mindos' }: McpAgentInstallProps) {
|
|
12
14
|
const m = t.settings?.mcp;
|
|
13
15
|
const [selected, setSelected] = useState<Set<string>>(new Set());
|
|
14
16
|
const [transport, setTransport] = useState<'auto' | 'stdio' | 'http'>('auto');
|
|
@@ -31,7 +33,8 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
|
|
|
31
33
|
});
|
|
32
34
|
};
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
/* ── MCP mode: install MCP config via API ── */
|
|
37
|
+
const handleMcpInstall = async () => {
|
|
35
38
|
if (selected.size === 0) return;
|
|
36
39
|
setInstalling(true);
|
|
37
40
|
setMessage(null);
|
|
@@ -50,7 +53,6 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
|
|
|
50
53
|
}),
|
|
51
54
|
transport,
|
|
52
55
|
...(transport === 'http' ? { url: httpUrl, token: httpToken } : {}),
|
|
53
|
-
// For auto mode, pass http settings for agents that need it
|
|
54
56
|
...(transport === 'auto' ? { url: httpUrl, token: httpToken } : {}),
|
|
55
57
|
};
|
|
56
58
|
const res = await apiFetch<{ results: Array<{ agent: string; status: string; message?: string }> }>('/api/mcp/install', {
|
|
@@ -81,8 +83,18 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
|
|
|
81
83
|
return agent?.preferredTransport === 'http';
|
|
82
84
|
}));
|
|
83
85
|
|
|
86
|
+
/* ═══ CLI mode: show skill install commands ═══ */
|
|
87
|
+
if (mode === 'cli') {
|
|
88
|
+
return <CliSkillInstall agents={agents} m={m} activeSkillName={activeSkillName} />;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ═══ MCP mode: full MCP config install ═══ */
|
|
84
92
|
return (
|
|
85
93
|
<div className="space-y-3 pt-2">
|
|
94
|
+
<p className="text-xs text-muted-foreground">
|
|
95
|
+
{m?.mcpInstallDesc ?? 'Install MCP config + Skill to detected agents on this machine.'}
|
|
96
|
+
</p>
|
|
97
|
+
|
|
86
98
|
{/* Agent list */}
|
|
87
99
|
<div className="space-y-1">
|
|
88
100
|
{agents.map(agent => (
|
|
@@ -109,7 +121,6 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
|
|
|
109
121
|
{agent.present ? (m?.detected ?? 'Detected') : (m?.notFound ?? 'Not found')}
|
|
110
122
|
</span>
|
|
111
123
|
)}
|
|
112
|
-
{/* Scope selector */}
|
|
113
124
|
{selected.has(agent.key) && agent.hasProjectScope && agent.hasGlobalScope && (
|
|
114
125
|
<CustomSelect
|
|
115
126
|
value={scopes[agent.key] || 'project'}
|
|
@@ -126,12 +137,10 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
|
|
|
126
137
|
))}
|
|
127
138
|
</div>
|
|
128
139
|
|
|
129
|
-
{/*
|
|
140
|
+
{/* Quick select */}
|
|
130
141
|
<div className="flex gap-2 text-xs pt-1">
|
|
131
142
|
<button type="button"
|
|
132
|
-
onClick={() => setSelected(new Set(
|
|
133
|
-
agents.filter(a => !a.installed && a.present).map(a => a.key)
|
|
134
|
-
))}
|
|
143
|
+
onClick={() => setSelected(new Set(agents.filter(a => !a.installed && a.present).map(a => a.key)))}
|
|
135
144
|
className="px-2.5 py-1 rounded-md border border-[var(--amber)] text-[var(--amber)] transition-colors hover:bg-muted/50">
|
|
136
145
|
{m?.selectDetected ?? 'Select Detected'}
|
|
137
146
|
</button>
|
|
@@ -163,32 +172,20 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
|
|
|
163
172
|
<div className="space-y-2 pl-5 text-xs">
|
|
164
173
|
<div className="space-y-1">
|
|
165
174
|
<label className="text-muted-foreground">{m?.httpUrl ?? 'MCP URL'}</label>
|
|
166
|
-
<input
|
|
167
|
-
|
|
168
|
-
value={httpUrl}
|
|
169
|
-
onChange={e => setHttpUrl(e.target.value)}
|
|
170
|
-
className="w-full px-2.5 py-1.5 text-xs rounded-md border border-border bg-background font-mono text-foreground outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
171
|
-
/>
|
|
175
|
+
<input type="text" value={httpUrl} onChange={e => setHttpUrl(e.target.value)}
|
|
176
|
+
className="w-full px-2.5 py-1.5 text-xs rounded-md border border-border bg-background font-mono text-foreground outline-none focus-visible:ring-1 focus-visible:ring-ring" />
|
|
172
177
|
</div>
|
|
173
178
|
<div className="space-y-1">
|
|
174
179
|
<label className="text-muted-foreground">{m?.httpToken ?? 'Auth Token'}</label>
|
|
175
|
-
<input
|
|
176
|
-
|
|
177
|
-
value={httpToken}
|
|
178
|
-
onChange={e => setHttpToken(e.target.value)}
|
|
179
|
-
placeholder="Bearer token"
|
|
180
|
-
className="w-full px-2.5 py-1.5 text-xs rounded-md border border-border bg-background font-mono text-foreground outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
181
|
-
/>
|
|
180
|
+
<input type="password" value={httpToken} onChange={e => setHttpToken(e.target.value)} placeholder="Bearer token"
|
|
181
|
+
className="w-full px-2.5 py-1.5 text-xs rounded-md border border-border bg-background font-mono text-foreground outline-none focus-visible:ring-1 focus-visible:ring-ring" />
|
|
182
182
|
</div>
|
|
183
183
|
</div>
|
|
184
184
|
)}
|
|
185
185
|
|
|
186
186
|
{/* Install button */}
|
|
187
|
-
<button
|
|
188
|
-
|
|
189
|
-
disabled={selected.size === 0 || installing}
|
|
190
|
-
className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-lg transition-colors disabled:opacity-40 disabled:cursor-not-allowed bg-[var(--amber)] text-[var(--amber-foreground)]"
|
|
191
|
-
>
|
|
187
|
+
<button onClick={handleMcpInstall} disabled={selected.size === 0 || installing}
|
|
188
|
+
className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-lg transition-colors disabled:opacity-40 disabled:cursor-not-allowed bg-[var(--amber)] text-[var(--amber-foreground)]">
|
|
192
189
|
{installing && <Loader2 size={12} className="animate-spin" />}
|
|
193
190
|
{installing ? (m?.installing ?? 'Installing...') : (m?.installSelected ?? 'Install Selected')}
|
|
194
191
|
</button>
|
|
@@ -206,3 +203,73 @@ export default function AgentInstall({ agents, t, onRefresh }: McpAgentInstallPr
|
|
|
206
203
|
</div>
|
|
207
204
|
);
|
|
208
205
|
}
|
|
206
|
+
|
|
207
|
+
/* ── CLI Skill Install — generates per-agent CLI commands ── */
|
|
208
|
+
|
|
209
|
+
function CliSkillInstall({ agents, m, activeSkillName }: {
|
|
210
|
+
agents: AgentInfo[];
|
|
211
|
+
m: Record<string, any> | undefined;
|
|
212
|
+
activeSkillName: string;
|
|
213
|
+
}) {
|
|
214
|
+
const [selectedAgent, setSelectedAgent] = useState(agents[0]?.key ?? 'claude-code');
|
|
215
|
+
const agent = agents.find(a => a.key === selectedAgent);
|
|
216
|
+
const cmd = `npx skills add GeminiLight/MindOS --skill ${activeSkillName} -a ${selectedAgent} -g -y`;
|
|
217
|
+
|
|
218
|
+
const handleCopy = async () => {
|
|
219
|
+
const ok = await copyToClipboard(cmd);
|
|
220
|
+
if (ok) toast.copy();
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const connected = agents.filter(a => a.present && a.installed);
|
|
224
|
+
const detected = agents.filter(a => a.present && !a.installed);
|
|
225
|
+
const notFound = agents.filter(a => !a.present);
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<div className="space-y-3 pt-2">
|
|
229
|
+
<p className="text-xs text-muted-foreground">
|
|
230
|
+
{m?.cliInstallDesc ?? 'Install the MindOS Skill to your agent so it can operate your knowledge base.'}
|
|
231
|
+
</p>
|
|
232
|
+
|
|
233
|
+
{/* Agent selector */}
|
|
234
|
+
<CustomSelect
|
|
235
|
+
value={selectedAgent}
|
|
236
|
+
onChange={setSelectedAgent}
|
|
237
|
+
size="sm"
|
|
238
|
+
options={[
|
|
239
|
+
...(connected.length > 0 ? [{ label: m?.connectedGroup ?? 'Connected', options: connected.map(a => ({ value: a.key, label: a.name })) }] : []),
|
|
240
|
+
...(detected.length > 0 ? [{ label: m?.detectedGroup ?? 'Detected', options: detected.map(a => ({ value: a.key, label: a.name })) }] : []),
|
|
241
|
+
...(notFound.length > 0 ? [{ label: m?.notFoundGroup ?? 'Not Installed', options: notFound.map(a => ({ value: a.key, label: a.name })) }] : []),
|
|
242
|
+
]}
|
|
243
|
+
/>
|
|
244
|
+
|
|
245
|
+
{/* Status */}
|
|
246
|
+
{agent && (
|
|
247
|
+
<div className="flex items-center gap-2 text-2xs">
|
|
248
|
+
{agent.present && agent.installed ? (
|
|
249
|
+
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full font-medium bg-success/10 text-success">
|
|
250
|
+
<CheckCircle2 size={10} /> {m?.tagConnected ?? 'Connected'}
|
|
251
|
+
</span>
|
|
252
|
+
) : agent.present ? (
|
|
253
|
+
<span className="text-muted-foreground">{m?.detected ?? 'Detected'}</span>
|
|
254
|
+
) : (
|
|
255
|
+
<span className="text-muted-foreground">{m?.notFound ?? 'Not found'}</span>
|
|
256
|
+
)}
|
|
257
|
+
{agent.installedSkillCount != null && agent.installedSkillCount > 0 && (
|
|
258
|
+
<span className="text-muted-foreground">{agent.installedSkillCount} {m?.skillsInstalled ?? 'skills installed'}</span>
|
|
259
|
+
)}
|
|
260
|
+
</div>
|
|
261
|
+
)}
|
|
262
|
+
|
|
263
|
+
{/* Command */}
|
|
264
|
+
<div className="flex items-center gap-1.5">
|
|
265
|
+
<code className="flex-1 text-[10px] font-mono bg-muted/50 border border-border rounded-lg px-2.5 py-2 text-muted-foreground select-all overflow-x-auto whitespace-nowrap">
|
|
266
|
+
{cmd}
|
|
267
|
+
</code>
|
|
268
|
+
<button onClick={handleCopy}
|
|
269
|
+
className="p-1.5 rounded-md border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0">
|
|
270
|
+
<Copy size={11} />
|
|
271
|
+
</button>
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
);
|
|
275
|
+
}
|
|
@@ -29,7 +29,7 @@ export default function SkillsSection({ t }: McpSkillsSectionProps) {
|
|
|
29
29
|
const [createError, setCreateError] = useState('');
|
|
30
30
|
|
|
31
31
|
const [search, setSearch] = useState('');
|
|
32
|
-
const [builtinCollapsed, setBuiltinCollapsed] = useState(
|
|
32
|
+
const [builtinCollapsed, setBuiltinCollapsed] = useState(true);
|
|
33
33
|
const [editing, setEditing] = useState<string | null>(null);
|
|
34
34
|
const [editContent, setEditContent] = useState('');
|
|
35
35
|
const [editError, setEditError] = useState('');
|