@portel/photon 1.18.0 → 1.19.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.
Files changed (172) hide show
  1. package/dist/auto-ui/beam.d.ts.map +1 -1
  2. package/dist/auto-ui/beam.js +14 -4
  3. package/dist/auto-ui/beam.js.map +1 -1
  4. package/dist/beam-form.bundle.js +5 -3
  5. package/dist/beam-form.bundle.js.map +2 -2
  6. package/dist/beam.bundle.js +686 -30
  7. package/dist/beam.bundle.js.map +3 -3
  8. package/dist/claude-code-plugin.js +1 -1
  9. package/dist/cli/commands/beam.d.ts.map +1 -1
  10. package/dist/cli/commands/beam.js +8 -2
  11. package/dist/cli/commands/beam.js.map +1 -1
  12. package/dist/cli/commands/changelog.d.ts +9 -0
  13. package/dist/cli/commands/changelog.d.ts.map +1 -0
  14. package/dist/cli/commands/changelog.js +133 -0
  15. package/dist/cli/commands/changelog.js.map +1 -0
  16. package/dist/cli/commands/maker.d.ts.map +1 -1
  17. package/dist/cli/commands/maker.js +23 -2
  18. package/dist/cli/commands/maker.js.map +1 -1
  19. package/dist/cli/commands/mcp.d.ts.map +1 -1
  20. package/dist/cli/commands/mcp.js +53 -0
  21. package/dist/cli/commands/mcp.js.map +1 -1
  22. package/dist/cli/commands/package.d.ts.map +1 -1
  23. package/dist/cli/commands/package.js +18 -2
  24. package/dist/cli/commands/package.js.map +1 -1
  25. package/dist/cli/commands/run.d.ts.map +1 -1
  26. package/dist/cli/commands/run.js +1 -0
  27. package/dist/cli/commands/run.js.map +1 -1
  28. package/dist/cli/commands/update.d.ts +3 -2
  29. package/dist/cli/commands/update.d.ts.map +1 -1
  30. package/dist/cli/commands/update.js +50 -43
  31. package/dist/cli/commands/update.js.map +1 -1
  32. package/dist/cli/index.d.ts.map +1 -1
  33. package/dist/cli/index.js +16 -2
  34. package/dist/cli/index.js.map +1 -1
  35. package/dist/cli-alias.js +1 -1
  36. package/dist/cli-alias.js.map +1 -1
  37. package/dist/context-store.d.ts +23 -33
  38. package/dist/context-store.d.ts.map +1 -1
  39. package/dist/context-store.js +147 -97
  40. package/dist/context-store.js.map +1 -1
  41. package/dist/context.d.ts +15 -10
  42. package/dist/context.d.ts.map +1 -1
  43. package/dist/context.js +37 -13
  44. package/dist/context.js.map +1 -1
  45. package/dist/daemon/server.js +4 -2
  46. package/dist/daemon/server.js.map +1 -1
  47. package/dist/data-migration.d.ts +27 -0
  48. package/dist/data-migration.d.ts.map +1 -0
  49. package/dist/data-migration.js +307 -0
  50. package/dist/data-migration.js.map +1 -0
  51. package/dist/editor-support/docblock-tag-catalog.d.ts.map +1 -1
  52. package/dist/editor-support/docblock-tag-catalog.js +6 -0
  53. package/dist/editor-support/docblock-tag-catalog.js.map +1 -1
  54. package/dist/loader.d.ts +10 -0
  55. package/dist/loader.d.ts.map +1 -1
  56. package/dist/loader.js +97 -12
  57. package/dist/loader.js.map +1 -1
  58. package/dist/marketplace-manager.d.ts.map +1 -1
  59. package/dist/marketplace-manager.js +25 -5
  60. package/dist/marketplace-manager.js.map +1 -1
  61. package/dist/photon-cli-runner.d.ts.map +1 -1
  62. package/dist/photon-cli-runner.js +47 -21
  63. package/dist/photon-cli-runner.js.map +1 -1
  64. package/dist/photon-doc-extractor.d.ts +1 -0
  65. package/dist/photon-doc-extractor.d.ts.map +1 -1
  66. package/dist/photon-doc-extractor.js +6 -0
  67. package/dist/photon-doc-extractor.js.map +1 -1
  68. package/dist/readme-syncer.d.ts.map +1 -1
  69. package/dist/readme-syncer.js +6 -1
  70. package/dist/readme-syncer.js.map +1 -1
  71. package/dist/server.d.ts +40 -0
  72. package/dist/server.d.ts.map +1 -1
  73. package/dist/server.js +143 -28
  74. package/dist/server.js.map +1 -1
  75. package/dist/shared/audit.js +4 -4
  76. package/dist/shared/audit.js.map +1 -1
  77. package/dist/tasks/store.d.ts.map +1 -1
  78. package/dist/tasks/store.js +6 -2
  79. package/dist/tasks/store.js.map +1 -1
  80. package/dist/version-notify.d.ts +27 -0
  81. package/dist/version-notify.d.ts.map +1 -0
  82. package/dist/version-notify.js +142 -0
  83. package/dist/version-notify.js.map +1 -0
  84. package/package.json +2 -2
  85. package/dist/auto-ui/bridge/openai-shim.d.ts +0 -20
  86. package/dist/auto-ui/bridge/openai-shim.d.ts.map +0 -1
  87. package/dist/auto-ui/bridge/openai-shim.js +0 -231
  88. package/dist/auto-ui/bridge/openai-shim.js.map +0 -1
  89. package/dist/auto-ui/bridge/photon-app.d.ts +0 -162
  90. package/dist/auto-ui/bridge/photon-app.d.ts.map +0 -1
  91. package/dist/auto-ui/bridge/photon-app.js +0 -460
  92. package/dist/auto-ui/bridge/photon-app.js.map +0 -1
  93. package/dist/auto-ui/daemon-tools.d.ts +0 -45
  94. package/dist/auto-ui/daemon-tools.d.ts.map +0 -1
  95. package/dist/auto-ui/daemon-tools.js +0 -581
  96. package/dist/auto-ui/daemon-tools.js.map +0 -1
  97. package/dist/auto-ui/design-system/index.d.ts +0 -21
  98. package/dist/auto-ui/design-system/index.d.ts.map +0 -1
  99. package/dist/auto-ui/design-system/index.js +0 -27
  100. package/dist/auto-ui/design-system/index.js.map +0 -1
  101. package/dist/auto-ui/design-system/transaction-ui.d.ts +0 -70
  102. package/dist/auto-ui/design-system/transaction-ui.d.ts.map +0 -1
  103. package/dist/auto-ui/design-system/transaction-ui.js +0 -982
  104. package/dist/auto-ui/design-system/transaction-ui.js.map +0 -1
  105. package/dist/auto-ui/playground-server.d.ts +0 -7
  106. package/dist/auto-ui/playground-server.d.ts.map +0 -1
  107. package/dist/auto-ui/playground-server.js +0 -840
  108. package/dist/auto-ui/playground-server.js.map +0 -1
  109. package/dist/auto-ui/rendering/components.d.ts +0 -29
  110. package/dist/auto-ui/rendering/components.d.ts.map +0 -1
  111. package/dist/auto-ui/rendering/components.js +0 -1341
  112. package/dist/auto-ui/rendering/components.js.map +0 -1
  113. package/dist/auto-ui/rendering/field-analyzer.d.ts +0 -104
  114. package/dist/auto-ui/rendering/field-analyzer.d.ts.map +0 -1
  115. package/dist/auto-ui/rendering/field-analyzer.js +0 -447
  116. package/dist/auto-ui/rendering/field-analyzer.js.map +0 -1
  117. package/dist/auto-ui/rendering/field-renderers.d.ts +0 -64
  118. package/dist/auto-ui/rendering/field-renderers.d.ts.map +0 -1
  119. package/dist/auto-ui/rendering/field-renderers.js +0 -317
  120. package/dist/auto-ui/rendering/field-renderers.js.map +0 -1
  121. package/dist/auto-ui/rendering/index.d.ts +0 -28
  122. package/dist/auto-ui/rendering/index.d.ts.map +0 -1
  123. package/dist/auto-ui/rendering/index.js +0 -60
  124. package/dist/auto-ui/rendering/index.js.map +0 -1
  125. package/dist/auto-ui/rendering/layout-selector.d.ts +0 -60
  126. package/dist/auto-ui/rendering/layout-selector.d.ts.map +0 -1
  127. package/dist/auto-ui/rendering/layout-selector.js +0 -476
  128. package/dist/auto-ui/rendering/layout-selector.js.map +0 -1
  129. package/dist/markdown-utils.d.ts +0 -8
  130. package/dist/markdown-utils.d.ts.map +0 -1
  131. package/dist/markdown-utils.js +0 -64
  132. package/dist/markdown-utils.js.map +0 -1
  133. package/dist/mcp-client.d.ts +0 -9
  134. package/dist/mcp-client.d.ts.map +0 -1
  135. package/dist/mcp-client.js +0 -11
  136. package/dist/mcp-client.js.map +0 -1
  137. package/dist/mcp-elicitation.d.ts +0 -32
  138. package/dist/mcp-elicitation.d.ts.map +0 -1
  139. package/dist/mcp-elicitation.js +0 -26
  140. package/dist/mcp-elicitation.js.map +0 -1
  141. package/dist/photons/builder-compass.photon.d.ts +0 -167
  142. package/dist/photons/builder-compass.photon.d.ts.map +0 -1
  143. package/dist/photons/builder-compass.photon.js +0 -816
  144. package/dist/photons/builder-compass.photon.js.map +0 -1
  145. package/dist/photons/builder-compass.photon.ts +0 -1129
  146. package/dist/photons/docs/ui/docs.html +0 -441
  147. package/dist/photons/docs.photon.d.ts +0 -237
  148. package/dist/photons/docs.photon.d.ts.map +0 -1
  149. package/dist/photons/docs.photon.js +0 -483
  150. package/dist/photons/docs.photon.js.map +0 -1
  151. package/dist/photons/docs.photon.ts +0 -536
  152. package/dist/photons/slides.photon.d.ts +0 -212
  153. package/dist/photons/slides.photon.d.ts.map +0 -1
  154. package/dist/photons/slides.photon.js +0 -355
  155. package/dist/photons/slides.photon.js.map +0 -1
  156. package/dist/photons/slides.photon.ts +0 -370
  157. package/dist/photons/spreadsheet/ui/spreadsheet.html +0 -779
  158. package/dist/photons/spreadsheet.photon.d.ts +0 -554
  159. package/dist/photons/spreadsheet.photon.d.ts.map +0 -1
  160. package/dist/photons/spreadsheet.photon.js +0 -1050
  161. package/dist/photons/spreadsheet.photon.js.map +0 -1
  162. package/dist/photons/spreadsheet.photon.ts +0 -1239
  163. package/dist/photons/ui/builder-compass.html +0 -1199
  164. package/dist/photons/ui/builder-compass.photon.html +0 -380
  165. package/dist/security-scanner.d.ts +0 -52
  166. package/dist/security-scanner.d.ts.map +0 -1
  167. package/dist/security-scanner.js +0 -181
  168. package/dist/security-scanner.js.map +0 -1
  169. package/dist/shared/performance.d.ts +0 -65
  170. package/dist/shared/performance.d.ts.map +0 -1
  171. package/dist/shared/performance.js +0 -136
  172. package/dist/shared/performance.js.map +0 -1
