@portel/photon 1.18.0 → 1.20.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 (238) hide show
  1. package/dist/auto-ui/beam/routes/api-browse.d.ts.map +1 -1
  2. package/dist/auto-ui/beam/routes/api-browse.js +16 -4
  3. package/dist/auto-ui/beam/routes/api-browse.js.map +1 -1
  4. package/dist/auto-ui/beam/routes/api-config.js +4 -4
  5. package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
  6. package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -1
  7. package/dist/auto-ui/beam/routes/api-marketplace.js +14 -1
  8. package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
  9. package/dist/auto-ui/beam.d.ts.map +1 -1
  10. package/dist/auto-ui/beam.js +196 -77
  11. package/dist/auto-ui/beam.js.map +1 -1
  12. package/dist/auto-ui/bridge/index.d.ts.map +1 -1
  13. package/dist/auto-ui/bridge/index.js +17 -0
  14. package/dist/auto-ui/bridge/index.js.map +1 -1
  15. package/dist/auto-ui/streamable-http-transport.d.ts +1 -0
  16. package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
  17. package/dist/auto-ui/streamable-http-transport.js +64 -16
  18. package/dist/auto-ui/streamable-http-transport.js.map +1 -1
  19. package/dist/auto-ui/types.d.ts +12 -0
  20. package/dist/auto-ui/types.d.ts.map +1 -1
  21. package/dist/auto-ui/types.js.map +1 -1
  22. package/dist/beam-form.bundle.js +49 -6
  23. package/dist/beam-form.bundle.js.map +2 -2
  24. package/dist/beam.bundle.js +2090 -512
  25. package/dist/beam.bundle.js.map +4 -4
  26. package/dist/capability-negotiator.d.ts +67 -0
  27. package/dist/capability-negotiator.d.ts.map +1 -0
  28. package/dist/capability-negotiator.js +104 -0
  29. package/dist/capability-negotiator.js.map +1 -0
  30. package/dist/channel-manager.d.ts +122 -0
  31. package/dist/channel-manager.d.ts.map +1 -0
  32. package/dist/channel-manager.js +266 -0
  33. package/dist/channel-manager.js.map +1 -0
  34. package/dist/claude-code-plugin.js +1 -1
  35. package/dist/cli/commands/beam.d.ts.map +1 -1
  36. package/dist/cli/commands/beam.js +8 -2
  37. package/dist/cli/commands/beam.js.map +1 -1
  38. package/dist/cli/commands/changelog.d.ts +9 -0
  39. package/dist/cli/commands/changelog.d.ts.map +1 -0
  40. package/dist/cli/commands/changelog.js +133 -0
  41. package/dist/cli/commands/changelog.js.map +1 -0
  42. package/dist/cli/commands/maker.d.ts.map +1 -1
  43. package/dist/cli/commands/maker.js +23 -2
  44. package/dist/cli/commands/maker.js.map +1 -1
  45. package/dist/cli/commands/mcp.d.ts.map +1 -1
  46. package/dist/cli/commands/mcp.js +53 -0
  47. package/dist/cli/commands/mcp.js.map +1 -1
  48. package/dist/cli/commands/package.d.ts.map +1 -1
  49. package/dist/cli/commands/package.js +43 -9
  50. package/dist/cli/commands/package.js.map +1 -1
  51. package/dist/cli/commands/run.d.ts.map +1 -1
  52. package/dist/cli/commands/run.js +1 -0
  53. package/dist/cli/commands/run.js.map +1 -1
  54. package/dist/cli/commands/update.d.ts +3 -2
  55. package/dist/cli/commands/update.d.ts.map +1 -1
  56. package/dist/cli/commands/update.js +50 -43
  57. package/dist/cli/commands/update.js.map +1 -1
  58. package/dist/cli/index.d.ts.map +1 -1
  59. package/dist/cli/index.js +16 -2
  60. package/dist/cli/index.js.map +1 -1
  61. package/dist/cli-alias.js +1 -1
  62. package/dist/cli-alias.js.map +1 -1
  63. package/dist/context-store.d.ts +23 -33
  64. package/dist/context-store.d.ts.map +1 -1
  65. package/dist/context-store.js +147 -97
  66. package/dist/context-store.js.map +1 -1
  67. package/dist/context.d.ts +15 -10
  68. package/dist/context.d.ts.map +1 -1
  69. package/dist/context.js +37 -13
  70. package/dist/context.js.map +1 -1
  71. package/dist/daemon/client.d.ts.map +1 -1
  72. package/dist/daemon/client.js +12 -0
  73. package/dist/daemon/client.js.map +1 -1
  74. package/dist/daemon/server.js +34 -51
  75. package/dist/daemon/server.js.map +1 -1
  76. package/dist/daemon/worker-manager.d.ts.map +1 -1
  77. package/dist/daemon/worker-manager.js +21 -7
  78. package/dist/daemon/worker-manager.js.map +1 -1
  79. package/dist/data-migration.d.ts +27 -0
  80. package/dist/data-migration.d.ts.map +1 -0
  81. package/dist/data-migration.js +307 -0
  82. package/dist/data-migration.js.map +1 -0
  83. package/dist/editor-support/docblock-tag-catalog.d.ts.map +1 -1
  84. package/dist/editor-support/docblock-tag-catalog.js +6 -0
  85. package/dist/editor-support/docblock-tag-catalog.js.map +1 -1
  86. package/dist/loader.d.ts +13 -0
  87. package/dist/loader.d.ts.map +1 -1
  88. package/dist/loader.js +169 -22
  89. package/dist/loader.js.map +1 -1
  90. package/dist/marketplace-manager.d.ts +6 -0
  91. package/dist/marketplace-manager.d.ts.map +1 -1
  92. package/dist/marketplace-manager.js +185 -62
  93. package/dist/marketplace-manager.js.map +1 -1
  94. package/dist/namespace-migration.d.ts +1 -0
  95. package/dist/namespace-migration.d.ts.map +1 -1
  96. package/dist/namespace-migration.js +86 -0
  97. package/dist/namespace-migration.js.map +1 -1
  98. package/dist/photon-cli-runner.d.ts.map +1 -1
  99. package/dist/photon-cli-runner.js +47 -21
  100. package/dist/photon-cli-runner.js.map +1 -1
  101. package/dist/photon-doc-extractor.d.ts +1 -0
  102. package/dist/photon-doc-extractor.d.ts.map +1 -1
  103. package/dist/photon-doc-extractor.js +6 -0
  104. package/dist/photon-doc-extractor.js.map +1 -1
  105. package/dist/readme-syncer.d.ts.map +1 -1
  106. package/dist/readme-syncer.js +6 -1
  107. package/dist/readme-syncer.js.map +1 -1
  108. package/dist/resource-server.d.ts +105 -0
  109. package/dist/resource-server.d.ts.map +1 -0
  110. package/dist/resource-server.js +723 -0
  111. package/dist/resource-server.js.map +1 -0
  112. package/dist/serv/auth/jwt.d.ts +2 -0
  113. package/dist/serv/auth/jwt.d.ts.map +1 -1
  114. package/dist/serv/auth/jwt.js +11 -5
  115. package/dist/serv/auth/jwt.js.map +1 -1
  116. package/dist/serv/vault/token-vault.d.ts +2 -0
  117. package/dist/serv/vault/token-vault.d.ts.map +1 -1
  118. package/dist/serv/vault/token-vault.js +6 -0
  119. package/dist/serv/vault/token-vault.js.map +1 -1
  120. package/dist/server.d.ts +30 -119
  121. package/dist/server.d.ts.map +1 -1
  122. package/dist/server.js +252 -1122
  123. package/dist/server.js.map +1 -1
  124. package/dist/shared/audit.d.ts.map +1 -1
  125. package/dist/shared/audit.js +11 -4
  126. package/dist/shared/audit.js.map +1 -1
  127. package/dist/shared/security.d.ts +10 -0
  128. package/dist/shared/security.d.ts.map +1 -1
  129. package/dist/shared/security.js +27 -0
  130. package/dist/shared/security.js.map +1 -1
  131. package/dist/task-executor.d.ts +69 -0
  132. package/dist/task-executor.d.ts.map +1 -0
  133. package/dist/task-executor.js +182 -0
  134. package/dist/task-executor.js.map +1 -0
  135. package/dist/tasks/store.d.ts.map +1 -1
  136. package/dist/tasks/store.js +6 -2
  137. package/dist/tasks/store.js.map +1 -1
  138. package/dist/types/photon-instance.d.ts +50 -0
  139. package/dist/types/photon-instance.d.ts.map +1 -0
  140. package/dist/types/photon-instance.js +9 -0
  141. package/dist/types/photon-instance.js.map +1 -0
  142. package/dist/types/server-types.d.ts +61 -0
  143. package/dist/types/server-types.d.ts.map +1 -0
  144. package/dist/types/server-types.js +8 -0
  145. package/dist/types/server-types.js.map +1 -0
  146. package/dist/version-notify.d.ts +27 -0
  147. package/dist/version-notify.d.ts.map +1 -0
  148. package/dist/version-notify.js +142 -0
  149. package/dist/version-notify.js.map +1 -0
  150. package/package.json +3 -3
  151. package/dist/auto-ui/bridge/openai-shim.d.ts +0 -20
  152. package/dist/auto-ui/bridge/openai-shim.d.ts.map +0 -1
  153. package/dist/auto-ui/bridge/openai-shim.js +0 -231
  154. package/dist/auto-ui/bridge/openai-shim.js.map +0 -1
  155. package/dist/auto-ui/bridge/photon-app.d.ts +0 -162
  156. package/dist/auto-ui/bridge/photon-app.d.ts.map +0 -1
  157. package/dist/auto-ui/bridge/photon-app.js +0 -460
  158. package/dist/auto-ui/bridge/photon-app.js.map +0 -1
  159. package/dist/auto-ui/daemon-tools.d.ts +0 -45
  160. package/dist/auto-ui/daemon-tools.d.ts.map +0 -1
  161. package/dist/auto-ui/daemon-tools.js +0 -581
  162. package/dist/auto-ui/daemon-tools.js.map +0 -1
  163. package/dist/auto-ui/design-system/index.d.ts +0 -21
  164. package/dist/auto-ui/design-system/index.d.ts.map +0 -1
  165. package/dist/auto-ui/design-system/index.js +0 -27
  166. package/dist/auto-ui/design-system/index.js.map +0 -1
  167. package/dist/auto-ui/design-system/transaction-ui.d.ts +0 -70
  168. package/dist/auto-ui/design-system/transaction-ui.d.ts.map +0 -1
  169. package/dist/auto-ui/design-system/transaction-ui.js +0 -982
  170. package/dist/auto-ui/design-system/transaction-ui.js.map +0 -1
  171. package/dist/auto-ui/playground-server.d.ts +0 -7
  172. package/dist/auto-ui/playground-server.d.ts.map +0 -1
  173. package/dist/auto-ui/playground-server.js +0 -840
  174. package/dist/auto-ui/playground-server.js.map +0 -1
  175. package/dist/auto-ui/rendering/components.d.ts +0 -29
  176. package/dist/auto-ui/rendering/components.d.ts.map +0 -1
  177. package/dist/auto-ui/rendering/components.js +0 -1341
  178. package/dist/auto-ui/rendering/components.js.map +0 -1
  179. package/dist/auto-ui/rendering/field-analyzer.d.ts +0 -104
  180. package/dist/auto-ui/rendering/field-analyzer.d.ts.map +0 -1
  181. package/dist/auto-ui/rendering/field-analyzer.js +0 -447
  182. package/dist/auto-ui/rendering/field-analyzer.js.map +0 -1
  183. package/dist/auto-ui/rendering/field-renderers.d.ts +0 -64
  184. package/dist/auto-ui/rendering/field-renderers.d.ts.map +0 -1
  185. package/dist/auto-ui/rendering/field-renderers.js +0 -317
  186. package/dist/auto-ui/rendering/field-renderers.js.map +0 -1
  187. package/dist/auto-ui/rendering/index.d.ts +0 -28
  188. package/dist/auto-ui/rendering/index.d.ts.map +0 -1
  189. package/dist/auto-ui/rendering/index.js +0 -60
  190. package/dist/auto-ui/rendering/index.js.map +0 -1
  191. package/dist/auto-ui/rendering/layout-selector.d.ts +0 -60
  192. package/dist/auto-ui/rendering/layout-selector.d.ts.map +0 -1
  193. package/dist/auto-ui/rendering/layout-selector.js +0 -476
  194. package/dist/auto-ui/rendering/layout-selector.js.map +0 -1
  195. package/dist/markdown-utils.d.ts +0 -8
  196. package/dist/markdown-utils.d.ts.map +0 -1
  197. package/dist/markdown-utils.js +0 -64
  198. package/dist/markdown-utils.js.map +0 -1
  199. package/dist/mcp-client.d.ts +0 -9
  200. package/dist/mcp-client.d.ts.map +0 -1
  201. package/dist/mcp-client.js +0 -11
  202. package/dist/mcp-client.js.map +0 -1
  203. package/dist/mcp-elicitation.d.ts +0 -32
  204. package/dist/mcp-elicitation.d.ts.map +0 -1
  205. package/dist/mcp-elicitation.js +0 -26
  206. package/dist/mcp-elicitation.js.map +0 -1
  207. package/dist/photons/builder-compass.photon.d.ts +0 -167
  208. package/dist/photons/builder-compass.photon.d.ts.map +0 -1
  209. package/dist/photons/builder-compass.photon.js +0 -816
  210. package/dist/photons/builder-compass.photon.js.map +0 -1
  211. package/dist/photons/builder-compass.photon.ts +0 -1129
  212. package/dist/photons/docs/ui/docs.html +0 -441
  213. package/dist/photons/docs.photon.d.ts +0 -237
  214. package/dist/photons/docs.photon.d.ts.map +0 -1
  215. package/dist/photons/docs.photon.js +0 -483
  216. package/dist/photons/docs.photon.js.map +0 -1
  217. package/dist/photons/docs.photon.ts +0 -536
  218. package/dist/photons/slides.photon.d.ts +0 -212
  219. package/dist/photons/slides.photon.d.ts.map +0 -1
  220. package/dist/photons/slides.photon.js +0 -355
  221. package/dist/photons/slides.photon.js.map +0 -1
  222. package/dist/photons/slides.photon.ts +0 -370
  223. package/dist/photons/spreadsheet/ui/spreadsheet.html +0 -779
  224. package/dist/photons/spreadsheet.photon.d.ts +0 -554
  225. package/dist/photons/spreadsheet.photon.d.ts.map +0 -1
  226. package/dist/photons/spreadsheet.photon.js +0 -1050
  227. package/dist/photons/spreadsheet.photon.js.map +0 -1
  228. package/dist/photons/spreadsheet.photon.ts +0 -1239
  229. package/dist/photons/ui/builder-compass.html +0 -1199
  230. package/dist/photons/ui/builder-compass.photon.html +0 -380
  231. package/dist/security-scanner.d.ts +0 -52
  232. package/dist/security-scanner.d.ts.map +0 -1
  233. package/dist/security-scanner.js +0 -181
  234. package/dist/security-scanner.js.map +0 -1
  235. package/dist/shared/performance.d.ts +0 -65
  236. package/dist/shared/performance.d.ts.map +0 -1
  237. package/dist/shared/performance.js +0 -136
  238. package/dist/shared/performance.js.map +0 -1
@@ -19402,7 +19402,7 @@ ConfirmDialog.styles = [
19402
19402
  }
19403
19403
 
19404
19404
  .btn-cancel:hover {
19405
- background: var(--bg-glass-strong, rgba(255, 255, 255, 0.08));
19405
+ background: var(--bg-glass-strong);
19406
19406
  }
19407
19407
 
