@f5-sales-demo/xcsh 21.50.0 → 22.0.1
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/README.md +0 -3
- package/package.json +8 -8
- package/src/browser/headless-bridge.ts +0 -2
- package/src/browser/host-profiles.ts +1 -1
- package/src/capability/extension.ts +2 -4
- package/src/capability/types.ts +6 -6
- package/src/cli/args.ts +0 -11
- package/src/cli/flag-spec.ts +0 -2
- package/src/commit/agentic/agent.ts +0 -1
- package/src/config/settings-schema.ts +0 -55
- package/src/cursor.ts +5 -26
- package/src/discovery/builtin.ts +1 -130
- package/src/discovery/claude-plugins.ts +1 -88
- package/src/discovery/claude.ts +0 -80
- package/src/discovery/codex.ts +11 -148
- package/src/discovery/cursor.ts +1 -84
- package/src/discovery/gemini.ts +0 -89
- package/src/discovery/helpers.ts +1 -1
- package/src/discovery/index.ts +0 -4
- package/src/discovery/opencode.ts +1 -106
- package/src/discovery/windsurf.ts +1 -82
- package/src/extensibility/custom-tools/types.ts +0 -4
- package/src/extensibility/extensions/types.ts +0 -4
- package/src/extensibility/plugins/marketplace/builtin-marketplace-snapshot.ts +1 -1
- package/src/extensibility/plugins/marketplace/builtin-marketplace.provenance.json +1 -1
- package/src/extensibility/plugins/marketplace/types.ts +0 -1
- package/src/internal-urls/api-catalog-discovery.ts +6 -5
- package/src/internal-urls/api-catalog-qmd-index.generated.ts +2 -2
- package/src/internal-urls/build-info.generated.ts +8 -8
- package/src/internal-urls/docs-index.generated.ts +13 -15
- package/src/internal-urls/index.ts +1 -2
- package/src/internal-urls/router.ts +1 -1
- package/src/internal-urls/types.ts +2 -2
- package/src/lifecycle/native-acceptance-driver.ts +0 -1
- package/src/lifecycle/native-acceptance.ts +1 -2
- package/src/locales/ar.json +1 -65
- package/src/locales/de.json +1 -65
- package/src/locales/en.json +1 -99
- package/src/locales/es.json +1 -65
- package/src/locales/fr.json +1 -65
- package/src/locales/hi.json +1 -65
- package/src/locales/it.json +1 -65
- package/src/locales/ja.json +1 -65
- package/src/locales/ko.json +1 -65
- package/src/locales/pt-br.json +1 -65
- package/src/locales/th.json +1 -65
- package/src/locales/zh-cn.json +1 -65
- package/src/locales/zh-tw.json +1 -65
- package/src/main.ts +3 -20
- package/src/modes/acp/acp-agent.ts +14 -146
- package/src/modes/components/agent-dashboard.ts +0 -1
- package/src/modes/components/extensions/extension-dashboard.ts +1 -2
- package/src/modes/components/extensions/state-manager.ts +0 -46
- package/src/modes/components/extensions/types.ts +0 -1
- package/src/modes/components/settings-defs.ts +1 -2
- package/src/modes/controllers/command-controller.ts +0 -14
- package/src/modes/controllers/selector-controller.ts +0 -8
- package/src/modes/interactive-mode.ts +3 -20
- package/src/modes/theme/theme.ts +0 -6
- package/src/modes/types.ts +0 -6
- package/src/prompts/internal-urls/about.md +1 -1
- package/src/prompts/system/progressive-system-prompt.md +1 -1
- package/src/prompts/system/system-prompt.md +0 -9
- package/src/prompts/tools/search-tool-bm25-progressive.md +3 -6
- package/src/qmd-smoke.ts +189 -24
- package/src/remote-control/interactions.ts +1 -1
- package/src/remote-control/protocol-methods.json +0 -10
- package/src/remote-control/router.ts +1 -2
- package/src/remote-control/voice-timeline.ts +2 -2
- package/src/sdk.ts +10 -252
- package/src/session/agent-session.ts +23 -321
- package/src/session/session-manager.ts +0 -40
- package/src/slash-commands/builtin-registry.ts +3 -85
- package/src/system-prompt.ts +0 -9
- package/src/task/executor.ts +0 -116
- package/src/task/index.ts +0 -4
- package/src/{mcp → tools}/discoverable-tool-metadata.ts +14 -84
- package/src/tools/index.ts +7 -28
- package/src/tools/path-utils.ts +2 -10
- package/src/tools/read.ts +2 -2
- package/src/tools/search-tool-bm25.ts +28 -72
- package/src/tools/vim.ts +1 -1
- package/src/web/search/index.ts +2 -5
- package/src/web/search/provider.ts +0 -3
- package/src/web/search/providers/exa.ts +4 -84
- package/src/web/search/types.ts +0 -2
- package/src/capability/mcp.ts +0 -74
- package/src/config/mcp-schema.json +0 -230
- package/src/discovery/mcp-json.ts +0 -171
- package/src/discovery/vscode.ts +0 -105
- package/src/exa/factory.ts +0 -61
- package/src/exa/index.ts +0 -27
- package/src/exa/mcp-client.ts +0 -293
- package/src/exa/render.ts +0 -232
- package/src/exa/researcher.ts +0 -47
- package/src/exa/search.ts +0 -86
- package/src/exa/types.ts +0 -166
- package/src/exa/websets.ts +0 -247
- package/src/internal-urls/mcp-protocol.ts +0 -156
- package/src/mcp/client.ts +0 -482
- package/src/mcp/config-writer.ts +0 -225
- package/src/mcp/config.ts +0 -365
- package/src/mcp/index.ts +0 -29
- package/src/mcp/json-rpc.ts +0 -84
- package/src/mcp/loader.ts +0 -124
- package/src/mcp/manager.ts +0 -1173
- package/src/mcp/oauth-discovery.ts +0 -349
- package/src/mcp/oauth-flow.ts +0 -398
- package/src/mcp/policy.ts +0 -24
- package/src/mcp/render.ts +0 -161
- package/src/mcp/runtime-controller.ts +0 -95
- package/src/mcp/smithery-auth.ts +0 -105
- package/src/mcp/smithery-connect.ts +0 -145
- package/src/mcp/smithery-registry.ts +0 -477
- package/src/mcp/tool-bridge.ts +0 -449
- package/src/mcp/tool-cache.ts +0 -117
- package/src/mcp/transports/http.ts +0 -475
- package/src/mcp/transports/index.ts +0 -6
- package/src/mcp/transports/stdio.ts +0 -325
- package/src/mcp/types.ts +0 -428
- package/src/modes/components/mcp-add-wizard.ts +0 -1346
- package/src/modes/controllers/mcp-command-controller.ts +0 -2502
- package/src/prompts/tools/search-tool-bm25.md +0 -38
- package/src/web/search/providers/zai.ts +0 -311
package/README.md
CHANGED
|
@@ -10,9 +10,6 @@ For installation, setup, provider configuration, model roles, slash commands, an
|
|
|
10
10
|
Package-specific references:
|
|
11
11
|
|
|
12
12
|
- [CHANGELOG](./CHANGELOG.md)
|
|
13
|
-
- [MCP configuration guide](../../docs/mcp-config.md)
|
|
14
|
-
- [MCP runtime lifecycle](../../docs/mcp-runtime-lifecycle.md)
|
|
15
|
-
- [MCP server/tool authoring](../../docs/mcp-server-tool-authoring.md)
|
|
16
13
|
- [Remote-control implementation](./src/remote-control/IMPLEMENTATION.md)
|
|
17
14
|
- [Remote-control acceptance](./src/remote-control/ACCEPTANCE.md)
|
|
18
15
|
- [CONTRIBUTING](../../CONTRIBUTING.md)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "22.0.1",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -67,13 +67,13 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@agentclientprotocol/sdk": "1.4.0",
|
|
70
|
-
"@f5-sales-demo/pi-agent-core": "
|
|
71
|
-
"@f5-sales-demo/pi-ai": "
|
|
72
|
-
"@f5-sales-demo/pi-natives": "
|
|
73
|
-
"@f5-sales-demo/pi-resource-management": "
|
|
74
|
-
"@f5-sales-demo/pi-tui": "
|
|
75
|
-
"@f5-sales-demo/pi-utils": "
|
|
76
|
-
"@f5-sales-demo/xcsh-stats": "
|
|
70
|
+
"@f5-sales-demo/pi-agent-core": "22.0.1",
|
|
71
|
+
"@f5-sales-demo/pi-ai": "22.0.1",
|
|
72
|
+
"@f5-sales-demo/pi-natives": "22.0.1",
|
|
73
|
+
"@f5-sales-demo/pi-resource-management": "22.0.1",
|
|
74
|
+
"@f5-sales-demo/pi-tui": "22.0.1",
|
|
75
|
+
"@f5-sales-demo/pi-utils": "22.0.1",
|
|
76
|
+
"@f5-sales-demo/xcsh-stats": "22.0.1",
|
|
77
77
|
"@mozilla/readability": "^0.6",
|
|
78
78
|
"@resvg/resvg-wasm": "2.6.2",
|
|
79
79
|
"@sinclair/typebox": "0.34.52",
|
|
@@ -180,7 +180,6 @@ export async function startHeadlessChatBridge(
|
|
|
180
180
|
hasUI: false,
|
|
181
181
|
toolNames: [...new Set([...BROWSER_TOOL_NAMES, ...EXTENSION_AGENT_TOOL_NAMES])],
|
|
182
182
|
customTools: createExtensionBridgeTools(bridge),
|
|
183
|
-
enableMCP: false,
|
|
184
183
|
enableLsp: false,
|
|
185
184
|
disableExtensionDiscovery: true,
|
|
186
185
|
...(process.env.XCSH_BENCH_EXTENSION
|
|
@@ -201,7 +200,6 @@ export async function startHeadlessChatBridge(
|
|
|
201
200
|
sessionManager: SessionManager.inMemory(cwd),
|
|
202
201
|
toolNames: [...OFFICE_TOOL_NAMES],
|
|
203
202
|
customTools: [],
|
|
204
|
-
enableMCP: false,
|
|
205
203
|
enableLsp: false,
|
|
206
204
|
disableExtensionDiscovery: true,
|
|
207
205
|
bundledExtensions: ["sandbox-guard"],
|
|
@@ -102,7 +102,7 @@ SAFETY — NEVER DO THESE:
|
|
|
102
102
|
const OFFICE_NATIVE_TOOLS_NOTE = `
|
|
103
103
|
NATIVE TOOLS: Beyond the document host tools, you have xcsh's full local toolset — \`bash\` (run shell commands, including CLIs like \`az\`, \`gh\`, \`terraform\`, \`git\` when installed and authenticated), file tools (\`read\`/\`write\`/\`edit\`), and \`grep\` — plus any skills available in this workspace. Reach for them when the task genuinely needs them (pull live data with a CLI, read a local file the user points you at). Prefer the document host tools for document work. Your file tools and shell are confined to the folder xcsh was launched from.
|
|
104
104
|
|
|
105
|
-
This pane
|
|
105
|
+
This pane exposes no plugin-provided tools — the tools listed above (plus the document host tools) are everything you can call. To use a cloud or SCM CLI, invoke it directly with \`bash\` (e.g. \`az account show\`, \`gh repo view\`).
|
|
106
106
|
|
|
107
107
|
Plugin RESOURCES are a different thing and they ARE available to you: an installed plugin's skills, slash commands, schemas, templates and engines. Read them through \`xcsh://plugin/<name>\` (summary), \`xcsh://plugin/<name>/<key>\` (a declared resource such as \`schema\`), or \`xcsh://plugin/<name>/file/<path>\` (any file in the plugin), and run a plugin's engine with \`bash\` (e.g. \`bun xcsh://plugin/<name>/file/engine/cli.ts <command>\`). When a plugin declares a deterministic engine, use it — never recompute by hand what the engine computes.
|
|
108
108
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Extensions Capability
|
|
3
3
|
*
|
|
4
|
-
* Gemini-style extensions that provide
|
|
4
|
+
* Gemini-style extensions that provide tools and context.
|
|
5
5
|
*/
|
|
6
6
|
import { defineCapability } from ".";
|
|
7
|
-
import type { MCPServer } from "./mcp";
|
|
8
7
|
import type { SourceMeta } from "./types";
|
|
9
8
|
|
|
10
9
|
/**
|
|
@@ -13,7 +12,6 @@ import type { SourceMeta } from "./types";
|
|
|
13
12
|
export interface ExtensionManifest {
|
|
14
13
|
name?: string;
|
|
15
14
|
description?: string;
|
|
16
|
-
mcpServers?: Record<string, Omit<MCPServer, "name" | "_source">>;
|
|
17
15
|
tools?: unknown[];
|
|
18
16
|
context?: unknown;
|
|
19
17
|
}
|
|
@@ -37,7 +35,7 @@ export interface Extension {
|
|
|
37
35
|
export const extensionCapability = defineCapability<Extension>({
|
|
38
36
|
id: "extensions",
|
|
39
37
|
displayName: "Extensions",
|
|
40
|
-
description: "Gemini-style extensions providing
|
|
38
|
+
description: "Gemini-style extensions providing tools and context",
|
|
41
39
|
key: ext => ext.name,
|
|
42
40
|
validate: ext => {
|
|
43
41
|
if (!ext.name) return "Missing extension name";
|
package/src/capability/types.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Core types for the capability-based config discovery system.
|
|
3
3
|
*
|
|
4
4
|
* This architecture inverts control: instead of callers knowing about paths like
|
|
5
|
-
* `.xcsh`, `.codex`, `.gemini`, they simply ask for
|
|
6
|
-
* a unified array of
|
|
5
|
+
* `.xcsh`, `.codex`, `.gemini`, they simply ask for a capability and get back
|
|
6
|
+
* a unified array of items.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -33,7 +33,7 @@ export interface LoadResult<T> {
|
|
|
33
33
|
* A provider that can load items for a capability.
|
|
34
34
|
*/
|
|
35
35
|
export interface Provider<T> {
|
|
36
|
-
/** Unique provider ID (e.g., "xcsh", "
|
|
36
|
+
/** Unique provider ID (e.g., "xcsh", "codex", "agents-md") */
|
|
37
37
|
id: string;
|
|
38
38
|
|
|
39
39
|
/** Human-readable name for UI display (e.g., "xcsh", "OpenAI Codex") */
|
|
@@ -47,7 +47,7 @@ export interface Provider<T> {
|
|
|
47
47
|
* Suggested ranges:
|
|
48
48
|
* 100+ : Primary providers (xcsh, pi)
|
|
49
49
|
* 50-99: Tool-specific providers (claude, codex, gemini)
|
|
50
|
-
* 1-49 : Shared standards (
|
|
50
|
+
* 1-49 : Shared standards (agents-md)
|
|
51
51
|
*/
|
|
52
52
|
priority: number;
|
|
53
53
|
|
|
@@ -110,10 +110,10 @@ export interface CapabilityResult<T> {
|
|
|
110
110
|
* Definition of a capability.
|
|
111
111
|
*/
|
|
112
112
|
export interface Capability<T> {
|
|
113
|
-
/** Capability ID (e.g., "
|
|
113
|
+
/** Capability ID (e.g., "skills", "context-files") */
|
|
114
114
|
id: string;
|
|
115
115
|
|
|
116
|
-
/** Human-readable name for UI display (e.g., "
|
|
116
|
+
/** Human-readable name for UI display (e.g., "Skills", "Context Files") */
|
|
117
117
|
displayName: string;
|
|
118
118
|
|
|
119
119
|
/** Short description for settings/status UI */
|
package/src/cli/args.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { type Effort, THINKING_EFFORTS } from "@f5-sales-demo/pi-ai";
|
|
5
5
|
import { APP_NAME, CONFIG_DIR_NAME, logger } from "@f5-sales-demo/pi-utils";
|
|
6
|
-
import { CliUsageError } from "@f5-sales-demo/pi-utils/cli";
|
|
7
6
|
import chalk from "chalk";
|
|
8
7
|
import { parseEffort } from "../thinking";
|
|
9
8
|
import {
|
|
@@ -50,8 +49,6 @@ export interface Args {
|
|
|
50
49
|
models?: string[];
|
|
51
50
|
tools?: string[];
|
|
52
51
|
noTools?: boolean;
|
|
53
|
-
mcp?: boolean;
|
|
54
|
-
noMcp?: boolean;
|
|
55
52
|
noLsp?: boolean;
|
|
56
53
|
noPty?: boolean;
|
|
57
54
|
hooks?: string[];
|
|
@@ -161,12 +158,6 @@ const APPLY: Record<LaunchFlagName, (result: Args, value: string | true) => void
|
|
|
161
158
|
"no-tools": r => {
|
|
162
159
|
r.noTools = true;
|
|
163
160
|
},
|
|
164
|
-
mcp: r => {
|
|
165
|
-
r.mcp = true;
|
|
166
|
-
},
|
|
167
|
-
"no-mcp": r => {
|
|
168
|
-
r.noMcp = true;
|
|
169
|
-
},
|
|
170
161
|
"no-lsp": r => {
|
|
171
162
|
r.noLsp = true;
|
|
172
163
|
},
|
|
@@ -404,8 +395,6 @@ export function parseArgs(args: string[], extensionFlags?: ExtensionFlagRegistry
|
|
|
404
395
|
result.unrecognizedFlags.push({ token, name: name ?? token.replace(/^-+/, "") });
|
|
405
396
|
}
|
|
406
397
|
|
|
407
|
-
if (result.mcp && result.noMcp) throw new CliUsageError("--mcp cannot be combined with --no-mcp");
|
|
408
|
-
if (result.mcp && result.noTools) throw new CliUsageError("--mcp cannot be combined with --no-tools");
|
|
409
398
|
return result;
|
|
410
399
|
}
|
|
411
400
|
|
package/src/cli/flag-spec.ts
CHANGED
|
@@ -79,8 +79,6 @@ export const LAUNCH_FLAGS = defineFlags({
|
|
|
79
79
|
"provider-session-id": { arity: "value", description: "Resume a provider-side session", hidden: true },
|
|
80
80
|
models: { arity: "value", description: "Comma-separated model patterns for Ctrl+P cycling" },
|
|
81
81
|
"no-tools": { arity: "boolean", description: "Disable all built-in tools" },
|
|
82
|
-
mcp: { arity: "boolean", description: "Enable MCP servers for this run" },
|
|
83
|
-
"no-mcp": { arity: "boolean", description: "Disable MCP server discovery and tools" },
|
|
84
82
|
"no-lsp": { arity: "boolean", description: "Disable LSP tools, formatting, and diagnostics" },
|
|
85
83
|
"no-pty": { arity: "boolean", description: "Disable PTY-based interactive bash execution" },
|
|
86
84
|
tools: { arity: "value", description: "Comma-separated list of tools to enable (default: all)" },
|
|
@@ -267,7 +267,6 @@ export const SETTINGS_SCHEMA = {
|
|
|
267
267
|
"cline",
|
|
268
268
|
"github",
|
|
269
269
|
"vscode",
|
|
270
|
-
"mcp-json",
|
|
271
270
|
"ssh-json",
|
|
272
271
|
] as string[],
|
|
273
272
|
},
|
|
@@ -1774,60 +1773,6 @@ export const SETTINGS_SCHEMA = {
|
|
|
1774
1773
|
},
|
|
1775
1774
|
},
|
|
1776
1775
|
|
|
1777
|
-
// MCP
|
|
1778
|
-
"mcp.enabled": {
|
|
1779
|
-
type: "boolean",
|
|
1780
|
-
default: false,
|
|
1781
|
-
scope: "user",
|
|
1782
|
-
ui: { tab: "tools", label: "MCP", description: "Enable MCP servers for new sessions" },
|
|
1783
|
-
},
|
|
1784
|
-
|
|
1785
|
-
"mcp.enableProjectConfig": {
|
|
1786
|
-
type: "boolean",
|
|
1787
|
-
default: true,
|
|
1788
|
-
ui: { tab: "tools", label: "MCP Project Config", description: "Load .mcp.json/mcp.json from project root" },
|
|
1789
|
-
},
|
|
1790
|
-
|
|
1791
|
-
"mcp.discoveryMode": {
|
|
1792
|
-
type: "boolean",
|
|
1793
|
-
default: false,
|
|
1794
|
-
ui: {
|
|
1795
|
-
tab: "tools",
|
|
1796
|
-
label: "MCP Tool Discovery",
|
|
1797
|
-
description: "Hide MCP tools by default and expose them through a tool discovery tool",
|
|
1798
|
-
},
|
|
1799
|
-
},
|
|
1800
|
-
|
|
1801
|
-
"mcp.discoveryDefaultServers": {
|
|
1802
|
-
type: "array",
|
|
1803
|
-
default: [] as string[],
|
|
1804
|
-
ui: {
|
|
1805
|
-
tab: "tools",
|
|
1806
|
-
label: "MCP Discovery Default Servers",
|
|
1807
|
-
description: "Keep MCP tools from these servers visible while discovery mode hides other MCP tools",
|
|
1808
|
-
},
|
|
1809
|
-
},
|
|
1810
|
-
|
|
1811
|
-
"mcp.notifications": {
|
|
1812
|
-
type: "boolean",
|
|
1813
|
-
default: false,
|
|
1814
|
-
ui: {
|
|
1815
|
-
tab: "tools",
|
|
1816
|
-
label: "MCP Update Injection",
|
|
1817
|
-
description: "Inject MCP resource updates into the agent conversation",
|
|
1818
|
-
},
|
|
1819
|
-
},
|
|
1820
|
-
|
|
1821
|
-
"mcp.notificationDebounceMs": {
|
|
1822
|
-
type: "number",
|
|
1823
|
-
default: 500,
|
|
1824
|
-
ui: {
|
|
1825
|
-
tab: "tools",
|
|
1826
|
-
label: "MCP Notification Debounce",
|
|
1827
|
-
description: "Debounce window for MCP resource update notifications before injecting into conversation",
|
|
1828
|
-
},
|
|
1829
|
-
},
|
|
1830
|
-
|
|
1831
1776
|
// ────────────────────────────────────────────────────────────────────────
|
|
1832
1777
|
// Tasks
|
|
1833
1778
|
// ────────────────────────────────────────────────────────────────────────
|
package/src/cursor.ts
CHANGED
|
@@ -8,8 +8,8 @@ import type {
|
|
|
8
8
|
AgentToolUpdateCallback,
|
|
9
9
|
} from "@f5-sales-demo/pi-agent-core";
|
|
10
10
|
import type {
|
|
11
|
-
CursorMcpCall,
|
|
12
11
|
CursorShellStreamCallbacks,
|
|
12
|
+
CursorToolCall,
|
|
13
13
|
CursorExecHandlers as ICursorExecHandlers,
|
|
14
14
|
ToolResultMessage,
|
|
15
15
|
} from "@f5-sales-demo/pi-ai";
|
|
@@ -145,7 +145,7 @@ function decodeToolCallId(toolCallId?: string): string {
|
|
|
145
145
|
return toolCallId && toolCallId.length > 0 ? toolCallId : randomUUID();
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
function
|
|
148
|
+
function decodeGenericToolArgs(rawArgs: Record<string, Uint8Array>): Record<string, unknown> {
|
|
149
149
|
const decoded: Record<string, unknown> = {};
|
|
150
150
|
for (const [key, value] of Object.entries(rawArgs)) {
|
|
151
151
|
const text = new TextDecoder().decode(value);
|
|
@@ -158,11 +158,6 @@ function decodeMcpArgs(rawArgs: Record<string, Uint8Array>): Record<string, unkn
|
|
|
158
158
|
return decoded;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
function formatMcpToolErrorMessage(toolName: string, availableTools: string[]): string {
|
|
162
|
-
const list = availableTools.length > 0 ? availableTools.join(", ") : "none";
|
|
163
|
-
return `MCP tool "${toolName}" not found. Available tools: ${list}`;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
161
|
export class CursorExecHandlers implements ICursorExecHandlers {
|
|
167
162
|
constructor(private options: CursorExecBridgeOptions) {}
|
|
168
163
|
|
|
@@ -298,26 +293,10 @@ export class CursorExecHandlers implements ICursorExecHandlers {
|
|
|
298
293
|
return toolResultMessage;
|
|
299
294
|
}
|
|
300
295
|
|
|
301
|
-
async
|
|
296
|
+
async tool(call: CursorToolCall) {
|
|
302
297
|
const toolName = call.toolName || call.name;
|
|
303
298
|
const toolCallId = decodeToolCallId(call.toolCallId);
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
const availableTools = Array.from(this.options.tools.keys()).filter(name => name.startsWith("mcp_"));
|
|
307
|
-
const message = formatMcpToolErrorMessage(toolName, availableTools);
|
|
308
|
-
const toolResult: ToolResultMessage = {
|
|
309
|
-
role: "toolResult",
|
|
310
|
-
toolCallId,
|
|
311
|
-
toolName,
|
|
312
|
-
content: [{ type: "text", text: message }],
|
|
313
|
-
isError: true,
|
|
314
|
-
timestamp: Date.now(),
|
|
315
|
-
};
|
|
316
|
-
return toolResult;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const args = Object.keys(call.args ?? {}).length > 0 ? call.args : decodeMcpArgs(call.rawArgs ?? {});
|
|
320
|
-
const toolResultMessage = await executeTool(this.options, toolName, toolCallId, args);
|
|
321
|
-
return toolResultMessage;
|
|
299
|
+
const args = Object.keys(call.args).length > 0 ? call.args : decodeGenericToolArgs(call.rawArgs);
|
|
300
|
+
return executeTool(this.options, toolName, toolCallId, args);
|
|
322
301
|
}
|
|
323
302
|
}
|
package/src/discovery/builtin.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Primary provider for OMP native configs. Supports all capabilities.
|
|
5
5
|
*/
|
|
6
6
|
import * as path from "node:path";
|
|
7
|
-
import {
|
|
7
|
+
import { parseFrontmatter, tryParseJson } from "@f5-sales-demo/pi-utils";
|
|
8
8
|
import { registerProvider } from "../capability";
|
|
9
9
|
import { type ContextFile, contextFileCapability } from "../capability/context-file";
|
|
10
10
|
import { type Extension, type ExtensionManifest, extensionCapability } from "../capability/extension";
|
|
@@ -12,7 +12,6 @@ import { type ExtensionModule, extensionModuleCapability } from "../capability/e
|
|
|
12
12
|
import { readDirEntries, readFile } from "../capability/fs";
|
|
13
13
|
import { type Hook, hookCapability } from "../capability/hook";
|
|
14
14
|
import { type Instruction, instructionCapability } from "../capability/instruction";
|
|
15
|
-
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
16
15
|
import { type Prompt, promptCapability } from "../capability/prompt";
|
|
17
16
|
import { type Rule, ruleCapability } from "../capability/rule";
|
|
18
17
|
import { type Settings, settingsCapability } from "../capability/settings";
|
|
@@ -26,7 +25,6 @@ import {
|
|
|
26
25
|
buildRuleFromMarkdown,
|
|
27
26
|
createSourceMeta,
|
|
28
27
|
discoverExtensionModulePaths,
|
|
29
|
-
expandEnvVarsDeep,
|
|
30
28
|
getExtensionNameFromPath,
|
|
31
29
|
loadFilesFromDir,
|
|
32
30
|
SOURCE_PATHS,
|
|
@@ -93,133 +91,6 @@ async function findNearestProjectConfigDir(
|
|
|
93
91
|
return null;
|
|
94
92
|
}
|
|
95
93
|
|
|
96
|
-
// MCP
|
|
97
|
-
async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>> {
|
|
98
|
-
const items: MCPServer[] = [];
|
|
99
|
-
const warnings: string[] = [];
|
|
100
|
-
|
|
101
|
-
const parseMcpServers = (content: string, path: string, level: "user" | "project"): MCPServer[] => {
|
|
102
|
-
const result: MCPServer[] = [];
|
|
103
|
-
const data = tryParseJson<{ mcpServers?: Record<string, unknown> }>(content);
|
|
104
|
-
if (!data?.mcpServers) return result;
|
|
105
|
-
|
|
106
|
-
const expanded = expandEnvVarsDeep(data.mcpServers);
|
|
107
|
-
for (const [serverName, config] of Object.entries(expanded)) {
|
|
108
|
-
const serverConfig = config as Record<string, unknown>;
|
|
109
|
-
|
|
110
|
-
// Validate enabled: coerce string "true"/"false", warn on other types
|
|
111
|
-
let enabled: boolean | undefined;
|
|
112
|
-
if (serverConfig.enabled === undefined || serverConfig.enabled === null) {
|
|
113
|
-
enabled = undefined;
|
|
114
|
-
} else if (typeof serverConfig.enabled === "boolean") {
|
|
115
|
-
enabled = serverConfig.enabled;
|
|
116
|
-
} else if (typeof serverConfig.enabled === "string") {
|
|
117
|
-
const lower = serverConfig.enabled.toLowerCase();
|
|
118
|
-
if (lower === "false" || lower === "0") enabled = false;
|
|
119
|
-
else if (lower === "true" || lower === "1") enabled = true;
|
|
120
|
-
else {
|
|
121
|
-
logger.warn(`MCP server "${serverName}": invalid enabled value "${serverConfig.enabled}", ignoring`);
|
|
122
|
-
enabled = undefined;
|
|
123
|
-
}
|
|
124
|
-
} else {
|
|
125
|
-
logger.warn(`MCP server "${serverName}": invalid enabled type ${typeof serverConfig.enabled}, ignoring`);
|
|
126
|
-
enabled = undefined;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Validate timeout: coerce numeric strings, warn on invalid
|
|
130
|
-
let timeout: number | undefined;
|
|
131
|
-
if (serverConfig.timeout === undefined || serverConfig.timeout === null) {
|
|
132
|
-
timeout = undefined;
|
|
133
|
-
} else if (typeof serverConfig.timeout === "number") {
|
|
134
|
-
if (Number.isFinite(serverConfig.timeout) && serverConfig.timeout > 0) {
|
|
135
|
-
timeout = serverConfig.timeout;
|
|
136
|
-
} else {
|
|
137
|
-
logger.warn(`MCP server "${serverName}": invalid timeout ${serverConfig.timeout}, ignoring`);
|
|
138
|
-
timeout = undefined;
|
|
139
|
-
}
|
|
140
|
-
} else if (typeof serverConfig.timeout === "string") {
|
|
141
|
-
const parsed = Number(serverConfig.timeout);
|
|
142
|
-
if (Number.isFinite(parsed) && parsed > 0) {
|
|
143
|
-
timeout = parsed;
|
|
144
|
-
} else {
|
|
145
|
-
logger.warn(`MCP server "${serverName}": invalid timeout "${serverConfig.timeout}", ignoring`);
|
|
146
|
-
timeout = undefined;
|
|
147
|
-
}
|
|
148
|
-
} else {
|
|
149
|
-
logger.warn(`MCP server "${serverName}": invalid timeout type ${typeof serverConfig.timeout}, ignoring`);
|
|
150
|
-
timeout = undefined;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
result.push({
|
|
154
|
-
name: serverName,
|
|
155
|
-
enabled,
|
|
156
|
-
timeout,
|
|
157
|
-
command: serverConfig.command as string | undefined,
|
|
158
|
-
args: serverConfig.args as string[] | undefined,
|
|
159
|
-
env: serverConfig.env as Record<string, string> | undefined,
|
|
160
|
-
cwd: serverConfig.cwd as string | undefined,
|
|
161
|
-
url: serverConfig.url as string | undefined,
|
|
162
|
-
headers: serverConfig.headers as Record<string, string> | undefined,
|
|
163
|
-
auth: serverConfig.auth as
|
|
164
|
-
| {
|
|
165
|
-
type: "oauth" | "apikey";
|
|
166
|
-
credentialId?: string;
|
|
167
|
-
tokenUrl?: string;
|
|
168
|
-
clientId?: string;
|
|
169
|
-
clientSecret?: string;
|
|
170
|
-
}
|
|
171
|
-
| undefined,
|
|
172
|
-
oauth: serverConfig.oauth as
|
|
173
|
-
| {
|
|
174
|
-
clientId?: string;
|
|
175
|
-
clientSecret?: string;
|
|
176
|
-
redirectUri?: string;
|
|
177
|
-
callbackPort?: number;
|
|
178
|
-
callbackPath?: string;
|
|
179
|
-
}
|
|
180
|
-
| undefined,
|
|
181
|
-
transport: serverConfig.type as "stdio" | "sse" | "http" | undefined,
|
|
182
|
-
_source: createSourceMeta(PROVIDER_ID, path, level),
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
return result;
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
const paths = [
|
|
189
|
-
{ path: path.join(ctx.cwd, PATHS.projectDir, "mcp.json"), level: "project" as const },
|
|
190
|
-
{ path: path.join(ctx.cwd, PATHS.projectDir, ".mcp.json"), level: "project" as const },
|
|
191
|
-
{ path: path.join(ctx.home, PATHS.userAgent, "mcp.json"), level: "user" as const },
|
|
192
|
-
{ path: path.join(ctx.home, PATHS.userAgent, ".mcp.json"), level: "user" as const },
|
|
193
|
-
];
|
|
194
|
-
|
|
195
|
-
const contents = await Promise.allSettled(
|
|
196
|
-
paths.map(async p => {
|
|
197
|
-
const content = await readFile(p.path);
|
|
198
|
-
if (content) {
|
|
199
|
-
return { path: p.path, content, level: p.level };
|
|
200
|
-
}
|
|
201
|
-
return null;
|
|
202
|
-
}),
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
for (const result of contents) {
|
|
206
|
-
if (result.status === "fulfilled" && result.value) {
|
|
207
|
-
const { path, content, level } = result.value;
|
|
208
|
-
items.push(...parseMcpServers(content, path, level));
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return { items, warnings };
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
registerProvider<MCPServer>(mcpCapability.id, {
|
|
216
|
-
id: PROVIDER_ID,
|
|
217
|
-
displayName: SOURCE_LABEL,
|
|
218
|
-
description: DESCRIPTION,
|
|
219
|
-
priority: PRIORITY,
|
|
220
|
-
load: loadMCPServers,
|
|
221
|
-
});
|
|
222
|
-
|
|
223
94
|
// System Prompt (SYSTEM.md)
|
|
224
95
|
async function loadSystemPrompt(ctx: LoadContext): Promise<LoadResult<SystemPrompt>> {
|
|
225
96
|
const items: SystemPrompt[] = [];
|
|
@@ -5,25 +5,13 @@
|
|
|
5
5
|
* Priority: 70 (below claude.ts at 80, so user overrides in .xcsh/ take precedence)
|
|
6
6
|
*/
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
-
import { logger } from "@f5-sales-demo/pi-utils";
|
|
9
8
|
import { registerProvider } from "../capability";
|
|
10
|
-
import { readFile } from "../capability/fs";
|
|
11
9
|
import { type Hook, hookCapability } from "../capability/hook";
|
|
12
|
-
import { type MCPServer, mcpCapability } from "../capability/mcp";
|
|
13
10
|
import { type Skill, skillCapability } from "../capability/skill";
|
|
14
11
|
import { type SlashCommand, slashCommandCapability } from "../capability/slash-command";
|
|
15
12
|
import { type CustomTool, toolCapability } from "../capability/tool";
|
|
16
13
|
import type { LoadContext, LoadResult } from "../capability/types";
|
|
17
|
-
import {
|
|
18
|
-
createSourceMeta,
|
|
19
|
-
listXcshPluginRoots,
|
|
20
|
-
loadFilesFromDir,
|
|
21
|
-
scanSkillsFromDir,
|
|
22
|
-
scopeToLevel,
|
|
23
|
-
type XcshPluginRoot,
|
|
24
|
-
} from "./helpers";
|
|
25
|
-
|
|
26
|
-
import { substitutePluginRoot } from "./substitute-plugin-root";
|
|
14
|
+
import { listXcshPluginRoots, loadFilesFromDir, scanSkillsFromDir, scopeToLevel, type XcshPluginRoot } from "./helpers";
|
|
27
15
|
|
|
28
16
|
const PROVIDER_ID = "xcsh-plugins";
|
|
29
17
|
const SOURCE_LABEL = "xcsh Marketplace";
|
|
@@ -186,73 +174,6 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
|
|
|
186
174
|
return { items, warnings };
|
|
187
175
|
}
|
|
188
176
|
|
|
189
|
-
// =============================================================================
|
|
190
|
-
// MCP Servers
|
|
191
|
-
// =============================================================================
|
|
192
|
-
|
|
193
|
-
async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>> {
|
|
194
|
-
const items: MCPServer[] = [];
|
|
195
|
-
const warnings: string[] = [];
|
|
196
|
-
|
|
197
|
-
const { roots, warnings: rootWarnings } = await listXcshPluginRoots(ctx.home, ctx.cwd);
|
|
198
|
-
warnings.push(...rootWarnings);
|
|
199
|
-
|
|
200
|
-
for (const root of roots) {
|
|
201
|
-
const mcpPath = path.join(root.path, ".mcp.json");
|
|
202
|
-
const raw = await readFile(mcpPath);
|
|
203
|
-
if (raw === null) continue; // file absent — skip silently
|
|
204
|
-
|
|
205
|
-
let parsed: unknown;
|
|
206
|
-
try {
|
|
207
|
-
parsed = JSON.parse(raw);
|
|
208
|
-
} catch {
|
|
209
|
-
warnings.push(`[claude-plugins] Invalid JSON in ${mcpPath}`);
|
|
210
|
-
logger.warn(`[claude-plugins] Invalid JSON in ${mcpPath}`);
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
|
|
215
|
-
const config = parsed as { mcpServers?: Record<string, unknown> };
|
|
216
|
-
if (!config.mcpServers || typeof config.mcpServers !== "object") continue;
|
|
217
|
-
|
|
218
|
-
for (const [serverName, serverCfg] of Object.entries(config.mcpServers)) {
|
|
219
|
-
if (!serverCfg || typeof serverCfg !== "object" || Array.isArray(serverCfg)) continue;
|
|
220
|
-
const raw = serverCfg as {
|
|
221
|
-
enabled?: boolean;
|
|
222
|
-
timeout?: number;
|
|
223
|
-
command?: string;
|
|
224
|
-
args?: string[];
|
|
225
|
-
env?: Record<string, string>;
|
|
226
|
-
cwd?: string;
|
|
227
|
-
url?: string;
|
|
228
|
-
headers?: Record<string, string>;
|
|
229
|
-
auth?: MCPServer["auth"];
|
|
230
|
-
oauth?: MCPServer["oauth"];
|
|
231
|
-
type?: string;
|
|
232
|
-
};
|
|
233
|
-
const namespacedName = root.plugin ? `${root.plugin}:${serverName}` : serverName;
|
|
234
|
-
const server: MCPServer = {
|
|
235
|
-
name: namespacedName,
|
|
236
|
-
...(raw.enabled !== undefined && { enabled: raw.enabled }),
|
|
237
|
-
...(raw.timeout !== undefined && { timeout: raw.timeout }),
|
|
238
|
-
...(raw.command !== undefined && { command: substitutePluginRoot(raw.command, root.path) }),
|
|
239
|
-
...(raw.args !== undefined && { args: substitutePluginRoot(raw.args, root.path) }),
|
|
240
|
-
...(raw.env !== undefined && { env: substitutePluginRoot(raw.env, root.path) }),
|
|
241
|
-
...(raw.cwd !== undefined && { cwd: substitutePluginRoot(raw.cwd, root.path) }),
|
|
242
|
-
...(raw.url !== undefined && { url: raw.url }),
|
|
243
|
-
...(raw.headers !== undefined && { headers: raw.headers }),
|
|
244
|
-
...(raw.auth !== undefined && { auth: raw.auth }),
|
|
245
|
-
...(raw.oauth !== undefined && { oauth: raw.oauth }),
|
|
246
|
-
...(raw.type !== undefined && { transport: raw.type as MCPServer["transport"] }),
|
|
247
|
-
_source: createSourceMeta(PROVIDER_ID, mcpPath, scopeToLevel(root.scope)),
|
|
248
|
-
};
|
|
249
|
-
items.push(server);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return { items, warnings };
|
|
254
|
-
}
|
|
255
|
-
|
|
256
177
|
// =============================================================================
|
|
257
178
|
// Provider Registration
|
|
258
179
|
// =============================================================================
|
|
@@ -288,11 +209,3 @@ registerProvider<CustomTool>(toolCapability.id, {
|
|
|
288
209
|
priority: PRIORITY,
|
|
289
210
|
load: loadTools,
|
|
290
211
|
});
|
|
291
|
-
|
|
292
|
-
registerProvider<MCPServer>(mcpCapability.id, {
|
|
293
|
-
id: PROVIDER_ID,
|
|
294
|
-
displayName: SOURCE_LABEL,
|
|
295
|
-
description: "Load MCP servers from marketplace plugin .mcp.json files",
|
|
296
|
-
priority: PRIORITY,
|
|
297
|
-
load: loadMCPServers,
|
|
298
|
-
});
|