package/dist/server.js CHANGED
@@ -105,7 +105,8 @@ class BeamCompatTransport {
105
105
  }
106
106
  // Otherwise push to SSE stream if connected
107
107
  if (this.sseResponse && !this.sseResponse.writableEnded) {
108
- this.sseResponse.write(`data: ${JSON.stringify(message)}\n\n`);
108
+ const id = message.id ?? crypto.randomUUID();
109
+ this.sseResponse.write(`event: message\nid: ${id}\ndata: ${JSON.stringify(message)}\n\n`);
109
110
  }
110
111
  }
111
112
  async handleHTTP(req, res, url) {
@@ -204,7 +205,10 @@ class BeamCompatTransport {
204
205
  // Notifications have no id — fire-and-forget
205
206
  if (parsed.id === undefined) {
206
207
  this.onmessage?.(parsed, { sessionId: this.sessionId });
207
- res.writeHead(202);
208
+ res.writeHead(202, {
209
+ 'Access-Control-Allow-Origin': '*',
210
+ 'Mcp-Session-Id': this.sessionId,
211
+ });
208
212
  res.end();
209
213
  return;
210
214
  }
@@ -224,11 +228,11 @@ class BeamCompatTransport {
224
228
  }
225
229
  // DELETE — session termination (spec compliance)
226
230
  if (req.method === 'DELETE') {
227
- res.writeHead(200);
231
+ res.writeHead(200, { 'Access-Control-Allow-Origin': '*' });
228
232
  res.end();
229
233
  return;
230
234
  }
231
- res.writeHead(405);
235
+ res.writeHead(405, { 'Access-Control-Allow-Origin': '*' });
232
236
  res.end('Method not allowed');
233
237
  }
234
238
  }
