@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
|
@@ -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>
|
|
@@ -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('');
|