diff --git a/cli/src/commands/code-search.ts b/cli/src/commands/code-search.ts index 0302da52..b4c60279 100644 --- a/cli/src/commands/code-search.ts +++ b/cli/src/commands/code-search.ts @@ -19,11 +19,7 @@ export function registerCodeSearchCommand(program: Command, context: CliContext) .option('--json', 'Output raw JSON instead of formatted text.') .action(async (query: string, options: CodeSearchCommandOptions) => { const endpoint = resolveEndpoint(program.opts<{ endpoint?: string }>().endpoint, context.env); - const client = context.createClient({ - endpoint, - clientName: 'mslearn', - clientVersion: context.version, - }); + const client = context.createClient({ endpoint }); try { const payload = await client.searchCodeSamples(query, options.language); diff --git a/cli/src/commands/doctor.ts b/cli/src/commands/doctor.ts index 4e38ddb2..901fa931 100644 --- a/cli/src/commands/doctor.ts +++ b/cli/src/commands/doctor.ts @@ -35,17 +35,13 @@ export function registerDoctorCommand(program: Command, context: CliContext): vo async function runDoctorChecks(endpoint: string, context: CliContext): Promise { const runtimeVersion = process.versions.node; const runtimeSupported = Number.parseInt(runtimeVersion.split('.')[0] ?? '0', 10) >= 22; - const reachability = await probeEndpoint(endpoint, context.fetchImpl); + const reachability = await probeEndpoint(endpoint); const errors: string[] = []; const tools: DoctorReport['tools'] = {}; let connected = false; let discovered = false; - const client = context.createClient({ - endpoint, - clientName: 'mslearn', - clientVersion: context.version, - }); + const client = context.createClient({ endpoint }); try { const mapping = await client.getToolMapping(true); diff --git a/cli/src/commands/fetch.ts b/cli/src/commands/fetch.ts index 3c7bcc63..bdc961be 100644 --- a/cli/src/commands/fetch.ts +++ b/cli/src/commands/fetch.ts @@ -20,11 +20,7 @@ export function registerFetchCommand(program: Command, context: CliContext): voi .action(async (url: string, options: FetchCommandOptions) => { const endpoint = resolveEndpoint(program.opts<{ endpoint?: string }>().endpoint, context.env); const normalizedUrl = normalizeUrl(url); - const client = context.createClient({ - endpoint, - clientName: 'mslearn', - clientVersion: context.version, - }); + const client = context.createClient({ endpoint }); try { const markdown = await client.fetchDocument(normalizedUrl); diff --git a/cli/src/commands/search.ts b/cli/src/commands/search.ts index c8424ee0..8a0a65cf 100644 --- a/cli/src/commands/search.ts +++ b/cli/src/commands/search.ts @@ -17,11 +17,7 @@ export function registerSearchCommand(program: Command, context: CliContext): vo .option('--json', 'Output raw JSON instead of formatted text.') .action(async (query: string, options: SearchCommandOptions) => { const endpoint = resolveEndpoint(program.opts<{ endpoint?: string }>().endpoint, context.env); - const client = context.createClient({ - endpoint, - clientName: 'mslearn', - clientVersion: context.version, - }); + const client = context.createClient({ endpoint }); try { const payload = await client.searchDocs(query); diff --git a/cli/src/context.ts b/cli/src/context.ts index ab8c04b6..8c3e9dc0 100644 --- a/cli/src/context.ts +++ b/cli/src/context.ts @@ -5,7 +5,6 @@ export interface CliContext { version: string; writeOut: (value: string) => void; writeErr: (value: string) => void; - fetchImpl: typeof fetch; createClient: (options: LearnClientOptions) => LearnCliClientLike; } @@ -19,7 +18,10 @@ export function createDefaultContext(version: string): CliContext { writeErr: (value) => { process.stderr.write(value); }, - fetchImpl: globalThis.fetch.bind(globalThis) as typeof fetch, - createClient: (options) => createLearnCliClient(options), + createClient: (options) => + createLearnCliClient({ + clientVersion: version, + ...options, + }), }; } diff --git a/cli/src/index.ts b/cli/src/index.ts index 14f610f2..5e952ff6 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -25,12 +25,8 @@ export function createProgram(context: CliContext): Command { .addOption(new Option('--endpoint ', 'Override the Learn MCP endpoint for this command.').hideHelp()) .showHelpAfterError() .configureOutput({ - writeOut: (value) => { - context.writeOut(value); - }, - writeErr: (value) => { - context.writeErr(value); - }, + writeOut: context.writeOut, + writeErr: context.writeErr, outputError: (value, write) => { write(value); }, diff --git a/cli/src/mcp/client.ts b/cli/src/mcp/client.ts index c064b69c..1566fd8a 100644 --- a/cli/src/mcp/client.ts +++ b/cli/src/mcp/client.ts @@ -7,6 +7,8 @@ import { OperationError } from '../utils/errors.js'; import { createFileLearnSessionCacheStore, type LearnSessionCacheStore } from './cache.js'; import { discoverLearnTools, type DiscoveredLearnTools, type ListedTool } from './tool-discovery.js'; +const DEFAULT_CLIENT_NAME = 'learn-cli'; + export interface LearnClientOptions { endpoint: string; clientName?: string; @@ -43,7 +45,7 @@ interface TransportLike { close(): Promise; } -export async function probeEndpoint(endpoint: string, fetchImpl: typeof fetch): Promise { +export async function probeEndpoint(endpoint: string, fetchImpl: typeof fetch = globalThis.fetch): Promise { try { const response = await fetchImpl(endpoint, { method: 'GET', @@ -271,7 +273,7 @@ class LearnCliClient implements LearnCliClientLike { private createDefaultSdkClient(): SdkClientLike { return new Client( { - name: this.options.clientName ?? 'mslearn', + name: this.options.clientName ?? DEFAULT_CLIENT_NAME, version: this.options.clientVersion ?? '0.1.0', }, { diff --git a/cli/test/unit/cli.test.ts b/cli/test/unit/cli.test.ts index 49b79382..1a639bf5 100644 --- a/cli/test/unit/cli.test.ts +++ b/cli/test/unit/cli.test.ts @@ -37,7 +37,6 @@ function createTestContext(client: LearnCliClientLike): { writeErr: (value) => { stderr.push(value); }, - fetchImpl: vi.fn(async () => new Response(null, { status: 405 })) as unknown as typeof fetch, createClient: () => client, }, stdout, diff --git a/skills/microsoft-code-reference/SKILL.md b/skills/microsoft-code-reference/SKILL.md index 5fb3cf8c..61bc2fe7 100644 --- a/skills/microsoft-code-reference/SKILL.md +++ b/skills/microsoft-code-reference/SKILL.md @@ -80,9 +80,9 @@ For simple lookups, step 1 alone may suffice. For complex API usage, complete al ## CLI Alternative -If the Learn MCP server is not available, use the `mslearn` CLI via Bash instead: +If the Learn MCP server is not available, use the `mslearn` CLI from the command line instead: -```bash +```sh # Run directly (no install needed) npx @microsoft/learn-cli search "BlobClient UploadAsync Azure.Storage.Blobs" diff --git a/skills/microsoft-docs/SKILL.md b/skills/microsoft-docs/SKILL.md index fabc1e2b..aaeedef0 100644 --- a/skills/microsoft-docs/SKILL.md +++ b/skills/microsoft-docs/SKILL.md @@ -58,9 +58,9 @@ Fetch after search when: ## CLI Alternative -If the Learn MCP server is not available, use the `mslearn` CLI via Bash instead: +If the Learn MCP server is not available, use the `mslearn` CLI from the command line instead: -```bash +```sh # Run directly (no install needed) npx @microsoft/learn-cli search "azure functions timeout" diff --git a/skills/microsoft-skill-creator/SKILL.md b/skills/microsoft-skill-creator/SKILL.md index 433b66c9..6193f087 100644 --- a/skills/microsoft-skill-creator/SKILL.md +++ b/skills/microsoft-skill-creator/SKILL.md @@ -39,9 +39,9 @@ skill-name/ ### CLI Alternative -If the Learn MCP server is not available, use the `mslearn` CLI via Bash instead: +If the Learn MCP server is not available, use the `mslearn` CLI from the command line instead: -```bash +```sh # Run directly (no install needed) npx @microsoft/learn-cli search "semantic kernel overview"