@@ -309,10 +313,14 @@ export class PhotonServer {
309
313
  baseLoggerOptions.scope = this.devMode ? 'dev' : 'runtime';
310
314
  }
311
315
  this.logger = createLogger(baseLoggerOptions);
312
- this.loader = new PhotonLoader(true, this.logger.child({ component: 'photon-loader', scope: 'loader' }), options.workingDir);
316
+ const loaderVerbose = (baseLoggerOptions.level ?? 'info') !== 'warn' &&
317
+ (baseLoggerOptions.level ?? 'info') !== 'error';
318
+ this.loader = new PhotonLoader(loaderVerbose, this.logger.child({ component: 'photon-loader', scope: 'loader' }), options.workingDir);
313
319
  // Create MCP server instance
320
+ // When channelMode is set, declare claude/channel capability and use photon name as server name
321
+ const serverName = options.channelMode && options.channelName ? options.channelName : 'photon-mcp';
314
322
  this.server = new Server({
315
- name: 'photon-mcp',
323
+ name: serverName,
316
324
  version: PHOTON_VERSION,
317
325
  }, {
318
326
  capabilities: {
@@ -335,7 +343,23 @@ export class PhotonServer {
335
343
  },
336
344
  // Note: Server doesn't declare elicitation capability - that's a client capability
337
345
  // The server uses elicitInput() when the client has elicitation support
346
+ //
347
+ // Channel capabilities — declare only the protocols specified by @channel tag.
348
+ // e.g. @channel claude → { 'claude/channel': {}, 'claude/channel/permission': {} }
349
+ ...(options.channelMode && options.channelTargets?.length
350
+ ? {
351
+ experimental: Object.fromEntries(options.channelTargets.flatMap((t) => [
352
+ [`${t}/channel`, {}],
353
+ [`${t}/channel/permission`, {}],
354
+ ])),
355
+ }
356
+ : {}),
338
357
  },
358
+ ...(options.channelMode && options.channelInstructions
359
+ ? {
360
+ instructions: options.channelInstructions,
361
+ }
362
+ : {}),
339
363
  });
