@portel/photon 1.29.0 → 1.31.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 +41 -11
- package/dist/asset-resolver.d.ts +44 -0
- package/dist/asset-resolver.d.ts.map +1 -0
- package/dist/asset-resolver.js +105 -0
- package/dist/asset-resolver.js.map +1 -0
- package/dist/auto-ui/beam/external-mcp-manager.d.ts +73 -0
- package/dist/auto-ui/beam/external-mcp-manager.d.ts.map +1 -0
- package/dist/auto-ui/beam/external-mcp-manager.js +65 -0
- package/dist/auto-ui/beam/external-mcp-manager.js.map +1 -0
- package/dist/auto-ui/beam/external-mcp.d.ts.map +1 -1
- package/dist/auto-ui/beam/external-mcp.js +25 -1
- package/dist/auto-ui/beam/external-mcp.js.map +1 -1
- package/dist/auto-ui/beam/photon-management.d.ts.map +1 -1
- package/dist/auto-ui/beam/photon-management.js +11 -8
- package/dist/auto-ui/beam/photon-management.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-browse.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-browse.js +7 -4
- package/dist/auto-ui/beam/routes/api-browse.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.js +3 -2
- package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.js +6 -2
- package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
- package/dist/auto-ui/beam/startup.js.map +1 -1
- package/dist/auto-ui/beam/types.d.ts +5 -2
- package/dist/auto-ui/beam/types.d.ts.map +1 -1
- package/dist/auto-ui/beam.d.ts.map +1 -1
- package/dist/auto-ui/beam.js +162 -45
- package/dist/auto-ui/beam.js.map +1 -1
- package/dist/auto-ui/bridge/index.d.ts.map +1 -1
- package/dist/auto-ui/bridge/index.js +11 -0
- package/dist/auto-ui/bridge/index.js.map +1 -1
- package/dist/auto-ui/bridge/types.d.ts +2 -0
- package/dist/auto-ui/bridge/types.d.ts.map +1 -1
- package/dist/auto-ui/openapi-generator.js +1 -4
- package/dist/auto-ui/openapi-generator.js.map +1 -1
- package/dist/auto-ui/photon-bridge.d.ts +4 -0
- package/dist/auto-ui/photon-bridge.d.ts.map +1 -1
- package/dist/auto-ui/photon-bridge.js.map +1 -1
- package/dist/auto-ui/photon-host.js.map +1 -1
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +24 -14
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/auto-ui/types.d.ts +15 -1
- package/dist/auto-ui/types.d.ts.map +1 -1
- package/dist/auto-ui/types.js.map +1 -1
- package/dist/beam.bundle.js +170 -22
- package/dist/beam.bundle.js.map +3 -3
- package/dist/capability-negotiator.d.ts +39 -1
- package/dist/capability-negotiator.d.ts.map +1 -1
- package/dist/capability-negotiator.js +5 -0
- package/dist/capability-negotiator.js.map +1 -1
- package/dist/cf-bindings-parser.d.ts +15 -0
- package/dist/cf-bindings-parser.d.ts.map +1 -0
- package/dist/cf-bindings-parser.js +98 -0
- package/dist/cf-bindings-parser.js.map +1 -0
- package/dist/cf-usage-scanner.d.ts +76 -0
- package/dist/cf-usage-scanner.d.ts.map +1 -0
- package/dist/cf-usage-scanner.js +179 -0
- package/dist/cf-usage-scanner.js.map +1 -0
- package/dist/cli/commands/build.js +1 -1
- package/dist/cli/commands/cf.d.ts +18 -0
- package/dist/cli/commands/cf.d.ts.map +1 -0
- package/dist/cli/commands/cf.js +207 -0
- package/dist/cli/commands/cf.js.map +1 -0
- package/dist/cli/commands/info.js +1 -1
- package/dist/cli/commands/info.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +59 -46
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +3 -0
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +43 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +40 -33
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/manager.d.ts +6 -2
- package/dist/daemon/manager.d.ts.map +1 -1
- package/dist/daemon/manager.js +30 -9
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/server.js +34 -13
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/worker-host.js.map +1 -1
- package/dist/deploy/cloudflare.d.ts +27 -0
- package/dist/deploy/cloudflare.d.ts.map +1 -1
- package/dist/deploy/cloudflare.js +129 -2
- package/dist/deploy/cloudflare.js.map +1 -1
- package/dist/embedded-runtime.js.map +1 -1
- package/dist/loader.d.ts +43 -66
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +185 -305
- package/dist/loader.js.map +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +20 -11
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/resource-server.d.ts +3 -3
- package/dist/resource-server.d.ts.map +1 -1
- package/dist/resource-server.js.map +1 -1
- package/dist/runtime/cf-local.d.ts +157 -0
- package/dist/runtime/cf-local.d.ts.map +1 -0
- package/dist/runtime/cf-local.js +406 -0
- package/dist/runtime/cf-local.js.map +1 -0
- package/dist/server.d.ts +42 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +166 -14
- package/dist/server.js.map +1 -1
- package/dist/settings-persistence.d.ts +50 -0
- package/dist/settings-persistence.d.ts.map +1 -0
- package/dist/settings-persistence.js +188 -0
- package/dist/settings-persistence.js.map +1 -0
- package/dist/shared/audit-sqlite.d.ts.map +1 -1
- package/dist/shared/audit-sqlite.js +0 -1
- package/dist/shared/audit-sqlite.js.map +1 -1
- package/dist/shared/error-handler.d.ts.map +1 -1
- package/dist/shared/error-handler.js +3 -1
- package/dist/shared/error-handler.js.map +1 -1
- package/dist/shared/io.d.ts.map +1 -1
- package/dist/shared/io.js +5 -2
- package/dist/shared/io.js.map +1 -1
- package/dist/shared/logger.js.map +1 -1
- package/dist/shared/sqlite-runtime.d.ts.map +1 -1
- package/dist/shared/sqlite-runtime.js +0 -1
- package/dist/shared/sqlite-runtime.js.map +1 -1
- package/dist/task-executor.js.map +1 -1
- package/dist/telemetry/sdk.d.ts.map +1 -1
- package/dist/telemetry/sdk.js +0 -1
- package/dist/telemetry/sdk.js.map +1 -1
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js.map +1 -1
- package/dist/types/server-types.d.ts +16 -8
- package/dist/types/server-types.d.ts.map +1 -1
- package/package.json +11 -4
- package/templates/cloudflare/worker.ts.template +338 -11
- package/templates/cloudflare/wrangler.toml.template +1 -6
- package/templates/photon.template.ts +13 -0
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AA2BnE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG5E,OAAO,EAAgB,MAAM,EAAE,aAAa,EAAY,MAAM,oBAAoB,CAAC;AAanF,OAAO,EAGL,KAAK,yBAAyB,EAC/B,MAAM,sBAAsB,CAAC;AAkB9B,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,KAAK,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -82,6 +82,17 @@ function uiSiblingMime(ext) {
|
|
|
82
82
|
return 'application/octet-stream';
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
+
function findFreePort(preferred = 0) {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const srv = createServer();
|
|
88
|
+
srv.listen(preferred, () => {
|
|
89
|
+
const addr = srv.address();
|
|
90
|
+
const port = typeof addr === 'object' && addr ? addr.port : preferred;
|
|
91
|
+
srv.close((err) => (err ? reject(err) : resolve(port)));
|
|
92
|
+
});
|
|
93
|
+
srv.on('error', reject);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
85
96
|
class BeamCompatTransport {
|
|
86
97
|
photonName;
|
|
87
98
|
photonMeta;
|
|
@@ -143,14 +154,16 @@ class BeamCompatTransport {
|
|
|
143
154
|
message.result.tools.push(...subTools);
|
|
144
155
|
}
|
|
145
156
|
}
|
|
146
|
-
//
|
|
147
|
-
|
|
157
|
+
// JSON-RPC notifications have no 'id' — route to SSE only, never to pendingResponse.
|
|
158
|
+
// Responses have 'id' + 'result'/'error'. Server-initiated requests have 'id' + 'method'.
|
|
159
|
+
const isResponse = message.id !== undefined && message.id !== null && !message.method;
|
|
160
|
+
if (isResponse && this.pendingResponse) {
|
|
148
161
|
const resolve = this.pendingResponse;
|
|
149
162
|
this.pendingResponse = null;
|
|
150
163
|
resolve(message);
|
|
151
164
|
return;
|
|
152
165
|
}
|
|
153
|
-
//
|
|
166
|
+
// Notifications and server-initiated requests go to the SSE stream
|
|
154
167
|
if (this.sseResponse && !this.sseResponse.writableEnded) {
|
|
155
168
|
const id = message.id ?? crypto.randomUUID();
|
|
156
169
|
this.sseResponse.write(`event: message\nid: ${id}\ndata: ${JSON.stringify(message)}\n\n`);
|
|
@@ -185,11 +198,17 @@ class BeamCompatTransport {
|
|
|
185
198
|
}, 15000);
|
|
186
199
|
req.on('close', () => {
|
|
187
200
|
clearInterval(keepalive);
|
|
188
|
-
this
|
|
201
|
+
// Only clear if this response is still the active SSE stream.
|
|
202
|
+
// A newer GET may have already replaced it — don't overwrite that.
|
|
203
|
+
if (this.sseResponse === res) {
|
|
204
|
+
this.sseResponse = null;
|
|
205
|
+
}
|
|
189
206
|
});
|
|
190
207
|
res.on('error', () => {
|
|
191
208
|
clearInterval(keepalive);
|
|
192
|
-
this.sseResponse
|
|
209
|
+
if (this.sseResponse === res) {
|
|
210
|
+
this.sseResponse = null;
|
|
211
|
+
}
|
|
193
212
|
});
|
|
194
213
|
return;
|
|
195
214
|
}
|
|
@@ -540,7 +559,7 @@ export class PhotonServer {
|
|
|
540
559
|
queueNotification(notification) {
|
|
541
560
|
this._notifyQueue = this._notifyQueue
|
|
542
561
|
.then(() => this.server?.notification(notification))
|
|
543
|
-
.catch(() => { });
|
|
562
|
+
.catch((err) => this.logger.debug('Failed to send notification', { error: getErrorMessage(err) }));
|
|
544
563
|
}
|
|
545
564
|
/**
|
|
546
565
|
* Create an MCP-aware input provider for generator ask yields
|
|
@@ -1212,6 +1231,12 @@ export class PhotonServer {
|
|
|
1212
1231
|
const uiMeta = this.resourceServer.buildUIToolMeta(this.mcp.name, linkedUI.id);
|
|
1213
1232
|
response._meta = { ...response._meta, ...uiMeta };
|
|
1214
1233
|
}
|
|
1234
|
+
// For SSE/Streamable-HTTP transports: flush the notification queue before
|
|
1235
|
+
// returning so that progress/status notifications are delivered via the GET
|
|
1236
|
+
// SSE stream BEFORE the HTTP POST response body is written. Without this, the
|
|
1237
|
+
// client receives the tool result, deletes its _progressHandlers entry, and then
|
|
1238
|
+
// silently drops any notifications that arrive later on the SSE stream.
|
|
1239
|
+
await this._notifyQueue;
|
|
1215
1240
|
return response;
|
|
1216
1241
|
}
|
|
1217
1242
|
handleListPrompts() {
|
|
@@ -1885,13 +1910,36 @@ export class PhotonServer {
|
|
|
1885
1910
|
// In channel mode, ChannelManager intercepts 'channel-push' events
|
|
1886
1911
|
// and translates them to notifications/claude/channel for the connected client.
|
|
1887
1912
|
await this.channelManager.subscribeToChannels();
|
|
1888
|
-
//
|
|
1913
|
+
// Announce web capability when the photon has @get / defined.
|
|
1914
|
+
// HTTP mode: the existing HTTP server already handles web routes at their
|
|
1915
|
+
// declared paths, so we expose the server's own base URL.
|
|
1916
|
+
// STDIO stateful: we spin up a companion HTTP server to host those routes
|
|
1917
|
+
// and expose its URL. Stateless photons cannot have a companion server.
|
|
1889
1918
|
const transport = this.options.transport || 'stdio';
|
|
1919
|
+
const photonWithMeta = this.mcp;
|
|
1920
|
+
const webRootRoute = photonWithMeta?._httpRoutes?.find((r) => r.method === 'GET' && r.path === '/');
|
|
1890
1921
|
if (transport === 'sse') {
|
|
1922
|
+
if (webRootRoute) {
|
|
1923
|
+
const httpPort = Number(this.options.port) || 3000;
|
|
1924
|
+
const webDescription = photonWithMeta?.description || `${photonWithMeta?.name} web interface`;
|
|
1925
|
+
this.server.registerCapabilities({
|
|
1926
|
+
web: { url: `http://localhost:${httpPort}`, description: webDescription },
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1891
1929
|
await this.startSSE();
|
|
1892
1930
|
}
|
|
1893
1931
|
else {
|
|
1894
|
-
|
|
1932
|
+
if (webRootRoute && photonStateful) {
|
|
1933
|
+
const webPort = await findFreePort(Number(this.options.port) || 0);
|
|
1934
|
+
const webDescription = photonWithMeta?.description || `${photonWithMeta?.name} web interface`;
|
|
1935
|
+
this.server.registerCapabilities({
|
|
1936
|
+
web: { url: `http://localhost:${webPort}`, description: webDescription },
|
|
1937
|
+
});
|
|
1938
|
+
await this.startStdio(webPort);
|
|
1939
|
+
}
|
|
1940
|
+
else {
|
|
1941
|
+
await this.startStdio();
|
|
1942
|
+
}
|
|
1895
1943
|
}
|
|
1896
1944
|
// In dev mode, we could set up file watching here
|
|
1897
1945
|
if (this.options.devMode) {
|
|
@@ -1907,22 +1955,116 @@ export class PhotonServer {
|
|
|
1907
1955
|
}
|
|
1908
1956
|
}
|
|
1909
1957
|
/**
|
|
1910
|
-
* Start server with stdio transport
|
|
1958
|
+
* Start server with stdio transport.
|
|
1959
|
+
* @param webPort - when set, start a companion HTTP server on this port
|
|
1960
|
+
* to serve @get/@post web routes for stateful photons.
|
|
1911
1961
|
*/
|
|
1912
|
-
async startStdio() {
|
|
1962
|
+
async startStdio(webPort) {
|
|
1913
1963
|
const transport = new StdioServerTransport();
|
|
1914
1964
|
// Wrap transport.send with a write mutex to prevent concurrent generators
|
|
1915
1965
|
// from interleaving JSON-RPC messages on stdout
|
|
1916
1966
|
const originalSend = transport.send.bind(transport);
|
|
1917
1967
|
let writeChain = Promise.resolve();
|
|
1918
1968
|
transport.send = (message) => {
|
|
1919
|
-
const p = writeChain
|
|
1969
|
+
const p = writeChain
|
|
1970
|
+
.then(() => originalSend(message))
|
|
1971
|
+
.catch((err) => this.logger.debug('STDIO send failed', { error: getErrorMessage(err) }));
|
|
1920
1972
|
writeChain = p;
|
|
1921
1973
|
return p;
|
|
1922
1974
|
};
|
|
1923
1975
|
this.capabilityNegotiator.interceptTransportForRawCapabilities(transport, this.server, (msg) => this.channelManager.interceptPermissionRequest(msg));
|
|
1924
1976
|
await this.server.connect(transport);
|
|
1925
1977
|
this.log('info', `Server started: ${this.mcp.name}`);
|
|
1978
|
+
if (webPort) {
|
|
1979
|
+
const webServer = createServer((req, res) => {
|
|
1980
|
+
void this.handleWebRoute(req, res);
|
|
1981
|
+
});
|
|
1982
|
+
await new Promise((resolve, reject) => {
|
|
1983
|
+
webServer.listen(webPort, () => resolve());
|
|
1984
|
+
webServer.on('error', reject);
|
|
1985
|
+
});
|
|
1986
|
+
this.log('info', `Web UI: http://localhost:${webPort}`);
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
/**
|
|
1990
|
+
* Dispatch an incoming HTTP request to the photon's @get/@post web routes.
|
|
1991
|
+
* Used by the companion HTTP server that runs alongside STDIO stateful photons.
|
|
1992
|
+
*/
|
|
1993
|
+
async handleWebRoute(req, res) {
|
|
1994
|
+
setSecurityHeaders(res);
|
|
1995
|
+
if (!req.url) {
|
|
1996
|
+
res.writeHead(400).end('Missing URL');
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
const url = new URL(req.url, `http://${req.headers.host || 'localhost'}`);
|
|
2000
|
+
const corsOrigin = getCorsOrigin(req);
|
|
2001
|
+
if (req.method === 'OPTIONS') {
|
|
2002
|
+
const preflightHeaders = {
|
|
2003
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
2004
|
+
'Access-Control-Allow-Headers': 'Content-Type, Accept',
|
|
2005
|
+
};
|
|
2006
|
+
if (corsOrigin)
|
|
2007
|
+
preflightHeaders['Access-Control-Allow-Origin'] = corsOrigin;
|
|
2008
|
+
res.writeHead(204, preflightHeaders).end();
|
|
2009
|
+
return;
|
|
2010
|
+
}
|
|
2011
|
+
const httpRoutes = this.mcp?._httpRoutes;
|
|
2012
|
+
if (httpRoutes?.length && req.method) {
|
|
2013
|
+
const route = httpRoutes.find((r) => r.method === req.method && r.path === url.pathname);
|
|
2014
|
+
if (route) {
|
|
2015
|
+
const targetMcp = await this.resolveInstanceMcp(undefined);
|
|
2016
|
+
const photonInstance = targetMcp?.instance;
|
|
2017
|
+
const fn = photonInstance?.[route.handler];
|
|
2018
|
+
if (typeof fn === 'function') {
|
|
2019
|
+
try {
|
|
2020
|
+
let bodyBuffer = Buffer.alloc(0);
|
|
2021
|
+
await new Promise((resolve) => {
|
|
2022
|
+
req.on('data', (chunk) => {
|
|
2023
|
+
bodyBuffer = Buffer.concat([bodyBuffer, chunk]);
|
|
2024
|
+
});
|
|
2025
|
+
req.on('end', resolve);
|
|
2026
|
+
});
|
|
2027
|
+
const webReq = new Request(url.toString(), {
|
|
2028
|
+
method: req.method,
|
|
2029
|
+
headers: req.headers,
|
|
2030
|
+
...(req.method !== 'GET' && bodyBuffer.length > 0 ? { body: bodyBuffer } : {}),
|
|
2031
|
+
});
|
|
2032
|
+
const result = await fn.call(photonInstance, webReq);
|
|
2033
|
+
if (result instanceof Response) {
|
|
2034
|
+
const responseHeaders = {};
|
|
2035
|
+
result.headers.forEach((value, key) => {
|
|
2036
|
+
responseHeaders[key] = value;
|
|
2037
|
+
});
|
|
2038
|
+
if (corsOrigin)
|
|
2039
|
+
responseHeaders['Access-Control-Allow-Origin'] = corsOrigin;
|
|
2040
|
+
res.writeHead(result.status, responseHeaders);
|
|
2041
|
+
res.end(Buffer.from(await result.arrayBuffer()));
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
const { negotiateAccept } = await import('./format/registry.js');
|
|
2045
|
+
const { getDefaultRegistry } = await import('./format/seed.js');
|
|
2046
|
+
const acceptHeader = req.headers['accept'];
|
|
2047
|
+
const rendered = negotiateAccept({
|
|
2048
|
+
accept: typeof acceptHeader === 'string' ? acceptHeader : undefined,
|
|
2049
|
+
declaredFormat: route.format,
|
|
2050
|
+
value: result,
|
|
2051
|
+
registry: getDefaultRegistry(),
|
|
2052
|
+
});
|
|
2053
|
+
const negotiatedHeaders = { 'Content-Type': rendered.mime };
|
|
2054
|
+
if (corsOrigin)
|
|
2055
|
+
negotiatedHeaders['Access-Control-Allow-Origin'] = corsOrigin;
|
|
2056
|
+
res.writeHead(200, negotiatedHeaders);
|
|
2057
|
+
res.end(typeof rendered.body === 'string' ? rendered.body : Buffer.from(rendered.body));
|
|
2058
|
+
return;
|
|
2059
|
+
}
|
|
2060
|
+
catch (err) {
|
|
2061
|
+
res.writeHead(500).end(err?.message ?? 'Internal Server Error');
|
|
2062
|
+
return;
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
res.writeHead(404).end('Not Found');
|
|
1926
2068
|
}
|
|
1927
2069
|
/**
|
|
1928
2070
|
* Start server with SSE transport (HTTP)
|
|
@@ -1956,6 +2098,9 @@ export class PhotonServer {
|
|
|
1956
2098
|
continue;
|
|
1957
2099
|
const icon = loaded.icon || '⚡';
|
|
1958
2100
|
const stateful = !!loaded.stateful;
|
|
2101
|
+
// ^^ getLoadedPhotons() returns the canonical PhotonClassExtended type;
|
|
2102
|
+
// these two callsites still need the narrower runtime cast until
|
|
2103
|
+
// the loader's return type widens to PhotonClassWithMeta.
|
|
1959
2104
|
const hasSettings = !!loaded.settingsSchema?.hasSettings;
|
|
1960
2105
|
// Convert PhotonTool[] to MCP tool format with UI linking
|
|
1961
2106
|
const uiAssets = loaded.assets?.ui || [];
|
|
@@ -2408,9 +2553,7 @@ export class PhotonServer {
|
|
|
2408
2553
|
if (req.method === 'GET' && url.pathname === '/api/diagnostics') {
|
|
2409
2554
|
const { PHOTON_VERSION } = await import('./version.js');
|
|
2410
2555
|
const photonName = this.mcp?.name || 'photon';
|
|
2411
|
-
const tools = this.mcp
|
|
2412
|
-
? Object.keys(this.mcp._toolSchemas || {}).length
|
|
2413
|
-
: 0;
|
|
2556
|
+
const tools = this.mcp ? Object.keys(this.mcp._toolSchemas || {}).length : 0;
|
|
2414
2557
|
const diagHeaders = { 'Content-Type': 'application/json' };
|
|
2415
2558
|
if (corsOrigin)
|
|
2416
2559
|
diagHeaders['Access-Control-Allow-Origin'] = corsOrigin;
|
|
@@ -2729,6 +2872,15 @@ export class PhotonServer {
|
|
|
2729
2872
|
method: 'notifications/resources/updated',
|
|
2730
2873
|
params: { uri },
|
|
2731
2874
|
});
|
|
2875
|
+
// Mirror web capability onto the per-session server when the photon has web routes.
|
|
2876
|
+
const sessionWebMeta = this.mcp?._httpRoutes?.find((r) => r.method === 'GET' && r.path === '/');
|
|
2877
|
+
if (sessionWebMeta) {
|
|
2878
|
+
const httpPort = Number(this.options.port) || 3000;
|
|
2879
|
+
const webDescription = this.mcp?.description || `${this.mcp?.name} web interface`;
|
|
2880
|
+
sessionServer.registerCapabilities({
|
|
2881
|
+
web: { url: `http://localhost:${httpPort}`, description: webDescription },
|
|
2882
|
+
});
|
|
2883
|
+
}
|
|
2732
2884
|
// Copy handlers to the session server
|
|
2733
2885
|
this.setupSessionHandlers(sessionServer, sessionSink);
|
|
2734
2886
|
// Create SSE transport
|