@wingmanjs/core 0.1.0
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/LICENSE +21 -0
- package/dist/client.d.ts +55 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +227 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +55 -0
- package/dist/config.js.map +1 -0
- package/dist/events.d.ts +77 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +231 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.d.ts +31 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +107 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/mcp.d.ts +28 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +241 -0
- package/dist/mcp.js.map +1 -0
- package/dist/server.d.ts +31 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +317 -0
- package/dist/server.js.map +1 -0
- package/dist/telemetry.d.ts +52 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +313 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +132 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +62 -0
- package/dist/types.js.map +1 -0
- package/package.json +70 -0
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Discovery ā Auto-discovers MCP servers from multiple sources.
|
|
3
|
+
*
|
|
4
|
+
* Discovery chain (later overrides earlier):
|
|
5
|
+
* 1. Built-in defaults (Power BI remote)
|
|
6
|
+
* 2. User global config (~/.copilot/mcp-config.json)
|
|
7
|
+
* 3. Installed Copilot CLI plugins (~/.copilot/installed-plugins/)
|
|
8
|
+
* 4. Project-level overrides (./mcp.json)
|
|
9
|
+
* 5. User overrides from wingman.config.ts (highest priority)
|
|
10
|
+
*/
|
|
11
|
+
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { homedir } from 'node:os';
|
|
14
|
+
import { trace, SpanStatusCode, context } from '@opentelemetry/api';
|
|
15
|
+
const MCP_TRACER = 'wingman';
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Safe filesystem helpers
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
async function exists(path) {
|
|
20
|
+
try {
|
|
21
|
+
await stat(path);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function readJson(path) {
|
|
29
|
+
try {
|
|
30
|
+
const content = await readFile(path, 'utf-8');
|
|
31
|
+
return JSON.parse(content);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Discovery pipeline
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
/** Built-in default MCP servers. */
|
|
41
|
+
function getBuiltinDefaults() {
|
|
42
|
+
return {
|
|
43
|
+
'powerbi-remote': {
|
|
44
|
+
type: 'http',
|
|
45
|
+
url: 'https://api.fabric.microsoft.com/v1/mcp/powerbi',
|
|
46
|
+
tools: ['*'],
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Load servers from ~/.copilot/mcp-config.json */
|
|
51
|
+
async function loadGlobalConfig() {
|
|
52
|
+
const configPath = join(homedir(), '.copilot', 'mcp-config.json');
|
|
53
|
+
const config = await readJson(configPath);
|
|
54
|
+
return config?.mcpServers ?? {};
|
|
55
|
+
}
|
|
56
|
+
/** Scan installed plugins for MCP server configs. */
|
|
57
|
+
async function loadPluginServers() {
|
|
58
|
+
const servers = {};
|
|
59
|
+
const skills = [];
|
|
60
|
+
const diagnostics = [];
|
|
61
|
+
const pluginsBase = join(homedir(), '.copilot', 'installed-plugins');
|
|
62
|
+
if (!(await exists(pluginsBase))) {
|
|
63
|
+
return { servers, skills, diagnostics };
|
|
64
|
+
}
|
|
65
|
+
// Scan catalog directories (_direct, copilot-plugins, awesome-copilot)
|
|
66
|
+
const catalogs = await readdir(pluginsBase).catch(() => []);
|
|
67
|
+
for (const catalog of catalogs) {
|
|
68
|
+
const catalogPath = join(pluginsBase, catalog);
|
|
69
|
+
const catalogStat = await stat(catalogPath).catch(() => null);
|
|
70
|
+
if (!catalogStat?.isDirectory())
|
|
71
|
+
continue;
|
|
72
|
+
const plugins = await readdir(catalogPath).catch(() => []);
|
|
73
|
+
for (const plugin of plugins) {
|
|
74
|
+
try {
|
|
75
|
+
const pluginPath = join(catalogPath, plugin);
|
|
76
|
+
const pluginJsonPath = join(pluginPath, 'plugin.json');
|
|
77
|
+
const pluginJson = await readJson(pluginJsonPath);
|
|
78
|
+
if (!pluginJson)
|
|
79
|
+
continue;
|
|
80
|
+
// MCP servers ā can be inline object or path to external JSON
|
|
81
|
+
if (pluginJson.mcpServers) {
|
|
82
|
+
let pluginServers = {};
|
|
83
|
+
if (typeof pluginJson.mcpServers === 'string') {
|
|
84
|
+
// External file reference
|
|
85
|
+
const externalPath = join(pluginPath, pluginJson.mcpServers);
|
|
86
|
+
const external = await readJson(externalPath);
|
|
87
|
+
if (external)
|
|
88
|
+
pluginServers = external;
|
|
89
|
+
}
|
|
90
|
+
else if (typeof pluginJson.mcpServers === 'object' && pluginJson.mcpServers !== null) {
|
|
91
|
+
pluginServers = pluginJson.mcpServers;
|
|
92
|
+
}
|
|
93
|
+
for (const [name, config] of Object.entries(pluginServers)) {
|
|
94
|
+
servers[name] = config;
|
|
95
|
+
diagnostics.push(` ā
${name} ā plugin (${catalog}/${plugin})`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Skills directory
|
|
99
|
+
if (pluginJson.skills) {
|
|
100
|
+
const skillsDir = join(pluginPath, pluginJson.skills);
|
|
101
|
+
if (await exists(skillsDir)) {
|
|
102
|
+
skills.push(skillsDir);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
diagnostics.push(` ā ļø ${catalog}/${plugin} ā failed to load: ${err instanceof Error ? err.message : String(err)}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { servers, skills, diagnostics };
|
|
112
|
+
}
|
|
113
|
+
/** Load project-level MCP config from ./mcp.json */
|
|
114
|
+
async function loadProjectConfig(projectRoot) {
|
|
115
|
+
const root = projectRoot ?? process.cwd();
|
|
116
|
+
const mcpJsonPath = join(root, 'mcp.json');
|
|
117
|
+
const config = await readJson(mcpJsonPath);
|
|
118
|
+
return config?.mcpServers ?? {};
|
|
119
|
+
}
|
|
120
|
+
async function runDiscoveryStage(tracer, parentCtx, spanName, fn) {
|
|
121
|
+
const span = tracer.startSpan(spanName, {}, parentCtx);
|
|
122
|
+
try {
|
|
123
|
+
await fn(span);
|
|
124
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
span.recordException(error);
|
|
128
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
span.end();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// Public API
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
/**
|
|
139
|
+
* Discover all MCP servers from the 5-stage pipeline.
|
|
140
|
+
* User-provided overrides (from wingman.config.ts) are merged last.
|
|
141
|
+
*/
|
|
142
|
+
export async function discoverMCPServers(userOverrides) {
|
|
143
|
+
const result = {};
|
|
144
|
+
// Stage 1: Built-in defaults
|
|
145
|
+
Object.assign(result, getBuiltinDefaults());
|
|
146
|
+
// Stage 2: Global config
|
|
147
|
+
Object.assign(result, await loadGlobalConfig());
|
|
148
|
+
// Stage 3: Plugins
|
|
149
|
+
const plugins = await loadPluginServers();
|
|
150
|
+
Object.assign(result, plugins.servers);
|
|
151
|
+
// Stage 4: Project config
|
|
152
|
+
Object.assign(result, await loadProjectConfig());
|
|
153
|
+
// Stage 5: User overrides from wingman.config.ts
|
|
154
|
+
if (userOverrides) {
|
|
155
|
+
Object.assign(result, userOverrides);
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Discover servers with full diagnostics ā returns source tracking
|
|
161
|
+
* and skill directories for logging and UI display.
|
|
162
|
+
*/
|
|
163
|
+
export async function discoverWithDiagnostics(userOverrides, projectRoot) {
|
|
164
|
+
const tracer = trace.getTracer(MCP_TRACER);
|
|
165
|
+
const discoverySpan = tracer.startSpan('mcp.discovery', {
|
|
166
|
+
attributes: {
|
|
167
|
+
'mcp.discovery.has_overrides': userOverrides != null && Object.keys(userOverrides).length > 0,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
const ctx = trace.setSpan(context.active(), discoverySpan);
|
|
171
|
+
const servers = {};
|
|
172
|
+
const sources = new Map();
|
|
173
|
+
const diagnostics = ['š MCP Servers Discovered:'];
|
|
174
|
+
const skillDirectories = [];
|
|
175
|
+
try {
|
|
176
|
+
// Stage 1: Built-in defaults
|
|
177
|
+
await runDiscoveryStage(tracer, ctx, 'mcp.discovery.stage1_builtins', async (stageSpan) => {
|
|
178
|
+
const builtins = getBuiltinDefaults();
|
|
179
|
+
for (const [name, config] of Object.entries(builtins)) {
|
|
180
|
+
servers[name] = config;
|
|
181
|
+
sources.set(name, 'built-in');
|
|
182
|
+
diagnostics.push(` ā
${name} ā built-in default`);
|
|
183
|
+
}
|
|
184
|
+
stageSpan.setAttribute('mcp.discovery.stage1.count', Object.keys(builtins).length);
|
|
185
|
+
});
|
|
186
|
+
// Stage 2: Global config
|
|
187
|
+
await runDiscoveryStage(tracer, ctx, 'mcp.discovery.stage2_global', async (stageSpan) => {
|
|
188
|
+
const globals = await loadGlobalConfig();
|
|
189
|
+
for (const [name, config] of Object.entries(globals)) {
|
|
190
|
+
servers[name] = config;
|
|
191
|
+
sources.set(name, 'global config');
|
|
192
|
+
diagnostics.push(` ā
${name} ā global config`);
|
|
193
|
+
}
|
|
194
|
+
stageSpan.setAttribute('mcp.discovery.stage2.count', Object.keys(globals).length);
|
|
195
|
+
});
|
|
196
|
+
// Stage 3: Plugins
|
|
197
|
+
await runDiscoveryStage(tracer, ctx, 'mcp.discovery.stage3_plugins', async (stageSpan) => {
|
|
198
|
+
const plugins = await loadPluginServers();
|
|
199
|
+
for (const [name, config] of Object.entries(plugins.servers)) {
|
|
200
|
+
servers[name] = config;
|
|
201
|
+
sources.set(name, 'plugin');
|
|
202
|
+
}
|
|
203
|
+
diagnostics.push(...plugins.diagnostics);
|
|
204
|
+
skillDirectories.push(...plugins.skills);
|
|
205
|
+
stageSpan.setAttribute('mcp.discovery.stage3.count', Object.keys(plugins.servers).length);
|
|
206
|
+
});
|
|
207
|
+
// Stage 4: Project config
|
|
208
|
+
await runDiscoveryStage(tracer, ctx, 'mcp.discovery.stage4_project', async (stageSpan) => {
|
|
209
|
+
const project = await loadProjectConfig(projectRoot);
|
|
210
|
+
for (const [name, config] of Object.entries(project)) {
|
|
211
|
+
servers[name] = config;
|
|
212
|
+
sources.set(name, 'project mcp.json');
|
|
213
|
+
diagnostics.push(` ā
${name} ā project mcp.json`);
|
|
214
|
+
}
|
|
215
|
+
stageSpan.setAttribute('mcp.discovery.stage4.count', Object.keys(project).length);
|
|
216
|
+
});
|
|
217
|
+
// Stage 5: User overrides
|
|
218
|
+
if (userOverrides && Object.keys(userOverrides).length > 0) {
|
|
219
|
+
await runDiscoveryStage(tracer, ctx, 'mcp.discovery.stage5_overrides', async (stageSpan) => {
|
|
220
|
+
for (const [name, config] of Object.entries(userOverrides)) {
|
|
221
|
+
servers[name] = config;
|
|
222
|
+
sources.set(name, 'wingman.config.ts');
|
|
223
|
+
diagnostics.push(` ā
${name} ā wingman.config.ts`);
|
|
224
|
+
}
|
|
225
|
+
stageSpan.setAttribute('mcp.discovery.stage5.count', Object.keys(userOverrides).length);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
discoverySpan.setAttribute('mcp.discovery.total_servers', Object.keys(servers).length);
|
|
229
|
+
discoverySpan.setStatus({ code: SpanStatusCode.OK });
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
discoverySpan.recordException(error);
|
|
233
|
+
discoverySpan.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
discoverySpan.end();
|
|
238
|
+
}
|
|
239
|
+
return { servers, sources, skillDirectories, diagnostics };
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wingman Express Server ā SSE streaming endpoint for the chat UI.
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - POST /api/chat ā SSE streaming chat endpoint
|
|
6
|
+
* - GET /api/health ā Health check
|
|
7
|
+
* - Static file serving for the React frontend
|
|
8
|
+
*
|
|
9
|
+
* SSE is the Phase 0 transport. Socket.IO upgrade happens in Phase 2.
|
|
10
|
+
*/
|
|
11
|
+
import { WingmanClient } from './client.js';
|
|
12
|
+
import type { WingmanConfig } from './types.js';
|
|
13
|
+
import type { Application } from 'express';
|
|
14
|
+
import type { Server } from 'node:http';
|
|
15
|
+
export interface CreateServerOptions {
|
|
16
|
+
config?: WingmanConfig;
|
|
17
|
+
/** Absolute path to the built React frontend (dist/client). */
|
|
18
|
+
staticDir?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ServerInstance {
|
|
21
|
+
app: Application;
|
|
22
|
+
client: WingmanClient;
|
|
23
|
+
config: Required<WingmanConfig>;
|
|
24
|
+
}
|
|
25
|
+
export interface RunningServerInstance extends ServerInstance {
|
|
26
|
+
server: Server;
|
|
27
|
+
}
|
|
28
|
+
export declare function createServer(options?: CreateServerOptions): ServerInstance;
|
|
29
|
+
/** Start the server and listen on the configured port. */
|
|
30
|
+
export declare function startServer(options?: CreateServerOptions): Promise<RunningServerInstance>;
|
|
31
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKhD,OAAO,KAAK,EAAE,WAAW,EAAqB,MAAM,SAAS,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAmBxC,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,WAAW,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,qBAAsB,SAAQ,cAAc;IAC3D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,cAAc,CAyS9E;AAED,0DAA0D;AAC1D,wBAAsB,WAAW,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAgCnG"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wingman Express Server ā SSE streaming endpoint for the chat UI.
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - POST /api/chat ā SSE streaming chat endpoint
|
|
6
|
+
* - GET /api/health ā Health check
|
|
7
|
+
* - Static file serving for the React frontend
|
|
8
|
+
*
|
|
9
|
+
* SSE is the Phase 0 transport. Socket.IO upgrade happens in Phase 2.
|
|
10
|
+
*/
|
|
11
|
+
import express from 'express';
|
|
12
|
+
import { resolve } from 'node:path';
|
|
13
|
+
import { WingmanClient } from './client.js';
|
|
14
|
+
import { resolveConfig } from './config.js';
|
|
15
|
+
import { discoverWithDiagnostics } from './mcp.js';
|
|
16
|
+
import { initTelemetry, shutdownTelemetry } from './instrumentation.js';
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Validation helpers
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
const SESSION_ID_PATTERN = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
21
|
+
function validateSessionId(req, res) {
|
|
22
|
+
const { sessionId } = req.params;
|
|
23
|
+
if (!SESSION_ID_PATTERN.test(sessionId)) {
|
|
24
|
+
res.status(400).json({ error: 'Invalid session ID format' });
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return sessionId;
|
|
28
|
+
}
|
|
29
|
+
const MAX_MESSAGE_LENGTH = 100_000;
|
|
30
|
+
export function createServer(options = {}) {
|
|
31
|
+
const config = resolveConfig(options.config ?? {});
|
|
32
|
+
const client = new WingmanClient({ config });
|
|
33
|
+
const app = express();
|
|
34
|
+
app.use(express.json({ limit: '1mb' }));
|
|
35
|
+
// CORS
|
|
36
|
+
const corsOption = config.server.cors;
|
|
37
|
+
const corsEnabled = corsOption === true
|
|
38
|
+
|| (typeof corsOption === 'string' && corsOption.length > 0)
|
|
39
|
+
|| (Array.isArray(corsOption) && corsOption.length > 0);
|
|
40
|
+
if (corsEnabled) {
|
|
41
|
+
// Warn when wildcard CORS is used in production
|
|
42
|
+
if (corsOption === true && process.env.NODE_ENV === 'production') {
|
|
43
|
+
console.warn('[wingman] ā ļø CORS is set to allow all origins (*). ' +
|
|
44
|
+
'This is unsafe in production. Set server.cors to a specific ' +
|
|
45
|
+
'origin or list of origins, e.g. cors: "https://myapp.com"');
|
|
46
|
+
}
|
|
47
|
+
const allowedOrigins = typeof corsOption === 'string' ? new Set([corsOption])
|
|
48
|
+
: Array.isArray(corsOption) ? new Set(corsOption)
|
|
49
|
+
: null; // null ā wildcard
|
|
50
|
+
app.use((req, res, next) => {
|
|
51
|
+
const origin = req.headers.origin;
|
|
52
|
+
if (allowedOrigins) {
|
|
53
|
+
if (origin && allowedOrigins.has(origin)) {
|
|
54
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
55
|
+
res.vary('Origin');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
60
|
+
}
|
|
61
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
62
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
63
|
+
if (req.method === 'OPTIONS') {
|
|
64
|
+
res.sendStatus(204);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
next();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
// Health check
|
|
71
|
+
app.get('/api/health', (_req, res) => {
|
|
72
|
+
res.json({ status: 'ok', version: '0.1.0' });
|
|
73
|
+
});
|
|
74
|
+
// MCP discovery info
|
|
75
|
+
app.get('/api/mcp', async (_req, res) => {
|
|
76
|
+
try {
|
|
77
|
+
const discovery = await discoverWithDiagnostics(config.mcpServers);
|
|
78
|
+
res.json({
|
|
79
|
+
servers: Object.keys(discovery.servers),
|
|
80
|
+
sources: Object.fromEntries(discovery.sources),
|
|
81
|
+
diagnostics: discovery.diagnostics,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
res.status(500).json({ error: String(err) });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// UI config (for React frontend)
|
|
89
|
+
app.get('/api/config', (_req, res) => {
|
|
90
|
+
res.json(config.ui);
|
|
91
|
+
});
|
|
92
|
+
// -------------------------------------------------------------------------
|
|
93
|
+
// RPC routes ā expose SDK controls for the UI
|
|
94
|
+
// -------------------------------------------------------------------------
|
|
95
|
+
// List available models
|
|
96
|
+
app.get('/api/models', async (_req, res) => {
|
|
97
|
+
try {
|
|
98
|
+
const models = await client.listModels();
|
|
99
|
+
res.json({ models });
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
res.status(500).json({ error: String(err) });
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
// Switch model for a session
|
|
106
|
+
app.post('/api/session/:sessionId/model', async (req, res) => {
|
|
107
|
+
const sessionId = validateSessionId(req, res);
|
|
108
|
+
if (!sessionId)
|
|
109
|
+
return;
|
|
110
|
+
const { model } = req.body;
|
|
111
|
+
if (!model || typeof model !== 'string') {
|
|
112
|
+
res.status(400).json({ error: 'model is required' });
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
await client.switchModel(sessionId, model);
|
|
117
|
+
res.json({ ok: true, model });
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
121
|
+
const status = msg.includes('No session found') ? 404 : 500;
|
|
122
|
+
res.status(status).json({ error: msg });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
// Get current mode for a session
|
|
126
|
+
app.get('/api/session/:sessionId/mode', async (req, res) => {
|
|
127
|
+
const sessionId = validateSessionId(req, res);
|
|
128
|
+
if (!sessionId)
|
|
129
|
+
return;
|
|
130
|
+
try {
|
|
131
|
+
const mode = await client.getMode(sessionId);
|
|
132
|
+
res.json({ mode });
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
136
|
+
const status = msg.includes('No session found') ? 404 : 500;
|
|
137
|
+
res.status(status).json({ error: msg });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
// Set mode for a session
|
|
141
|
+
app.post('/api/session/:sessionId/mode', async (req, res) => {
|
|
142
|
+
const sessionId = validateSessionId(req, res);
|
|
143
|
+
if (!sessionId)
|
|
144
|
+
return;
|
|
145
|
+
const { mode } = req.body;
|
|
146
|
+
if (!mode || typeof mode !== 'string') {
|
|
147
|
+
res.status(400).json({ error: 'mode is required' });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const allowedModes = ['interactive', 'plan', 'autopilot'];
|
|
151
|
+
if (!allowedModes.includes(mode)) {
|
|
152
|
+
res.status(400).json({ error: 'invalid mode', allowedModes });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
await client.setMode(sessionId, mode);
|
|
157
|
+
res.json({ ok: true, mode });
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
161
|
+
const status = msg.includes('No session found') ? 404 : 500;
|
|
162
|
+
res.status(status).json({ error: msg });
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
// Get account quota
|
|
166
|
+
app.get('/api/quota', async (_req, res) => {
|
|
167
|
+
try {
|
|
168
|
+
const quota = await client.getQuota();
|
|
169
|
+
res.json(quota ?? {});
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
res.status(500).json({ error: String(err) });
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
// Chat SSE endpoint
|
|
176
|
+
app.post('/api/chat', async (req, res) => {
|
|
177
|
+
const { message, sessionId } = req.body;
|
|
178
|
+
// Input validation
|
|
179
|
+
if (!message || typeof message !== 'string' || message.trim().length === 0) {
|
|
180
|
+
res.status(400).json({ error: 'message is required' });
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (message.length > MAX_MESSAGE_LENGTH) {
|
|
184
|
+
res.status(400).json({ error: `Message too long (max ${MAX_MESSAGE_LENGTH} characters)` });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (sessionId !== undefined && typeof sessionId !== 'string') {
|
|
188
|
+
res.status(400).json({ error: 'sessionId must be a string' });
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (sessionId !== undefined && !SESSION_ID_PATTERN.test(sessionId)) {
|
|
192
|
+
res.status(400).json({ error: 'Invalid session ID format' });
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
// SSE headers
|
|
196
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
197
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
198
|
+
res.setHeader('Connection', 'keep-alive');
|
|
199
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
200
|
+
res.flushHeaders();
|
|
201
|
+
// Disable Nagle's algorithm for immediate delivery
|
|
202
|
+
if (res.socket) {
|
|
203
|
+
res.socket.setNoDelay(true);
|
|
204
|
+
}
|
|
205
|
+
// SSE send helper
|
|
206
|
+
const send = (event, data) => {
|
|
207
|
+
if (closed)
|
|
208
|
+
return;
|
|
209
|
+
res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
|
|
210
|
+
};
|
|
211
|
+
// Request timeout: must exceed SDK's 300s so SDK error fires first
|
|
212
|
+
const DEFAULT_TIMEOUT = 330_000;
|
|
213
|
+
const parsed = parseInt(process.env.REQUEST_TIMEOUT ?? '', 10);
|
|
214
|
+
const REQUEST_TIMEOUT = Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_TIMEOUT;
|
|
215
|
+
const timeout = setTimeout(() => {
|
|
216
|
+
if (!closed) {
|
|
217
|
+
send('error', { message: 'Request timeout exceeded' });
|
|
218
|
+
res.end();
|
|
219
|
+
}
|
|
220
|
+
}, REQUEST_TIMEOUT);
|
|
221
|
+
// Keepalive pings to prevent browser/proxy timeout
|
|
222
|
+
const keepalive = setInterval(() => {
|
|
223
|
+
if (!closed) {
|
|
224
|
+
res.write(`: keepalive\n\n`);
|
|
225
|
+
}
|
|
226
|
+
}, 5000);
|
|
227
|
+
// Track client disconnection ā registered after timers to avoid TDZ
|
|
228
|
+
let closed = false;
|
|
229
|
+
res.on('close', () => {
|
|
230
|
+
closed = true;
|
|
231
|
+
clearInterval(keepalive);
|
|
232
|
+
clearTimeout(timeout);
|
|
233
|
+
});
|
|
234
|
+
// Send initial heartbeat
|
|
235
|
+
send('heartbeat', { status: 'connected' });
|
|
236
|
+
try {
|
|
237
|
+
const resultSessionId = await client.sendMessage(sessionId, message.trim(), {
|
|
238
|
+
onDelta: (content) => send('delta', { content }),
|
|
239
|
+
onReasoningDelta: (content, reasoningId) => send('reasoning_delta', { content, reasoningId }),
|
|
240
|
+
onReasoning: (content, reasoningId) => send('reasoning', { content, reasoningId }),
|
|
241
|
+
onUsage: (usage) => send('usage', usage),
|
|
242
|
+
onTurnStart: (turnId) => send('turn_start', { turnId }),
|
|
243
|
+
onTurnEnd: (turnId) => send('turn_end', { turnId }),
|
|
244
|
+
onIntent: (intent) => send('intent', { intent }),
|
|
245
|
+
onToolStart: (tool) => send('tool_start', tool),
|
|
246
|
+
onToolComplete: (toolCallId, toolName, result) => send('tool_complete', { toolCallId, toolName, result }),
|
|
247
|
+
onToolProgress: (toolCallId, message) => send('tool_progress', { toolCallId, message }),
|
|
248
|
+
onSkillInvoked: (name, pluginName) => send('skill_invoked', { name, pluginName }),
|
|
249
|
+
onSubagentStarted: (toolCallId, name, displayName) => send('subagent_started', { toolCallId, name, displayName }),
|
|
250
|
+
onSubagentCompleted: (toolCallId, name) => send('subagent_completed', { toolCallId, name }),
|
|
251
|
+
onSubagentFailed: (toolCallId, name, error) => send('subagent_failed', { toolCallId, name, error }),
|
|
252
|
+
onError: (message) => send('error', { message }),
|
|
253
|
+
onInfo: (infoType, message) => send('info', { infoType, message }),
|
|
254
|
+
onWarning: (warningType, message) => send('warning', { warningType, message }),
|
|
255
|
+
onModelChange: (model) => send('model_change', { model }),
|
|
256
|
+
onTitleChanged: (title) => send('title_changed', { title }),
|
|
257
|
+
onModeChanged: (mode) => send('mode_changed', { mode }),
|
|
258
|
+
onTruncation: (data) => send('truncation', data),
|
|
259
|
+
onCompactionStart: () => send('compaction_start', {}),
|
|
260
|
+
onCompactionComplete: () => send('compaction_complete', {}),
|
|
261
|
+
});
|
|
262
|
+
if (!closed) {
|
|
263
|
+
send('done', { sessionId: resultSessionId });
|
|
264
|
+
res.end();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
269
|
+
if (!closed) {
|
|
270
|
+
send('error', { message: errMsg });
|
|
271
|
+
res.end();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
clearInterval(keepalive);
|
|
276
|
+
clearTimeout(timeout);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
// Serve static React frontend if staticDir provided
|
|
280
|
+
if (options.staticDir) {
|
|
281
|
+
app.use(express.static(resolve(options.staticDir)));
|
|
282
|
+
// SPA fallback ā serve index.html for all non-API routes
|
|
283
|
+
app.get('*', (_req, res) => {
|
|
284
|
+
res.sendFile(resolve(options.staticDir, 'index.html'));
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
return { app, client, config };
|
|
288
|
+
}
|
|
289
|
+
/** Start the server and listen on the configured port. */
|
|
290
|
+
export async function startServer(options = {}) {
|
|
291
|
+
// Initialize OTel before constructing app/client so the tracer provider
|
|
292
|
+
// is registered before any trace.getTracer() calls
|
|
293
|
+
const preConfig = resolveConfig(options.config ?? {});
|
|
294
|
+
await initTelemetry(preConfig.telemetry);
|
|
295
|
+
const { app, client, config } = createServer(options);
|
|
296
|
+
const port = config.server.port;
|
|
297
|
+
// Log MCP discovery
|
|
298
|
+
const discovery = await discoverWithDiagnostics(config.mcpServers);
|
|
299
|
+
for (const line of discovery.diagnostics) {
|
|
300
|
+
console.log(line);
|
|
301
|
+
}
|
|
302
|
+
const server = app.listen(port, () => {
|
|
303
|
+
console.log(`\nš¦ Wingman running at http://localhost:${port}\n`);
|
|
304
|
+
});
|
|
305
|
+
// Graceful shutdown
|
|
306
|
+
const shutdown = async () => {
|
|
307
|
+
console.log('\nShutting down...');
|
|
308
|
+
server.close();
|
|
309
|
+
await client.stop();
|
|
310
|
+
await shutdownTelemetry();
|
|
311
|
+
process.exit(0);
|
|
312
|
+
};
|
|
313
|
+
process.on('SIGINT', shutdown);
|
|
314
|
+
process.on('SIGTERM', shutdown);
|
|
315
|
+
return { server, app, client, config };
|
|
316
|
+
}
|
|
317
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|