340
364
  // Set up protocol handlers
341
365
  this.setupHandlers();
@@ -466,6 +490,62 @@ export class PhotonServer {
466
490
  return true;
467
491
  return false;
468
492
  }
493
+ /**
494
+ * Get the channel notification method for the connected client.
495
+ * Each client uses its own notification namespace under the MCP experimental extension point.
496
+ * Returns undefined if the client is unknown or doesn't support channels.
497
+ */
498
+ /**
499
+ * Get the notification methods for all declared channel targets.
500
+ * Each target (e.g. 'claude') maps to its notification method.
501
+ */
502
+ getChannelNotificationMethods() {
503
+ const targets = this.options.channelTargets || [];
504
+ // Each target's notification method follows the pattern: notifications/{target}/channel
505
+ return targets.map((t) => `notifications/${t}/channel`);
506
+ }
507
+ /**
508
+ * Handle permission request from the client (e.g. Claude Code asking "Allow tool X?").
509
+ * Forwards to the photon instance via channel._dispatchPermission().
510
+ */
511
+ handlePermissionRequest(params) {
512
+ if (!params?.request_id || !params?.tool_name)
513
+ return;
514
+ const request = {
515
+ request_id: params.request_id,
516
+ tool_name: params.tool_name,
517
+ description: params.description || '',
518
+ input_preview: params.input_preview || '',
519
+ };
520
+ this.log('info', `Permission request: ${request.tool_name} (${request.request_id})`);
521
+ // Dispatch to the photon instance's permission handler
522
+ const instance = this.mcp;
523
+ if (instance?.channel?._dispatchPermission) {
524
+ instance.channel._dispatchPermission(request);
525
+ }
526
+ }
527
+ /**
528
+ * Send a permission response back to the client.
529
+ * Called by the photon instance (via this.channel.respond) when the user approves/denies.
530
+ */
531
+ respondToPermission(response) {
532
+ const targets = this.options.channelTargets || [];
533
+ for (const target of targets) {
534
+ const notification = {
535
+ method: `notifications/${target}/channel/permission`,
536
+ params: {
537
+ request_id: response.request_id,
538
+ behavior: response.behavior,
539
+ },
540
+ };
541
+ this.server.notification(notification).catch((e) => {
542
+ this.log('debug', 'Permission response failed', { error: getErrorMessage(e) });
543
+ });
544
+ for (const session of Array.from(this.sseSessions.values())) {
545
+ session.server.notification(notification).catch(() => { });
546
+ }
547
+ }
548
+ }
469
549
  /**
470
550
  * Log client identity and capabilities for debugging tier detection
471
551
  */