19408
19408
  .btn-confirm {
@@ -19442,10 +19442,12 @@ ConfirmDialog = __decorateClass([
19442
19442
  t4("confirm-dialog")
19443
19443
  ], ConfirmDialog);
19444
19444
  async function confirmDialog(message, options) {
19445
- let dialog = document.querySelector("confirm-dialog");
19445
+ const beamApp = document.querySelector("beam-app");
19446
+ const root = beamApp?.shadowRoot ?? document.body;
19447
+ let dialog = root.querySelector("confirm-dialog");
19446
19448
  if (!dialog) {
19447
19449
  dialog = document.createElement("confirm-dialog");
19448
- document.body.appendChild(dialog);
19450
+ root.appendChild(dialog);
19449
19451
  }
19450
19452
  return dialog.show(message, options);
19451
19453
  }
@@ -21738,8 +21740,13 @@ var MCPClientService = class {
21738
21740
  id: tool["x-photon-id"] || serverName,
21739
21741
  // Use hash ID, fallback to name
21740
21742
  name: serverName,
21743
+ shortName: tool["x-photon-short-name"],
21744
+ namespace: tool["x-photon-namespace"],
21745
+ qualifiedName: tool["x-photon-qualified-name"],
21741
21746
  path: tool["x-photon-path"],
21742
21747
  // File path for View Source
21748
+ editable: tool["x-photon-editable"] ?? false,
21749
+ // User-owned (at baseDir root)
21743
21750
  description: tool["x-photon-description"],
21744
21751
  icon: tool["x-photon-icon"],
21745
21752
  internal: tool["x-photon-internal"],
@@ -22433,6 +22440,62 @@ var ViewportManager = class {
22433
22440
  }
22434
22441
  };
22435
22442
 
22443
+ // src/auto-ui/frontend/utils/beam-route.ts
22444
+ function decodeBeamPathSegments(pathname) {
22445
+ return pathname.split("/").filter(Boolean).map((segment) => {
22446
+ try {
22447
+ return decodeURIComponent(segment);
22448
+ } catch {
22449
+ return segment;
22450
+ }
22451
+ });
22452
+ }
22453
+ function matchesNamespacedPhoton(photon, namespace, shortName) {
22454
+ return photon.namespace === namespace && (photon.shortName || photon.name) === shortName;
22455
+ }
22456
+ function parseBeamRoutePath(pathname, photons, externalMCPs = []) {
22457
+ const segments = decodeBeamPathSegments(pathname);
22458
+ if (segments.length === 0) {
22459
+ return { photonName: null, methodNames: [] };
22460
+ }
22461
+ if (segments.length === 1) {
22462
+ return { photonName: segments[0], methodNames: [] };
22463
+ }
22464
+ if (segments.length === 2) {
22465
+ const [first, second] = segments;
22466
+ const namespacedPhoton2 = photons.find(
22467
+ (photon) => matchesNamespacedPhoton(photon, first, second)
22468
+ );
22469
+ if (namespacedPhoton2) {
22470
+ return { photonName: namespacedPhoton2.name, methodNames: [] };
22471
+ }
22472
+ return { photonName: first, methodNames: second.split("+").filter(Boolean) };
22473
+ }
22474
+ const namespace = segments[segments.length - 3];
22475
+ const shortName = segments[segments.length - 2];
22476
+ const methodSegment = segments[segments.length - 1];
22477
+ const namespacedPhoton = photons.find((photon) => matchesNamespacedPhoton(photon, namespace, shortName)) || externalMCPs.find((photon) => matchesNamespacedPhoton(photon, namespace, shortName));
22478
+ if (namespacedPhoton) {
22479
+ return {
22480
+ photonName: namespacedPhoton.name,
22481
+ methodNames: methodSegment.split("+").filter(Boolean)
22482
+ };
22483
+ }
22484
+ const photonName = segments[segments.length - 2];
22485
+ return { photonName, methodNames: methodSegment.split("+").filter(Boolean) };
22486
+ }
22487
+ function buildBeamRoutePath(photon, methodName, splitPanelMethodNames = []) {
22488
+ if (!photon) return "/";
22489
+ const baseSegments = photon.namespace && photon.shortName ? [photon.namespace, photon.shortName] : [photon.name];
22490
+ if (!methodName) {
22491
+ return "/" + baseSegments.map((segment) => encodeURIComponent(segment)).join("/");
22492
+ }
22493
+ const methodSegments = [methodName, ...splitPanelMethodNames].map(
22494
+ (name2) => encodeURIComponent(name2)
22495
+ );
22496
+ return "/" + baseSegments.map((segment) => encodeURIComponent(segment)).join("/") + "/" + methodSegments.join("+");
22497
+ }
22498
+
22436
22499
  // src/auto-ui/frontend/components/beam-app.ts
22437
22500
  var THEME_STORAGE_KEY = "beam-theme";
22438
22501
  var PROTOCOL_STORAGE_KEY = "beam-protocol";
@@ -22447,6 +22510,10 @@ var BeamApp = class extends i4 {
22447
22510
  this._reconnectAttempt = 0;
22448
22511
  this._connectRetries = 0;
22449
22512
  this._sidebarVisible = false;
22513
+ this._sidebarWidth = parseInt(
22514
+ localStorage.getItem("beam-sidebar-width") || "300",
22515
+ 10
22516
+ );
22450
22517
  this._focusMode = false;
22451
22518
  this._viewMode = "full";
22452
22519
  this._photons = [];
@@ -22501,7 +22568,11 @@ var BeamApp = class extends i4 {
22501
22568
  this._splitPanels = [];
22502
22569
  this._methodPickerOpen = false;
22503
22570
  this._methodPickerPanelId = null;
22571
+ this._splitPrimaryWidth = null;
22572
+ this._mainTab = "methods";
22504
22573
  this._nextPanelId = 0;
22574
+ // Maps progressToken → panelId so progress events route to the correct split pane
22575
+ this._panelProgressTokens = /* @__PURE__ */ new Map();
22505
22576
  // Collection auto-subscription for ReactiveArray/Map/Set events
22506
22577
  this._collectionUnsubscribes = [];
22507
22578
  this._currentCollectionName = null;
@@ -22536,9 +22607,13 @@ var BeamApp = class extends i4 {
22536
22607
  this._initialConnectDone = false;
22537
22608
  this._handleRouteChange = () => {
22538
22609
  void (async () => {
22539
- const fullPath = window.location.pathname.slice(1);
22540
22610
  const queryPart = window.location.search.slice(1);
22541
- const [photonName, methodName] = fullPath.split("/");
22611
+ const { photonName, methodNames } = parseBeamRoutePath(
22612
+ window.location.pathname,
22613
+ this._photons,
22614
+ this._externalMCPs
22615
+ );
22616
+ const methodName = methodNames[0];
22542
22617
  this._sharedFormParams = null;
22543
22618
  let sharedParams = {};
22544
22619
  if (queryPart) {
@@ -22601,10 +22676,11 @@ var BeamApp = class extends i4 {
22601
22676
  if (photon.isExternalMCP && photon.hasMcpApp) {
22602
22677
  this._selectedMethod = null;
22603
22678
  this._view = "mcp-app";
22679
+ this._mainTab = "app";
22604
22680
  return;
22605
22681
  }
22606
22682
  if (methodName && photon.methods) {
22607
- const [firstMethodName, secondMethodName] = methodName.split("+");
22683
+ const [firstMethodName, secondMethodName] = methodNames;
22608
22684
  const method = photon.methods.find((m3) => m3.name === firstMethodName);
22609
22685
  if (method) {
22610
22686
  if (Object.keys(sharedParams).length > 0) {
@@ -22615,11 +22691,13 @@ var BeamApp = class extends i4 {
22615
22691
  }
22616
22692
  this._selectedMethod = method;
22617
22693
  this._view = "form";
22694
+ if (photon.isApp && photon.appEntry?.name === method.name) {
22695
+ this._mainTab = "app";
22696
+ } else if (!photon.isApp) {
22697
+ this._mainTab = "methods";
22698
+ }
22618
22699
  this._maybeAutoInvoke(method);
22619
22700
  if (secondMethodName) {
22620
- const urlPath = location.pathname;
22621
- const methodPart = urlPath.split("/").pop() || "";
22622
- const methodNames = methodPart.split("+");
22623
22701
  for (let i7 = 1; i7 < methodNames.length; i7++) {
22624
22702
  const name2 = methodNames[i7];
22625
22703
  if (name2 === "source") {
@@ -22642,10 +22720,12 @@ var BeamApp = class extends i4 {
22642
22720
  }
22643
22721
  this._selectedMethod = photon.appEntry;
22644
22722
  this._view = "form";
22723
+ this._mainTab = "app";
22645
22724
  this._maybeAutoInvoke(photon.appEntry);
22646
22725
  } else {
22647
22726
  this._selectedMethod = null;
22648
22727
  this._view = "list";
22728
+ this._mainTab = "methods";
22649
22729
  }
22650
22730
  }
22651
22731
  }
@@ -22845,7 +22925,7 @@ var BeamApp = class extends i4 {
22845
22925
  try {
22846
22926
  const res = await fetch("/api/marketplace/add", {
22847
22927
  method: "POST",
22848
- headers: { "Content-Type": "application/json" },
22928
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
22849
22929
  body: JSON.stringify({ name: name2 }),
22850
22930
  signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
22851
22931
  });
@@ -22874,15 +22954,19 @@ var BeamApp = class extends i4 {
22874
22954
  this._showForkDialog = false;
22875
22955
  this._forkPhotonName = "";
22876
22956
  this._forkOriginRepo = "";
22957
+ this._forkRequireNewName = false;
22958
+ this._forkSuggestedName = "";
22877
22959
  this._forkTargets = [];
22878
22960
  this._handleFork = async () => {
22879
22961
  if (!this._selectedPhoton) return;
22880
- this._forkPhotonName = this._selectedPhoton.name;
22962
+ this._forkPhotonName = this._selectedPhoton.qualifiedName || this._selectedPhoton.name;
22881
22963
  this._forkOriginRepo = this._selectedPhoton.installSource?.marketplace || "";
22964
+ this._forkRequireNewName = !this._selectedPhoton.installSource;
22965
+ this._forkSuggestedName = `${this._selectedPhoton.shortName || this._selectedPhoton.name}-copy`;
22882
22966
  await this._openForkDialog();
22883
22967
  };
22884
22968
  this._handleForkConfirm = async (e8) => {
22885
- const { target: target2 } = e8.detail;
22969
+ const { target: target2, newName } = e8.detail;
22886
22970
  const name2 = this._forkPhotonName;
22887
22971
  if (!name2) return;
22888
22972
  this._showForkDialog = false;
@@ -22890,8 +22974,8 @@ var BeamApp = class extends i4 {
22890
22974
  try {
22891
22975
  const res = await fetch("/api/marketplace/fork", {
22892
22976
  method: "POST",
22893
- headers: { "Content-Type": "application/json" },
22894
- body: JSON.stringify({ name: name2, target: target2 }),
22977
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
22978
+ body: JSON.stringify({ name: name2, target: target2, newName }),
22895
22979
  signal: AbortSignal.timeout(3e4)
22896
22980
  });
22897
22981
  const result = await res.json();
@@ -22918,6 +23002,8 @@ var BeamApp = class extends i4 {
22918
23002
  const { name: name2 } = e8.detail;
22919
23003
  this._forkPhotonName = name2;
22920
23004
  this._forkOriginRepo = "";
23005
+ this._forkRequireNewName = false;
23006
+ this._forkSuggestedName = `${name2}-copy`;
22921
23007
  await this._openForkDialog();
22922
23008
  };
22923
23009
  this._handleContribute = async () => {
@@ -22927,7 +23013,7 @@ var BeamApp = class extends i4 {
22927
23013
  try {
22928
23014
  const res = await fetch("/api/marketplace/contribute", {
22929
23015
  method: "POST",
22930
- headers: { "Content-Type": "application/json" },
23016
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
22931
23017
  body: JSON.stringify({ name: name2 }),
22932
23018
  signal: AbortSignal.timeout(6e4)
22933
23019
  });
@@ -23021,7 +23107,8 @@ var BeamApp = class extends i4 {
23021
23107
  const data = mcpClient.parseToolResult(result);
23022
23108
  if (data && data.code) {
23023
23109
  this._sourceData = data;
23024
- this._showSourceModal = true;
23110
+ this._mainTab = "source";
23111
+ this._view = "source";
23025
23112
  } else {
23026
23113
  showToast("No source code returned", "error");
23027
23114
  }
@@ -23033,14 +23120,17 @@ var BeamApp = class extends i4 {
23033
23120
  };
23034
23121
  /** Navigate to inline source view (Phase 2) */
23035
23122
  this._handleViewSourceInline = async () => {
23036
- if (this._view === "source") {
23037
- this._view = "studio";
23123
+ if (this._view === "source" || this._view === "studio") {
23038
23124
  return;
23039
23125
  }
23040
- await this._handleViewSource();
23041
- if (this._sourceData) {
23042
- this._showSourceModal = false;
23043
- this._view = "source";
23126
+ const isEditable = this._selectedPhoton?.editable && !this._selectedPhoton?.isExternalMCP;
23127
+ if (isEditable) {
23128
+ this._view = "studio";
23129
+ } else {
23130
+ await this._handleViewSource();
23131
+ if (this._sourceData) {
23132
+ this._view = "source";
23133
+ }
23044
23134
  }
23045
23135
  };
23046
23136
  /** Open settings for the current photon (Phase 3) */
@@ -23110,12 +23200,15 @@ var BeamApp = class extends i4 {
23110
23200
  const newName = detail.cloneName;
23111
23201
  if (!newName) return;
23112
23202
  try {
23113
- const res = await fetch(`/api/instances/${photonName}/${detail.instance}/clone`, {
23114
- method: "POST",
23115
- headers: { "Content-Type": "application/json" },
23116
- body: JSON.stringify({ newName }),
23117
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23118
- });
23203
+ const res = await fetch(
23204
+ `/api/instances/${encodeURIComponent(photonName)}/${encodeURIComponent(detail.instance)}/clone`,
23205
+ {
23206
+ method: "POST",
23207
+ headers: { "Content-Type": "application/json" },
23208
+ body: JSON.stringify({ newName }),
23209
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23210
+ }
23211
+ );
23119
23212
  if (res.ok) {
23120
23213
  await this._fetchInstances(photonName);
23121
23214
  showToast(`Cloned as: ${newName}`, "success");
@@ -23132,12 +23225,15 @@ var BeamApp = class extends i4 {
23132
23225
  const newName = detail.newName;
23133
23226
  if (!newName) return;
23134
23227
  try {
23135
- const res = await fetch(`/api/instances/${photonName}/${detail.instance}/rename`, {
23136
- method: "POST",
23137
- headers: { "Content-Type": "application/json" },
23138
- body: JSON.stringify({ newName }),
23139
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23140
- });
23228
+ const res = await fetch(
23229
+ `/api/instances/${encodeURIComponent(photonName)}/${encodeURIComponent(detail.instance)}/rename`,
23230
+ {
23231
+ method: "POST",
23232
+ headers: { "Content-Type": "application/json" },
23233
+ body: JSON.stringify({ newName }),
23234
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23235
+ }
23236
+ );
23141
23237
  if (res.ok) {
23142
23238
  await mcpClient.callTool(`${photonName}/_use`, { name: newName });
23143
23239
  this._setCurrentInstance(photonName, newName);
@@ -23159,10 +23255,13 @@ var BeamApp = class extends i4 {
23159
23255
  return;
23160
23256
  }
23161
23257
  try {
23162
- const res = await fetch(`/api/instances/${photonName}/${instanceToDelete}`, {
23163
- method: "DELETE",
23164
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23165
- });
23258
+ const res = await fetch(
23259
+ `/api/instances/${encodeURIComponent(photonName)}/${encodeURIComponent(instanceToDelete)}`,
23260
+ {
23261
+ method: "DELETE",
23262
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23263
+ }
23264
+ );
23166
23265
  if (res.ok) {
23167
23266
  await mcpClient.callTool(`${photonName}/_use`, { name: "default" });
23168
23267
  this._setCurrentInstance(photonName, "default");
@@ -23181,11 +23280,19 @@ var BeamApp = class extends i4 {
23181
23280
  };
23182
23281
  this._handleDeletePhoton = async () => {
23183
23282
  this._closeSettingsMenu();
23184
- if (await confirmDialog(
23185
- `Are you sure you want to delete "${this._selectedPhoton?.name}"? This cannot be undone.`,
23186
- { confirm: "Delete", destructive: true }
23187
- )) {
23188
- void this._invokeMakerMethod("delete");
23283
+ if (await confirmDialog(`Remove "${this._selectedPhoton?.name}"? It will be moved to trash.`, {
23284
+ confirm: "Remove",
23285
+ destructive: true
23286
+ })) {
23287
+ const deletedName = this._selectedPhoton?.name;
23288
+ await this._invokeMakerMethod("delete");
23289
+ if (deletedName) {
23290
+ this._photons = this._photons.filter((p5) => p5.name !== deletedName);
23291
+ this._selectedPhoton = this._photons[0] || null;
23292
+ this._selectedMethod = null;
23293
+ this._lastResult = null;
23294
+ this.requestUpdate();
23295
+ }
23189
23296
  }
23190
23297
  };
23191
23298
  /**
@@ -23469,16 +23576,9 @@ var BeamApp = class extends i4 {
23469
23576
  this._showHelp = false;
23470
23577
  return;
23471
23578
  }
23472
- if (this._showPhotonHelp) {
23473
- this._showPhotonHelp = false;
23474
- return;
23475
- }
23476
- if (this._view === "source") {
23477
- this._view = "list";
23478
- return;
23479
- }
23480
- if (this._showSourceModal) {
23481
- this._closeSourceModal();
23579
+ if (this._mainTab === "help" || this._mainTab === "source") {
23580
+ this._mainTab = "methods";
23581
+ if (this._view === "source") this._view = "list";
23482
23582
  return;
23483
23583
  }
23484
23584
  if (this._view === "form" && this._selectedMethod) {
@@ -23593,6 +23693,26 @@ var BeamApp = class extends i4 {
23593
23693
  this._photonHelpLoading = false;
23594
23694
  }
23595
23695
  };
23696
+ /** Load help content for inline help tab view */
23697
+ this._loadPhotonHelp = async () => {
23698
+ if (!this._selectedPhoton) return;
23699
+ this._photonHelpMarkdown = "";
23700
+ this._photonHelpLoading = true;
23701
+ const markdown = await mcpClient.getPhotonHelp(this._selectedPhoton.name);
23702
+ if (markdown) {
23703
+ this._photonHelpMarkdown = markdown;
23704
+ } else {
23705
+ this._photonHelpMarkdown = this._generatePhotonHelpMarkdown();
23706
+ }
23707
+ this._photonHelpLoading = false;
23708
+ if (this._view === "source" || this._view === "studio") {
23709
+ if (this._selectedMethod) {
23710
+ this._view = "form";
23711
+ } else {
23712
+ this._view = "list";
23713
+ }
23714
+ }
23715
+ };
23596
23716
  this._toggleFocusMode = () => {
23597
23717
  this._focusMode = !this._focusMode;
23598
23718
  if (this._focusMode) {
@@ -23696,7 +23816,8 @@ var BeamApp = class extends i4 {
23696
23816
  void this._handleRemove();
23697
23817
  break;
23698
23818
  case "help":
23699
- void this._showPhotonHelpModal();
23819
+ this._mainTab = "help";
23820
+ void this._loadPhotonHelp();
23700
23821
  break;
23701
23822
  case "fullscreen":
23702
23823
  this._handleFullscreen();
@@ -24230,8 +24351,12 @@ var BeamApp = class extends i4 {
24230
24351
  }
24231
24352
  }
24232
24353
  if (!this._selectedPhoton && window.location.pathname !== "/") {
24233
- const pathPhotonName = window.location.pathname.slice(1).split("/")[0];
24234
- const routePhoton = pathPhotonName ? this._photons.find((p5) => p5.name === pathPhotonName) : null;
24354
+ const { photonName: pathPhotonName } = parseBeamRoutePath(
24355
+ window.location.pathname,
24356
+ this._photons,
24357
+ this._externalMCPs
24358
+ );
24359
+ const routePhoton = pathPhotonName ? this._photons.find((p5) => p5.name === pathPhotonName) || this._externalMCPs.find((p5) => p5.name === pathPhotonName) : null;
24235
24360
  if (routePhoton) {
24236
24361
  void this._handleRouteChange();
24237
24362
  } else {
@@ -24253,18 +24378,15 @@ var BeamApp = class extends i4 {
24253
24378
  });
24254
24379
  mcpClient.on("progress", (data) => {
24255
24380
  this._log("info", data.message || "Processing...");
24256
- if (typeof data.progress === "number") {
24257
- if (data.progress > 0) {
24258
- this._progress = {
24259
- value: data.total ? data.progress / data.total : data.progress,
24260
- message: data.message || "Processing..."
24261
- };
24262
- } else {
24263
- this._progress = {
24264
- value: -1,
24265
- message: data.message || "Processing..."
24266
- };
24267
- }
24381
+ const panelId = data.progressToken != null ? this._panelProgressTokens.get(data.progressToken) : void 0;
24382
+ const progressValue = typeof data.progress === "number" ? data.progress > 0 ? {
24383
+ value: data.total ? data.progress / data.total : data.progress,
24384
+ message: data.message || "Processing..."
24385
+ } : { value: -1, message: data.message || "Processing..." } : null;
24386
+ if (panelId && progressValue) {
24387
+ this._updatePanel(panelId, { progress: progressValue });
24388
+ } else if (progressValue) {
24389
+ this._progress = progressValue;
24268
24390
  }
24269
24391
  });
24270
24392
  mcpClient.on("toast", (data) => {
@@ -24335,6 +24457,7 @@ var BeamApp = class extends i4 {
24335
24457
  "stack",
24336
24458
  "columns",
24337
24459
  "qr",
24460
+ "guide",
24338
24461
  "slides",
24339
24462
  "presentation"
24340
24463
  ]);
@@ -24565,17 +24688,16 @@ var BeamApp = class extends i4 {
24565
24688
  } else if (!this._selectedPhoton) {
24566
24689
  path = "/";
24567
24690
  } else {
24568
- path = "/" + this._selectedPhoton.name;
24569
- if (this._selectedMethod) {
24570
- path += `/${this._selectedMethod.name}`;
24571
- for (const panel of this._splitPanels) {
24572
- if (panel.type === "method" && panel.method) {
24573
- path += `+${panel.method.name}`;
24574
- } else if (panel.type === "source") {
24575
- path += `+source`;
24576
- }
24577
- }
24578
- }
24691
+ const splitPanelMethodNames = this._selectedMethod ? this._splitPanels.map((panel) => {
24692
+ if (panel.type === "method" && panel.method) return panel.method.name;
24693
+ if (panel.type === "source") return "source";
24694
+ return null;
24695
+ }).filter((name2) => !!name2) : [];
24696
+ path = buildBeamRoutePath(
24697
+ this._selectedPhoton,
24698
+ this._selectedMethod?.name,
24699
+ splitPanelMethodNames
24700
+ );
24579
24701
  }
24580
24702
  if (replace2) {
24581
24703
  history.replaceState(null, "", path);
@@ -24964,7 +25086,7 @@ var BeamApp = class extends i4 {
24964
25086
 
24965
25087
  <nav
24966
25088
  class="sidebar-area glass-panel ${this._sidebarVisible ? "visible" : ""}"
24967
- style="margin: var(--space-sm); border-radius: var(--radius-md);"
25089
+ style="margin: var(--space-sm); border-radius: var(--radius-md); --sidebar-width: ${this._sidebarWidth}px;"
24968
25090
  aria-label="Photon navigation"
24969
25091
  >
24970
25092
  <beam-sidebar
@@ -24975,6 +25097,57 @@ var BeamApp = class extends i4 {
24975
25097
  .connected=${this._connected}
24976
25098
  .reconnecting=${this._reconnecting}
24977
25099
  .updatesAvailable=${this._updatesAvailable.length}
25100
+ .mainTab=${this._mainTab}
25101
+ .isApp=${!!(this._selectedPhoton?.isApp || this._selectedPhoton?.isExternalMCP && this._selectedPhoton?.hasMcpApp)}
25102
+ .hasSettings=${!!(this._selectedPhoton?.hasSettings && !this._selectedPhoton?.isExternalMCP)}
25103
+ .isExternalMCP=${!!this._selectedPhoton?.isExternalMCP}
25104
+ .hasPath=${!!this._selectedPhoton?.path}
25105
+ @tab-change=${(e8) => {
25106
+ const tab = e8.detail.tab;
25107
+ this._mainTab = tab;
25108
+ if (tab === "methods") {
25109
+ this._closeSecondPanel();
25110
+ this._selectedMethod = null;
25111
+ this._view = "list";
25112
+ this._updateRoute();
25113
+ return;
25114
+ }
25115
+ if (tab === "source") {
25116
+ void this._handleViewSourceInline();
25117
+ return;
25118
+ }
25119
+ if (tab === "help") {
25120
+ void this._loadPhotonHelp();
25121
+ return;
25122
+ }
25123
+ if (this._view === "source" || this._view === "studio") {
25124
+ if (this._selectedMethod) {
25125
+ this._view = "form";
25126
+ } else {
25127
+ this._view = "list";
25128
+ }
25129
+ }
25130
+ if (tab === "settings" && this._selectedPhoton) {
25131
+ const settingsMethod = this._selectedPhoton.methods?.find(
25132
+ (m3) => m3.name === "settings"
25133
+ );
25134
+ if (settingsMethod) {
25135
+ this._selectedMethod = settingsMethod;
25136
+ this._view = "form";
25137
+ this._maybeAutoInvoke(settingsMethod);
25138
+ }
25139
+ return;
25140
+ }
25141
+ if (tab === "app" && this._selectedPhoton?.isExternalMCP && this._selectedPhoton?.hasMcpApp) {
25142
+ this._view = "mcp-app";
25143
+ }
25144
+ if (tab === "app" && this._selectedPhoton?.isApp && this._selectedPhoton?.appEntry) {
25145
+ this._selectedMethod = this._selectedPhoton.appEntry;
25146
+ this._view = "form";
25147
+ this._maybeAutoInvoke(this._selectedPhoton.appEntry);
25148
+ }
25149
+ }}
25150
+ @toggle-focus=${() => this._toggleFocusMode()}
24978
25151
  @home=${this._goHome}
24979
25152
  @select=${(e8) => this._handlePhotonSelectMobile(e8)}
24980
25153
  @marketplace=${() => this._handleMarketplaceMobile()}
@@ -24990,7 +25163,7 @@ var BeamApp = class extends i4 {
24990
25163
  }}
24991
25164
  @open-studio=${(e8) => {
24992
25165
  const photon = this._photons.find((p5) => p5.name === e8.detail.photonName);
24993
- if (photon) {
25166
+ if (photon?.editable && !photon?.isExternalMCP) {
24994
25167
  this._selectedPhoton = photon;
24995
25168
  this._view = "studio";
24996
25169
  }
@@ -25004,61 +25177,20 @@ var BeamApp = class extends i4 {
25004
25177
  }
25005
25178
  }}
25006
25179
  ></beam-sidebar>
25180
+ <div
25181
+ class="sidebar-resize-handle"
25182
+ @pointerdown=${(e8) => this._handleSidebarResizeStart(e8)}
25183
+ ></div>
25007
25184
  </nav>
25008
25185
 
25009
- <main
25010
- class="main-area"
25011
- id="main-content"
25012
- tabindex="-1"
25013
- aria-label="Main content"
25014
- style="${this._splitViewEnabled ? "overflow: hidden !important;" : ""}"
25015
- >
25016
- ${this._focusMode && this._selectedPhoton ? b2`<div class="focus-toolbar">
25017
- ${this._selectedMethod && !this._selectedPhoton.isApp ? b2`<button
25018
- class="focus-toolbar-back"
25019
- @click=${() => this._handleBackFromMethod()}
25020
- @mouseenter=${(e8) => {
25021
- e8.target.style.color = "var(--t-primary)";
25022
- e8.target.style.borderColor = "var(--accent-primary)";
25023
- }}
25024
- @mouseleave=${(e8) => {
25025
- e8.target.style.color = "var(--t-muted)";
25026
- e8.target.style.borderColor = "var(--border-glass)";
25027
- }}
25028
- title="Back to ${this._selectedPhoton.name}"
25029
- >
25030
- <svg
25031
- width="16"
25032
- height="16"
25033
- viewBox="0 0 24 24"
25034
- fill="none"
25035
- stroke="currentColor"
25036
- stroke-width="2"
25037
- stroke-linecap="round"
25038
- stroke-linejoin="round"
25039
- >
25040
- <path d="m15 18-6-6 6-6" />
25041
- </svg>
25042
- </button>` : ""}
25043
- <button
25044
- @click=${this._toggleFocusMode}
25045
- @mouseenter=${(e8) => {
25046
- e8.target.style.color = "var(--t-primary)";
25047
- e8.target.style.borderColor = "var(--accent-primary)";
25048
- }}
25049
- @mouseleave=${(e8) => {
25050
- e8.target.style.color = "var(--t-muted)";
25051
- e8.target.style.borderColor = "var(--border-glass)";
25052
- }}
25053
- title="Exit focus mode"
25054
- >
25055
- ${collapse}
25056
- </button>
25057
- </div>` : ""}
25058
- ${this._selectedPhoton ? b2`<div class="main-toolbar">
25059
- <div>
25186
+ <main class="main-area" id="main-content" tabindex="-1" aria-label="Main content">
25187
+ <div
25188
+ class="main-content-scroll"
25189
+ style="${this._splitViewEnabled ? "overflow: hidden !important; padding: 0;" : this._mainTab === "app" && (this._selectedPhoton?.isApp || this._selectedPhoton?.isExternalMCP && this._selectedPhoton?.hasMcpApp) ? "overflow: hidden; padding: 0;" : this._mainTab === "source" ? "padding: 0; overflow: hidden;" : this._view === "studio" ? "padding: 0; overflow: hidden;" : ""}"
25190
+ >
25191
+ ${this._focusMode && this._selectedPhoton ? b2`<div class="focus-toolbar">
25060
25192
  ${this._selectedMethod && !this._selectedPhoton.isApp ? b2`<button
25061
- class="beam-back-btn"
25193
+ class="focus-toolbar-back"
25062
25194
  @click=${() => this._handleBackFromMethod()}
25063
25195
  @mouseenter=${(e8) => {
25064
25196
  e8.target.style.color = "var(--t-primary)";
@@ -25083,31 +25215,7 @@ var BeamApp = class extends i4 {
25083
25215
  <path d="m15 18-6-6 6-6" />
25084
25216
  </svg>
25085
25217
  </button>` : ""}
25086
- </div>
25087
- <div style="display: flex; gap: 4px; align-items: center;">
25088
- ${this._selectedPhoton.isApp ? b2`<div style="position: relative;">
25089
- <button
25090
- class="beam-fullscreen-btn"
25091
- @click=${() => {
25092
- this._methodPickerOpen = !this._methodPickerOpen;
25093
- this._methodPickerPanelId = null;
25094
- }}
25095
- @mouseenter=${(e8) => {
25096
- e8.target.style.color = "var(--accent-secondary)";
25097
- e8.target.style.borderColor = "var(--accent-secondary)";
25098
- }}
25099
- @mouseleave=${(e8) => {
25100
- e8.target.style.color = "var(--t-muted)";
25101
- e8.target.style.borderColor = "var(--border-glass)";
25102
- }}
25103
- title="Add panel"
25104
- >
25105
- +
25106
- </button>
25107
- ${this._methodPickerOpen && this._methodPickerPanelId === null ? this._renderMethodPickerPopover() : ""}
25108
- </div>` : ""}
25109
25218
  <button
25110
- class="beam-fullscreen-btn"
25111
25219
  @click=${this._toggleFocusMode}
25112
25220
  @mouseenter=${(e8) => {
25113
25221
  e8.target.style.color = "var(--t-primary)";
@@ -25117,18 +25225,21 @@ var BeamApp = class extends i4 {
25117
25225
  e8.target.style.color = "var(--t-muted)";
25118
25226
  e8.target.style.borderColor = "var(--border-glass)";
25119
25227
  }}
25120
- title=${this._focusMode ? "Exit focus mode" : "Focus mode"}
25228
+ title="Exit focus mode"
25121
25229
  >
25122
- ${this._focusMode ? collapse : expand}
25230
+ ${collapse}
25123
25231
  </button>
25124
- </div>
25125
- </div>` : ""}
25126
- ${this._renderContent()}
25127
- <activity-log
25128
- .items=${this._activityLog}
25129
- .filter=${this._selectedPhoton?.name}
25130
- @clear=${() => this._activityLog = []}
25131
- ></activity-log>
25232
+ </div>` : ""}
25233
+ ${this._selectedPhoton && !this._selectedMethod && this._mainTab === "methods" ? b2`<div class="main-toolbar">
25234
+ <div style="flex: 1; min-width: 0;">${this._renderPhotonToolbar()}</div>
25235
+ </div>` : ""}
25236
+ ${this._mainTab === "log" ? b2`<activity-log
25237
+ .items=${this._activityLog}
25238
+ .filter=${this._selectedPhoton?.name}
25239
+ .fullscreen=${true}
25240
+ @clear=${() => this._activityLog = []}
25241
+ ></activity-log>` : this._mainTab === "help" && this._selectedPhoton ? this._renderPhotonHelpView() : this._mainTab === "settings" && this._selectedPhoton ? this._renderSettingsView() : this._mainTab === "methods" && !this._selectedMethod && (this._selectedPhoton?.isApp || this._selectedPhoton?.isExternalMCP && this._selectedPhoton?.hasMcpApp) ? this._renderMethodsBentoOnly() : this._renderContent()}
25242
+ </div>
25132
25243
  </main>
25133
25244
 
25134
25245
  <toast-manager></toast-manager>
@@ -25149,13 +25260,13 @@ var BeamApp = class extends i4 {
25149
25260
  </div>
25150
25261
  ` : ""}
25151
25262
  ${this._showHelp ? this._renderHelpModal() : ""}
25152
- ${this._showPhotonHelp ? this._renderPhotonHelpModal() : ""}
25153
- ${this._showSourceModal ? this._renderSourceModal() : ""}
25154
25263
  ${this._selectedPrompt?.content ? this._renderPromptModal() : ""}
25155
25264
  ${this._selectedResource?.content ? this._renderResourceModal() : ""}
25156
25265
  ${this._showForkDialog ? b2`<fork-dialog
25157
25266
  .photonName=${this._forkPhotonName}
25158
25267
  .originRepo=${this._forkOriginRepo}
25268
+ .requireNewName=${this._forkRequireNewName}
25269
+ .suggestedName=${this._forkSuggestedName}
25159
25270
  .targets=${this._forkTargets}
25160
25271
  @fork-confirm=${this._handleForkConfirm}
25161
25272
  @fork-cancel=${() => {
@@ -25172,6 +25283,43 @@ var BeamApp = class extends i4 {
25172
25283
  ></elicitation-modal>
25173
25284
  `;
25174
25285
  }
25286
+ _renderMethodsBentoOnly() {
25287
+ if (!this._selectedPhoton) return b2``;
25288
+ const methods = this._getVisibleMethods();
25289
+ if (methods.length === 0)
25290
+ return b2`<p style="color: var(--t-muted); padding: var(--space-md);">
25291
+ No methods available.
25292
+ </p>`;
25293
+ const hasTools = methods.some((m3) => !m3.isTemplate);
25294
+ const hasPrompts = methods.some((m3) => m3.isTemplate);
25295
+ const title = hasTools && hasPrompts ? "Methods & Prompts" : hasPrompts ? "Prompts" : "Methods";
25296
+ return b2`
25297
+ ${this._renderAnchorNav()}
25298
+ <div id="photon-methods" class="bento-methods">
25299
+ <h3 class="bento-section-title">${title}</h3>
25300
+ <div class="cards-grid">
25301
+ ${methods.map(
25302
+ (method) => b2`
25303
+ <method-card
25304
+ .method=${method}
25305
+ .photonName=${this._selectedPhoton.name}
25306
+ .selected=${this._selectedMethod?.name === method.name}
25307
+ @select=${(e8) => {
25308
+ this._selectedMethod = e8.detail.method;
25309
+ this._view = "form";
25310
+ this._mainTab = "methods";
25311
+ this._updateRoute();
25312
+ }}
25313
+ ></method-card>
25314
+ `
25315
+ )}
25316
+ </div>
25317
+ </div>
25318
+ <div id="photon-prompts" class="bento-bottom-grid">
25319
+ ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25320
+ </div>
25321
+ `;
25322
+ }
25175
25323
  _renderContent() {
25176
25324
  if (this._view === "source") {
25177
25325
  return this._renderSourceView();
@@ -25729,62 +25877,72 @@ ${photon.errorMessage || "Unknown error"}</pre
25729
25877
  ` : ""}
25730
25878
  <div
25731
25879
  class="glass-panel"
25732
- style="padding: 0; overflow: hidden; min-height: calc(100vh - 80px); position: relative; ${hasMultipleUIs ? "border-radius: 0 0 var(--radius-md) var(--radius-md);" : ""}"
25880
+ style="padding: 0; overflow: hidden; ${this._mainTab === "app" ? "flex: 1; display: flex; flex-direction: column;" : "min-height: calc(100vh - 80px);"} position: relative; ${hasMultipleUIs ? "border-radius: 0 0 var(--radius-md) var(--radius-md);" : ""}"
25733
25881
  >
25734
25882
  <mcp-app-renderer
25735
25883
  .mcpName=${this._selectedPhoton.name}
25736
25884
  .appUri=${currentUri}
25737
25885
  .linkedTool=${linkedMethod?.name || ""}
25738
25886
  .theme=${this._theme}
25739
- style="height: calc(100vh - ${hasMultipleUIs ? "120px" : "80px"});"
25887
+ style="${this._mainTab === "app" ? "flex: 1; height: 100%;" : `height: calc(100vh - ${hasMultipleUIs ? "120px" : "80px"});`}"
25740
25888
  ></mcp-app-renderer>
25741
25889
  </div>
25742
25890
 
25743
- ${this._renderPhotonToolbar()} ${this._renderAnchorNav()}
25744
- <div id="photon-methods" class="bento-methods">
25745
- <h3 class="bento-section-title">
25746
- ${(() => {
25891
+ ${this._mainTab !== "app" ? b2`
25892
+ ${this._renderAnchorNav()}
25893
+ <div id="photon-methods" class="bento-methods">
25894
+ <h3 class="bento-section-title">
25895
+ ${(() => {
25747
25896
  const visible = this._getVisibleMethods();
25748
25897
  const hasTools = visible.some((m3) => !m3.isTemplate);
25749
25898
  const hasPrompts = visible.some((m3) => m3.isTemplate);
25750
25899
  return hasTools && hasPrompts ? "Methods & Prompts" : hasPrompts ? "Prompts" : "Methods";
25751
25900
  })()}
25752
- </h3>
25753
- ${this._getVisibleMethods().length > 0 ? b2`
25754
- <div class="cards-grid">
25755
- ${this._getVisibleMethods().map(
25901
+ </h3>
25902
+ ${this._getVisibleMethods().length > 0 ? b2`
25903
+ <div class="cards-grid">
25904
+ ${this._getVisibleMethods().map(
25756
25905
  (method) => b2`
25757
- <method-card
25758
- .method=${method}
25759
- .photonName=${this._selectedPhoton.name}
25760
- .selected=${this._selectedMethod?.name === method.name}
25761
- @select=${(e8) => {
25906
+ <method-card
25907
+ .method=${method}
25908
+ .photonName=${this._selectedPhoton.name}
25909
+ .selected=${this._selectedMethod?.name === method.name}
25910
+ @select=${(e8) => {
25762
25911
  this._selectedMethod = e8.detail.method;
25763
25912
  this._view = "form";
25764
25913
  this._updateRoute();
25765
25914
  }}
25766
- ></method-card>
25767
- `
25915
+ ></method-card>
25916
+ `
25768
25917
  )}
25769
- </div>
25770
- ` : ""}
25771
- </div>
25772
- <div id="photon-prompts" class="bento-bottom-grid">
25773
- ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25774
- </div>
25918
+ </div>
25919
+ ` : ""}
25920
+ </div>
25921
+ <div id="photon-prompts" class="bento-bottom-grid">
25922
+ ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25923
+ </div>
25924
+ ` : ""}
25775
25925
  `;
25776
25926
  }
25777
25927
  if (this._view === "form" && this._selectedMethod) {
25778
25928
  const isAppMain = this._selectedPhoton.isApp && this._selectedMethod.name === "main";
25779
25929
  if (isAppMain && !this._selectedMethod.linkedUi) {
25780
25930
  const otherMethods = this._getVisibleMethods().filter((m3) => m3.name !== "main");
25931
+ const appTabActive = this._mainTab === "app";
25781
25932
  return b2`
25782
25933
  <app-layout
25783
25934
  .photonName=${this._selectedPhoton.name}
25784
25935
  .photonIcon=${this._selectedPhoton.appEntry?.icon || "\u{1F4F1}"}
25936
+ .hideBelow=${appTabActive}
25785
25937
  >
25786
- <div slot="app" style="min-height: calc(100vh - 140px);">
25787
- <div class="glass-panel" style="min-height: calc(100vh - 140px); overflow: hidden;">
25938
+ <div
25939
+ slot="app"
25940
+ style="${appTabActive ? "height: calc(100vh - 80px);" : "min-height: calc(100vh - 140px);"}"
25941
+ >
25942
+ <div
25943
+ class="glass-panel"
25944
+ style="${appTabActive ? "height: calc(100vh - 80px);" : "min-height: calc(100vh - 140px);"} overflow: hidden;"
25945
+ >
25788
25946
  ${this._renderMethodBody({
25789
25947
  photon: this._selectedPhoton,
25790
25948
  method: this._selectedMethod,
@@ -25799,44 +25957,45 @@ ${photon.errorMessage || "Unknown error"}</pre
25799
25957
  </div>
25800
25958
  </div>
25801
25959
  <div slot="popout" style="height: 100%;"></div>
25802
- <div slot="below-fold">
25803
- ${this._renderPhotonToolbar()} ${this._renderAnchorNav()}
25804
- ${otherMethods.length > 0 ? b2`
25805
- <div id="photon-methods" class="bento-methods">
25806
- <h3 class="bento-section-title">
25807
- ${(() => {
25960
+ ${appTabActive ? b2`<div slot="below-fold"></div>` : b2`<div slot="below-fold">
25961
+ ${this._renderAnchorNav()}
25962
+ ${otherMethods.length > 0 ? b2`
25963
+ <div id="photon-methods" class="bento-methods">
25964
+ <h3 class="bento-section-title">
25965
+ ${(() => {
25808
25966
  const hasTools = otherMethods.some((m3) => !m3.isTemplate);
25809
25967
  const hasPrompts = otherMethods.some((m3) => m3.isTemplate);
25810
25968
  return hasTools && hasPrompts ? "Methods & Prompts" : hasPrompts ? "Prompts" : "Methods";
25811
25969
  })()}
25812
- </h3>
25813
- <div class="cards-grid">
25814
- ${otherMethods.map(
25970
+ </h3>
25971
+ <div class="cards-grid">
25972
+ ${otherMethods.map(
25815
25973
  (method) => b2`
25816
- <method-card
25817
- .method=${method}
25818
- .photonName=${this._selectedPhoton.name}
25819
- @select=${(e8) => this._handleMethodSelect(e8)}
25820
- @update-metadata=${this._handleMethodMetadataUpdate}
25821
- ></method-card>
25822
- `
25974
+ <method-card
25975
+ .method=${method}
25976
+ .photonName=${this._selectedPhoton.name}
25977
+ @select=${(e8) => this._handleMethodSelect(e8)}
25978
+ @update-metadata=${this._handleMethodMetadataUpdate}
25979
+ ></method-card>
25980
+ `
25823
25981
  )}
25824
- </div>
25825
- </div>
25826
- ` : ""}
25827
- <div id="photon-prompts" class="bento-bottom-grid">
25828
- ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25829
- </div>
25830
- </div>
25982
+ </div>
25983
+ </div>
25984
+ ` : ""}
25985
+ <div id="photon-prompts" class="bento-bottom-grid">
25986
+ ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25987
+ </div>
25988
+ </div>`}
25831
25989
  </app-layout>
25832
25990
  `;
25833
25991
  }
25834
25992
  if (this._selectedMethod.linkedUi) {
25835
25993
  const otherMethods = isAppMain ? this._getVisibleMethods().filter((m3) => m3.name !== "main") : [];
25836
25994
  const isExternalMCP = this._selectedPhoton.isExternalMCP;
25995
+ const appFillStyle = this._mainTab === "app" && isAppMain ? "height: 100%; min-height: 0;" : "height: calc(100vh - 140px);";
25837
25996
  const appRenderer = this._isExecuting ? b2`
25838
25997
  <div
25839
- style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; height: calc(100vh - 140px);"
25998
+ style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; ${appFillStyle}"
25840
25999
  >
25841
26000
  <span class="spinner"></span>
25842
26001
  <span style="color: var(--t-muted); font-size: 13px;">
@@ -25849,7 +26008,7 @@ ${photon.errorMessage || "Unknown error"}</pre
25849
26008
  .appUri=${`ui://${this._selectedPhoton.name}/${this._selectedMethod.linkedUi}`}
25850
26009
  .linkedTool=${this._selectedMethod.name}
25851
26010
  .theme=${this._theme}
25852
- style="height: calc(100vh - 140px);"
26011
+ style="${appFillStyle}"
25853
26012
  ></mcp-app-renderer>
25854
26013
  ` : b2`
25855
26014
  <custom-ui-renderer
@@ -25859,7 +26018,7 @@ ${photon.errorMessage || "Unknown error"}</pre
25859
26018
  .theme=${this._theme}
25860
26019
  .initialResult=${this._lastResult}
25861
26020
  .revision=${this._customUiRevision}
25862
- style="height: calc(100vh - 140px);"
26021
+ style="${appFillStyle}"
25863
26022
  ></custom-ui-renderer>
25864
26023
  `;
25865
26024
  if (isAppMain) {
@@ -25877,7 +26036,7 @@ ${photon.errorMessage || "Unknown error"}</pre
25877
26036
  ${this._splitPanels.map(
25878
26037
  (panel) => b2`
25879
26038
  <div
25880
- style="flex: 1; min-width: 0; min-height: 0; overflow: auto; background: var(--bg-panel);"
26039
+ style="flex: 1; min-width: 0; min-height: 0; overflow: hidden; background: var(--bg-panel);"
25881
26040
  >
25882
26041
  ${panel.type === "method" ? this._renderSinglePanel(this._buildAdditionalPanelOpts(panel)) : this._renderSourcePanel(panel.id)}
25883
26042
  </div>
@@ -25886,46 +26045,54 @@ ${photon.errorMessage || "Unknown error"}</pre
25886
26045
  </div>
25887
26046
  `;
25888
26047
  }
26048
+ const appTabActive2 = this._mainTab === "app";
25889
26049
  return b2`
25890
26050
  <app-layout
25891
26051
  .photonName=${this._selectedPhoton.name}
25892
26052
  .photonIcon=${this._selectedPhoton.appEntry?.icon || "\u{1F4F1}"}
26053
+ .hideBelow=${appTabActive2}
25893
26054
  >
25894
- <div slot="app" style="min-height: calc(100vh - 140px);">${appRenderer}</div>
26055
+ <div
26056
+ slot="app"
26057
+ style="${appTabActive2 ? "height: 100%; min-height: 0; display: flex; flex-direction: column;" : "min-height: calc(100vh - 140px);"}"
26058
+ >
26059
+ ${appRenderer}
26060
+ </div>
25895
26061
  <!-- Popout slot is lazily populated when app-layout toggles popout mode.
25896
26062
  Eagerly creating a second renderer causes Safari to load two
25897
26063
  iframes simultaneously (one with zero dimensions), leading to
25898
26064
  blank screens. -->
25899
26065
  <div slot="popout" style="height: 100%;"></div>
25900
- <div slot="below-fold">
25901
- ${this._renderPhotonToolbar()} ${this._renderAnchorNav()}
25902
- ${otherMethods.length > 0 ? b2`
25903
- <div id="photon-methods" class="bento-methods">
25904
- <h3 class="bento-section-title">
25905
- ${(() => {
26066
+ ${appTabActive2 ? b2`<div slot="below-fold"></div>` : b2`<div slot="below-fold">
26067
+ ${this._renderAnchorNav()}
26068
+ ${otherMethods.length > 0 ? b2`
26069
+ <div id="photon-methods" class="bento-methods">
26070
+ <h3 class="bento-section-title">
26071
+ ${(() => {
25906
26072
  const hasTools = otherMethods.some((m3) => !m3.isTemplate);
25907
26073
  const hasPrompts = otherMethods.some((m3) => m3.isTemplate);
25908
26074
  return hasTools && hasPrompts ? "Methods & Prompts" : hasPrompts ? "Prompts" : "Methods";
25909
26075
  })()}
25910
- </h3>
25911
- <div class="cards-grid">
25912
- ${otherMethods.map(
26076
+ </h3>
26077
+ <div class="cards-grid">
26078
+ ${otherMethods.map(
25913
26079
  (method) => b2`
25914
- <method-card
25915
- .method=${method}
25916
- .photonName=${this._selectedPhoton.name}
25917
- @select=${(e8) => this._handleMethodSelect(e8)}
25918
- @update-metadata=${this._handleMethodMetadataUpdate}
25919
- ></method-card>
25920
- `
26080
+ <method-card
26081
+ .method=${method}
26082
+ .photonName=${this._selectedPhoton.name}
26083
+ .editable=${!!this._selectedPhoton.editable && !this._selectedPhoton.isExternalMCP}
26084
+ @select=${(e8) => this._handleMethodSelect(e8)}
26085
+ @update-metadata=${this._handleMethodMetadataUpdate}
26086
+ ></method-card>
26087
+ `
25921
26088
  )}
25922
- </div>
25923
- </div>
25924
- ` : ""}
25925
- <div id="photon-prompts" class="bento-bottom-grid">
25926
- ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25927
- </div>
25928
- </div>
26089
+ </div>
26090
+ </div>
26091
+ ` : ""}
26092
+ <div id="photon-prompts" class="bento-bottom-grid">
26093
+ ${this._renderPromptsSection()} ${this._renderResourcesSection()}
26094
+ </div>
26095
+ </div>`}
25929
26096
  </app-layout>
25930
26097
  `;
25931
26098
  }
@@ -25965,7 +26132,7 @@ ${photon.errorMessage || "Unknown error"}</pre
25965
26132
  ${this._splitPanels.map(
25966
26133
  (panel) => b2`
25967
26134
  <div
25968
- style="flex: 1; min-width: 0; min-height: 0; overflow: auto; background: var(--bg-panel);"
26135
+ style="flex: 1; min-width: 0; min-height: 0; overflow: hidden; background: var(--bg-panel);"
25969
26136
  >
25970
26137
  ${panel.type === "method" ? this._renderSinglePanel(this._buildAdditionalPanelOpts(panel)) : this._renderSourcePanel(panel.id)}
25971
26138
  </div>
@@ -26001,8 +26168,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26001
26168
  return b2` ${this._renderMethodContent()} `;
26002
26169
  }
26003
26170
  return b2`
26004
- ${this._renderPhotonToolbar()} ${this._editingIcon ? this._renderEmojiPicker() : ""}
26005
- ${this._renderAnchorNav()}
26171
+ ${this._editingIcon ? this._renderEmojiPicker() : ""} ${this._renderAnchorNav()}
26006
26172
 
26007
26173
  <div id="photon-methods" class="bento-methods">
26008
26174
  <h3 class="bento-section-title">
@@ -26075,6 +26241,50 @@ ${photon.errorMessage || "Unknown error"}</pre
26075
26241
  _closeSidebar() {
26076
26242
  this._sidebarVisible = false;
26077
26243
  }
26244
+ _handleSplitResizeStart(e8) {
26245
+ e8.preventDefault();
26246
+ const divider = e8.currentTarget;
26247
+ divider.setPointerCapture(e8.pointerId);
26248
+ divider.classList.add("dragging");
26249
+ const container = divider.parentElement;
26250
+ const containerRect = container.getBoundingClientRect();
26251
+ const startX = e8.clientX;
26252
+ const primaryPanel = divider.previousElementSibling;
26253
+ const startWidth = primaryPanel.getBoundingClientRect().width;
26254
+ const onMove = (moveEvent) => {
26255
+ const delta = moveEvent.clientX - startX;
26256
+ const minWidth = 200;
26257
+ const maxWidth = containerRect.width - 200 - 5;
26258
+ this._splitPrimaryWidth = Math.min(maxWidth, Math.max(minWidth, startWidth + delta));
26259
+ };
26260
+ const onUp = () => {
26261
+ divider.classList.remove("dragging");
26262
+ divider.removeEventListener("pointermove", onMove);
26263
+ divider.removeEventListener("pointerup", onUp);
26264
+ };
26265
+ divider.addEventListener("pointermove", onMove);
26266
+ divider.addEventListener("pointerup", onUp);
26267
+ }
26268
+ _handleSidebarResizeStart(e8) {
26269
+ e8.preventDefault();
26270
+ const handle = e8.currentTarget;
26271
+ handle.setPointerCapture(e8.pointerId);
26272
+ handle.classList.add("dragging");
26273
+ const startX = e8.clientX;
26274
+ const startWidth = this._sidebarWidth;
26275
+ const onMove = (moveEvent) => {
26276
+ const newWidth = Math.min(500, Math.max(200, startWidth + moveEvent.clientX - startX));
26277
+ this._sidebarWidth = newWidth;
26278
+ };
26279
+ const onUp = () => {
26280
+ handle.classList.remove("dragging");
26281
+ localStorage.setItem("beam-sidebar-width", String(this._sidebarWidth));
26282
+ handle.removeEventListener("pointermove", onMove);
26283
+ handle.removeEventListener("pointerup", onUp);
26284
+ };
26285
+ handle.addEventListener("pointermove", onMove);
26286
+ handle.addEventListener("pointerup", onUp);
26287
+ }
26078
26288
  _handlePhotonSelectMobile(e8) {
26079
26289
  this._closeSidebar();
26080
26290
  void this._handlePhotonSelect(e8);
@@ -26141,6 +26351,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26141
26351
  }
26142
26352
  if (this._selectedPhoton.isExternalMCP && this._selectedPhoton.hasMcpApp) {
26143
26353
  this._view = "mcp-app";
26354
+ this._mainTab = "app";
26144
26355
  this._updateRoute();
26145
26356
  return;
26146
26357
  }
@@ -26168,18 +26379,20 @@ ${photon.errorMessage || "Unknown error"}</pre
26168
26379
  }
26169
26380
  this._selectedMethod = this._selectedPhoton.appEntry;
26170
26381
  this._view = "form";
26382
+ this._mainTab = "app";
26171
26383
  this._updateRoute();
26172
26384
  this._maybeAutoInvoke(this._selectedPhoton.appEntry);
26173
26385
  return;
26174
26386
  } else {
26175
26387
  this._view = "list";
26388
+ this._mainTab = "methods";
26176
26389
  }
26177
26390
  this._updateRoute();
26178
26391
  }
26179
26392
  /** Fetch available instances for a stateful photon from the server */
26180
26393
  async _fetchInstances(photonName) {
26181
26394
  try {
26182
- const res = await fetch(`/api/instances/${photonName}`, {
26395
+ const res = await fetch(`/api/instances/${encodeURIComponent(photonName)}`, {
26183
26396
  signal: AbortSignal.timeout(1e4)
26184
26397
  });
26185
26398
  if (res.ok) {
@@ -26305,6 +26518,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26305
26518
  return b2`<p>${cleaned}</p>`;
26306
26519
  }
26307
26520
  _renderMethodContent() {
26521
+ const showBackButton = this._mainTab === "methods" || !this._selectedPhoton?.isApp;
26308
26522
  if (this._isHtmlUiMode()) {
26309
26523
  return b2`
26310
26524
  <div class="glass-panel html-ui-panel" style="padding: 0; overflow: hidden;">
@@ -26325,10 +26539,10 @@ ${photon.errorMessage || "Unknown error"}</pre
26325
26539
  }
26326
26540
  if (this._splitPanels.length > 0) {
26327
26541
  return b2`
26328
- <div style="display: flex; gap: 1px; height: 100%; overflow: hidden; width: 100%;">
26542
+ <div style="display: flex; height: 100%; overflow: hidden; width: 100%;">
26329
26543
  <!-- Primary Panel -->
26330
26544
  <div
26331
- style="flex: 1; min-width: 0; min-height: 0; overflow: auto; background: var(--bg-panel);"
26545
+ style="${this._splitPrimaryWidth != null ? `width: ${this._splitPrimaryWidth}px; flex-shrink: 0;` : "flex: 1;"} min-width: 0; min-height: 0; overflow: auto; background: var(--bg-panel);"
26332
26546
  >
26333
26547
  ${this._renderSinglePanel({
26334
26548
  photon: this._selectedPhoton,
@@ -26357,7 +26571,9 @@ ${photon.errorMessage || "Unknown error"}</pre
26357
26571
  showDelete: false,
26358
26572
  showHelp: !this._selectedPhoton?.isExternalMCP
26359
26573
  }),
26360
- onOverflowSelect: (id2) => this._handleOverflowAction(id2)
26574
+ onOverflowSelect: (id2) => this._handleOverflowAction(id2),
26575
+ onBack: showBackButton ? () => void this._handleBackFromMethod() : void 0,
26576
+ backLabel: this._selectedPhoton?.name
26361
26577
  })}
26362
26578
  </div>
26363
26579
 
@@ -26365,7 +26581,11 @@ ${photon.errorMessage || "Unknown error"}</pre
26365
26581
  ${this._splitPanels.map(
26366
26582
  (panel) => b2`
26367
26583
  <div
26368
- style="flex: 1; min-width: 0; min-height: 0; overflow: auto; background: var(--bg-panel);"
26584
+ class="split-divider"
26585
+ @pointerdown=${(e8) => this._handleSplitResizeStart(e8)}
26586
+ ></div>
26587
+ <div
26588
+ style="flex: 1; min-width: 0; min-height: 0; overflow: hidden; background: var(--bg-panel);"
26369
26589
  >
26370
26590
  ${panel.type === "method" ? this._renderSinglePanel(this._buildAdditionalPanelOpts(panel)) : this._renderSourcePanel(panel.id)}
26371
26591
  </div>
@@ -26410,7 +26630,9 @@ ${photon.errorMessage || "Unknown error"}</pre
26410
26630
  showDelete: false,
26411
26631
  showHelp: !this._selectedPhoton?.isExternalMCP
26412
26632
  }),
26413
- onOverflowSelect: (id2) => this._handleOverflowAction(id2)
26633
+ onOverflowSelect: (id2) => this._handleOverflowAction(id2),
26634
+ onBack: showBackButton ? () => void this._handleBackFromMethod() : void 0,
26635
+ backLabel: this._selectedPhoton?.name
26414
26636
  });
26415
26637
  }
26416
26638
  /** Render a single panel with self-contained header */
@@ -26426,6 +26648,33 @@ ${photon.errorMessage || "Unknown error"}</pre
26426
26648
  class="panel-header"
26427
26649
  style="display: flex; align-items: center; gap: 8px; padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid var(--border-glass); flex-shrink: 0; position: relative;"
26428
26650
  >
26651
+ <!-- Back button -->
26652
+ ${opts.onBack ? b2`<button
26653
+ @click=${() => opts.onBack()}
26654
+ style="padding: 0; width: 24px; height: 24px; background: none; border: 1px solid var(--border-glass); border-radius: var(--radius-xs, 4px); color: var(--t-muted); cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all 0.15s ease;"
26655
+ @mouseenter=${(e8) => {
26656
+ e8.target.style.color = "var(--t-primary)";
26657
+ e8.target.style.borderColor = "var(--accent-primary)";
26658
+ }}
26659
+ @mouseleave=${(e8) => {
26660
+ e8.target.style.color = "var(--t-muted)";
26661
+ e8.target.style.borderColor = "var(--border-glass)";
26662
+ }}
26663
+ title="Back to ${opts.backLabel || "methods"}"
26664
+ >
26665
+ <svg
26666
+ width="14"
26667
+ height="14"
26668
+ viewBox="0 0 24 24"
26669
+ fill="none"
26670
+ stroke="currentColor"
26671
+ stroke-width="2"
26672
+ stroke-linecap="round"
26673
+ stroke-linejoin="round"
26674
+ >
26675
+ <path d="m15 18-6-6 6-6" />
26676
+ </svg>
26677
+ </button>` : ""}
26429
26678
  <!-- LED dot (stateful/live indicator) -->
26430
26679
  ${opts.isStateful ? b2`<span
26431
26680
  style="width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: ${opts.isLive ? "var(--color-success, #22c55e)" : "var(--t-tertiary, #666)"}; box-shadow: ${opts.isLive ? "0 0 6px var(--color-success, #22c55e)" : "none"};"
@@ -26506,9 +26755,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26506
26755
  _renderMethodBody(opts) {
26507
26756
  const hasParams = !!opts.method?.params?.properties && Object.keys(opts.method.params.properties).length > 0;
26508
26757
  return b2`
26509
- <div
26510
- style="display: flex; flex-direction: column; flex: 1; min-height: 0; overflow-y: auto; scrollbar-gutter: stable;"
26511
- >
26758
+ <div style="display: flex; flex-direction: column; flex: 1; min-height: 0;">
26512
26759
  ${opts.appSurface ? "" : this._renderDescription(opts.method.description)}
26513
26760
  ${opts.appSurface && !hasParams ? "" : b2`
26514
26761
  <invoke-form
@@ -26618,6 +26865,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26618
26865
  /** Close all split panels and return to single-panel mode */
26619
26866
  _closeSecondPanel() {
26620
26867
  this._splitPanels = [];
26868
+ this._splitPrimaryWidth = null;
26621
26869
  this._methodPickerOpen = false;
26622
26870
  this._methodPickerPanelId = null;
26623
26871
  this._updateRoute();
@@ -26665,17 +26913,11 @@ ${photon.errorMessage || "Unknown error"}</pre
26665
26913
  const panel = this._splitPanels.find((p5) => p5.id === panelId);
26666
26914
  if (!panel || panel.type !== "method" || !panel.method) return;
26667
26915
  this._updatePanel(panelId, { executing: true, result: null, progress: null, formParams: args });
26916
+ const progressToken = `panel_${panelId}_${Date.now()}`;
26917
+ this._panelProgressTokens.set(progressToken, panelId);
26668
26918
  try {
26669
26919
  const toolName = `${this._selectedPhoton.name}/${panel.method.name}`;
26670
- const result = await mcpClient.callTool(
26671
- toolName,
26672
- args,
26673
- void 0,
26674
- panel.instance || this._currentInstance,
26675
- (progress) => {
26676
- this._updatePanel(panelId, { progress });
26677
- }
26678
- );
26920
+ const result = await mcpClient.callTool(toolName, args, progressToken);
26679
26921
  this._updatePanel(panelId, {
26680
26922
  result: mcpClient.parseToolResult(result),
26681
26923
  executing: false,
@@ -26688,6 +26930,8 @@ ${photon.errorMessage || "Unknown error"}</pre
26688
26930
  executing: false,
26689
26931
  progress: null
26690
26932
  });
26933
+ } finally {
26934
+ this._panelProgressTokens.delete(progressToken);
26691
26935
  }
26692
26936
  }
26693
26937
  /** Change the method in a split panel */
@@ -26794,7 +27038,8 @@ ${photon.errorMessage || "Unknown error"}</pre
26794
27038
  void this._runTests();
26795
27039
  break;
26796
27040
  case "help":
26797
- this._showPhotonHelp = true;
27041
+ this._mainTab = "help";
27042
+ void this._loadPhotonHelp();
26798
27043
  break;
26799
27044
  default:
26800
27045
  this._handleContextAction(new CustomEvent("context-action", { detail: { action: id2 } }));
@@ -27463,6 +27708,61 @@ ${photon.errorMessage || "Unknown error"}</pre
27463
27708
  _closePhotonHelp() {
27464
27709
  this._showPhotonHelp = false;
27465
27710
  }
27711
+ /** Render the inline help view (used as a tab, not a modal) */
27712
+ _renderPhotonHelpView() {
27713
+ const markdown = this._photonHelpLoading ? this._generatePhotonHelpMarkdown() : this._photonHelpMarkdown || this._generatePhotonHelpMarkdown();
27714
+ let htmlContent = markdown;
27715
+ if (window.marked) {
27716
+ const mermaidBlocks = [];
27717
+ let processed = markdown.replace(
27718
+ /```mermaid\s*\n([\s\S]*?)```/g,
27719
+ (_match, code) => {
27720
+ const id2 = `help-mermaid-${Math.random().toString(36).substr(2, 9)}`;
27721
+ mermaidBlocks.push({ id: id2, code: code.trim() });
27722
+ return `<div data-mermaid-id="${id2}" style="min-height: 80px; display: flex; align-items: center; justify-content: center; color: var(--t-muted);">Loading diagram...</div>`;
27723
+ }
27724
+ );
27725
+ htmlContent = window.marked.parse(processed);
27726
+ if (mermaidBlocks.length > 0 && window.mermaid) {
27727
+ const mermaid = window.mermaid;
27728
+ const isDark = this.getAttribute("data-theme") !== "light";
27729
+ mermaid.initialize({ startOnLoad: false, theme: isDark ? "dark" : "default" });
27730
+ requestAnimationFrame(() => {
27731
+ for (const { id: id2, code } of mermaidBlocks) {
27732
+ const el2 = this.shadowRoot?.querySelector(`[data-mermaid-id="${id2}"]`);
27733
+ if (el2) {
27734
+ mermaid.render(id2 + "-svg", code).then(({ svg: svg2 }) => {
27735
+ el2.innerHTML = svg2;
27736
+ el2.style.minHeight = "";
27737
+ el2.style.background = isDark ? "hsla(220, 15%, 18%, 0.8)" : "hsla(0, 0%, 97%, 0.8)";
27738
+ el2.style.borderRadius = "8px";
27739
+ el2.style.padding = "12px";
27740
+ }).catch(() => {
27741
+ el2.textContent = "Diagram rendering failed";
27742
+ });
27743
+ }
27744
+ }
27745
+ });
27746
+ }
27747
+ }
27748
+ return b2`
27749
+ <div
27750
+ style="display: flex; flex-direction: column; height: 100%; overflow: auto; padding: var(--space-lg);"
27751
+ >
27752
+ <div style="max-width: 700px; width: 100%;">
27753
+ <h2 class="text-gradient" style="margin: 0 0 var(--space-md) 0;">
27754
+ Help
27755
+ ${this._photonHelpLoading ? b2`<span style="font-size: 0.7em; opacity: 0.6; margin-left: 8px;"
27756
+ >Loading...</span
27757
+ >` : ""}
27758
+ </h2>
27759
+ <div class="markdown-body" style="color: var(--t-default);">
27760
+ ${window.marked ? b2`${o5(htmlContent)}` : b2`<pre style="white-space: pre-wrap;">${markdown}</pre>`}
27761
+ </div>
27762
+ </div>
27763
+ </div>
27764
+ `;
27765
+ }
27466
27766
  _generatePhotonHelpMarkdown() {
27467
27767
  if (!this._selectedPhoton) return "";
27468
27768
  const photon = this._selectedPhoton;
@@ -27596,7 +27896,8 @@ ${photon.errorMessage || "Unknown error"}</pre
27596
27896
  const hasInstallSource = !!this._selectedPhoton?.installSource;
27597
27897
  const isStateful = !!this._selectedPhoton?.stateful;
27598
27898
  const hasSettings = !!this._selectedPhoton?.hasSettings;
27599
- const sourceMode = isExternalMCP ? "hidden" : this._view === "source" ? "edit" : hasPath && !this._selectedPhoton?.internal ? "source" : "hidden";
27899
+ const isEditable = !!this._selectedPhoton?.editable && !isExternalMCP;
27900
+ const sourceMode = isExternalMCP ? "hidden" : this._view === "source" ? "edit" : hasPath && !this._selectedPhoton?.internal && isEditable ? "source" : "hidden";
27600
27901
  return b2`
27601
27902
  <context-bar
27602
27903
  .photon=${this._selectedPhoton}
@@ -27608,17 +27909,17 @@ ${photon.errorMessage || "Unknown error"}</pre
27608
27909
  .instances=${this._instances}
27609
27910
  .instanceSelectorMode=${this._instanceSelectorMode}
27610
27911
  .autoInstance=${this._autoInstance}
27611
- .sourceMode=${sourceMode}
27612
- .hasSettings=${hasSettings && !isExternalMCP}
27912
+ .sourceMode=${"hidden"}
27913
+ .hasSettings=${false}
27613
27914
  .overflowItems=${this._buildOverflowItems({
27614
27915
  showRefresh: !isExternalMCP,
27615
27916
  showEdit: false,
27616
27917
  showUpgrade: !!this._selectedPhoton?.hasUpdate,
27617
- showRename: !isExternalMCP,
27918
+ showRename: isEditable,
27618
27919
  showViewSource: false,
27619
- showFork: hasInstallSource && !isExternalMCP,
27920
+ showFork: !isEditable && !isExternalMCP,
27620
27921
  showContribute: hasInstallSource && !isExternalMCP,
27621
- showDelete: !isExternalMCP,
27922
+ showDelete: isEditable,
27622
27923
  showHelp: !isExternalMCP
27623
27924
  })}
27624
27925
  @context-action=${this._handleContextAction}
@@ -27762,6 +28063,7 @@ ${photon.errorMessage || "Unknown error"}</pre
27762
28063
  _renderPhotonHeader() {
27763
28064
  if (!this._selectedPhoton) return "";
27764
28065
  const isApp = this._selectedPhoton.isApp;
28066
+ const isEditable = !!this._selectedPhoton.editable && !this._selectedPhoton.isExternalMCP;
27765
28067
  const methods = this._selectedPhoton.methods || [];
27766
28068
  const templateCount = methods.filter((m3) => m3.isTemplate).length;
27767
28069
  const toolCount = methods.filter((m3) => !m3.isTemplate).length;
@@ -27774,42 +28076,42 @@ ${photon.errorMessage || "Unknown error"}</pre
27774
28076
  const displayIcon = customIcon || defaultIcon;
27775
28077
  return b2`
27776
28078
  <header class="photon-header">
27777
- <button
27778
- type="button"
27779
- class="photon-icon-large editable ${isApp ? "" : "mcp-icon"}"
27780
- @click=${this._startEditingIcon}
27781
- title="Click to change icon"
27782
- aria-label="Change icon"
27783
- >
27784
- ${displayIcon}
27785
- </button>
28079
+ ${isEditable ? b2`<button
28080
+ type="button"
28081
+ class="photon-icon-large editable ${isApp ? "" : "mcp-icon"}"
28082
+ @click=${this._startEditingIcon}
28083
+ title="Click to change icon"
28084
+ aria-label="Change icon"
28085
+ >
28086
+ ${displayIcon}
28087
+ </button>` : b2`<span class="photon-icon-large ${isApp ? "" : "mcp-icon"}">${displayIcon}</span>`}
27786
28088
  ${this._editingIcon ? this._renderEmojiPicker() : ""}
27787
28089
  <div class="photon-header-info">
27788
28090
  <h1 class="photon-header-name">${this._selectedPhoton.name}</h1>
27789
- ${this._editingDescription ? b2`
27790
- <p class="photon-header-desc editable editing">
27791
- <input
27792
- class="editable-input"
27793
- type="text"
27794
- .value=${this._editedDescription}
27795
- placeholder="Add a description..."
27796
- @input=${(e8) => this._editedDescription = e8.target.value}
27797
- @blur=${this._saveDescription}
27798
- @keydown=${this._handleDescriptionKeydown}
27799
- autofocus
27800
- />
27801
- </p>
27802
- ` : b2`
27803
- <button
27804
- type="button"
27805
- class="photon-header-desc editable ${isGenericDesc ? "placeholder" : ""}"
27806
- @click=${this._startEditingDescription}
27807
- title="Click to edit description"
27808
- aria-label="Edit description"
27809
- >
27810
- ${isGenericDesc ? "Click to add a description..." : description}
27811
- </button>
27812
- `}
28091
+ ${isEditable ? this._editingDescription ? b2`
28092
+ <p class="photon-header-desc editable editing">
28093
+ <input
28094
+ class="editable-input"
28095
+ type="text"
28096
+ .value=${this._editedDescription}
28097
+ placeholder="Add a description..."
28098
+ @input=${(e8) => this._editedDescription = e8.target.value}
28099
+ @blur=${this._saveDescription}
28100
+ @keydown=${this._handleDescriptionKeydown}
28101
+ autofocus
28102
+ />
28103
+ </p>
28104
+ ` : b2`
28105
+ <button
28106
+ type="button"
28107
+ class="photon-header-desc editable ${isGenericDesc ? "placeholder" : ""}"
28108
+ @click=${this._startEditingDescription}
28109
+ title="Click to edit description"
28110
+ aria-label="Edit description"
28111
+ >
28112
+ ${isGenericDesc ? "Click to add a description..." : description}
28113
+ </button>
28114
+ ` : b2`<p class="photon-header-desc">${description}</p>`}
27813
28115
  <div class="photon-header-meta">
27814
28116
  ${isApp ? b2`<span class="photon-badge app">App</span>` : b2`<span class="photon-badge">MCP</span>`}
27815
28117
  ${templateCount > 0 && toolCount === 0 ? b2`<span class="photon-badge"
@@ -28275,14 +28577,133 @@ ${photon.errorMessage || "Unknown error"}</pre
28275
28577
  </div>
28276
28578
  `;
28277
28579
  }
28580
+ /** Render the settings view — a professional two-column settings panel */
28581
+ _renderSettingsView() {
28582
+ const photon = this._selectedPhoton;
28583
+ if (!photon) return "";
28584
+ const settingsMethod = photon.methods?.find((m3) => m3.name === "settings");
28585
+ if (!settingsMethod)
28586
+ return b2`<div style="padding: var(--space-xl); color: var(--t-muted); text-align: center;">
28587
+ No settings available for this photon.
28588
+ </div>`;
28589
+ const params = settingsMethod.params;
28590
+ const properties = params?.properties || {};
28591
+ const propEntries = Object.entries(properties);
28592
+ const hasResult = this._lastResult !== null;
28593
+ let statusEntries = [];
28594
+ if (hasResult) {
28595
+ try {
28596
+ const resultData = typeof this._lastResult === "string" ? JSON.parse(this._lastResult) : Array.isArray(this._lastResult) ? this._lastResult.find((c5) => c5.type === "text")?.text ? JSON.parse(this._lastResult.find((c5) => c5.type === "text").text) : this._lastResult : this._lastResult;
28597
+ if (resultData && typeof resultData === "object" && !Array.isArray(resultData)) {
28598
+ statusEntries = Object.entries(resultData).filter(([, v2]) => v2 !== null && v2 !== void 0).map(([k3, v2]) => [k3, String(v2)]);
28599
+ }
28600
+ } catch {
28601
+ }
28602
+ }
28603
+ return b2`
28604
+ <div style="padding: var(--space-lg); max-width: 900px; margin: 0 auto; width: 100%;">
28605
+ <!-- Settings Header -->
28606
+ <div style="margin-bottom: var(--space-xl);">
28607
+ <h2
28608
+ style="font-family: var(--font-display); font-size: var(--text-xl); font-weight: 700; color: var(--t-primary); margin: 0 0 4px 0;"
28609
+ >
28610
+ ${photon.name} Settings
28611
+ </h2>
28612
+ ${settingsMethod.description ? b2`<p
28613
+ style="color: var(--t-muted); font-size: var(--text-sm); margin: 0; line-height: 1.5;"
28614
+ >
28615
+ View or update photon configuration. Changes are applied immediately.
28616
+ </p>` : ""}
28617
+ </div>
28618
+
28619
+ <!-- Configuration Section -->
28620
+ ${propEntries.length > 0 ? b2`
28621
+ <div class="glass-panel" style="margin-bottom: var(--space-lg); overflow: hidden;">
28622
+ <div
28623
+ style="padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--border-glass); background: var(--bg-glass);"
28624
+ >
28625
+ <span
28626
+ style="font-family: var(--font-display); font-size: var(--text-sm); font-weight: 600; color: var(--t-primary); text-transform: uppercase; letter-spacing: 0.05em;"
28627
+ >Configuration</span
28628
+ >
28629
+ </div>
28630
+ <div class="method-detail" style="padding: 0;">
28631
+ <invoke-form
28632
+ .params=${params}
28633
+ .loading=${this._isExecuting}
28634
+ .photonName=${photon.name}
28635
+ .methodName=${"settings"}
28636
+ .rememberValues=${this._rememberFormValues}
28637
+ .sharedValues=${this._sharedFormParams ?? this._lastFormParams}
28638
+ .settingsLayout=${true}
28639
+ @submit=${(e8) => void this._handleExecute(e8)}
28640
+ @cancel=${() => {
28641
+ }}
28642
+ ></invoke-form>
28643
+ <div
28644
+ style="display: flex; justify-content: flex-end; padding: var(--space-sm) var(--space-md); border-top: 1px solid var(--border-glass);"
28645
+ >
28646
+ <button
28647
+ class="btn-primary"
28648
+ style="font-size: var(--text-sm); padding: 6px 20px;"
28649
+ @click=${(e8) => {
28650
+ const panel = e8.target.closest(".glass-panel");
28651
+ const form = panel?.querySelector("invoke-form");
28652
+ form?.handleSubmit();
28653
+ }}
28654
+ ?disabled=${this._isExecuting}
28655
+ >
28656
+ ${this._isExecuting ? b2`<span class="btn-loading"
28657
+ ><span class="spinner"></span>Saving...</span
28658
+ >` : "Save Settings"}
28659
+ </button>
28660
+ </div>
28661
+ </div>
28662
+ </div>
28663
+ ` : ""}
28664
+
28665
+ <!-- Status Section (from last result) -->
28666
+ ${statusEntries.length > 0 ? b2`
28667
+ <div class="glass-panel" style="overflow: hidden;">
28668
+ <div
28669
+ style="padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--border-glass); background: var(--bg-glass);"
28670
+ >
28671
+ <span
28672
+ style="font-family: var(--font-display); font-size: var(--text-sm); font-weight: 600; color: var(--t-primary); text-transform: uppercase; letter-spacing: 0.05em;"
28673
+ >Status</span
28674
+ >
28675
+ </div>
28676
+ <div style="padding: 0;">
28677
+ ${statusEntries.map(
28678
+ ([key, value], i7) => b2`
28679
+ <div
28680
+ style="display: grid; grid-template-columns: 200px 1fr; border-bottom: ${i7 < statusEntries.length - 1 ? "1px solid var(--border-glass)" : "none"};"
28681
+ >
28682
+ <div
28683
+ style="padding: 10px var(--space-md); font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--t-muted); background: var(--bg-glass);"
28684
+ >
28685
+ ${key.replace(/([A-Z])/g, " $1").replace(/_/g, " ").trim()}
28686
+ </div>
28687
+ <div
28688
+ style="padding: 10px var(--space-md); font-size: var(--text-sm); color: var(--t-primary); word-break: break-word;"
28689
+ >
28690
+ ${value}
28691
+ </div>
28692
+ </div>
28693
+ `
28694
+ )}
28695
+ </div>
28696
+ </div>
28697
+ ` : ""}
28698
+ </div>
28699
+ `;
28700
+ }
28278
28701
  /** Render source code as an inline view (not a modal) — Phase 2 */
28279
28702
  _renderSourceView() {
28280
28703
  if (!this._sourceData) {
28281
28704
  return b2`
28282
- ${this._renderPhotonToolbar({ showConfigure: false, showCopyConfig: false })}
28283
28705
  <div
28284
- class="glass-panel"
28285
- style="padding: var(--space-xl); text-align: center; color: var(--t-muted);"
28706
+ style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--t-muted);"
28286
28707
  >
28287
28708
  Loading source...
28288
28709
  </div>
@@ -28313,26 +28734,56 @@ ${photon.errorMessage || "Unknown error"}</pre
28313
28734
  if (Prism && Prism.languages[language2]) {
28314
28735
  highlightedCode = Prism.highlight(this._sourceData.code, Prism.languages[language2], language2);
28315
28736
  }
28737
+ const isProtected = !this._selectedPhoton?.editable;
28316
28738
  return b2`
28317
- ${this._renderPhotonToolbar({ showConfigure: false, showCopyConfig: false })}
28318
- <div
28319
- class="glass-panel"
28320
- style="margin-top: var(--space-md); display: flex; flex-direction: column; max-height: calc(100vh - 120px);"
28321
- >
28739
+ <div style="display: flex; flex-direction: column; height: 100%;">
28322
28740
  <div
28323
- style="display: flex; justify-content: space-between; align-items: center; padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--border-glass); flex-shrink: 0;"
28741
+ style="display: flex; justify-content: space-between; align-items: center; padding: 6px var(--space-md); border-bottom: 1px solid var(--border-glass); flex-shrink: 0; background: var(--bg-panel);"
28324
28742
  >
28325
- <div style="font-family: var(--font-mono); font-size: 0.85rem; color: var(--t-muted);">
28326
- ${filename}
28743
+ <div style="display: flex; align-items: center; gap: 8px;">
28744
+ <div style="font-family: var(--font-mono); font-size: 0.85rem; color: var(--t-muted);">
28745
+ ${filename}
28746
+ </div>
28747
+ ${isProtected ? b2`<span
28748
+ style="font-size: var(--text-2xs); padding: 2px 6px; background: var(--bg-glass-strong); border: 1px solid var(--border-glass); border-radius: var(--radius-xs); color: var(--t-muted); text-transform: uppercase; letter-spacing: 0.05em;"
28749
+ >Protected</span
28750
+ >` : ""}
28751
+ </div>
28752
+ <div style="display: flex; gap: 6px; align-items: center;">
28753
+ ${isProtected ? b2`<button
28754
+ class="action-btn"
28755
+ style="display: inline-flex; align-items: center; background: var(--bg-glass); border: 1px solid var(--accent-secondary); color: var(--accent-secondary); padding: 4px 10px; border-radius: var(--radius-sm); cursor: pointer; font-size: var(--text-xs);"
28756
+ @click=${this._handleFork}
28757
+ title="Fork to create an editable local copy"
28758
+ >
28759
+ <svg
28760
+ width="12"
28761
+ height="12"
28762
+ viewBox="0 0 24 24"
28763
+ fill="none"
28764
+ stroke="currentColor"
28765
+ stroke-width="2"
28766
+ stroke-linecap="round"
28767
+ stroke-linejoin="round"
28768
+ style="margin-right: 3px;"
28769
+ >
28770
+ <circle cx="12" cy="18" r="3" />
28771
+ <circle cx="6" cy="6" r="3" />
28772
+ <circle cx="18" cy="6" r="3" />
28773
+ <path d="M18 9v2c0 .6-.4 1-1 1H7c-.6 0-1-.4-1-1V9" />
28774
+ <path d="M12 12v3" />
28775
+ </svg>
28776
+ Fork
28777
+ </button>` : ""}
28778
+ <button
28779
+ class="action-btn"
28780
+ style="display: inline-flex; align-items: center; background: var(--bg-glass); border: 1px solid var(--border-glass); color: var(--t-muted); padding: 4px 10px; border-radius: var(--radius-sm); cursor: pointer; font-size: var(--text-xs);"
28781
+ @click=${this._copySourceCode}
28782
+ title="Copy source code"
28783
+ >
28784
+ ${clipboard} Copy
28785
+ </button>
28327
28786
  </div>
28328
- <button
28329
- class="action-btn"
28330
- style="background: var(--bg-glass); border: 1px solid var(--border-glass); color: var(--t-muted); padding: 4px 10px; border-radius: var(--radius-sm); cursor: pointer; font-size: var(--text-xs);"
28331
- @click=${this._copySourceCode}
28332
- title="Copy source code"
28333
- >
28334
- ${clipboard} Copy
28335
- </button>
28336
28787
  </div>
28337
28788
  <pre
28338
28789
  class="language-${language2}"
@@ -28347,7 +28798,6 @@ ${photon.errorMessage || "Unknown error"}</pre
28347
28798
  font-size: 0.85rem;
28348
28799
  line-height: 1.6;
28349
28800
  tab-size: 2;
28350
- border-radius: 0 0 var(--radius-md) var(--radius-md);
28351
28801
  "
28352
28802
  ><code class="language-${language2}" style="display: block; overflow-x: visible;">${Prism ? o5(highlightedCode) : this._sourceData.code}</code></pre>
28353
28803
  </div>
@@ -28406,7 +28856,7 @@ ${photon.errorMessage || "Unknown error"}</pre
28406
28856
  </div>
28407
28857
  </div>
28408
28858
  <div style="display: flex; gap: var(--space-sm);">
28409
- ${this._selectedPhoton?.path && !this._selectedPhoton?.isExternalMCP ? b2`
28859
+ ${this._selectedPhoton?.editable && !this._selectedPhoton?.isExternalMCP ? b2`
28410
28860
  <button
28411
28861
  class="toolbar-btn"
28412
28862
  style="padding: 6px 12px; font-size: 0.85rem; background: var(--accent-primary); border-color: var(--accent-primary); color: white;"
@@ -28601,11 +29051,31 @@ BeamApp.styles = [
28601
29051
  }
28602
29052
 
28603
29053
  .sidebar-area {
28604
- width: 300px;
29054
+ width: var(--sidebar-width, 300px);
28605
29055
  flex-shrink: 0;
28606
29056
  z-index: 10;
28607
29057
  display: flex;
28608
29058
  flex-direction: column;
29059
+ position: relative;
29060
+ overflow: visible;
29061
+ }
29062
+
29063
+ .sidebar-resize-handle {
29064
+ position: absolute;
29065
+ right: -3px;
29066
+ top: 0;
29067
+ bottom: 0;
29068
+ width: 6px;
29069
+ cursor: col-resize;
29070
+ z-index: 20;
29071
+ background: transparent;
29072
+ transition: background 0.15s;
29073
+ }
29074
+
29075
+ .sidebar-resize-handle:hover,
29076
+ .sidebar-resize-handle.dragging {
29077
+ background: var(--accent-primary);
29078
+ opacity: 0.5;
28609
29079
  }
28610
29080
 
28611
29081
  :host(.focus-mode) .sidebar-area {
@@ -28831,10 +29301,20 @@ BeamApp.styles = [
28831
29301
  flex: 1;
28832
29302
  min-width: 0;
28833
29303
  position: relative;
29304
+ display: flex;
29305
+ flex-direction: column;
29306
+ overflow: hidden;
29307
+ }
29308
+
29309
+ .main-content-scroll {
29310
+ flex: 1;
29311
+ min-height: 0;
28834
29312
  overflow-y: auto;
28835
29313
  overflow-x: hidden;
28836
29314
  padding: var(--space-lg);
28837
29315
  scrollbar-gutter: stable;
29316
+ display: flex;
29317
+ flex-direction: column;
28838
29318
  }
28839
29319
 
28840
29320
  /* Page transition when switching photons */
@@ -28855,9 +29335,9 @@ BeamApp.styles = [
28855
29335
 
28856
29336
  .main-toolbar {
28857
29337
  display: flex;
28858
- justify-content: space-between;
28859
29338
  align-items: center;
28860
- margin: calc(-1 * var(--space-lg) + 4px) calc(-1 * var(--space-lg) + 4px) 4px;
29339
+ gap: var(--space-sm);
29340
+ margin-bottom: 8px;
28861
29341
  flex-shrink: 0;
28862
29342
  }
28863
29343
 
@@ -28886,9 +29366,22 @@ BeamApp.styles = [
28886
29366
  margin-left: auto;
28887
29367
  }
28888
29368
 
29369
+ .beam-tab-btn.active {
29370
+ color: var(--accent-secondary);
29371
+ border-color: var(--accent-secondary);
29372
+ }
29373
+
29374
+ .tab-group-divider {
29375
+ width: 1px;
29376
+ height: 16px;
29377
+ background: var(--border-glass);
29378
+ margin: 0 2px;
29379
+ align-self: center;
29380
+ }
29381
+
28889
29382
  .cards-grid {
28890
29383
  display: grid;
28891
- grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
29384
+ grid-template-columns: repeat(auto-fill, minmax(280px, min(100%, 380px)));
28892
29385
  gap: var(--space-md);
28893
29386
  align-items: stretch;
28894
29387
  }
@@ -28940,7 +29433,7 @@ BeamApp.styles = [
28940
29433
  .anchor-nav {
28941
29434
  display: flex;
28942
29435
  gap: var(--space-md);
28943
- margin: var(--space-md) 0 var(--space-lg);
29436
+ margin: 0 0 var(--space-md);
28944
29437
  }
28945
29438
 
28946
29439
  .anchor-link {
@@ -28986,7 +29479,7 @@ BeamApp.styles = [
28986
29479
  display: flex;
28987
29480
  align-items: flex-start;
28988
29481
  gap: var(--space-lg);
28989
- margin-bottom: var(--space-xl);
29482
+ margin-bottom: var(--space-md);
28990
29483
  }
28991
29484
 
28992
29485
  .photon-icon-large {
@@ -30148,6 +30641,34 @@ BeamApp.styles = [
30148
30641
  margin-top: var(--space-md);
30149
30642
  }
30150
30643
 
30644
+ .split-divider {
30645
+ width: 5px;
30646
+ flex-shrink: 0;
30647
+ cursor: col-resize;
30648
+ background: var(--border-glass);
30649
+ position: relative;
30650
+ transition: background 0.15s;
30651
+ }
30652
+
30653
+ .split-divider::after {
30654
+ content: '';
30655
+ position: absolute;
30656
+ top: 50%;
30657
+ left: 50%;
30658
+ transform: translate(-50%, -50%);
30659
+ width: 1px;
30660
+ height: 32px;
30661
+ background: var(--t-muted);
30662
+ border-radius: 2px;
30663
+ opacity: 0.4;
30664
+ }
30665
+
30666
+ .split-divider:hover,
30667
+ .split-divider.dragging {
30668
+ background: var(--accent-primary);
30669
+ opacity: 0.6;
30670
+ }
30671
+
30151
30672
  .method-detail h2 {
30152
30673
  margin-top: 0;
30153
30674
  }
@@ -30383,6 +30904,9 @@ __decorateClass([
30383
30904
  __decorateClass([
30384
30905
  r5()
30385
30906
  ], BeamApp.prototype, "_sidebarVisible", 2);
30907
+ __decorateClass([
30908
+ r5()
30909
+ ], BeamApp.prototype, "_sidebarWidth", 2);
30386
30910
  __decorateClass([
30387
30911
  r5()
30388
30912
  ], BeamApp.prototype, "_focusMode", 2);
@@ -30542,6 +31066,12 @@ __decorateClass([
30542
31066
  __decorateClass([
30543
31067
  r5()
30544
31068
  ], BeamApp.prototype, "_methodPickerPanelId", 2);
31069
+ __decorateClass([
31070
+ r5()
31071
+ ], BeamApp.prototype, "_splitPrimaryWidth", 2);
31072
+ __decorateClass([
31073
+ r5()
31074
+ ], BeamApp.prototype, "_mainTab", 2);
30545
31075
  __decorateClass([
30546
31076
  e7("beam-sidebar")
30547
31077
  ], BeamApp.prototype, "_sidebar", 2);
@@ -30557,6 +31087,12 @@ __decorateClass([
30557
31087
  __decorateClass([
30558
31088
  r5()
30559
31089
  ], BeamApp.prototype, "_forkOriginRepo", 2);
31090
+ __decorateClass([
31091
+ r5()
31092
+ ], BeamApp.prototype, "_forkRequireNewName", 2);
31093
+ __decorateClass([
31094
+ r5()
31095
+ ], BeamApp.prototype, "_forkSuggestedName", 2);
30560
31096
  __decorateClass([
30561
31097
  r5()
30562
31098
  ], BeamApp.prototype, "_forkTargets", 2);
@@ -30576,6 +31112,11 @@ var BeamSidebar = class extends i4 {
30576
31112
  this.reconnecting = false;
30577
31113
  this.updatesAvailable = 0;
30578
31114
  this.pendingApprovals = 0;
31115
+ this.mainTab = "methods";
31116
+ this.isApp = false;
31117
+ this.hasSettings = false;
31118
+ this.isExternalMCP = false;
31119
+ this.hasPath = false;
30579
31120
  this._searchQuery = "";
30580
31121
  this._showFavoritesOnly = false;
30581
31122
  this._favorites = /* @__PURE__ */ new Set();
@@ -30665,6 +31206,11 @@ var BeamSidebar = class extends i4 {
30665
31206
  super.updated(changedProps);
30666
31207
  if (changedProps.has("selectedPhoton")) {
30667
31208
  this._ensureActiveSectionOpen();
31209
+ if (this.selectedPhoton) {
31210
+ this._scrollPhotonIntoView(this.selectedPhoton, false);
31211
+ } else {
31212
+ this._scrollSidebarToTop();
31213
+ }
30668
31214
  }
30669
31215
  }
30670
31216
  get _filteredPhotons() {
@@ -30740,6 +31286,25 @@ var BeamSidebar = class extends i4 {
30740
31286
  title="${this.connected ? "Connected" : this.reconnecting ? "Reconnecting..." : "Disconnected"}"
30741
31287
  ></span>
30742
31288
  </button>
31289
+ <button
31290
+ class="sidebar-minimize-btn"
31291
+ @click=${() => this.dispatchEvent(new CustomEvent("toggle-focus"))}
31292
+ title="Minimize sidebar"
31293
+ >
31294
+ <svg
31295
+ width="14"
31296
+ height="14"
31297
+ viewBox="0 0 24 24"
31298
+ fill="none"
31299
+ stroke="currentColor"
31300
+ stroke-width="2"
31301
+ stroke-linecap="round"
31302
+ stroke-linejoin="round"
31303
+ >
31304
+ <path d="M11 19H4a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h5" />
31305
+ <polyline points="13 15 9 12 13 9" />
31306
+ </svg>
31307
+ </button>
30743
31308
  </div>
30744
31309
  <div class="search-box" role="search">
30745
31310
  <input
@@ -30772,29 +31337,30 @@ var BeamSidebar = class extends i4 {
30772
31337
  </div>
30773
31338
  </div>
30774
31339
 
30775
- ${(() => {
31340
+ <div class="sidebar-scroll">
31341
+ ${(() => {
30776
31342
  const apps = this._sortByRecency(this._apps);
30777
31343
  const configured = this._sortByRecency(this._configured);
30778
31344
  return b2`
30779
- ${apps.length > 0 ? this._renderSection(
31345
+ ${apps.length > 0 ? this._renderSection(
30780
31346
  "apps",
30781
31347
  "APPS",
30782
31348
  apps,
30783
31349
  (p5) => p5.isExternalMCP ? this._renderExternalMCPItem(p5) : this._renderPhotonItem(p5, "app")
30784
31350
  ) : ""}
30785
- ${configured.length > 0 ? this._renderSection(
31351
+ ${configured.length > 0 ? this._renderSection(
30786
31352
  "photons",
30787
31353
  "PHOTONS",
30788
31354
  configured,
30789
31355
  (p5) => this._renderPhotonItem(p5, "configured")
30790
31356
  ) : ""}
30791
- `;
31357
+ `;
30792
31358
  })()}
30793
- ${(() => {
31359
+ ${(() => {
30794
31360
  const needsConfig = this._needsSetup.filter((p5) => p5.errorReason !== "load-error");
30795
31361
  const loadErrors = this._needsSetup.filter((p5) => p5.errorReason === "load-error");
30796
31362
  return b2`
30797
- ${needsConfig.length > 0 ? this._renderSection(
31363
+ ${needsConfig.length > 0 ? this._renderSection(
30798
31364
  "config",
30799
31365
  "NEEDS CONFIGURATION",
30800
31366
  needsConfig,
@@ -30802,7 +31368,7 @@ var BeamSidebar = class extends i4 {
30802
31368
  "attention",
30803
31369
  warning
30804
31370
  ) : ""}
30805
- ${loadErrors.length > 0 ? this._renderSection(
31371
+ ${loadErrors.length > 0 ? this._renderSection(
30806
31372
  "errors",
30807
31373
  "LOAD ERRORS",
30808
31374
  loadErrors,
@@ -30810,35 +31376,36 @@ var BeamSidebar = class extends i4 {
30810
31376
  "attention",
30811
31377
  xMark
30812
31378
  ) : ""}
30813
- `;
31379
+ `;
30814
31380
  })()}
30815
- ${this._nonAppExternalMCPs.length > 0 ? this._renderSection(
31381
+ ${this._nonAppExternalMCPs.length > 0 ? this._renderSection(
30816
31382
  "mcps",
30817
31383
  "MCPS",
30818
31384
  this._sortByRecency(this._nonAppExternalMCPs),
30819
31385
  (mcp) => this._renderExternalMCPItem(mcp)
30820
31386
  ) : ""}
30821
- ${this._apps.length === 0 && this._configured.length === 0 && this._needsSetup.length === 0 && this._nonAppExternalMCPs.length === 0 ? b2`
30822
- <div class="empty-state">
30823
- ${this._searchQuery.trim() ? b2`
30824
- <div class="empty-icon">${search}</div>
30825
- <div class="empty-title">No results</div>
30826
- <div class="empty-hint">No photons match "${this._searchQuery}"</div>
30827
- ` : b2`
30828
- <div class="empty-icon">${packageBox}</div>
30829
- <div class="empty-title">No photons yet</div>
30830
- <div class="empty-hint">
30831
- Add photons from the marketplace or create your own
30832
- </div>
30833
- <button
30834
- class="empty-action"
30835
- @click=${() => this.dispatchEvent(new CustomEvent("marketplace"))}
30836
- >
30837
- ${marketplace} Browse Marketplace
30838
- </button>
30839
- `}
30840
- </div>
30841
- ` : ""}
31387
+ ${this._apps.length === 0 && this._configured.length === 0 && this._needsSetup.length === 0 && this._nonAppExternalMCPs.length === 0 ? b2`
31388
+ <div class="empty-state">
31389
+ ${this._searchQuery.trim() ? b2`
31390
+ <div class="empty-icon">${search}</div>
31391
+ <div class="empty-title">No results</div>
31392
+ <div class="empty-hint">No photons match "${this._searchQuery}"</div>
31393
+ ` : b2`
31394
+ <div class="empty-icon">${packageBox}</div>
31395
+ <div class="empty-title">No photons yet</div>
31396
+ <div class="empty-hint">
31397
+ Add photons from the marketplace or create your own
31398
+ </div>
31399
+ <button
31400
+ class="empty-action"
31401
+ @click=${() => this.dispatchEvent(new CustomEvent("marketplace"))}
31402
+ >
31403
+ ${marketplace} Browse Marketplace
31404
+ </button>
31405
+ `}
31406
+ </div>
31407
+ ` : ""}
31408
+ </div>
30842
31409
  </nav>
30843
31410
 
30844
31411
  <div class="sidebar-footer">
@@ -30855,14 +31422,6 @@ var BeamSidebar = class extends i4 {
30855
31422
  <span class="approval-badge">${this.pendingApprovals}</span>
30856
31423
  </button>
30857
31424
  ` : ""}
30858
- <button
30859
- class="footer-link"
30860
- @click=${() => this.dispatchEvent(new CustomEvent("diagnostics", { bubbles: true, composed: true }))}
30861
- title="Server diagnostics"
30862
- aria-label="Show diagnostics"
30863
- >
30864
- ${activity}
30865
- </button>
30866
31425
  <button
30867
31426
  class="footer-link"
30868
31427
  @click=${() => this._showShortcuts()}
@@ -30939,7 +31498,7 @@ var BeamSidebar = class extends i4 {
30939
31498
  class="photon-list motion-stagger ${collapsed ? "collapsed" : ""}"
30940
31499
  role="listbox"
30941
31500
  aria-labelledby=${headerId}
30942
- style="max-height: ${collapsed ? "0" : items.length * 52 + "px"}"
31501
+ style="max-height: ${collapsed ? "0" : this._estimateSectionHeight(items) + "px"}"
30943
31502
  >
30944
31503
  ${items.map(renderItem)}
30945
31504
  </ul>
@@ -30963,41 +31522,46 @@ var BeamSidebar = class extends i4 {
30963
31522
  const isLight = this.theme === "light";
30964
31523
  initialsStyle = isLight ? `background: hsl(${hue2}, 30%, 90%); color: hsl(${hue2}, 50%, 35%);` : `background: hsl(${hue2}, 35%, 22%); color: hsl(${hue2}, 60%, 75%);`;
30965
31524
  }
31525
+ const isSelected = this.selectedPhoton === photon.name;
30966
31526
  return b2`
30967
31527
  <li
30968
- class="photon-item ${this.selectedPhoton === photon.name ? "active" : ""} ${photon.internal ? "internal" : ""} ${this._isPhotonWarm(photon.name) ? "warmth" : ""}"
31528
+ class="photon-item ${isSelected ? "active" : ""} ${photon.internal ? "internal" : ""} ${this._isPhotonWarm(photon.name) ? "warmth" : ""}"
30969
31529
  role="option"
30970
- aria-selected="${this.selectedPhoton === photon.name}"
31530
+ aria-selected="${isSelected}"
30971
31531
  tabindex="0"
30972
31532
  @click=${() => this._selectPhoton(photon)}
30973
31533
  @keydown=${(e8) => e8.key === "Enter" && this._selectPhoton(photon)}
30974
31534
  title="${photon.description || photon.name}${photon.path ? `
30975
31535
  ${photon.path}` : ""}"
30976
31536
  >
30977
- <div
30978
- class="photon-icon ${isEmoji ? "emoji-icon" : ""}"
30979
- style="${initialsStyle}"
30980
- aria-hidden="true"
30981
- >
30982
- ${displayIcon}
30983
- </div>
30984
- <div class="photon-info">
30985
- <div class="photon-name">${photon.name}</div>
30986
- ${photon.internal ? b2`<span class="internal-badge">System</span>` : ""}
31537
+ <div class="photon-item-body">
31538
+ <div class="photon-main-row">
31539
+ <div
31540
+ class="photon-icon ${isEmoji ? "emoji-icon" : ""}"
31541
+ style="${initialsStyle}"
31542
+ aria-hidden="true"
31543
+ >
31544
+ ${displayIcon}
31545
+ </div>
31546
+ <div class="photon-info">
31547
+ <div class="photon-name">${photon.name}</div>
31548
+ ${photon.internal ? b2`<span class="internal-badge">System</span>` : ""}
31549
+ </div>
31550
+ <button
31551
+ class="star-btn ${isFavorited ? "favorited" : ""}"
31552
+ @click=${(e8) => this._toggleFavorite(e8, photon.name)}
31553
+ title="${isFavorited ? "Remove from favorites" : "Add to favorites"}"
31554
+ aria-label="${isFavorited ? `Remove ${photon.name} from favorites` : `Add ${photon.name} to favorites`}"
31555
+ aria-pressed="${isFavorited}"
31556
+ >
31557
+ ${isFavorited ? starFilled : starOutline}
31558
+ </button>
31559
+ ${isUnconfigured ? photon.errorReason === "load-error" ? b2`<span class="method-count error" aria-label="Error loading">×</span>` : b2`<span class="method-count unconfigured" aria-label="Needs configuration"
31560
+ >?</span
31561
+ >` : this._renderCountsPill(photon, methodCount)}
31562
+ </div>
31563
+ ${isSelected ? this._renderInlineViewTabs() : ""}
30987
31564
  </div>
30988
- ${""}
30989
- <button
30990
- class="star-btn ${isFavorited ? "favorited" : ""}"
30991
- @click=${(e8) => this._toggleFavorite(e8, photon.name)}
30992
- title="${isFavorited ? "Remove from favorites" : "Add to favorites"}"
30993
- aria-label="${isFavorited ? `Remove ${photon.name} from favorites` : `Add ${photon.name} to favorites`}"
30994
- aria-pressed="${isFavorited}"
30995
- >
30996
- ${isFavorited ? starFilled : starOutline}
30997
- </button>
30998
- ${isUnconfigured ? photon.errorReason === "load-error" ? b2`<span class="method-count error" aria-label="Error loading">×</span>` : b2`<span class="method-count unconfigured" aria-label="Needs configuration"
30999
- >?</span
31000
- >` : this._renderCountsPill(photon, methodCount)}
31001
31565
  </li>
31002
31566
  `;
31003
31567
  }
@@ -31006,46 +31570,120 @@ ${photon.path}` : ""}"
31006
31570
  const isConnected = mcp.connected !== false;
31007
31571
  const displayIcon = mcp.icon || plug;
31008
31572
  const isFavorited = this._favorites.has(mcp.name);
31573
+ const isSelected = this.selectedPhoton === mcp.name;
31009
31574
  return b2`
31010
31575
  <li
31011
- class="photon-item ${this.selectedPhoton === mcp.name ? "active" : ""} ${!isConnected ? "disconnected" : ""}"
31576
+ class="photon-item ${isSelected ? "active" : ""} ${!isConnected ? "disconnected" : ""}"
31012
31577
  role="option"
31013
- aria-selected="${this.selectedPhoton === mcp.name}"
31578
+ aria-selected="${isSelected}"
31014
31579
  tabindex="0"
31015
31580
  @click=${() => this._selectPhoton(mcp)}
31016
31581
  @keydown=${(e8) => e8.key === "Enter" && this._selectPhoton(mcp)}
31017
31582
  title="${mcp.description || "External MCP server"}${mcp.errorMessage ? `
31018
31583
  \u26A0\uFE0F ${mcp.errorMessage}` : ""}"
31019
31584
  >
31020
- <div class="photon-icon external-mcp-icon" aria-hidden="true">${displayIcon}</div>
31021
- <div class="photon-info">
31022
- <div class="photon-name">${mcp.name}</div>
31585
+ <div class="photon-item-body">
31586
+ <div class="photon-main-row">
31587
+ <div class="photon-icon external-mcp-icon" aria-hidden="true">${displayIcon}</div>
31588
+ <div class="photon-info">
31589
+ <div class="photon-name">${mcp.name}</div>
31590
+ </div>
31591
+ <button
31592
+ class="star-btn ${isFavorited ? "favorited" : ""}"
31593
+ @click=${(e8) => this._toggleFavorite(e8, mcp.name)}
31594
+ title="${isFavorited ? "Remove from favorites" : "Add to favorites"}"
31595
+ aria-label="${isFavorited ? `Remove ${mcp.name} from favorites` : `Add ${mcp.name} to favorites`}"
31596
+ aria-pressed="${isFavorited}"
31597
+ >
31598
+ ${isFavorited ? starFilled : starOutline}
31599
+ </button>
31600
+ ${!isConnected ? b2`
31601
+ <span class="disconnect-badge" title="${mcp.errorMessage || "Disconnected"}"
31602
+ >Offline</span
31603
+ >
31604
+ <button
31605
+ class="reconnect-btn"
31606
+ @click=${(e8) => this._reconnectMCP(e8, mcp.name)}
31607
+ title="Reconnect"
31608
+ aria-label="Reconnect ${mcp.name}"
31609
+ >
31610
+
31611
+ </button>
31612
+ ` : this._renderCountsPill(mcp, methodCount)}
31613
+ </div>
31614
+ ${isSelected ? this._renderInlineViewTabs() : ""}
31023
31615
  </div>
31024
- <button
31025
- class="star-btn ${isFavorited ? "favorited" : ""}"
31026
- @click=${(e8) => this._toggleFavorite(e8, mcp.name)}
31027
- title="${isFavorited ? "Remove from favorites" : "Add to favorites"}"
31028
- aria-label="${isFavorited ? `Remove ${mcp.name} from favorites` : `Add ${mcp.name} to favorites`}"
31029
- aria-pressed="${isFavorited}"
31030
- >
31031
- ${isFavorited ? starFilled : starOutline}
31032
- </button>
31033
- ${!isConnected ? b2`
31034
- <span class="disconnect-badge" title="${mcp.errorMessage || "Disconnected"}"
31035
- >Offline</span
31036
- >
31037
- <button
31038
- class="reconnect-btn"
31039
- @click=${(e8) => this._reconnectMCP(e8, mcp.name)}
31040
- title="Reconnect"
31041
- aria-label="Reconnect ${mcp.name}"
31042
- >
31043
-
31044
- </button>
31045
- ` : this._renderCountsPill(mcp, methodCount)}
31046
31616
  </li>
31047
31617
  `;
31048
31618
  }
31619
+ _renderInlineViewTabs() {
31620
+ const appTabIcon = b2`<svg
31621
+ width="14"
31622
+ height="14"
31623
+ viewBox="0 0 24 24"
31624
+ fill="none"
31625
+ stroke="currentColor"
31626
+ stroke-width="2"
31627
+ stroke-linecap="round"
31628
+ stroke-linejoin="round"
31629
+ aria-hidden="true"
31630
+ >
31631
+ <rect x="3" y="3" width="18" height="18" rx="2" />
31632
+ <path d="M3 9h18" />
31633
+ <path d="M9 21V9" />
31634
+ </svg>`;
31635
+ const methodsTabIcon = b2`<svg
31636
+ width="14"
31637
+ height="14"
31638
+ viewBox="0 0 24 24"
31639
+ fill="none"
31640
+ stroke="currentColor"
31641
+ stroke-width="2"
31642
+ stroke-linecap="round"
31643
+ stroke-linejoin="round"
31644
+ aria-hidden="true"
31645
+ >
31646
+ <rect x="3" y="3" width="7" height="7" />
31647
+ <rect x="14" y="3" width="7" height="7" />
31648
+ <rect x="3" y="14" width="7" height="7" />
31649
+ <rect x="14" y="14" width="7" height="7" />
31650
+ </svg>`;
31651
+ const tabs = [
31652
+ ...this.isApp ? [{ id: "app", label: "App", icon: appTabIcon }] : [],
31653
+ { id: "methods", label: "Methods", icon: methodsTabIcon },
31654
+ { id: "log", label: "Activity", icon: activity },
31655
+ ...this.hasSettings ? [{ id: "settings", label: "Settings", icon: settings }] : [],
31656
+ ...this.hasPath && !this.isExternalMCP ? [{ id: "source", label: "Source", icon: source }] : [],
31657
+ { id: "help", label: "Help", icon: docs }
31658
+ ];
31659
+ return b2`
31660
+ <div class="photon-view-tabs" role="tablist" aria-label="Selected photon views">
31661
+ ${tabs.map(
31662
+ (tab) => b2`
31663
+ <button
31664
+ class="photon-view-tab ${this.mainTab === tab.id ? "active" : ""}"
31665
+ role="tab"
31666
+ aria-selected=${String(this.mainTab === tab.id)}
31667
+ title=${tab.label}
31668
+ aria-label=${tab.label}
31669
+ @click=${(e8) => {
31670
+ e8.stopPropagation();
31671
+ this._emitTabChange(tab.id);
31672
+ }}
31673
+ >
31674
+ ${tab.icon}
31675
+ </button>
31676
+ `
31677
+ )}
31678
+ </div>
31679
+ `;
31680
+ }
31681
+ _estimateSectionHeight(items) {
31682
+ return items.reduce((height, item) => {
31683
+ const isSelected = item.name === this.selectedPhoton;
31684
+ return height + (isSelected ? 92 : 52);
31685
+ }, 0);
31686
+ }
31049
31687
  _reconnectMCP(e8, mcpName) {
31050
31688
  e8.stopPropagation();
31051
31689
  this.dispatchEvent(
@@ -31091,6 +31729,9 @@ ${photon.path}` : ""}"
31091
31729
  })
31092
31730
  );
31093
31731
  }
31732
+ _emitTabChange(tab) {
31733
+ this.dispatchEvent(new CustomEvent("tab-change", { detail: { tab } }));
31734
+ }
31094
31735
  _handleSearch(e8) {
31095
31736
  this._searchQuery = e8.target.value;
31096
31737
  }
@@ -31148,6 +31789,9 @@ ${photon.path}` : ""}"
31148
31789
  return this._showFavoritesOnly;
31149
31790
  }
31150
31791
  scrollPhotonIntoView(name2) {
31792
+ this._scrollPhotonIntoView(name2, true);
31793
+ }
31794
+ _scrollPhotonIntoView(name2, flashHighlight) {
31151
31795
  void this.updateComplete.then(() => {
31152
31796
  const items = this.shadowRoot?.querySelectorAll(".photon-item");
31153
31797
  if (!items) return;
@@ -31155,13 +31799,23 @@ ${photon.path}` : ""}"
31155
31799
  const nameEl = item.querySelector(".photon-name");
31156
31800
  if (nameEl?.textContent?.trim() === name2) {
31157
31801
  item.scrollIntoView({ behavior: "smooth", block: "nearest" });
31158
- item.classList.add("flash-highlight");
31159
- setTimeout(() => item.classList.remove("flash-highlight"), 600);
31802
+ if (flashHighlight) {
31803
+ item.classList.add("flash-highlight");
31804
+ setTimeout(() => item.classList.remove("flash-highlight"), 600);
31805
+ }
31160
31806
  break;
31161
31807
  }
31162
31808
  }
31163
31809
  });
31164
31810
  }
31811
+ _scrollSidebarToTop() {
31812
+ void this.updateComplete.then(() => {
31813
+ const scrollEl = this.shadowRoot?.querySelector(".sidebar-scroll");
31814
+ if (scrollEl) {
31815
+ scrollEl.scrollTo({ top: 0, behavior: "smooth" });
31816
+ }
31817
+ });
31818
+ }
31165
31819
  /**
31166
31820
  * Check if a photon currently has a warmth indicator (notification received within last 5 seconds)
31167
31821
  */
@@ -31195,9 +31849,17 @@ BeamSidebar.styles = [
31195
31849
  flex-direction: column;
31196
31850
  height: 100%;
31197
31851
  color: var(--t-primary);
31852
+ overflow: visible;
31198
31853
  }
31199
31854
 
31200
31855
  .sidebar-content {
31856
+ flex: 1;
31857
+ overflow: hidden;
31858
+ display: flex;
31859
+ flex-direction: column;
31860
+ }
31861
+
31862
+ .sidebar-scroll {
31201
31863
  flex: 1;
31202
31864
  overflow-y: auto;
31203
31865
  padding-right: 4px;
@@ -31289,6 +31951,7 @@ BeamSidebar.styles = [
31289
31951
  .header {
31290
31952
  padding: var(--space-md);
31291
31953
  border-bottom: 1px solid var(--border-glass);
31954
+ flex-shrink: 0;
31292
31955
  }
31293
31956
 
31294
31957
  .header-row {
@@ -31398,6 +32061,27 @@ BeamSidebar.styles = [
31398
32061
  position: relative;
31399
32062
  }
31400
32063
 
32064
+ .sidebar-minimize-btn {
32065
+ width: 28px;
32066
+ height: 28px;
32067
+ border-radius: var(--radius-sm);
32068
+ background: transparent;
32069
+ border: none;
32070
+ color: var(--t-muted);
32071
+ cursor: pointer;
32072
+ display: flex;
32073
+ align-items: center;
32074
+ justify-content: center;
32075
+ transition: all 0.15s ease;
32076
+ padding: 0;
32077
+ flex-shrink: 0;
32078
+ }
32079
+
32080
+ .sidebar-minimize-btn:hover {
32081
+ color: var(--t-primary);
32082
+ background: var(--bg-glass);
32083
+ }
32084
+
31401
32085
  input {
31402
32086
  padding: var(--space-sm) var(--space-md);
31403
32087
  }
@@ -31491,6 +32175,9 @@ BeamSidebar.styles = [
31491
32175
  border-left: 2px solid var(--accent-primary);
31492
32176
  color: var(--accent-primary);
31493
32177
  font-weight: 500;
32178
+ align-items: stretch;
32179
+ padding-top: calc(var(--space-sm) + 2px);
32180
+ padding-bottom: calc(var(--space-sm) + 2px);
31494
32181
  }
31495
32182
 
31496
32183
  .photon-item.flash-highlight {
@@ -31560,6 +32247,25 @@ BeamSidebar.styles = [
31560
32247
  flex: 1;
31561
32248
  }
31562
32249
 
32250
+ .photon-item-body {
32251
+ min-width: 0;
32252
+ flex: 1;
32253
+ display: flex;
32254
+ flex-direction: column;
32255
+ gap: 8px;
32256
+ }
32257
+
32258
+ .photon-main-row {
32259
+ display: flex;
32260
+ align-items: center;
32261
+ gap: var(--space-sm);
32262
+ min-width: 0;
32263
+ }
32264
+
32265
+ .photon-main-row .photon-info {
32266
+ min-width: 0;
32267
+ }
32268
+
31563
32269
  .photon-name {
31564
32270
  font-family: var(--font-display);
31565
32271
  font-weight: 600;
@@ -31576,6 +32282,45 @@ BeamSidebar.styles = [
31576
32282
  text-overflow: ellipsis;
31577
32283
  }
31578
32284
 
32285
+ .photon-view-tabs {
32286
+ display: flex;
32287
+ align-items: center;
32288
+ gap: 4px;
32289
+ margin-left: calc(28px + var(--space-sm));
32290
+ }
32291
+
32292
+ .photon-view-tab {
32293
+ width: 26px;
32294
+ height: 26px;
32295
+ display: inline-flex;
32296
+ align-items: center;
32297
+ justify-content: center;
32298
+ border: 1px solid var(--border-glass);
32299
+ background: color-mix(in srgb, var(--bg-glass-strong) 82%, transparent);
32300
+ color: var(--t-muted);
32301
+ border-radius: var(--radius-sm);
32302
+ padding: 0;
32303
+ cursor: pointer;
32304
+ transition: all 0.15s ease;
32305
+ }
32306
+
32307
+ .photon-view-tab svg {
32308
+ width: 13px;
32309
+ height: 13px;
32310
+ }
32311
+
32312
+ .photon-view-tab:hover {
32313
+ color: var(--t-primary);
32314
+ border-color: color-mix(in srgb, var(--accent-primary) 38%, var(--border-glass));
32315
+ background: color-mix(in srgb, var(--accent-primary) 10%, var(--bg-glass-strong));
32316
+ }
32317
+
32318
+ .photon-view-tab.active {
32319
+ color: white;
32320
+ border-color: var(--accent-primary);
32321
+ background: color-mix(in srgb, var(--accent-primary) 78%, black 22%);
32322
+ }
32323
+
31579
32324
  .method-count {
31580
32325
  font-size: var(--text-2xs);
31581
32326
  padding: 2px 6px;
@@ -31876,6 +32621,10 @@ BeamSidebar.styles = [
31876
32621
  min-height: 44px;
31877
32622
  }
31878
32623
 
32624
+ .photon-view-tabs {
32625
+ margin-left: 0;
32626
+ }
32627
+
31879
32628
  .photon-item .star-btn {
31880
32629
  padding: var(--space-sm);
31881
32630
  opacity: 0.4;
@@ -31930,6 +32679,21 @@ __decorateClass([
31930
32679
  __decorateClass([
31931
32680
  n4({ type: Number })
31932
32681
  ], BeamSidebar.prototype, "pendingApprovals", 2);
32682
+ __decorateClass([
32683
+ n4({ type: String })
32684
+ ], BeamSidebar.prototype, "mainTab", 2);
32685
+ __decorateClass([
32686
+ n4({ type: Boolean })
32687
+ ], BeamSidebar.prototype, "isApp", 2);
32688
+ __decorateClass([
32689
+ n4({ type: Boolean })
32690
+ ], BeamSidebar.prototype, "hasSettings", 2);
32691
+ __decorateClass([
32692
+ n4({ type: Boolean })
32693
+ ], BeamSidebar.prototype, "isExternalMCP", 2);
32694
+ __decorateClass([
32695
+ n4({ type: Boolean })
32696
+ ], BeamSidebar.prototype, "hasPath", 2);
31933
32697
  __decorateClass([
31934
32698
  r5()
31935
32699
  ], BeamSidebar.prototype, "_searchQuery", 2);
@@ -31960,6 +32724,7 @@ var MethodCard = class extends i4 {
31960
32724
  constructor() {
31961
32725
  super(...arguments);
31962
32726
  this.photonName = "";
32727
+ this.editable = false;
31963
32728
  this._editingDescription = false;
31964
32729
  this._editingIcon = false;
31965
32730
  this._editedDescription = "";
@@ -32023,20 +32788,20 @@ var MethodCard = class extends i4 {
32023
32788
  ${this.method.icon}
32024
32789
  </div>
32025
32790
  ` : ""}
32026
- <span class="editable">
32791
+ <span class="${this.editable ? "editable" : ""}">
32027
32792
  <h3 class="title">
32028
32793
  <span class="title-name">${this.method.name}</span>${this._renderParamSignature()}
32029
32794
  </h3>
32030
- <span
32031
- class="edit-pencil"
32032
- role="button"
32033
- tabindex="0"
32034
- @click=${(e8) => this._handleNameEditClick(e8)}
32035
- @keydown=${(e8) => (e8.key === "Enter" || e8.key === " ") && (e8.preventDefault(), this._handleNameEditClick(e8))}
32036
- title="Rename method"
32037
- aria-label="Rename method"
32038
- >${pencil}</span
32039
- >
32795
+ ${this.editable ? b2`<span
32796
+ class="edit-pencil"
32797
+ role="button"
32798
+ tabindex="0"
32799
+ @click=${(e8) => this._handleNameEditClick(e8)}
32800
+ @keydown=${(e8) => (e8.key === "Enter" || e8.key === " ") && (e8.preventDefault(), this._handleNameEditClick(e8))}
32801
+ title="Rename method"
32802
+ aria-label="Rename method"
32803
+ >${pencil}</span
32804
+ >` : ""}
32040
32805
  </span>
32041
32806
  </div>
32042
32807
  ${this.method.isTemplate ? b2`<span class="badge prompt">Prompt</span>` : ""}
@@ -32076,21 +32841,24 @@ var MethodCard = class extends i4 {
32076
32841
  <span class="char-counter">${this._editedDescription.length}/500</span>
32077
32842
  </div>
32078
32843
  ` : b2`
32079
- <div class="editable" style="flex:1; align-items: flex-start;">
32844
+ <div
32845
+ class="${this.editable ? "editable" : ""}"
32846
+ style="flex:1; align-items: flex-start;"
32847
+ >
32080
32848
  <div class="description ${hasDescription ? "" : "placeholder"}" style="flex:1;">
32081
- ${hasDescription ? this._renderDescription(this.method.description) : "Add description..."}
32849
+ ${hasDescription ? this._renderDescription(this.method.description) : this.editable ? "Add description..." : ""}
32082
32850
  </div>
32083
- <span
32084
- class="edit-pencil"
32085
- role="button"
32086
- tabindex="0"
32087
- @click=${(e8) => this._handleDescriptionEditClick(e8)}
32088
- @keydown=${(e8) => (e8.key === "Enter" || e8.key === " ") && (e8.preventDefault(), this._handleDescriptionEditClick(e8))}
32089
- title="Edit description"
32090
- aria-label="Edit description"
32091
- style="margin-top: 2px;"
32092
- >${pencil}</span
32093
- >
32851
+ ${this.editable ? b2`<span
32852
+ class="edit-pencil"
32853
+ role="button"
32854
+ tabindex="0"
32855
+ @click=${(e8) => this._handleDescriptionEditClick(e8)}
32856
+ @keydown=${(e8) => (e8.key === "Enter" || e8.key === " ") && (e8.preventDefault(), this._handleDescriptionEditClick(e8))}
32857
+ title="Edit description"
32858
+ aria-label="Edit description"
32859
+ style="margin-top: 2px;"
32860
+ >${pencil}</span
32861
+ >` : ""}
32094
32862
  </div>
32095
32863
  `}
32096
32864
  </div>
@@ -32687,6 +33455,9 @@ __decorateClass([
32687
33455
  __decorateClass([
32688
33456
  n4({ type: String })
32689
33457
  ], MethodCard.prototype, "photonName", 2);
33458
+ __decorateClass([
33459
+ n4({ type: Boolean })
33460
+ ], MethodCard.prototype, "editable", 2);
32690
33461
  __decorateClass([
32691
33462
  r5()
32692
33463
  ], MethodCard.prototype, "_editingDescription", 2);
@@ -32801,6 +33572,7 @@ var InvokeForm = class extends i4 {
32801
33572
  this.methodName = "";
32802
33573
  this.rememberValues = false;
32803
33574
  this.sharedValues = null;
33575
+ this.settingsLayout = false;
32804
33576
  this._values = {};
32805
33577
  this._initialValues = {};
32806
33578
  this._passwordVisible = {};
@@ -32906,12 +33678,13 @@ var InvokeForm = class extends i4 {
32906
33678
  const result = await mcpClient.callTool(`${this.photonName}/${toolName}`, {});
32907
33679
  let values = [];
32908
33680
  let data = result;
32909
- if (result && Array.isArray(result.content)) {
32910
- if (result.isError) {
33681
+ const mcpResult = result;
33682
+ if (result && Array.isArray(mcpResult.content)) {
33683
+ if (mcpResult.isError) {
32911
33684
  hasUnresolved = true;
32912
33685
  continue;
32913
33686
  }
32914
- const textBlock = result.content.find((c5) => c5.type === "text");
33687
+ const textBlock = mcpResult.content.find((c5) => c5.type === "text");
32915
33688
  if (textBlock?.text) {
32916
33689
  try {
32917
33690
  data = JSON.parse(textBlock.text);
@@ -33011,6 +33784,42 @@ var InvokeForm = class extends i4 {
33011
33784
  const isRequired = Array.isArray(requiredList) ? requiredList.includes(key) : !!schema.required;
33012
33785
  const error2 = this._errors[key];
33013
33786
  const inputId = `field-${key}`;
33787
+ if (this.settingsLayout) {
33788
+ const isBoolean = schema.type === "boolean" || schema.type === '"boolean"';
33789
+ return b2`
33790
+ <div
33791
+ style="display: grid; grid-template-columns: 200px 1fr; border-bottom: 1px solid var(--border-glass); min-height: 48px;"
33792
+ >
33793
+ <div
33794
+ style="padding: 12px var(--space-md); display: flex; flex-direction: column; justify-content: center; background: var(--bg-glass);"
33795
+ >
33796
+ <label
33797
+ for=${inputId}
33798
+ style="font-size: var(--text-sm); font-weight: 600; color: var(--t-primary); margin: 0;"
33799
+ >
33800
+ ${formatLabel(key)}
33801
+ </label>
33802
+ ${schema.description ? b2`<span
33803
+ style="font-size: var(--text-2xs); color: var(--t-muted); margin-top: 2px; line-height: 1.3;"
33804
+ >${this._cleanDescription(schema.description, schema)}</span
33805
+ >` : ""}
33806
+ </div>
33807
+ <div
33808
+ style="padding: ${isBoolean ? "8px" : "6px"} var(--space-md); display: flex; align-items: center;"
33809
+ >
33810
+ ${this._renderInput(key, schema, !!error2, inputId)}
33811
+ ${error2 ? b2`<div
33812
+ class="error-text"
33813
+ style="margin-left: 8px;"
33814
+ id="${inputId}-error"
33815
+ role="alert"
33816
+ >
33817
+ ${error2}
33818
+ </div>` : ""}
33819
+ </div>
33820
+ </div>
33821
+ `;
33822
+ }
33014
33823
  return b2`
33015
33824
  <div class="form-group">
33016
33825
  <label for=${inputId}>
@@ -34815,6 +35624,9 @@ __decorateClass([
34815
35624
  __decorateClass([
34816
35625
  n4({ type: Object })
34817
35626
  ], InvokeForm.prototype, "sharedValues", 2);
35627
+ __decorateClass([
35628
+ n4({ type: Boolean })
35629
+ ], InvokeForm.prototype, "settingsLayout", 2);
34818
35630
  __decorateClass([
34819
35631
  r5()
34820
35632
  ], InvokeForm.prototype, "_values", 2);
@@ -34842,6 +35654,7 @@ var ActivityLog = class extends i4 {
34842
35654
  constructor() {
34843
35655
  super(...arguments);
34844
35656
  this.items = [];
35657
+ this.fullscreen = false;
34845
35658
  this._filterActive = false;
34846
35659
  this._collapsed = false;
34847
35660
  this._lastFilter = void 0;
@@ -35009,6 +35822,24 @@ ActivityLog.styles = [
35009
35822
  list-style: none;
35010
35823
  margin: 0;
35011
35824
  padding: 0;
35825
+ max-height: 180px;
35826
+ overflow-y: auto;
35827
+ }
35828
+
35829
+ :host([fullscreen]) {
35830
+ display: flex;
35831
+ flex-direction: column;
35832
+ flex: 1;
35833
+ min-height: 0;
35834
+ margin-top: 0;
35835
+ border-top: none;
35836
+ padding-top: 0;
35837
+ }
35838
+
35839
+ :host([fullscreen]) .log-list {
35840
+ max-height: none;
35841
+ flex: 1;
35842
+ min-height: 0;
35012
35843
  }
35013
35844
 
35014
35845
  .log-item {
@@ -35148,6 +35979,9 @@ __decorateClass([
35148
35979
  __decorateClass([
35149
35980
  n4({ type: String })
35150
35981
  ], ActivityLog.prototype, "filter", 2);
35982
+ __decorateClass([
35983
+ n4({ type: Boolean, reflect: true })
35984
+ ], ActivityLog.prototype, "fullscreen", 2);
35151
35985
  __decorateClass([
35152
35986
  r5()
35153
35987
  ], ActivityLog.prototype, "_filterActive", 2);
@@ -35462,6 +36296,12 @@ var ResultViewer = class extends i4 {
35462
36296
  // per-slide bg (color, url, gradient)
35463
36297
  this._slidesEffects = /* @__PURE__ */ new Map();
35464
36298
  // per-slide element effect
36299
+ this._slidesMoods = /* @__PURE__ */ new Map();
36300
+ // per-slide mood (dramatic, techy, etc.)
36301
+ this._slidesGlobalMood = "";
36302
+ // frontmatter mood default
36303
+ this._slidesBgEffects = /* @__PURE__ */ new Map();
36304
+ // per-slide bg effect (gradient-mesh, etc.)
35465
36305
  this._slidesCols = /* @__PURE__ */ new Map();
35466
36306
  // per-slide column count
35467
36307
  this._slidesBuilds = /* @__PURE__ */ new Map();
@@ -36423,6 +37263,7 @@ var ResultViewer = class extends i4 {
36423
37263
  case "slides":
36424
37264
  return typeof data === "string";
36425
37265
  case "checklist":
37266
+ case "guide":
36426
37267
  return Array.isArray(data);
36427
37268
  case "magazine":
36428
37269
  case "article":
@@ -36495,6 +37336,8 @@ var ResultViewer = class extends i4 {
36495
37336
  return this._renderSlides(filteredData);
36496
37337
  case "checklist":
36497
37338
  return this._renderChecklist(filteredData);
37339
+ case "guide":
37340
+ return this._renderGuide(filteredData);
36498
37341
  case "magazine":
36499
37342
  case "article":
36500
37343
  return this._renderMagazine(filteredData);
@@ -37427,6 +38270,8 @@ ${code}</pre>`;
37427
38270
  this._slidesTransitions.clear();
37428
38271
  this._slidesBackgrounds.clear();
37429
38272
  this._slidesEffects.clear();
38273
+ this._slidesMoods.clear();
38274
+ this._slidesBgEffects.clear();
37430
38275
  this._slidesCols.clear();
37431
38276
  this._slidesBuilds.clear();
37432
38277
  slides.forEach((slide, i7) => {
@@ -37436,10 +38281,15 @@ ${code}</pre>`;
37436
38281
  if (bgMatch) this._slidesBackgrounds.set(i7, bgMatch[1].trim());
37437
38282
  const fxMatch = slide.match(/<!--\s*effect:\s*(\S+)\s*-->/);
37438
38283
  if (fxMatch) this._slidesEffects.set(i7, fxMatch[1].trim());
38284
+ const moodMatch = slide.match(/<!--\s*mood:\s*(\w+)\s*-->/);
38285
+ if (moodMatch) this._slidesMoods.set(i7, moodMatch[1].trim());
38286
+ const bgFxMatch = slide.match(/<!--\s*background:\s*(\S+)\s*-->/);
38287
+ if (bgFxMatch) this._slidesBgEffects.set(i7, bgFxMatch[1].trim());
37439
38288
  const colMatch = slide.match(/<!--\s*cols:\s*(\d+)\s*-->/);
37440
38289
  if (colMatch) this._slidesCols.set(i7, Math.min(Math.max(parseInt(colMatch[1], 10), 2), 4));
37441
38290
  if (/<!--\s*build\s*-->/.test(slide)) this._slidesBuilds.set(i7, true);
37442
38291
  });
38292
+ this._slidesGlobalMood = config3.mood || "";
37443
38293
  const defaultTheme2 = "auto";
37444
38294
  return { slides, theme: config3.theme || defaultTheme2, config: config3 };
37445
38295
  }
@@ -37491,7 +38341,7 @@ ${code}</pre>`;
37491
38341
  return this._slidesBridgeScript || "";
37492
38342
  }
37493
38343
  /** Build an iframe srcdoc for a slide with the bridge loaded */
37494
- _buildSlideSrcdoc(slideHtml, codeBlocks, headerText, footerText, pageNum, slideBg, slideEffect) {
38344
+ _buildSlideSrcdoc(slideHtml, codeBlocks, headerText, footerText, pageNum, slideBg, slideEffect, slideBgEffect) {
37495
38345
  const bridge = this._slidesBridgeScript || "";
37496
38346
  const photonPrefix = this.photonName ? this.photonName + "/" : "";
37497
38347
  let html = slideHtml;
@@ -37516,11 +38366,15 @@ ${code}</pre>`;
37516
38366
  }
37517
38367
  }
37518
38368
  const themeClass = this._slidesThemeClass || "slides-theme-default";
38369
+ const themeName = themeClass.replace("slides-theme-", "");
38370
+ const fontSpec = ResultViewer._THEME_FONTS[themeName];
38371
+ const fontLink = fontSpec ? `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=${fontSpec}&display=swap">` : "";
37519
38372
  return `<!doctype html>
37520
38373
  <html lang="en" class="${themeClass}">
37521
38374
  <head>
37522
38375
  <meta charset="UTF-8">
37523
38376
  <meta name="photon-template" content="true">
38377
+ ${fontLink}
37524
38378
  ${bridge}
37525
38379
  <style>
37526
38380
  /* reveal.js-style scaling: fixed design canvas + transform:scale() */
@@ -37578,6 +38432,20 @@ ${bridge}
37578
38432
  [data-enter="flip-in"] { animation: motion-flip-in 0.5s cubic-bezier(0.16,1,0.3,1) both; }
37579
38433
  [data-enter="fade-in"] { animation: motion-fade-in 0.3s cubic-bezier(0.16,1,0.3,1) both; }
37580
38434
  [data-enter="drop-in"] { animation: motion-drop-in 0.5s cubic-bezier(0.16,1,0.3,1) both; }
38435
+ [data-enter="mood-dramatic"] { animation: mood-dramatic 0.6s ease both; }
38436
+ [data-enter="mood-techy"] { animation: mood-techy 0.3s ease-out both; }
38437
+ [data-enter="mood-playful"] { animation: mood-playful 0.4s ease both; }
38438
+ [data-enter="mood-calm"] { animation: mood-calm 0.8s ease-in-out both; }
38439
+ /* Hide slide children initially, auto-reveal after 1.5s fallback if stagger doesn't fire */
38440
+ .slide-body > :not(.slide-content-area):not([data-enter]) {
38441
+ opacity: 0;
38442
+ animation: stagger-fallback 0.3s ease 1.5s both;
38443
+ }
38444
+ .slide-content-area > :not([data-enter]) {
38445
+ opacity: 0;
38446
+ animation: stagger-fallback 0.3s ease 1.5s both;
38447
+ }
38448
+ @keyframes stagger-fallback { to { opacity: 1; } }
37581
38449
  @media (prefers-reduced-motion: reduce) {
37582
38450
  [data-enter] { animation: none !important; opacity: 1 !important; }
37583
38451
  }
@@ -37708,6 +38576,8 @@ ${bridge}
37708
38576
  /* Full-bleed image */
37709
38577
  .hero { width: 100%; border-radius: var(--radius-lg, 14px);
37710
38578
  box-shadow: var(--shadow-lg, 0 24px 60px rgba(0,0,0,0.28)); }
38579
+ /* Theme presets (shared with outer shadow DOM) */
38580
+ ${ResultViewer._BRIDGE_THEME_CSS}
37711
38581
  </style>
37712
38582
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"><\/script>
37713
38583
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-typescript.min.js"><\/script>
@@ -37726,7 +38596,8 @@ ${bridge}
37726
38596
  </head>
37727
38597
  <body>
37728
38598
  ${this._buildSlideBgHtml(slideBg || "")}
37729
- <div class="slide-canvas"${slideEffect ? ` data-effect="${slideEffect}"` : ""}>
38599
+ ${slideBgEffect ? `<div style="position:absolute;inset:0;pointer-events:none;z-index:0;${slideBgEffect === "gradient-mesh" ? "background:radial-gradient(ellipse at 20% 50%,rgba(120,80,255,0.15) 0%,transparent 50%),radial-gradient(ellipse at 80% 20%,rgba(255,100,80,0.12) 0%,transparent 50%),radial-gradient(ellipse at 50% 80%,rgba(80,200,255,0.1) 0%,transparent 50%);animation:bgdrift 12s ease-in-out infinite alternate;" : slideBgEffect === "noise" ? "opacity:0.06;background-image:url(&quot;data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%27200%27 height=%27200%27%3E%3Cfilter id=%27n%27%3E%3CfeTurbulence type=%27fractalNoise%27 baseFrequency=%270.75%27 numOctaves=%274%27 stitchTiles=%27stitch%27/%3E%3C/filter%3E%3Crect width=%27100%25%27 height=%27100%25%27 filter=%27url(%23n)%27/%3E%3C/svg%3E&quot;);" : slideBgEffect === "grid" ? "background-image:linear-gradient(rgba(255,255,255,0.05) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.05) 1px,transparent 1px);background-size:32px 32px;" : slideBgEffect === "particles" ? "overflow:hidden;" : ""}"></div>` : ""}
38600
+ <div class="slide-canvas"${slideEffect ? ` data-effect="${slideEffect}"` : ""} style="position:relative;z-index:1;">
37730
38601
  ${headerText ? `<div class="slide-header">${headerText}</div>` : ""}
37731
38602
  <div class="slide-body">${html}</div>
37732
38603
  ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</span><span>${pageNum || ""}</span></div>` : ""}
@@ -37779,6 +38650,74 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
37779
38650
  return document.querySelectorAll('.slide-fragment:not(.visible)').length === 0;
37780
38651
  };
37781
38652
  <\/script>
38653
+ <script>
38654
+ // Text effects for bridge slides
38655
+ (function() {
38656
+ var canvas = document.querySelector('.slide-canvas');
38657
+ var effect = canvas ? canvas.getAttribute('data-effect') : '';
38658
+ if (!effect) return;
38659
+ var heading = document.querySelector('.slide-body h1, .slide-body h2');
38660
+ if (!heading) return;
38661
+ var text = heading.textContent || '';
38662
+ if (!text) return;
38663
+
38664
+ if (effect === 'typing') {
38665
+ heading.textContent = '';
38666
+ heading.style.borderRight = '2px solid currentColor';
38667
+ var i = 0;
38668
+ function typeChar() {
38669
+ if (i < text.length) {
38670
+ heading.textContent += text[i]; i++;
38671
+ requestAnimationFrame(function() { setTimeout(typeChar, 40 + Math.random() * 30); });
38672
+ } else { setTimeout(function() { heading.style.borderRight = 'none'; }, 800); }
38673
+ }
38674
+ setTimeout(typeChar, 300);
38675
+ } else if (effect === 'scramble') {
38676
+ var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
38677
+ var revealed = new Array(text.length).fill(false);
38678
+ var iter = 0;
38679
+ function scrambleStep() {
38680
+ var d = '';
38681
+ for (var j = 0; j < text.length; j++) {
38682
+ d += (revealed[j] || text[j] === ' ') ? text[j] : chars[Math.floor(Math.random() * chars.length)];
38683
+ }
38684
+ heading.textContent = d;
38685
+ if (iter > 5) {
38686
+ var ur = []; for (var k = 0; k < revealed.length; k++) { if (!revealed[k] && text[k] !== ' ') ur.push(k); }
38687
+ if (ur.length > 0) revealed[ur[Math.floor(Math.random() * ur.length)]] = true;
38688
+ }
38689
+ iter++;
38690
+ if (ur && ur.length > 0) requestAnimationFrame(scrambleStep);
38691
+ else heading.textContent = text;
38692
+ }
38693
+ setTimeout(scrambleStep, 300);
38694
+ } else if (effect === 'wave') {
38695
+ heading.innerHTML = '';
38696
+ text.split('').forEach(function(ch, idx) {
38697
+ var s = document.createElement('span');
38698
+ s.textContent = ch === ' ' ? '\\u00A0' : ch;
38699
+ s.style.display = 'inline-block';
38700
+ s.style.opacity = '0';
38701
+ s.style.transform = 'translateY(20px)';
38702
+ s.style.transition = 'all 0.4s ease ' + (idx * 30) + 'ms';
38703
+ heading.appendChild(s);
38704
+ requestAnimationFrame(function() { s.style.opacity = '1'; s.style.transform = 'none'; });
38705
+ });
38706
+ } else if (effect === 'fly-in') {
38707
+ heading.innerHTML = '';
38708
+ text.split(' ').forEach(function(word, idx) {
38709
+ var s = document.createElement('span');
38710
+ s.textContent = word + ' ';
38711
+ s.style.display = 'inline-block';
38712
+ s.style.opacity = '0';
38713
+ s.style.transform = 'translate(' + ((Math.random()-0.5)*200) + 'px,' + ((Math.random()-0.5)*100) + 'px)';
38714
+ s.style.transition = 'all 0.6s cubic-bezier(0.16,1,0.3,1) ' + (idx * 80) + 'ms';
38715
+ heading.appendChild(s);
38716
+ requestAnimationFrame(function() { s.style.opacity = '1'; s.style.transform = 'none'; });
38717
+ });
38718
+ }
38719
+ })();
38720
+ <\/script>
37782
38721
  </body>
37783
38722
  </html>`;
37784
38723
  }
@@ -37855,6 +38794,17 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
37855
38794
  const resolvedTheme = rawTheme === "auto" || rawTheme === "default" ? this.theme === "light" ? "uncover" : "default" : rawTheme;
37856
38795
  const themeClass = `slides-theme-${resolvedTheme}`;
37857
38796
  this._slidesThemeClass = themeClass;
38797
+ const fontSpec = ResultViewer._THEME_FONTS[resolvedTheme];
38798
+ if (fontSpec) {
38799
+ const linkId = `photon-font-${resolvedTheme}`;
38800
+ if (!document.getElementById(linkId)) {
38801
+ const link2 = document.createElement("link");
38802
+ link2.id = linkId;
38803
+ link2.rel = "stylesheet";
38804
+ link2.href = `https://fonts.googleapis.com/css2?family=${fontSpec}&display=swap`;
38805
+ document.head.appendChild(link2);
38806
+ }
38807
+ }
37858
38808
  const bgOverride = config3.backgroundColor ? `background:${config3.backgroundColor};` : "";
37859
38809
  const colorOverride = config3.color ? `color:${config3.color};` : "";
37860
38810
  const viewportStyle = bgOverride + colorOverride;
@@ -37864,6 +38814,7 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
37864
38814
  const currentTransition = this._getSlideTransition(idx);
37865
38815
  const slideBg = this._slidesBackgrounds.get(idx) || "";
37866
38816
  const slideEffect = this._slidesEffects.get(idx) || "";
38817
+ const slideBgEffect = this._slidesBgEffects.get(idx) || "";
37867
38818
  const slideBgStyle = this._buildSlideBgStyle(slideBg);
37868
38819
  const isVideoBg = /\.(mp4|webm|mov)(\?|$)/i.test(slideBg) || slideBg.startsWith("video:");
37869
38820
  return b2`
@@ -37886,6 +38837,7 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
37886
38837
  loop
37887
38838
  playsinline
37888
38839
  ></video>` : b2`<div class="slides-bg-layer" style="${slideBgStyle}"></div>` : ""}
38840
+ ${slideBgEffect ? b2`<div class="slides-bgfx slides-bgfx-${slideBgEffect}"></div>` : ""}
37889
38841
  <div class="slides-content">
37890
38842
  ${this._slidesBridgeScript ? b2`<iframe
37891
38843
  class="slide-bridge-frame"
@@ -37896,7 +38848,8 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
37896
38848
  footerText,
37897
38849
  showPaginate ? `${idx + 1} / ${total}` : "",
37898
38850
  slideBg,
37899
- slideEffect
38851
+ slideEffect,
38852
+ slideBgEffect
37900
38853
  )}
37901
38854
  sandbox="allow-scripts allow-same-origin allow-popups"
37902
38855
  frameborder="0"
@@ -37974,8 +38927,6 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
37974
38927
  position: relative;
37975
38928
  border-radius: var(--radius-md, 8px);
37976
38929
  outline: none;
37977
- background: #1a1a2e;
37978
- color: #e5e5e5;
37979
38930
  font-family:
37980
38931
  system-ui,
37981
38932
  -apple-system,
@@ -37990,14 +38941,14 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
37990
38941
  display: flex;
37991
38942
  align-items: center;
37992
38943
  justify-content: center;
37993
- padding: 48px 64px;
38944
+ padding: clamp(24px, 4vw, 48px) clamp(32px, 5vw, 64px);
37994
38945
  overflow: hidden;
37995
38946
  position: relative;
37996
38947
  }
37997
38948
  .slides-container:fullscreen .slides-viewport {
37998
38949
  flex: 1;
37999
38950
  aspect-ratio: auto;
38000
- padding: 64px 120px;
38951
+ padding: clamp(32px, 5vh, 64px) clamp(48px, 8vw, 120px);
38001
38952
  }
38002
38953
  .slides-container:fullscreen .slides-viewport:has(.slide-bridge-frame) {
38003
38954
  padding: 0;
@@ -38052,26 +39003,26 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
38052
39003
  z-index: -1;
38053
39004
  }
38054
39005
  .slides-content h1 {
38055
- font-size: 2.4em;
39006
+ font-size: clamp(1.8rem, 5vw, 3.5rem);
38056
39007
  margin: 0 0 0.4em;
38057
39008
  font-weight: 800;
38058
39009
  letter-spacing: -0.02em;
38059
39010
  line-height: 1.15;
38060
39011
  }
38061
39012
  .slides-content h2 {
38062
- font-size: 1.8em;
39013
+ font-size: clamp(1.4rem, 3.5vw, 2.4rem);
38063
39014
  margin: 0 0 0.4em;
38064
39015
  font-weight: 700;
38065
39016
  letter-spacing: -0.01em;
38066
39017
  }
38067
39018
  .slides-content h3 {
38068
- font-size: 1.3em;
39019
+ font-size: clamp(1.1rem, 2.5vw, 1.6rem);
38069
39020
  margin: 0 0 0.3em;
38070
39021
  font-weight: 600;
38071
39022
  }
38072
39023
  .slides-content p {
38073
39024
  margin: 0.5em 0;
38074
- font-size: 1.15em;
39025
+ font-size: clamp(0.95rem, 1.8vw, 1.25rem);
38075
39026
  line-height: 1.65;
38076
39027
  }
38077
39028
  .slides-content ul,
@@ -38376,6 +39327,300 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
38376
39327
  background: #191a21;
38377
39328
  }
38378
39329
 
39330
+ /* ═══ AUTO THEME — inherits MCP client colors ═══ */
39331
+ .slides-theme-auto {
39332
+ background: var(--bg-panel, #1a1a2e);
39333
+ color: var(--t-primary, #e0e0e0);
39334
+ }
39335
+ .slides-theme-auto .slides-content h1,
39336
+ .slides-theme-auto .slides-content h2 {
39337
+ color: var(--accent, #6366f1);
39338
+ }
39339
+ .slides-theme-auto .slides-controls {
39340
+ background: var(--bg-glass, rgba(0, 0, 0, 0.4));
39341
+ }
39342
+
39343
+ /* ═══ NEON THEME ═══ */
39344
+ .slides-theme-neon {
39345
+ background: #0a0a1a;
39346
+ color: #e0e0ff;
39347
+ font-family: 'JetBrains Mono', var(--font-mono), monospace;
39348
+ }
39349
+ .slides-theme-neon .slides-content h1,
39350
+ .slides-theme-neon .slides-content h2 {
39351
+ color: #00f0ff;
39352
+ text-shadow:
39353
+ 0 0 10px rgba(0, 240, 255, 0.5),
39354
+ 0 0 40px rgba(0, 240, 255, 0.2);
39355
+ }
39356
+ .slides-theme-neon .slides-content blockquote {
39357
+ border-left: 3px solid #00f0ff;
39358
+ box-shadow: -4px 0 20px rgba(0, 240, 255, 0.15);
39359
+ }
39360
+ .slides-theme-neon .slides-content pre {
39361
+ border: 1px solid rgba(0, 240, 255, 0.2);
39362
+ box-shadow: 0 0 15px rgba(0, 240, 255, 0.1);
39363
+ }
39364
+ .slides-theme-neon .slides-viewport::after {
39365
+ content: '';
39366
+ position: absolute;
39367
+ inset: 0;
39368
+ pointer-events: none;
39369
+ background: repeating-linear-gradient(
39370
+ 0deg,
39371
+ transparent,
39372
+ transparent 2px,
39373
+ rgba(0, 240, 255, 0.015) 2px,
39374
+ rgba(0, 240, 255, 0.015) 4px
39375
+ );
39376
+ z-index: 2;
39377
+ }
39378
+ .slides-theme-neon .slides-controls {
39379
+ background: #050510;
39380
+ }
39381
+
39382
+ /* ═══ EDITORIAL THEME ═══ */
39383
+ .slides-theme-editorial,
39384
+ .slides-theme-editorial .slides-viewport {
39385
+ background: #faf8f5;
39386
+ color: #2c2c2c;
39387
+ font-family: Georgia, 'Times New Roman', serif;
39388
+ }
39389
+ .slides-theme-editorial .slides-content h1,
39390
+ .slides-theme-editorial .slides-content h2 {
39391
+ font-family: 'Cormorant Garamond', Georgia, serif;
39392
+ color: #1a1a1a;
39393
+ font-weight: 600;
39394
+ }
39395
+ .slides-theme-editorial .slides-content h1 {
39396
+ letter-spacing: -0.03em;
39397
+ }
39398
+ .slides-theme-editorial .slides-content p:first-of-type::first-letter {
39399
+ float: left;
39400
+ font-size: 3.4em;
39401
+ line-height: 0.8;
39402
+ padding-right: 8px;
39403
+ padding-top: 4px;
39404
+ font-weight: 700;
39405
+ color: #c0392b;
39406
+ font-family: 'Cormorant Garamond', Georgia, serif;
39407
+ }
39408
+ .slides-theme-editorial .slides-content blockquote {
39409
+ border-left: 2px solid #c0392b;
39410
+ font-style: italic;
39411
+ font-size: 1.15em;
39412
+ color: #555;
39413
+ }
39414
+ .slides-theme-editorial .slides-content hr {
39415
+ border: none;
39416
+ height: 1px;
39417
+ background: linear-gradient(to right, transparent, #ccc, transparent);
39418
+ margin: 1.5em 0;
39419
+ }
39420
+ .slides-theme-editorial .slides-controls {
39421
+ background: #f0ece6;
39422
+ color: #666;
39423
+ }
39424
+
39425
+ /* ═══ BOLD-SIGNAL THEME ═══ */
39426
+ .slides-theme-bold-signal {
39427
+ background: linear-gradient(135deg, #0f0c29, #1a1a3e, #24243e);
39428
+ color: #e8e8f0;
39429
+ font-family: 'Space Grotesk', var(--font-sans), sans-serif;
39430
+ }
39431
+ .slides-theme-bold-signal .slides-content h1 {
39432
+ color: #ff6b35;
39433
+ font-weight: 700;
39434
+ }
39435
+ .slides-theme-bold-signal .slides-content h2 {
39436
+ color: #ffd166;
39437
+ }
39438
+ .slides-theme-bold-signal .slides-content blockquote {
39439
+ background: rgba(255, 107, 53, 0.1);
39440
+ border-left: 4px solid #ff6b35;
39441
+ border-radius: 0 8px 8px 0;
39442
+ padding: 16px 20px;
39443
+ }
39444
+ .slides-theme-bold-signal .slides-controls {
39445
+ background: #0a0820;
39446
+ }
39447
+
39448
+ /* ═══ SWISS THEME ═══ */
39449
+ .slides-theme-swiss,
39450
+ .slides-theme-swiss .slides-viewport {
39451
+ background: #ffffff;
39452
+ color: #1a1a1a;
39453
+ font-family: 'Helvetica Neue', 'Inter', Arial, sans-serif;
39454
+ }
39455
+ .slides-theme-swiss .slides-viewport::before {
39456
+ content: '';
39457
+ position: absolute;
39458
+ inset: 0;
39459
+ pointer-events: none;
39460
+ background-image:
39461
+ linear-gradient(rgba(0, 0, 0, 0.04) 1px, transparent 1px),
39462
+ linear-gradient(90deg, rgba(0, 0, 0, 0.04) 1px, transparent 1px);
39463
+ background-size: 40px 40px;
39464
+ z-index: 0;
39465
+ }
39466
+ .slides-theme-swiss .slides-content {
39467
+ position: relative;
39468
+ z-index: 1;
39469
+ }
39470
+ .slides-theme-swiss .slides-content h1 {
39471
+ color: #e63946;
39472
+ text-transform: uppercase;
39473
+ letter-spacing: 0.05em;
39474
+ font-weight: 900;
39475
+ }
39476
+ .slides-theme-swiss .slides-content h2 {
39477
+ color: #1d3557;
39478
+ font-weight: 700;
39479
+ }
39480
+ .slides-theme-swiss .slides-controls {
39481
+ background: #f1f1f1;
39482
+ color: #333;
39483
+ }
39484
+
39485
+ /* ═══ NOTEBOOK THEME ═══ */
39486
+ .slides-theme-notebook {
39487
+ background: #1a1a2e;
39488
+ color: #3c3c3c;
39489
+ }
39490
+ .slides-theme-notebook .slides-viewport {
39491
+ background: #fdf6e3;
39492
+ border-radius: 8px;
39493
+ margin: 12px;
39494
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);
39495
+ border-left: 5px solid #e74c3c;
39496
+ }
39497
+ .slides-theme-notebook .slides-content h1,
39498
+ .slides-theme-notebook .slides-content h2 {
39499
+ font-family: 'Caveat', cursive, sans-serif;
39500
+ color: #2c3e50;
39501
+ }
39502
+ .slides-theme-notebook .slides-content h1 {
39503
+ font-size: clamp(2rem, 6vw, 4rem);
39504
+ }
39505
+ .slides-theme-notebook .slides-controls {
39506
+ background: #f5edd6;
39507
+ color: #666;
39508
+ }
39509
+
39510
+ /* ═══ MOOD KEYFRAMES ═══ */
39511
+ @keyframes mood-dramatic {
39512
+ from {
39513
+ opacity: 0;
39514
+ transform: scale(0.95) translateY(10px);
39515
+ }
39516
+ to {
39517
+ opacity: 1;
39518
+ transform: none;
39519
+ }
39520
+ }
39521
+ @keyframes mood-techy {
39522
+ 0% {
39523
+ opacity: 0;
39524
+ transform: translateY(8px);
39525
+ filter: blur(4px);
39526
+ }
39527
+ 50% {
39528
+ opacity: 1;
39529
+ filter: blur(0);
39530
+ }
39531
+ 100% {
39532
+ transform: none;
39533
+ }
39534
+ }
39535
+ @keyframes mood-playful {
39536
+ 0% {
39537
+ opacity: 0;
39538
+ transform: translateY(20px);
39539
+ }
39540
+ 60% {
39541
+ transform: translateY(-4px);
39542
+ }
39543
+ 80% {
39544
+ transform: translateY(2px);
39545
+ }
39546
+ 100% {
39547
+ opacity: 1;
39548
+ transform: none;
39549
+ }
39550
+ }
39551
+ @keyframes mood-calm {
39552
+ from {
39553
+ opacity: 0;
39554
+ }
39555
+ to {
39556
+ opacity: 1;
39557
+ }
39558
+ }
39559
+
39560
+ /* ═══ BACKGROUND EFFECTS ═══ */
39561
+ .slides-bgfx {
39562
+ position: absolute;
39563
+ inset: 0;
39564
+ pointer-events: none;
39565
+ z-index: 0;
39566
+ }
39567
+ .slides-bgfx-gradient-mesh {
39568
+ background:
39569
+ radial-gradient(ellipse at 20% 50%, rgba(120, 80, 255, 0.15) 0%, transparent 50%),
39570
+ radial-gradient(ellipse at 80% 20%, rgba(255, 100, 80, 0.12) 0%, transparent 50%),
39571
+ radial-gradient(ellipse at 50% 80%, rgba(80, 200, 255, 0.1) 0%, transparent 50%);
39572
+ animation: bgfx-drift 12s ease-in-out infinite alternate;
39573
+ }
39574
+ @keyframes bgfx-drift {
39575
+ 0% {
39576
+ transform: translate(0, 0) scale(1);
39577
+ }
39578
+ 50% {
39579
+ transform: translate(5%, -3%) scale(1.05);
39580
+ }
39581
+ 100% {
39582
+ transform: translate(-3%, 4%) scale(1.02);
39583
+ }
39584
+ }
39585
+ .slides-bgfx-noise {
39586
+ opacity: 0.06;
39587
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
39588
+ }
39589
+ .slides-bgfx-grid {
39590
+ background-image:
39591
+ linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px),
39592
+ linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
39593
+ background-size: 32px 32px;
39594
+ }
39595
+ .slides-bgfx-particles::before,
39596
+ .slides-bgfx-particles::after {
39597
+ content: '';
39598
+ position: absolute;
39599
+ width: 4px;
39600
+ height: 4px;
39601
+ border-radius: 50%;
39602
+ background: rgba(255, 255, 255, 0.2);
39603
+ box-shadow:
39604
+ 40px 80px 0 rgba(255, 255, 255, 0.15),
39605
+ 120px 40px 0 rgba(255, 255, 255, 0.1),
39606
+ 200px 120px 0 rgba(255, 255, 255, 0.12),
39607
+ 300px 60px 0 rgba(255, 255, 255, 0.08),
39608
+ 400px 140px 0 rgba(255, 255, 255, 0.15);
39609
+ animation: bgfx-float 8s ease-in-out infinite alternate;
39610
+ }
39611
+ .slides-bgfx-particles::after {
39612
+ animation-delay: -4s;
39613
+ animation-direction: alternate-reverse;
39614
+ }
39615
+ @keyframes bgfx-float {
39616
+ from {
39617
+ transform: translateY(0);
39618
+ }
39619
+ to {
39620
+ transform: translateY(-15px);
39621
+ }
39622
+ }
39623
+
38379
39624
  /* ═══ VIEW TRANSITIONS ═══ */
38380
39625
  .slides-content {
38381
39626
  view-transition-name: slide-content;
@@ -38691,11 +39936,14 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
38691
39936
  { once: true }
38692
39937
  );
38693
39938
  }
38694
- /** Trigger stagger-in animation on slide content children after transition.
38695
- * Uses the universal data-enter attribute from the motion system. */
38696
39939
  _slidesStaggerIn() {
38697
- const slideEffect = this._slidesEffects.get(this._slidesCurrentIndex) || "";
38698
- const enterValue = ResultViewer._EFFECT_MAP[slideEffect] || (slideEffect ? slideEffect : "slide-up");
39940
+ const idx = this._slidesCurrentIndex;
39941
+ const mood = this._slidesMoods.get(idx) || this._slidesGlobalMood;
39942
+ const moodCfg = ResultViewer._MOOD_CONFIG[mood];
39943
+ const slideEffect = this._slidesEffects.get(idx) || "";
39944
+ const enterValue = moodCfg ? moodCfg.enter : ResultViewer._EFFECT_MAP[slideEffect] || (slideEffect ? slideEffect : "slide-up");
39945
+ const delayMs = moodCfg?.delayMs ?? 60;
39946
+ const durationMs = moodCfg?.durationMs ?? 300;
38699
39947
  const CHILD_SELECTOR = ":scope > h1, :scope > h2, :scope > h3, :scope > p, :scope > ul, :scope > ol, :scope > table, :scope > blockquote, :scope > pre, :scope > div:not(.slide-header):not(.slide-footer), :scope > figure, :scope > img, :scope > .slide-content-area";
38700
39948
  const applyToChildren = (container) => {
38701
39949
  const children = container.querySelectorAll(CHILD_SELECTOR);
@@ -38704,7 +39952,8 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
38704
39952
  htmlEl.removeAttribute("data-enter");
38705
39953
  void htmlEl.offsetWidth;
38706
39954
  htmlEl.setAttribute("data-enter", enterValue);
38707
- htmlEl.style.animationDelay = `${i7 * 60}ms`;
39955
+ htmlEl.style.animationDelay = `${i7 * delayMs}ms`;
39956
+ htmlEl.style.animationDuration = `${durationMs}ms`;
38708
39957
  });
38709
39958
  };
38710
39959
  const iframe = this.shadowRoot?.querySelector(".slide-bridge-frame");
@@ -38724,6 +39973,97 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
38724
39973
  const content2 = this.shadowRoot?.querySelector(".slides-content");
38725
39974
  if (content2) applyToChildren(content2);
38726
39975
  }
39976
+ _slidesApplyTextEffect() {
39977
+ const effect = this._slidesEffects.get(this._slidesCurrentIndex) || "";
39978
+ if (!ResultViewer._PRETEXT_EFFECTS.has(effect)) return;
39979
+ const content2 = this.shadowRoot?.querySelector(".slides-content");
39980
+ if (!content2) return;
39981
+ const heading2 = content2.querySelector("h1, h2");
39982
+ if (!heading2) return;
39983
+ const text = heading2.textContent || "";
39984
+ if (!text) return;
39985
+ switch (effect) {
39986
+ case "typing": {
39987
+ heading2.textContent = "";
39988
+ heading2.style.borderRight = "2px solid currentColor";
39989
+ let i7 = 0;
39990
+ const type = () => {
39991
+ if (i7 < text.length) {
39992
+ heading2.textContent += text[i7];
39993
+ i7++;
39994
+ requestAnimationFrame(() => setTimeout(type, 40 + Math.random() * 30));
39995
+ } else {
39996
+ setTimeout(() => {
39997
+ heading2.style.borderRight = "none";
39998
+ }, 800);
39999
+ }
40000
+ };
40001
+ setTimeout(type, 200);
40002
+ break;
40003
+ }
40004
+ case "scramble": {
40005
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$%&";
40006
+ const revealed = new Array(text.length).fill(false);
40007
+ let iterations = 0;
40008
+ const scramble = () => {
40009
+ let display = "";
40010
+ for (let j2 = 0; j2 < text.length; j2++) {
40011
+ if (revealed[j2] || text[j2] === " ") {
40012
+ display += text[j2];
40013
+ } else {
40014
+ display += chars[Math.floor(Math.random() * chars.length)];
40015
+ }
40016
+ }
40017
+ heading2.textContent = display;
40018
+ if (iterations > 5) {
40019
+ const unrevealed = revealed.map((r7, idx) => !r7 && text[idx] !== " " ? idx : -1).filter((x3) => x3 >= 0);
40020
+ if (unrevealed.length > 0) {
40021
+ const pick2 = unrevealed[Math.floor(Math.random() * unrevealed.length)];
40022
+ revealed[pick2] = true;
40023
+ }
40024
+ }
40025
+ iterations++;
40026
+ if (revealed.some((r7) => !r7) && revealed.filter((r7) => r7).length < text.length) {
40027
+ requestAnimationFrame(scramble);
40028
+ } else {
40029
+ heading2.textContent = text;
40030
+ }
40031
+ };
40032
+ setTimeout(scramble, 200);
40033
+ break;
40034
+ }
40035
+ case "wave": {
40036
+ heading2.innerHTML = "";
40037
+ const chars = text.split("");
40038
+ chars.forEach((char, i7) => {
40039
+ const span = document.createElement("span");
40040
+ span.textContent = char === " " ? "\xA0" : char;
40041
+ span.style.display = "inline-block";
40042
+ span.style.animation = `mood-playful 0.5s ease ${i7 * 30}ms both`;
40043
+ heading2.appendChild(span);
40044
+ });
40045
+ break;
40046
+ }
40047
+ case "fly-in": {
40048
+ heading2.innerHTML = "";
40049
+ const words = text.split(" ");
40050
+ words.forEach((word, i7) => {
40051
+ const span = document.createElement("span");
40052
+ span.textContent = word + " ";
40053
+ span.style.display = "inline-block";
40054
+ span.style.opacity = "0";
40055
+ span.style.transform = `translate(${(Math.random() - 0.5) * 200}px, ${(Math.random() - 0.5) * 100}px)`;
40056
+ span.style.transition = `all 0.6s cubic-bezier(0.16, 1, 0.3, 1) ${i7 * 80}ms`;
40057
+ heading2.appendChild(span);
40058
+ requestAnimationFrame(() => {
40059
+ span.style.opacity = "1";
40060
+ span.style.transform = "none";
40061
+ });
40062
+ });
40063
+ break;
40064
+ }
40065
+ }
40066
+ }
38727
40067
  /** Advance the next hidden build fragment. Returns true if a fragment was revealed. */
38728
40068
  _slidesAdvanceBuild() {
38729
40069
  const hasBuild = this._slidesBuilds.get(this._slidesCurrentIndex);
@@ -38788,6 +40128,7 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
38788
40128
  this._afterSlideRender();
38789
40129
  }
38790
40130
  this._slidesStaggerIn();
40131
+ this._slidesApplyTextEffect();
38791
40132
  };
38792
40133
  if (transition === "none" || !("startViewTransition" in document) || this._slidesBridgeScript) {
38793
40134
  this._slidesCurrentIndex = newIndex;
@@ -39200,33 +40541,32 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
39200
40541
  }
39201
40542
  }
39202
40543
  _renderSlideFormat(target2, data, format) {
39203
- const win = window;
39204
40544
  const doRender = () => {
39205
- if (win._photonRenderers?.render) {
39206
- win._photonRenderers.render(target2, data, format);
40545
+ if (window._photonRenderers?.render) {
40546
+ window._photonRenderers.render(target2, data, format);
39207
40547
  } else {
39208
40548
  target2.textContent = typeof data === "object" ? JSON.stringify(data, null, 2) : String(data ?? "");
39209
40549
  }
39210
40550
  };
39211
- if (win._photonRenderers) {
40551
+ if (window._photonRenderers) {
39212
40552
  doRender();
39213
- } else if (win._photonRenderersLoading) {
39214
- win._photonRenderersQueue = win._photonRenderersQueue || [];
39215
- win._photonRenderersQueue.push(doRender);
40553
+ } else if (window._photonRenderersLoading) {
40554
+ window._photonRenderersQueue = window._photonRenderersQueue || [];
40555
+ window._photonRenderersQueue.push(doRender);
39216
40556
  } else {
39217
- win._photonRenderersLoading = true;
39218
- win._photonRenderersQueue = [doRender];
40557
+ window._photonRenderersLoading = true;
40558
+ window._photonRenderersQueue = [doRender];
39219
40559
  fetch("/api/photon-renderers.js").then((r7) => r7.text()).then((code) => {
39220
40560
  try {
39221
40561
  (0, eval)(code);
39222
40562
  } catch {
39223
40563
  }
39224
- const queue = win._photonRenderersQueue || [];
39225
- win._photonRenderersQueue = [];
40564
+ const queue = window._photonRenderersQueue || [];
40565
+ window._photonRenderersQueue = [];
39226
40566
  queue.forEach((fn2) => fn2());
39227
40567
  }).catch(() => {
39228
- const queue = win._photonRenderersQueue || [];
39229
- win._photonRenderersQueue = [];
40568
+ const queue = window._photonRenderersQueue || [];
40569
+ window._photonRenderersQueue = [];
39230
40570
  queue.forEach((fn2) => fn2());
39231
40571
  });
39232
40572
  }
@@ -39663,6 +41003,77 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
39663
41003
  </div>
39664
41004
  `;
39665
41005
  }
41006
+ // ── Guide Renderer — horizontal stepper for multi-step flows ──
41007
+ _renderGuide(data) {
41008
+ const steps2 = Array.isArray(data) ? data : [];
41009
+ if (steps2.length === 0) {
41010
+ return b2`<div class="empty-state">No steps</div>`;
41011
+ }
41012
+ return b2`
41013
+ <div
41014
+ style="display: flex; align-items: flex-start; gap: 0; padding: 16px 8px; overflow-x: auto;"
41015
+ >
41016
+ ${steps2.map((step, i7) => {
41017
+ const status = step.status || "pending";
41018
+ const isDone = status === "done";
41019
+ const isActive = status === "active";
41020
+ const circleColor = isDone ? "var(--accent-primary, #3b82f6)" : isActive ? "var(--accent-primary, #3b82f6)" : "var(--bg-tertiary, #374151)";
41021
+ const circleBorder = isActive ? "2px solid var(--accent-primary, #3b82f6)" : "none";
41022
+ const circleText = isDone ? "#fff" : isActive ? "var(--accent-primary, #3b82f6)" : "var(--t-muted, #9ca3af)";
41023
+ const circleBg = isDone ? circleColor : isActive ? "transparent" : circleColor;
41024
+ const labelColor = isDone || isActive ? "var(--t-primary, #f5f5f5)" : "var(--t-muted, #9ca3af)";
41025
+ const lineColor = isDone ? "var(--accent-primary, #3b82f6)" : "var(--bg-tertiary, #374151)";
41026
+ return b2`
41027
+ <div style="display: flex; align-items: flex-start; flex: 1; min-width: 0;">
41028
+ <div
41029
+ style="display: flex; flex-direction: column; align-items: center; flex-shrink: 0; width: 100%;"
41030
+ >
41031
+ <div
41032
+ style="
41033
+ width: 28px; height: 28px; border-radius: 50%;
41034
+ background: ${circleBg}; border: ${circleBorder};
41035
+ display: flex; align-items: center; justify-content: center;
41036
+ font-size: 12px; font-weight: 600; color: ${circleText};
41037
+ transition: all 0.2s ease;
41038
+ "
41039
+ >
41040
+ ${isDone ? b2`<svg
41041
+ width="14"
41042
+ height="14"
41043
+ viewBox="0 0 12 12"
41044
+ fill="none"
41045
+ stroke="currentColor"
41046
+ stroke-width="2"
41047
+ stroke-linecap="round"
41048
+ >
41049
+ <path d="M2.5 6l2.5 2.5 4.5-5" />
41050
+ </svg>` : i7 + 1}
41051
+ </div>
41052
+ <div
41053
+ style="margin-top: 6px; font-size: 12px; font-weight: ${isActive ? "600" : "500"}; color: ${labelColor}; text-align: center; line-height: 1.3; padding: 0 4px;"
41054
+ >
41055
+ ${step.label}
41056
+ </div>
41057
+ ${step.detail ? b2`<div
41058
+ style="margin-top: 2px; font-size: 11px; color: var(--t-muted, #9ca3af); text-align: center; padding: 0 4px;"
41059
+ >
41060
+ ${step.detail}
41061
+ </div>` : ""}
41062
+ </div>
41063
+ ${i7 < steps2.length - 1 ? b2`<div
41064
+ style="
41065
+ position: relative; top: 14px;
41066
+ flex: 1; height: 2px; min-width: 20px;
41067
+ background: ${lineColor};
41068
+ transition: background 0.2s ease;
41069
+ "
41070
+ ></div>` : ""}
41071
+ </div>
41072
+ `;
41073
+ })}
41074
+ </div>
41075
+ `;
41076
+ }
39666
41077
  // ── Magazine Renderer — markdown-powered multi-column layout ──
39667
41078
  _renderMagazine(data) {
39668
41079
  const text = typeof data === "string" ? data : data?.text || "";
@@ -43525,6 +44936,52 @@ ResultViewer._TIMESTAMP_FIELDS = [
43525
44936
  // ReactiveArray auto-stamp (fallback for creation)
43526
44937
  ];
43527
44938
  // Map slide effect directives to universal motion data-enter values
44939
+ // Shared theme CSS injected into both shadow DOM styles and bridge srcdoc
44940
+ ResultViewer._BRIDGE_THEME_CSS = `
44941
+ .slides-theme-default { background: #1a1a2e; color: #e6e6e6; }
44942
+ .slides-theme-default h1, .slides-theme-default h2 { color: #a5b4fc; }
44943
+ .slides-theme-uncover { background: #f8f8f8; color: #333; }
44944
+ .slides-theme-uncover h1, .slides-theme-uncover h2 { color: #1a1a1a; }
44945
+ .slides-theme-gaia { background: #1a472a; color: #e0f0e0; }
44946
+ .slides-theme-gaia h1, .slides-theme-gaia h2 { color: #66bb6a; }
44947
+ .slides-theme-rose { background: #2d1b2e; color: #f0e0e8; }
44948
+ .slides-theme-rose h1, .slides-theme-rose h2 { color: #f48fb1; }
44949
+ .slides-theme-dracula { background: #282a36; color: #f8f8f2; }
44950
+ .slides-theme-dracula h1, .slides-theme-dracula h2 { color: #bd93f9; }
44951
+ .slides-theme-auto { background: var(--bg-panel, #1a1a2e); color: var(--t-primary, #e0e0e0); }
44952
+ .slides-theme-auto h1, .slides-theme-auto h2 { color: var(--accent, #6366f1); }
44953
+ .slides-theme-neon { background: #0a0a1a; color: #e0e0ff; font-family: 'JetBrains Mono', monospace; }
44954
+ .slides-theme-neon h1, .slides-theme-neon h2 { color: #00f0ff; text-shadow: 0 0 10px rgba(0,240,255,0.5), 0 0 40px rgba(0,240,255,0.2); }
44955
+ .slides-theme-editorial { background: #faf8f5; color: #2c2c2c; font-family: Georgia, 'Times New Roman', serif; }
44956
+ .slides-theme-editorial h1, .slides-theme-editorial h2 { font-family: 'Cormorant Garamond', Georgia, serif; color: #1a1a1a; }
44957
+ .slides-theme-bold-signal { background: linear-gradient(135deg, #0f0c29, #1a1a3e, #24243e); color: #e8e8f0; font-family: 'Space Grotesk', sans-serif; }
44958
+ .slides-theme-bold-signal h1 { color: #ff6b35; }
44959
+ .slides-theme-bold-signal h2 { color: #ffd166; }
44960
+ .slides-theme-swiss { background: #ffffff; color: #1a1a1a; font-family: 'Helvetica Neue', 'Inter', Arial, sans-serif; }
44961
+ .slides-theme-swiss h1 { color: #e63946; text-transform: uppercase; letter-spacing: 0.05em; }
44962
+ .slides-theme-swiss h2 { color: #1d3557; }
44963
+ .slides-theme-notebook { background: #1a1a2e; color: #3c3c3c; }
44964
+ .slides-theme-notebook .slide-canvas { background: #fdf6e3; border-left: 5px solid #e74c3c; border-radius: 8px; }
44965
+ .slides-theme-notebook h1, .slides-theme-notebook h2 { font-family: 'Caveat', cursive; color: #2c3e50; }
44966
+ @keyframes mood-dramatic { from { opacity: 0; transform: scale(0.95) translateY(10px); } to { opacity: 1; transform: none; } }
44967
+ @keyframes mood-techy { 0% { opacity: 0; transform: translateY(8px); filter: blur(4px); } 50% { opacity: 1; filter: blur(0); } 100% { transform: none; } }
44968
+ @keyframes mood-playful { 0% { opacity: 0; transform: translateY(20px); } 60% { transform: translateY(-4px); } 80% { transform: translateY(2px); } 100% { opacity: 1; transform: none; } }
44969
+ @keyframes mood-calm { from { opacity: 0; } to { opacity: 1; } }
44970
+ @keyframes bgdrift { 0% { transform: translate(0,0) scale(1); } 50% { transform: translate(5%,-3%) scale(1.05); } 100% { transform: translate(-3%,4%) scale(1.02); } }
44971
+ .slides-theme-neon body::after { content: ''; position: fixed; inset: 0; pointer-events: none; background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,240,255,0.015) 2px, rgba(0,240,255,0.015) 4px); z-index: 100; }
44972
+ .slides-theme-neon .slide-body blockquote { border-left: 3px solid #00f0ff; box-shadow: -4px 0 20px rgba(0,240,255,0.15); }
44973
+ .slides-theme-neon .slide-body pre { border: 1px solid rgba(0,240,255,0.2); box-shadow: 0 0 15px rgba(0,240,255,0.1); }
44974
+ .slides-theme-editorial .slide-body p:first-of-type::first-letter { float: left; font-size: 3.4em; line-height: 0.8; padding-right: 8px; padding-top: 4px; font-weight: 700; color: #c0392b; font-family: 'Cormorant Garamond', Georgia, serif; }
44975
+ .slides-theme-editorial .slide-body blockquote { border-left: 2px solid #c0392b; font-style: italic; color: #555; }
44976
+ .slides-theme-bold-signal .slide-body blockquote { background: rgba(255,107,53,0.1); border-left: 4px solid #ff6b35; border-radius: 0 8px 8px 0; padding: 16px 20px; }
44977
+ .slides-theme-swiss body::before { content: ''; position: fixed; inset: 0; pointer-events: none; background-image: linear-gradient(rgba(0,0,0,0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(0,0,0,0.04) 1px, transparent 1px); background-size: 40px 40px; z-index: 0; }
44978
+ `;
44979
+ // Google Fonts per theme
44980
+ ResultViewer._THEME_FONTS = {
44981
+ editorial: "Cormorant+Garamond:wght@400;600;700",
44982
+ "bold-signal": "Space+Grotesk:wght@500;700",
44983
+ notebook: "Caveat:wght@400;700"
44984
+ };
43528
44985
  ResultViewer._EFFECT_MAP = {
43529
44986
  "fade-up": "slide-up",
43530
44987
  "fade-down": "slide-down",
@@ -43543,6 +45000,18 @@ ResultViewer._EFFECT_MAP = {
43543
45000
  "scale-up": "scale-up",
43544
45001
  "flip-in": "flip-in"
43545
45002
  };
45003
+ /** Trigger stagger-in animation on slide content children after transition.
45004
+ * Uses the universal data-enter attribute from the motion system. */
45005
+ // Mood → animation config
45006
+ ResultViewer._MOOD_CONFIG = {
45007
+ dramatic: { enter: "mood-dramatic", delayMs: 100, durationMs: 600 },
45008
+ techy: { enter: "mood-techy", delayMs: 40, durationMs: 300 },
45009
+ playful: { enter: "mood-playful", delayMs: 80, durationMs: 400 },
45010
+ professional: { enter: "fade-in", delayMs: 30, durationMs: 200 },
45011
+ calm: { enter: "mood-calm", delayMs: 120, durationMs: 800 }
45012
+ };
45013
+ // Pretext-powered text effects: typing, scramble, wave, fly-in
45014
+ ResultViewer._PRETEXT_EFFECTS = /* @__PURE__ */ new Set(["typing", "scramble", "wave", "fly-in"]);
43546
45015
  __decorateClass([
43547
45016
  n4({ type: Object })
43548
45017
  ], ResultViewer.prototype, "result", 2);
@@ -44963,7 +46432,7 @@ var MarketplaceView = class extends i4 {
44963
46432
  try {
44964
46433
  const res = await fetch("/api/marketplace/sources/remove", {
44965
46434
  method: "POST",
44966
- headers: { "Content-Type": "application/json" },
46435
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
44967
46436
  body: JSON.stringify({ name: name2 }),
44968
46437
  signal: AbortSignal.timeout(1e4)
44969
46438
  });
@@ -44994,6 +46463,7 @@ var MarketplaceView = class extends i4 {
44994
46463
  try {
44995
46464
  const res = await fetch("/api/marketplace/add", {
44996
46465
  method: "POST",
46466
+ headers: { "X-Photon-Request": "1" },
44997
46467
  body: JSON.stringify({ name: item.name }),
44998
46468
  signal: AbortSignal.timeout(3e4)
44999
46469
  // 30s for installation
@@ -45029,6 +46499,7 @@ var MarketplaceView = class extends i4 {
45029
46499
  try {
45030
46500
  const res = await fetch("/api/marketplace/remove", {
45031
46501
  method: "POST",
46502
+ headers: { "X-Photon-Request": "1" },
45032
46503
  body: JSON.stringify({ name: item.name }),
45033
46504
  signal: AbortSignal.timeout(1e4)
45034
46505
  });
@@ -45058,6 +46529,7 @@ var MarketplaceView = class extends i4 {
45058
46529
  try {
45059
46530
  const res = await fetch("/api/marketplace/add", {
45060
46531
  method: "POST",
46532
+ headers: { "X-Photon-Request": "1" },
45061
46533
  body: JSON.stringify({ name: item.name }),
45062
46534
  signal: AbortSignal.timeout(3e4)
45063
46535
  });
@@ -45137,7 +46609,7 @@ var MarketplaceView = class extends i4 {
45137
46609
  try {
45138
46610
  const res = await fetch("/api/marketplace/sources/add", {
45139
46611
  method: "POST",
45140
- headers: { "Content-Type": "application/json" },
46612
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
45141
46613
  body: JSON.stringify({ source: source3 }),
45142
46614
  signal: AbortSignal.timeout(3e4)
45143
46615
  // 30s for adding repo
@@ -46090,6 +47562,23 @@ var beamTypographyTokens = {
46090
47562
  };
46091
47563
 
46092
47564
  // src/auto-ui/frontend/components/custom-ui-renderer.ts
47565
+ function getBeamThemeTokens(themeMode) {
47566
+ const tokens = getThemeTokens(themeMode);
47567
+ if (themeMode === "dark") {
47568
+ tokens["--color-surface"] = "hsl(220, 15%, 10%)";
47569
+ tokens["--color-surface-container"] = "hsl(220, 15%, 12%)";
47570
+ tokens["--color-surface-container-high"] = "hsl(220, 15%, 14%)";
47571
+ tokens["--color-surface-container-highest"] = "hsl(220, 15%, 16%)";
47572
+ tokens["--bg"] = "hsl(220, 15%, 10%)";
47573
+ } else {
47574
+ tokens["--color-surface"] = "#eae4dd";
47575
+ tokens["--color-surface-container"] = "#f8f5f1";
47576
+ tokens["--color-surface-container-high"] = "#f0ebe5";
47577
+ tokens["--color-surface-container-highest"] = "#e8e2db";
47578
+ tokens["--bg"] = "#eae4dd";
47579
+ }
47580
+ return tokens;
47581
+ }
46093
47582
  var CustomUiRenderer = class extends i4 {
46094
47583
  constructor() {
46095
47584
  super(...arguments);
@@ -46134,7 +47623,7 @@ var CustomUiRenderer = class extends i4 {
46134
47623
  }
46135
47624
  if (changedProperties.has("theme")) {
46136
47625
  if (this._iframeRef?.contentWindow) {
46137
- const themeTokens = getThemeTokens(this.theme);
47626
+ const themeTokens = getBeamThemeTokens(this.theme);
46138
47627
  this._iframeRef.contentWindow.postMessage(
46139
47628
  {
46140
47629
  jsonrpc: "2.0",
@@ -46179,6 +47668,7 @@ var CustomUiRenderer = class extends i4 {
46179
47668
  "sandbox",
46180
47669
  "allow-scripts allow-forms allow-same-origin allow-popups allow-modals"
46181
47670
  );
47671
+ iframe.setAttribute("allowtransparency", "true");
46182
47672
  iframe.addEventListener("load", (e8) => this._handleIframeLoad(e8));
46183
47673
  iframe.src = this._blobUrl;
46184
47674
  container.appendChild(iframe);
@@ -46417,7 +47907,7 @@ var CustomUiRenderer = class extends i4 {
46417
47907
  _handleIframeLoad(e8) {
46418
47908
  const iframe = e8.target;
46419
47909
  this._iframeRef = iframe;
46420
- const themeTokens = getThemeTokens(this.theme);
47910
+ const themeTokens = getBeamThemeTokens(this.theme);
46421
47911
  this._iframeRef?.contentWindow?.postMessage(
46422
47912
  {
46423
47913
  jsonrpc: "2.0",
@@ -46455,16 +47945,20 @@ var CustomUiRenderer = class extends i4 {
46455
47945
  this._contentResizeObserver?.disconnect();
46456
47946
  const body = iframe.contentDocument?.body;
46457
47947
  if (body) {
46458
- this._contentResizeObserver = new ResizeObserver(() => {
46459
- const scrollH = iframe.contentDocument?.body.scrollHeight ?? 0;
46460
- const containerH = this.offsetHeight || 500;
46461
- if (scrollH > containerH) {
46462
- iframe.style.height = scrollH + "px";
46463
- } else {
46464
- iframe.style.height = "";
46465
- }
46466
- });
46467
- this._contentResizeObserver.observe(body);
47948
+ const bodyOverflow = iframe.contentDocument?.defaultView ? getComputedStyle(iframe.contentDocument.body).overflow : "";
47949
+ const isFullHeightApp = bodyOverflow === "hidden";
47950
+ if (!isFullHeightApp) {
47951
+ this._contentResizeObserver = new ResizeObserver(() => {
47952
+ const scrollH = iframe.contentDocument?.body.scrollHeight ?? 0;
47953
+ const containerH = this.offsetHeight || 500;
47954
+ if (scrollH > containerH) {
47955
+ iframe.style.height = scrollH + "px";
47956
+ } else {
47957
+ iframe.style.height = "";
47958
+ }
47959
+ });
47960
+ this._contentResizeObserver.observe(body);
47961
+ }
46468
47962
  }
46469
47963
  }
46470
47964
  disconnectedCallback() {
@@ -46488,7 +47982,7 @@ CustomUiRenderer.styles = [
46488
47982
  width: 100%;
46489
47983
  height: 100%;
46490
47984
  min-height: 500px;
46491
- background: var(--bg-panel, #0d0d0d);
47985
+ background: transparent;
46492
47986
  border-radius: var(--radius-md);
46493
47987
  overflow: visible;
46494
47988
  }
@@ -66468,6 +67962,23 @@ function X_(r7, i7) {
66468
67962
  }
66469
67963
 
66470
67964
  // src/auto-ui/frontend/components/mcp-app-renderer.ts
67965
+ function getBeamThemeTokens2(themeMode) {
67966
+ const tokens = getThemeTokens(themeMode);
67967
+ if (themeMode === "dark") {
67968
+ tokens["--color-surface"] = "hsl(220, 15%, 10%)";
67969
+ tokens["--color-surface-container"] = "hsl(220, 15%, 12%)";
67970
+ tokens["--color-surface-container-high"] = "hsl(220, 15%, 14%)";
67971
+ tokens["--color-surface-container-highest"] = "hsl(220, 15%, 16%)";
67972
+ tokens["--bg"] = "hsl(220, 15%, 10%)";
67973
+ } else {
67974
+ tokens["--color-surface"] = "#eae4dd";
67975
+ tokens["--color-surface-container"] = "#f8f5f1";
67976
+ tokens["--color-surface-container-high"] = "#f0ebe5";
67977
+ tokens["--color-surface-container-highest"] = "#e8e2db";
67978
+ tokens["--bg"] = "#eae4dd";
67979
+ }
67980
+ return tokens;
67981
+ }
66471
67982
  var VALID_STYLE_KEYS = /* @__PURE__ */ new Set([
66472
67983
  // Background colors
66473
67984
  "--color-background-primary",
@@ -66596,14 +68107,14 @@ var McpAppRenderer = class extends i4 {
66596
68107
  willUpdate(changedProperties) {
66597
68108
  if (changedProperties.has("theme")) {
66598
68109
  if (this._bridge) {
66599
- const specTokens = filterSpecVariables(getThemeTokens(this.theme));
68110
+ const specTokens = filterSpecVariables(getBeamThemeTokens2(this.theme));
66600
68111
  this._bridge.setHostContext({
66601
68112
  theme: this.theme,
66602
68113
  styles: { variables: specTokens }
66603
68114
  });
66604
68115
  }
66605
68116
  if (this._iframeRef?.contentWindow) {
66606
- const themeTokens = getThemeTokens(this.theme);
68117
+ const themeTokens = getBeamThemeTokens2(this.theme);
66607
68118
  this._iframeRef.contentWindow.postMessage(
66608
68119
  {
66609
68120
  jsonrpc: "2.0",
@@ -66659,6 +68170,7 @@ var McpAppRenderer = class extends i4 {
66659
68170
  "sandbox",
66660
68171
  "allow-scripts allow-forms allow-same-origin allow-popups allow-modals"
66661
68172
  );
68173
+ iframe.setAttribute("allowtransparency", "true");
66662
68174
  iframe.addEventListener("load", (e8) => this._handleIframeLoad(e8));
66663
68175
  iframe.src = this._blobUrl;
66664
68176
  container.appendChild(iframe);
@@ -66716,7 +68228,7 @@ var McpAppRenderer = class extends i4 {
66716
68228
  const iframe = e8.target;
66717
68229
  this._iframeRef = iframe;
66718
68230
  if (!iframe.contentWindow) return;
66719
- const themeTokens = getThemeTokens(this.theme);
68231
+ const themeTokens = getBeamThemeTokens2(this.theme);
66720
68232
  iframe.contentWindow.postMessage(
66721
68233
  {
66722
68234
  jsonrpc: "2.0",
@@ -66760,7 +68272,7 @@ var McpAppRenderer = class extends i4 {
66760
68272
  const msg = event.data;
66761
68273
  if (!msg || typeof msg !== "object") return;
66762
68274
  if (msg.jsonrpc === "2.0" && msg.method === "ui/initialize" && msg.id != null) {
66763
- const themeTokens2 = getThemeTokens(this.theme);
68275
+ const themeTokens2 = getBeamThemeTokens2(this.theme);
66764
68276
  iframe.contentWindow?.postMessage(
66765
68277
  {
66766
68278
  jsonrpc: "2.0",
@@ -66829,7 +68341,7 @@ var McpAppRenderer = class extends i4 {
66829
68341
  void asyncMessageHandler(event);
66830
68342
  };
66831
68343
  window.addEventListener("message", this._messageHandler);
66832
- const specTokens = filterSpecVariables(getThemeTokens(this.theme));
68344
+ const specTokens = filterSpecVariables(getBeamThemeTokens2(this.theme));
66833
68345
  this._bridge = new W_(
66834
68346
  null,
66835
68347
  { name: "Photon Beam", version: "1.0.0" },
@@ -66968,7 +68480,7 @@ McpAppRenderer.styles = [
66968
68480
  width: 100%;
66969
68481
  height: 100%;
66970
68482
  min-height: 500px;
66971
- background: var(--bg-panel, #0d0d0d);
68483
+ background: transparent;
66972
68484
  border-radius: var(--radius-md);
66973
68485
  overflow: visible;
66974
68486
  }
@@ -92284,6 +93796,12 @@ function buildPhotonDocblockTagCatalog(runtimeVersion) {
92284
93796
  apply: "@stateful true",
92285
93797
  type: "keyword"
92286
93798
  },
93799
+ {
93800
+ label: "@channel",
93801
+ detail: "Channel support \u2014 sends messages into client conversations (e.g. @channel claude)",
93802
+ apply: "@channel claude",
93803
+ type: "keyword"
93804
+ },
92287
93805
  {
92288
93806
  label: "@idleTimeout",
92289
93807
  detail: "Idle timeout in ms",
@@ -96283,6 +97801,7 @@ var ElicitationModal = class extends i4 {
96283
97801
  case "confirm":
96284
97802
  return this._renderConfirm();
96285
97803
  case "oauth":
97804
+ case "url":
96286
97805
  return this._renderOAuth();
96287
97806
  case "form":
96288
97807
  return this._renderForm();
@@ -96467,17 +97986,19 @@ var ElicitationModal = class extends i4 {
96467
97986
  };
96468
97987
  const provider = this.data?.provider || "OAuth";
96469
97988
  const icon2 = providerIcons[provider.toLowerCase()] || providerIcons.default;
96470
- const scopes = (this.data?.scopes || []).join(", ") || "basic access";
97989
+ const scopes = (this.data?.scopes || []).join(", ");
97990
+ const customMessage = this.data?.message;
97991
+ const buttonLabel = customMessage ? "Open" : `Authorize ${provider}`;
96471
97992
  return b2`
96472
97993
  <div class="oauth-content">
96473
97994
  <div class="oauth-icon">${icon2}</div>
96474
- <p class="oauth-message">Authorization is required to access ${provider}.</p>
96475
- <p class="oauth-scopes">Requested permissions: ${scopes}</p>
97995
+ <p class="oauth-message">
97996
+ ${customMessage || `Authorization is required to access ${provider}.`}
97997
+ </p>
97998
+ ${scopes ? b2`<p class="oauth-scopes">Requested permissions: ${scopes}</p>` : ""}
96476
97999
  <div class="actions" style="justify-content: center;">
96477
98000
  <button class="btn-secondary" @click=${() => this._cancel()}>Cancel</button>
96478
- <button class="btn-primary" @click=${() => this._startOAuth()}>
96479
- Authorize ${provider}
96480
- </button>
98001
+ <button class="btn-primary" @click=${() => this._startOAuth()}>${buttonLabel}</button>
96481
98002
  </div>
96482
98003
  </div>
96483
98004
  `;
@@ -98952,15 +100473,21 @@ var ForkDialog = class extends i4 {
98952
100473
  super(...arguments);
98953
100474
  this.photonName = "";
98954
100475
  this.originRepo = "";
100476
+ this.requireNewName = false;
100477
+ this.suggestedName = "";
98955
100478
  this.targets = [];
98956
100479
  this._selectedTarget = "local";
98957
100480
  this._newRepoName = "";
100481
+ this._newPhotonName = "";
98958
100482
  }
98959
100483
  render() {
98960
100484
  return b2`
98961
100485
  <div class="modal-content" @click=${(e8) => e8.stopPropagation()}>
98962
100486
  <h3>Fork ${this.photonName}</h3>
98963
100487
  ${this.originRepo ? b2`<div class="origin-info">From ${this.originRepo}</div>` : ""}
100488
+ <div class="origin-info">
100489
+ ${this.requireNewName ? "This photon is already local, so the fork needs a new local name." : "Marketplace forks keep the same local name unless you choose another one."}
100490
+ </div>
98964
100491
 
98965
100492
  <div class="target-list">
98966
100493
  ${this.targets.map(
@@ -99012,16 +100539,26 @@ var ForkDialog = class extends i4 {
99012
100539
  <div class="target-radio"></div>
99013
100540
  <div class="target-info">
99014
100541
  <div class="target-name">Local only</div>
99015
- <div class="target-repo">Remove marketplace tracking, keep file as-is</div>
100542
+ <div class="target-repo">Create or keep a local editable copy</div>
99016
100543
  </div>
99017
100544
  </div>
99018
100545
  </div>
99019
100546
 
100547
+ <input
100548
+ class="create-repo-input"
100549
+ type="text"
100550
+ placeholder=${this.suggestedName || (this.requireNewName ? "new-local-name" : "Optional local name")}
100551
+ .value=${this._newPhotonName}
100552
+ @input=${(e8) => {
100553
+ this._newPhotonName = e8.target.value;
100554
+ }}
100555
+ />
100556
+
99020
100557
  <div class="actions">
99021
100558
  <button class="btn" @click=${() => this._cancel()}>Cancel</button>
99022
100559
  <button
99023
100560
  class="btn btn-primary"
99024
- ?disabled=${this._selectedTarget === "create" && !this._newRepoName.trim()}
100561
+ ?disabled=${this._selectedTarget === "create" && !this._newRepoName.trim() || this.requireNewName && !this._newPhotonName.trim()}
99025
100562
  @click=${() => this._confirm()}
99026
100563
  >
99027
100564
  Fork
@@ -99039,7 +100576,7 @@ var ForkDialog = class extends i4 {
99039
100576
  }
99040
100577
  this.dispatchEvent(
99041
100578
  new CustomEvent("fork-confirm", {
99042
- detail: { target: target2 },
100579
+ detail: { target: target2, newName: this._newPhotonName.trim() || void 0 },
99043
100580
  bubbles: true,
99044
100581
  composed: true
99045
100582
  })
@@ -99223,6 +100760,12 @@ __decorateClass([
99223
100760
  __decorateClass([
99224
100761
  n4()
99225
100762
  ], ForkDialog.prototype, "originRepo", 2);
100763
+ __decorateClass([
100764
+ n4({ type: Boolean })
100765
+ ], ForkDialog.prototype, "requireNewName", 2);
100766
+ __decorateClass([
100767
+ n4()
100768
+ ], ForkDialog.prototype, "suggestedName", 2);
99226
100769
  __decorateClass([
99227
100770
  n4({ type: Array })
99228
100771
  ], ForkDialog.prototype, "targets", 2);
@@ -99232,6 +100775,9 @@ __decorateClass([
99232
100775
  __decorateClass([
99233
100776
  r5()
99234
100777
  ], ForkDialog.prototype, "_newRepoName", 2);
100778
+ __decorateClass([
100779
+ r5()
100780
+ ], ForkDialog.prototype, "_newPhotonName", 2);
99235
100781
  ForkDialog = __decorateClass([
99236
100782
  t4("fork-dialog")
99237
100783
  ], ForkDialog);
@@ -99242,6 +100788,7 @@ var AppLayout = class extends i4 {
99242
100788
  super(...arguments);
99243
100789
  this.photonName = "";
99244
100790
  this.photonIcon = "";
100791
+ this.hideBelow = false;
99245
100792
  this._poppedOut = false;
99246
100793
  this._handleKeydown = (e8) => {
99247
100794
  if (e8.key === "Escape" && this._poppedOut) {
@@ -99299,6 +100846,34 @@ AppLayout.styles = [
99299
100846
  display: block;
99300
100847
  }
99301
100848
 
100849
+ :host([hide-below]) .scroll-divider,
100850
+ :host([hide-below]) .below-fold {
100851
+ display: none;
100852
+ }
100853
+
100854
+ /* App tab mode: fill the available flex height instead of using min-height */
100855
+ :host([hide-below]) {
100856
+ flex: 1;
100857
+ min-height: 0;
100858
+ height: 100%;
100859
+ }
100860
+
100861
+ :host([hide-below]) .app-viewport {
100862
+ min-height: unset;
100863
+ height: 100%;
100864
+ display: flex;
100865
+ flex-direction: column;
100866
+ /* Remove rounded corners and clipping — we fill the full viewport */
100867
+ border-radius: 0;
100868
+ overflow: visible;
100869
+ }
100870
+
100871
+ :host([hide-below]) .app-content {
100872
+ overflow: hidden;
100873
+ flex: 1;
100874
+ min-height: 0;
100875
+ }
100876
+
99302
100877
  .app-viewport {
99303
100878
  min-height: calc(100vh - 140px);
99304
100879
  border-radius: var(--radius-md);
@@ -99408,6 +100983,9 @@ __decorateClass([
99408
100983
  __decorateClass([
99409
100984
  n4({ type: String })
99410
100985
  ], AppLayout.prototype, "photonIcon", 2);
100986
+ __decorateClass([
100987
+ n4({ type: Boolean, reflect: true, attribute: "hide-below" })
100988
+ ], AppLayout.prototype, "hideBelow", 2);
99411
100989
  __decorateClass([
99412
100990
  r5()
99413
100991
  ], AppLayout.prototype, "_poppedOut", 2);