@@ -1887,6 +1967,8 @@ export class PhotonServer {
1887
1967
  const metadata = await extractor.extractFullMetadata();
1888
1968
  const isStateful = metadata.stateful;
1889
1969
  // Start daemon for stateful photons (enables cross-client communication)
1970
+ // Channel mode also uses the daemon — the singleton instance holds the
1971
+ // bot connection, and multiple MCP clients subscribe to its events
1890
1972
  if (isStateful) {
1891
1973
  const photonName = metadata.name;
1892
1974
  this.daemonName = photonName; // Store for subscription
@@ -1921,7 +2003,9 @@ export class PhotonServer {
1921
2003
  this.mcp = await this.loader.loadFile(this.options.filePath);
1922
2004
  }
1923
2005
  }
1924
- // Subscribe to daemon channels for cross-process notifications
2006
+ // Subscribe to daemon channels for cross-process notifications.
2007
+ // In channel mode, handleChannelMessage intercepts 'channel-push' events
2008
+ // and translates them to notifications/claude/channel for the connected client.
1925
2009
  await this.subscribeToChannels();
1926
2010
  // Start with the appropriate transport
1927
2011
  const transport = this.options.transport || 'stdio';
@@ -1982,6 +2066,40 @@ export class PhotonServer {
1982
2066
  if (process.env.PHOTON_DEBUG_EVENTS === '1') {
1983
2067
  console.error(`[PHOTON-SERVER] Received daemon message on ${String(msg.channel)}: event=${String(msg.event)}`);
1984
2068
  }
2069
+ // Channel permission responses — photon called this.channel.respond()
2070
+ if (this.options.channelMode && String(msg.channel).endsWith(':channel-permission-response')) {
2071
+ const data = msg.data;
2072
+ if (data?.request_id && data?.behavior) {
2073
+ this.respondToPermission({
2074
+ request_id: data.request_id,
2075
+ behavior: data.behavior,
2076
+ });
2077
+ }
2078
+ return;
2079
+ }
2080
+ // Channel events — translate to client-specific channel notifications.
2081
+ // Each declared target (e.g. 'claude') gets its own notification method.
2082
+ if (this.options.channelMode && String(msg.channel).endsWith(':channel-push')) {
2083
+ const pushData = msg.data;
2084
+ const methods = this.getChannelNotificationMethods();
2085
+ if (methods.length === 0)
2086
+ return;
2087
+ const content = typeof pushData?.content === 'string' ? pushData.content : '';
2088
+ const meta = pushData?.meta || {};
2089
+ try {
2090
+ for (const method of methods) {
2091
+ const notification = { method, params: { content, meta } };
2092
+ await this.server.notification(notification);
2093
+ for (const session of Array.from(this.sseSessions.values())) {
2094
+ await session.server.notification(notification);
2095
+ }
2096
+ }
2097
+ }
2098
+ catch (e) {
2099
+ this.log('debug', 'Channel notification failed', { error: getErrorMessage(e) });
2100
+ }
2101
+ return; // Don't also forward as a regular photon event
2102
+ }
1985
2103
  // Use STANDARD notification with embedded photon data
1986
2104
  // Claude Desktop will forward this (it's a standard notification)
1987
2105
  // Our bridge extracts _photon and routes to the appropriate event handler
@@ -2031,9 +2149,15 @@ export class PhotonServer {
2031
2149
  interceptTransportForRawCapabilities(transport, targetServer) {
2032
2150
  const origOnMessage = transport.onmessage;
2033
2151
  transport.onmessage = (message, extra) => {
2034
- // Capture raw capabilities from initialize request
2035
- if (message?.method === 'initialize' && message?.params?.capabilities) {
2036
- this.rawClientCapabilities.set(targetServer, message.params.capabilities);
2152
+ // Capture raw capabilities and client name from initialize request
2153
+ if (message?.method === 'initialize' && message?.params) {
2154
+ if (message.params.capabilities) {
2155
+ this.rawClientCapabilities.set(targetServer, message.params.capabilities);
2156
+ }
2157
+ }
2158
+ // Intercept channel permission requests from the client
2159
+ if (this.options.channelMode && message?.method?.endsWith('/channel/permission_request')) {
2160
+ this.handlePermissionRequest(message.params);
2037
2161
  }
2038
2162
  origOnMessage?.(message, extra);
2039
2163
  };
@@ -2052,15 +2176,16 @@ export class PhotonServer {
2052
2176
  */
2053
2177
  async startSSE() {
2054
2178
  const port = this.options.port || 3000;
2055
- const useStreamableHTTP = !!this.options.embeddedAssets;
2056
2179
  const ssePath = '/mcp';
2057
2180
  const messagesPath = '/mcp/messages';
2058
- // For compiled binaries with Beam UI, use a minimal Streamable HTTP transport
2059
- // that matches what the Beam frontend sends:
2060
- // POST /mcp — JSON-RPC request, Accept: application/json JSON response
2061
- // GET /mcp?sessionId=X EventSource for server-to-client notifications
2181
+ // Always use Streamable HTTP transport for SSE mode.
2182
+ // The legacy SSE transport (endpoint event + /mcp/messages?sessionId=) is deprecated
2183
+ // in the MCP spec and not supported by modern clients (e.g. llama.cpp).
2184
+ // Streamable HTTP uses the standard protocol:
2185
+ // POST /mcp — JSON-RPC request → JSON response
2186
+ // GET /mcp — SSE stream for server-to-client notifications
2062
2187
  let beamTransport = null;
2063
- if (useStreamableHTTP) {
2188
+ {
2064
2189
  const photonName = this.mcp?.name || 'photon';
2065
2190
  beamTransport = new BeamCompatTransport(photonName, {
2066
2191
  description: this.mcp?.description,
@@ -2132,7 +2257,7 @@ export class PhotonServer {
2132
2257
  res.writeHead(204, {
2133
2258
  'Access-Control-Allow-Origin': '*',
2134
2259
  'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
2135
- 'Access-Control-Allow-Headers': 'Content-Type, Accept, Mcp-Session-Id',
2260
+ 'Access-Control-Allow-Headers': 'Content-Type, Accept, Mcp-Session-Id, Mcp-Protocol-Version',
2136
2261
  'Access-Control-Expose-Headers': 'Mcp-Session-Id',
2137
2262
  });
2138
2263
  res.end();
@@ -2499,17 +2624,7 @@ export class PhotonServer {
2499
2624
  });
2500
2625
  await new Promise((resolve) => {
2501
2626
  this.httpServer.listen(port, () => {
2502
- this.log('info', `${this.mcp.name} MCP server listening`, {
2503
- transport: 'sse',
2504
- port,
2505
- devMode: this.devMode,
2506
- });
2507
- this.log('debug', 'SSE endpoints ready', {
2508
- baseUrl: `http://localhost:${port}`,
2509
- ssePath,
2510
- messagesPath,
2511
- playground: this.devMode ? `http://localhost:${port}/playground` : undefined,
2512
- });
2627
+ process.stdout.write(`⚡ ${this.mcp.name} http://localhost:${port}${ssePath}\n`);
2513
2628
  resolve();
2514
2629
  });
2515
2630
  });