@portel/photon 1.19.0 → 1.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) 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.d.ts.map +1 -1
  5. package/dist/auto-ui/beam/routes/api-config.js +165 -24
  6. package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
  7. package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -1
  8. package/dist/auto-ui/beam/routes/api-marketplace.js +14 -1
  9. package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
  10. package/dist/auto-ui/beam.d.ts.map +1 -1
  11. package/dist/auto-ui/beam.js +187 -77
  12. package/dist/auto-ui/beam.js.map +1 -1
  13. package/dist/auto-ui/bridge/index.d.ts.map +1 -1
  14. package/dist/auto-ui/bridge/index.js +17 -0
  15. package/dist/auto-ui/bridge/index.js.map +1 -1
  16. package/dist/auto-ui/bridge/renderers.d.ts.map +1 -1
  17. package/dist/auto-ui/bridge/renderers.js +12 -4
  18. package/dist/auto-ui/bridge/renderers.js.map +1 -1
  19. package/dist/auto-ui/streamable-http-transport.d.ts +1 -0
  20. package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
  21. package/dist/auto-ui/streamable-http-transport.js +179 -44
  22. package/dist/auto-ui/streamable-http-transport.js.map +1 -1
  23. package/dist/auto-ui/types.d.ts +12 -0
  24. package/dist/auto-ui/types.d.ts.map +1 -1
  25. package/dist/auto-ui/types.js.map +1 -1
  26. package/dist/beam-form.bundle.js +63 -185
  27. package/dist/beam-form.bundle.js.map +4 -4
  28. package/dist/beam.bundle.js +2115 -761
  29. package/dist/beam.bundle.js.map +4 -4
  30. package/dist/capability-negotiator.d.ts +67 -0
  31. package/dist/capability-negotiator.d.ts.map +1 -0
  32. package/dist/capability-negotiator.js +104 -0
  33. package/dist/capability-negotiator.js.map +1 -0
  34. package/dist/channel-manager.d.ts +122 -0
  35. package/dist/channel-manager.d.ts.map +1 -0
  36. package/dist/channel-manager.js +266 -0
  37. package/dist/channel-manager.js.map +1 -0
  38. package/dist/cli/commands/beam.d.ts.map +1 -1
  39. package/dist/cli/commands/beam.js +47 -30
  40. package/dist/cli/commands/beam.js.map +1 -1
  41. package/dist/cli/commands/build.d.ts.map +1 -1
  42. package/dist/cli/commands/build.js +27 -2
  43. package/dist/cli/commands/build.js.map +1 -1
  44. package/dist/cli/commands/daemon.d.ts.map +1 -1
  45. package/dist/cli/commands/daemon.js +12 -6
  46. package/dist/cli/commands/daemon.js.map +1 -1
  47. package/dist/cli/commands/mcp.d.ts.map +1 -1
  48. package/dist/cli/commands/mcp.js +18 -6
  49. package/dist/cli/commands/mcp.js.map +1 -1
  50. package/dist/cli/commands/package.d.ts.map +1 -1
  51. package/dist/cli/commands/package.js +25 -7
  52. package/dist/cli/commands/package.js.map +1 -1
  53. package/dist/cli/commands/serve.d.ts.map +1 -1
  54. package/dist/cli/commands/serve.js +14 -2
  55. package/dist/cli/commands/serve.js.map +1 -1
  56. package/dist/cli-alias.d.ts.map +1 -1
  57. package/dist/cli-alias.js +2 -3
  58. package/dist/cli-alias.js.map +1 -1
  59. package/dist/context-store.d.ts +4 -4
  60. package/dist/context-store.d.ts.map +1 -1
  61. package/dist/context-store.js +18 -15
  62. package/dist/context-store.js.map +1 -1
  63. package/dist/context.d.ts +25 -2
  64. package/dist/context.d.ts.map +1 -1
  65. package/dist/context.js +69 -4
  66. package/dist/context.js.map +1 -1
  67. package/dist/daemon/client.d.ts.map +1 -1
  68. package/dist/daemon/client.js +16 -1
  69. package/dist/daemon/client.js.map +1 -1
  70. package/dist/daemon/manager.d.ts +2 -0
  71. package/dist/daemon/manager.d.ts.map +1 -1
  72. package/dist/daemon/manager.js +40 -8
  73. package/dist/daemon/manager.js.map +1 -1
  74. package/dist/daemon/server.js +89 -64
  75. package/dist/daemon/server.js.map +1 -1
  76. package/dist/daemon/worker-host.js +7 -0
  77. package/dist/daemon/worker-host.js.map +1 -1
  78. package/dist/daemon/worker-manager.d.ts.map +1 -1
  79. package/dist/daemon/worker-manager.js +79 -17
  80. package/dist/daemon/worker-manager.js.map +1 -1
  81. package/dist/daemon/worker-protocol.d.ts +3 -0
  82. package/dist/daemon/worker-protocol.d.ts.map +1 -1
  83. package/dist/deploy/cloudflare.d.ts.map +1 -1
  84. package/dist/deploy/cloudflare.js +2 -4
  85. package/dist/deploy/cloudflare.js.map +1 -1
  86. package/dist/loader.d.ts +11 -1
  87. package/dist/loader.d.ts.map +1 -1
  88. package/dist/loader.js +129 -13
  89. package/dist/loader.js.map +1 -1
  90. package/dist/marketplace-manager.d.ts +7 -1
  91. package/dist/marketplace-manager.d.ts.map +1 -1
  92. package/dist/marketplace-manager.js +165 -61
  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 +40 -21
  100. package/dist/photon-cli-runner.js.map +1 -1
  101. package/dist/photon-doc-extractor.d.ts.map +1 -1
  102. package/dist/photon-doc-extractor.js +59 -15
  103. package/dist/photon-doc-extractor.js.map +1 -1
  104. package/dist/resource-server.d.ts +105 -0
  105. package/dist/resource-server.d.ts.map +1 -0
  106. package/dist/resource-server.js +723 -0
  107. package/dist/resource-server.js.map +1 -0
  108. package/dist/serv/auth/jwt.d.ts +2 -0
  109. package/dist/serv/auth/jwt.d.ts.map +1 -1
  110. package/dist/serv/auth/jwt.js +11 -5
  111. package/dist/serv/auth/jwt.js.map +1 -1
  112. package/dist/serv/vault/token-vault.d.ts +2 -0
  113. package/dist/serv/vault/token-vault.d.ts.map +1 -1
  114. package/dist/serv/vault/token-vault.js +6 -0
  115. package/dist/serv/vault/token-vault.js.map +1 -1
  116. package/dist/server.d.ts +20 -149
  117. package/dist/server.d.ts.map +1 -1
  118. package/dist/server.js +246 -1233
  119. package/dist/server.js.map +1 -1
  120. package/dist/shared/audit.d.ts.map +1 -1
  121. package/dist/shared/audit.js +7 -0
  122. package/dist/shared/audit.js.map +1 -1
  123. package/dist/shared/security.d.ts +10 -0
  124. package/dist/shared/security.d.ts.map +1 -1
  125. package/dist/shared/security.js +27 -0
  126. package/dist/shared/security.js.map +1 -1
  127. package/dist/shared-utils.d.ts +4 -0
  128. package/dist/shared-utils.d.ts.map +1 -1
  129. package/dist/shared-utils.js +22 -0
  130. package/dist/shared-utils.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/template-manager.d.ts.map +1 -1
  136. package/dist/template-manager.js +56 -234
  137. package/dist/template-manager.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/package.json +3 -3
@@ -19269,187 +19269,33 @@ function showToast(message, type = "info", duration4 = 3e3, action) {
19269
19269
  ToastManager.show(message, type, duration4, action);
19270
19270
  }
19271
19271
 
19272
- // src/auto-ui/frontend/components/confirm-dialog.ts
19273
- var ConfirmDialog = class extends i4 {
19274
- constructor() {
19275
- super(...arguments);
19276
- this.open = false;
19277
- this.message = "";
19278
- this.confirmLabel = "OK";
19279
- this.cancelLabel = "Cancel";
19280
- this.destructive = false;
19281
- }
19282
- show(message, options) {
19283
- this.message = message;
19284
- this.confirmLabel = options?.confirm ?? "OK";
19285
- this.cancelLabel = options?.cancel ?? "Cancel";
19286
- this.destructive = options?.destructive ?? false;
19287
- this.open = true;
19288
- return new Promise((resolve2) => {
19289
- this._resolve = resolve2;
19290
- });
19291
- }
19292
- _handleConfirm() {
19293
- this.open = false;
19294
- this._resolve?.(true);
19295
- }
19296
- _handleCancel() {
19297
- this.open = false;
19298
- this._resolve?.(false);
19299
- }
19300
- _handleKeydown(e8) {
19301
- if (e8.key === "Escape") this._handleCancel();
19302
- if (e8.key === "Enter") this._handleConfirm();
19303
- }
19304
- render() {
19305
- return b2`
19306
- <div class="dialog" @keydown=${(e8) => this._handleKeydown(e8)}>
19307
- <div class="message">${this.message}</div>
19308
- <div class="actions">
19309
- <button class="btn-cancel" @click=${() => this._handleCancel()}>
19310
- ${this.cancelLabel}
19311
- </button>
19312
- <button
19313
- class="btn-confirm ${this.destructive ? "destructive" : ""}"
19314
- @click=${() => this._handleConfirm()}
19315
- >
19316
- ${this.confirmLabel}
19317
- </button>
19318
- </div>
19319
- </div>
19320
- `;
19321
- }
19322
- };
19323
- ConfirmDialog.styles = [
19324
- theme,
19325
- i`
19326
- :host {
19327
- display: none;
19328
- }
19329
-
19330
- @keyframes backdrop-in {
19331
- from {
19332
- opacity: 0;
19333
- }
19334
- to {
19335
- opacity: 1;
19336
- }
19337
- }
19338
-
19339
- @keyframes content-in {
19340
- from {
19341
- opacity: 0;
19342
- transform: scale(0.95) translateY(8px);
19343
- }
19344
- to {
19345
- opacity: 1;
19346
- transform: scale(1) translateY(0);
19347
- }
19348
- }
19349
-
19350
- :host([open]) {
19351
- display: flex;
19352
- position: fixed;
19353
- inset: 0;
19354
- background: rgba(0, 0, 0, 0.6);
19355
- backdrop-filter: blur(4px);
19356
- z-index: 10001;
19357
- align-items: center;
19358
- justify-content: center;
19359
- animation: backdrop-in 0.15s ease-out both;
19360
- }
19361
-
19362
- .dialog {
19363
- background: var(--bg-panel);
19364
- border: 1px solid var(--border-glass);
19365
- border-radius: var(--radius-md, 12px);
19366
- padding: 24px;
19367
- max-width: 400px;
19368
- width: 90%;
19369
- box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
19370
- animation: content-in 0.2s cubic-bezier(0.16, 1, 0.3, 1) both;
19371
- animation-delay: 0.05s;
19372
- }
19373
-
19374
- .message {
19375
- font-size: 14px;
19376
- line-height: 1.5;
19377
- color: var(--t-primary);
19378
- margin-bottom: 20px;
19379
- }
19380
-
19381
- .actions {
19382
- display: flex;
19383
- justify-content: flex-end;
19384
- gap: 8px;
19385
- }
19386
-
19387
- button {
19388
- padding: 8px 16px;
19389
- border-radius: var(--radius-sm, 6px);
19390
- font-size: 13px;
19391
- font-weight: 500;
19392
- cursor: pointer;
19393
- transition: all 0.15s ease;
19394
- font-family: inherit;
19395
- border: none;
19396
- }
19397
-
19398
- .btn-cancel {
19399
- background: var(--bg-glass);
19400
- color: var(--t-primary);
19401
- border: 1px solid var(--border-glass);
19402
- }
19403
-
19404
- .btn-cancel:hover {
19405
- background: var(--bg-glass-strong);
19406
- }
19407
-
19408
- .btn-confirm {
19409
- background: var(--accent);
19410
- color: #fff;
19411
- }
19412
-
19413
- .btn-confirm:hover {
19414
- opacity: 0.9;
19415
- }
19416
-
19417
- .btn-confirm.destructive {
19418
- background: hsl(0, 60%, 50%);
19419
- }
19420
-
19421
- .btn-confirm.destructive:hover {
19422
- background: hsl(0, 60%, 45%);
19423
- }
19424
- `
19425
- ];
19426
- __decorateClass([
19427
- n4({ type: Boolean, reflect: true })
19428
- ], ConfirmDialog.prototype, "open", 2);
19429
- __decorateClass([
19430
- n4({ type: String })
19431
- ], ConfirmDialog.prototype, "message", 2);
19432
- __decorateClass([
19433
- n4({ type: String })
19434
- ], ConfirmDialog.prototype, "confirmLabel", 2);
19435
- __decorateClass([
19436
- n4({ type: String })
19437
- ], ConfirmDialog.prototype, "cancelLabel", 2);
19438
- __decorateClass([
19439
- n4({ type: Boolean })
19440
- ], ConfirmDialog.prototype, "destructive", 2);
19441
- ConfirmDialog = __decorateClass([
19442
- t4("confirm-dialog")
19443
- ], ConfirmDialog);
19444
- async function confirmDialog(message, options) {
19445
- const beamApp = document.querySelector("beam-app");
19446
- const root = beamApp?.shadowRoot ?? document.body;
19447
- let dialog = root.querySelector("confirm-dialog");
19448
- if (!dialog) {
19449
- dialog = document.createElement("confirm-dialog");
19450
- root.appendChild(dialog);
19451
- }
19452
- return dialog.show(message, options);
19272
+ // src/auto-ui/frontend/utils/elicit.ts
19273
+ function elicit(data) {
19274
+ return new Promise((resolve2) => {
19275
+ document.dispatchEvent(
19276
+ new CustomEvent("beam:elicit-local", {
19277
+ detail: { data, resolve: resolve2 }
19278
+ })
19279
+ );
19280
+ });
19281
+ }
19282
+ async function confirmElicit(message, options) {
19283
+ const result = await elicit({
19284
+ ask: "confirm",
19285
+ message,
19286
+ default: false,
19287
+ ...options?.confirm && { placeholder: options.confirm }
19288
+ });
19289
+ return result.action === "accept" && result.value !== false;
19290
+ }
19291
+ async function promptElicit(message, defaultValue = "") {
19292
+ const result = await elicit({
19293
+ ask: "text",
19294
+ message,
19295
+ default: defaultValue
19296
+ });
19297
+ if (result.action === "cancel") return null;
19298
+ return result.value ?? null;
19453
19299
  }
19454
19300
 
19455
19301
  // node_modules/lit-html/directives/unsafe-svg.js
@@ -20857,6 +20703,258 @@ function loadSavedThemeConfig() {
20857
20703
  return null;
20858
20704
  }
20859
20705
 
20706
+ // src/auto-ui/frontend/components/pending-approvals.ts
20707
+ var PendingApprovals = class extends i4 {
20708
+ constructor() {
20709
+ super(...arguments);
20710
+ this.approvals = [];
20711
+ this._resolving = /* @__PURE__ */ new Set();
20712
+ }
20713
+ render() {
20714
+ return b2`
20715
+ <div class="header">
20716
+ <span class="header-title">${shieldCheck} Pending Approvals</span>
20717
+ <button
20718
+ class="close-btn"
20719
+ @click=${() => this.dispatchEvent(new CustomEvent("close", { bubbles: true, composed: true }))}
20720
+ aria-label="Close"
20721
+ >
20722
+ ${xMark}
20723
+ </button>
20724
+ </div>
20725
+
20726
+ <div class="content">
20727
+ ${this.approvals.length === 0 ? b2`
20728
+ <div class="empty">
20729
+ ${shieldCheck}
20730
+ <div>No pending approvals</div>
20731
+ </div>
20732
+ ` : this.approvals.map((a5) => this._renderApproval(a5))}
20733
+ </div>
20734
+ `;
20735
+ }
20736
+ _renderApproval(approval) {
20737
+ const isResolving = this._resolving.has(approval.id);
20738
+ const timeLeft = this._formatTimeLeft(approval.expiresAt);
20739
+ return b2`
20740
+ <div class="approval-card ${approval.destructive ? "destructive" : ""}">
20741
+ <div class="approval-meta">
20742
+ <span>${approval.photon}.${approval.method}</span>
20743
+ ${approval.destructive ? b2`<span class="destructive-label">${warning} destructive</span>` : A}
20744
+ </div>
20745
+ <div class="approval-message">${approval.message}</div>
20746
+ ${approval.preview ? b2`<div class="preview">
20747
+ ${typeof approval.preview === "string" ? approval.preview : JSON.stringify(approval.preview, null, 2)}
20748
+ </div>` : A}
20749
+ <div class="expiry">Expires ${timeLeft}</div>
20750
+ <div class="actions">
20751
+ <button
20752
+ class="btn btn-reject"
20753
+ ?disabled=${isResolving}
20754
+ @click=${() => this._respond(approval, false)}
20755
+ >
20756
+ ${xMark} Reject
20757
+ </button>
20758
+ <button
20759
+ class="btn btn-approve"
20760
+ ?disabled=${isResolving}
20761
+ @click=${() => this._respond(approval, true)}
20762
+ >
20763
+ ${check} Approve
20764
+ </button>
20765
+ </div>
20766
+ </div>
20767
+ `;
20768
+ }
20769
+ _respond(approval, approved) {
20770
+ this._resolving.add(approval.id);
20771
+ this.requestUpdate();
20772
+ this.dispatchEvent(
20773
+ new CustomEvent("approval-response", {
20774
+ detail: { approvalId: approval.id, photon: approval.photon, approved },
20775
+ bubbles: true,
20776
+ composed: true
20777
+ })
20778
+ );
20779
+ }
20780
+ _formatTimeLeft(expiresAt) {
20781
+ const diff = new Date(expiresAt).getTime() - Date.now();
20782
+ if (diff <= 0) return "expired";
20783
+ const hours = Math.floor(diff / (1e3 * 60 * 60));
20784
+ const minutes = Math.floor(diff % (1e3 * 60 * 60) / (1e3 * 60));
20785
+ if (hours > 0) return `in ${hours}h ${minutes}m`;
20786
+ return `in ${minutes}m`;
20787
+ }
20788
+ };
20789
+ PendingApprovals.styles = [
20790
+ theme,
20791
+ buttons,
20792
+ i`
20793
+ :host {
20794
+ display: flex;
20795
+ flex-direction: column;
20796
+ height: 100%;
20797
+ color: var(--t-primary);
20798
+ }
20799
+
20800
+ .header {
20801
+ display: flex;
20802
+ align-items: center;
20803
+ justify-content: space-between;
20804
+ padding: var(--space-sm) var(--space-md);
20805
+ border-bottom: 1px solid var(--t-border);
20806
+ }
20807
+
20808
+ .header-title {
20809
+ display: flex;
20810
+ align-items: center;
20811
+ gap: var(--space-xs);
20812
+ font-weight: 600;
20813
+ font-size: var(--text-sm);
20814
+ }
20815
+
20816
+ .close-btn {
20817
+ background: none;
20818
+ border: none;
20819
+ color: var(--t-secondary);
20820
+ cursor: pointer;
20821
+ padding: var(--space-xs);
20822
+ border-radius: var(--radius-sm);
20823
+ display: flex;
20824
+ align-items: center;
20825
+ }
20826
+
20827
+ .close-btn:hover {
20828
+ background: var(--t-hover);
20829
+ }
20830
+
20831
+ .content {
20832
+ flex: 1;
20833
+ overflow-y: auto;
20834
+ padding: var(--space-sm);
20835
+ }
20836
+
20837
+ .empty {
20838
+ display: flex;
20839
+ flex-direction: column;
20840
+ align-items: center;
20841
+ justify-content: center;
20842
+ padding: var(--space-xl);
20843
+ text-align: center;
20844
+ color: var(--t-secondary);
20845
+ }
20846
+
20847
+ .empty svg {
20848
+ opacity: 0.4;
20849
+ margin-bottom: var(--space-sm);
20850
+ width: 32px;
20851
+ height: 32px;
20852
+ }
20853
+
20854
+ .approval-card {
20855
+ border: 1px solid var(--t-border);
20856
+ border-radius: var(--radius-md);
20857
+ padding: var(--space-sm) var(--space-md);
20858
+ margin-bottom: var(--space-sm);
20859
+ background: var(--t-surface);
20860
+ }
20861
+
20862
+ .approval-card.destructive {
20863
+ border-color: hsl(0, 60%, 50%);
20864
+ }
20865
+
20866
+ .approval-meta {
20867
+ display: flex;
20868
+ align-items: center;
20869
+ gap: var(--space-xs);
20870
+ font-size: var(--text-xs);
20871
+ color: var(--t-secondary);
20872
+ margin-bottom: var(--space-xs);
20873
+ }
20874
+
20875
+ .approval-message {
20876
+ font-size: var(--text-sm);
20877
+ margin-bottom: var(--space-sm);
20878
+ }
20879
+
20880
+ .preview {
20881
+ font-size: var(--text-xs);
20882
+ color: var(--t-secondary);
20883
+ background: var(--t-bg);
20884
+ padding: var(--space-xs) var(--space-sm);
20885
+ border-radius: var(--radius-sm);
20886
+ margin-bottom: var(--space-sm);
20887
+ max-height: 80px;
20888
+ overflow-y: auto;
20889
+ font-family: var(--font-mono);
20890
+ white-space: pre-wrap;
20891
+ }
20892
+
20893
+ .expiry {
20894
+ font-size: var(--text-xs);
20895
+ color: var(--t-secondary);
20896
+ }
20897
+
20898
+ .actions {
20899
+ display: flex;
20900
+ gap: var(--space-xs);
20901
+ margin-top: var(--space-sm);
20902
+ }
20903
+
20904
+ .btn {
20905
+ flex: 1;
20906
+ padding: var(--space-xs) var(--space-sm);
20907
+ border: 1px solid var(--t-border);
20908
+ border-radius: var(--radius-sm);
20909
+ cursor: pointer;
20910
+ font-size: var(--text-xs);
20911
+ font-weight: 600;
20912
+ display: flex;
20913
+ align-items: center;
20914
+ justify-content: center;
20915
+ gap: var(--space-xs);
20916
+ transition: all 0.15s;
20917
+ }
20918
+
20919
+ .btn-approve {
20920
+ background: hsl(142, 60%, 45%);
20921
+ color: white;
20922
+ border-color: hsl(142, 60%, 40%);
20923
+ }
20924
+
20925
+ .btn-approve:hover {
20926
+ background: hsl(142, 60%, 40%);
20927
+ }
20928
+
20929
+ .btn-reject {
20930
+ background: var(--t-surface);
20931
+ color: var(--t-primary);
20932
+ }
20933
+
20934
+ .btn-reject:hover {
20935
+ background: var(--t-hover);
20936
+ }
20937
+
20938
+ .destructive-label {
20939
+ display: inline-flex;
20940
+ align-items: center;
20941
+ gap: 2px;
20942
+ color: hsl(0, 70%, 55%);
20943
+ font-size: var(--text-2xs);
20944
+ font-weight: 600;
20945
+ }
20946
+ `
20947
+ ];
20948
+ __decorateClass([
20949
+ n4({ type: Array })
20950
+ ], PendingApprovals.prototype, "approvals", 2);
20951
+ __decorateClass([
20952
+ r5()
20953
+ ], PendingApprovals.prototype, "_resolving", 2);
20954
+ PendingApprovals = __decorateClass([
20955
+ t4("pending-approvals")
20956
+ ], PendingApprovals);
20957
+
20860
20958
  // src/auto-ui/frontend/services/photon-instance-manager.ts
20861
20959
  var SimpleEventEmitter = class {
20862
20960
  constructor() {
@@ -21645,6 +21743,32 @@ var MCPClientService = class {
21645
21743
  return { success: false };
21646
21744
  }
21647
21745
  }
21746
+ /**
21747
+ * Send approval response (approve/reject) for a pending approval
21748
+ */
21749
+ async sendApprovalResponse(approvalId, photon, approved) {
21750
+ try {
21751
+ await this.sendRequest("beam/approval-response", {
21752
+ approvalId,
21753
+ photon,
21754
+ approved
21755
+ });
21756
+ return { success: true };
21757
+ } catch {
21758
+ return { success: false };
21759
+ }
21760
+ }
21761
+ /**
21762
+ * Fetch all pending approvals from the server
21763
+ */
21764
+ async fetchPendingApprovals() {
21765
+ try {
21766
+ const result = await this.sendRequest("beam/approvals-list", {});
21767
+ return result?.approvals || [];
21768
+ } catch {
21769
+ return [];
21770
+ }
21771
+ }
21648
21772
  /**
21649
21773
  * Get rich help documentation for a photon via beam/photon-help tool
21650
21774
  */
@@ -21740,8 +21864,13 @@ var MCPClientService = class {
21740
21864
  id: tool["x-photon-id"] || serverName,
21741
21865
  // Use hash ID, fallback to name
21742
21866
  name: serverName,
21867
+ shortName: tool["x-photon-short-name"],
21868
+ namespace: tool["x-photon-namespace"],
21869
+ qualifiedName: tool["x-photon-qualified-name"],
21743
21870
  path: tool["x-photon-path"],
21744
21871
  // File path for View Source
21872
+ editable: tool["x-photon-editable"] ?? false,
21873
+ // User-owned (at baseDir root)
21745
21874
  description: tool["x-photon-description"],
21746
21875
  icon: tool["x-photon-icon"],
21747
21876
  internal: tool["x-photon-internal"],
@@ -21933,6 +22062,12 @@ var MCPClientService = class {
21933
22062
  case "beam/elicitation":
21934
22063
  this.emit("elicitation", notification.params);
21935
22064
  break;
22065
+ case "beam/elicitation-deferred":
22066
+ this.emit("elicitation-deferred", notification.params);
22067
+ break;
22068
+ case "beam/approval-resolved":
22069
+ this.emit("approval-resolved", notification.params);
22070
+ break;
21936
22071
  case "beam/result":
21937
22072
  this.emit("result", notification.params);
21938
22073
  break;
@@ -22435,6 +22570,62 @@ var ViewportManager = class {
22435
22570
  }
22436
22571
  };
22437
22572
 
22573
+ // src/auto-ui/frontend/utils/beam-route.ts
22574
+ function decodeBeamPathSegments(pathname) {
22575
+ return pathname.split("/").filter(Boolean).map((segment) => {
22576
+ try {
22577
+ return decodeURIComponent(segment);
22578
+ } catch {
22579
+ return segment;
22580
+ }
22581
+ });
22582
+ }
22583
+ function matchesNamespacedPhoton(photon, namespace, shortName) {
22584
+ return photon.namespace === namespace && (photon.shortName || photon.name) === shortName;
22585
+ }
22586
+ function parseBeamRoutePath(pathname, photons, externalMCPs = []) {
22587
+ const segments = decodeBeamPathSegments(pathname);
22588
+ if (segments.length === 0) {
22589
+ return { photonName: null, methodNames: [] };
22590
+ }
22591
+ if (segments.length === 1) {
22592
+ return { photonName: segments[0], methodNames: [] };
22593
+ }
22594
+ if (segments.length === 2) {
22595
+ const [first, second] = segments;
22596
+ const namespacedPhoton2 = photons.find(
22597
+ (photon) => matchesNamespacedPhoton(photon, first, second)
22598
+ );
22599
+ if (namespacedPhoton2) {
22600
+ return { photonName: namespacedPhoton2.name, methodNames: [] };
22601
+ }
22602
+ return { photonName: first, methodNames: second.split("+").filter(Boolean) };
22603
+ }
22604
+ const namespace = segments[segments.length - 3];
22605
+ const shortName = segments[segments.length - 2];
22606
+ const methodSegment = segments[segments.length - 1];
22607
+ const namespacedPhoton = photons.find((photon) => matchesNamespacedPhoton(photon, namespace, shortName)) || externalMCPs.find((photon) => matchesNamespacedPhoton(photon, namespace, shortName));
22608
+ if (namespacedPhoton) {
22609
+ return {
22610
+ photonName: namespacedPhoton.name,
22611
+ methodNames: methodSegment.split("+").filter(Boolean)
22612
+ };
22613
+ }
22614
+ const photonName = segments[segments.length - 2];
22615
+ return { photonName, methodNames: methodSegment.split("+").filter(Boolean) };
22616
+ }
22617
+ function buildBeamRoutePath(photon, methodName, splitPanelMethodNames = []) {
22618
+ if (!photon) return "/";
22619
+ const baseSegments = photon.namespace && photon.shortName ? [photon.namespace, photon.shortName] : [photon.name];
22620
+ if (!methodName) {
22621
+ return "/" + baseSegments.map((segment) => encodeURIComponent(segment)).join("/");
22622
+ }
22623
+ const methodSegments = [methodName, ...splitPanelMethodNames].map(
22624
+ (name2) => encodeURIComponent(name2)
22625
+ );
22626
+ return "/" + baseSegments.map((segment) => encodeURIComponent(segment)).join("/") + "/" + methodSegments.join("+");
22627
+ }
22628
+
22438
22629
  // src/auto-ui/frontend/components/beam-app.ts
22439
22630
  var THEME_STORAGE_KEY = "beam-theme";
22440
22631
  var PROTOCOL_STORAGE_KEY = "beam-protocol";
@@ -22449,6 +22640,10 @@ var BeamApp = class extends i4 {
22449
22640
  this._reconnectAttempt = 0;
22450
22641
  this._connectRetries = 0;
22451
22642
  this._sidebarVisible = false;
22643
+ this._sidebarWidth = parseInt(
22644
+ localStorage.getItem("beam-sidebar-width") || "300",
22645
+ 10
22646
+ );
22452
22647
  this._focusMode = false;
22453
22648
  this._viewMode = "full";
22454
22649
  this._photons = [];
@@ -22477,6 +22672,8 @@ var BeamApp = class extends i4 {
22477
22672
  this._photonHelpLoading = false;
22478
22673
  this._elicitationData = null;
22479
22674
  this._showElicitation = false;
22675
+ this._showApprovals = false;
22676
+ this._pendingApprovalsList = [];
22480
22677
  this._protocolMode = "legacy";
22481
22678
  this._selectedMcpAppUri = null;
22482
22679
  this._mcpReady = false;
@@ -22503,7 +22700,11 @@ var BeamApp = class extends i4 {
22503
22700
  this._splitPanels = [];
22504
22701
  this._methodPickerOpen = false;
22505
22702
  this._methodPickerPanelId = null;
22703
+ this._splitPrimaryWidth = null;
22704
+ this._mainTab = "methods";
22506
22705
  this._nextPanelId = 0;
22706
+ // Maps progressToken → panelId so progress events route to the correct split pane
22707
+ this._panelProgressTokens = /* @__PURE__ */ new Map();
22507
22708
  // Collection auto-subscription for ReactiveArray/Map/Set events
22508
22709
  this._collectionUnsubscribes = [];
22509
22710
  this._currentCollectionName = null;
@@ -22538,9 +22739,13 @@ var BeamApp = class extends i4 {
22538
22739
  this._initialConnectDone = false;
22539
22740
  this._handleRouteChange = () => {
22540
22741
  void (async () => {
22541
- const fullPath = window.location.pathname.slice(1);
22542
22742
  const queryPart = window.location.search.slice(1);
22543
- const [photonName, methodName] = fullPath.split("/");
22743
+ const { photonName, methodNames } = parseBeamRoutePath(
22744
+ window.location.pathname,
22745
+ this._photons,
22746
+ this._externalMCPs
22747
+ );
22748
+ const methodName = methodNames[0];
22544
22749
  this._sharedFormParams = null;
22545
22750
  let sharedParams = {};
22546
22751
  if (queryPart) {
@@ -22603,10 +22808,11 @@ var BeamApp = class extends i4 {
22603
22808
  if (photon.isExternalMCP && photon.hasMcpApp) {
22604
22809
  this._selectedMethod = null;
22605
22810
  this._view = "mcp-app";
22811
+ this._mainTab = "app";
22606
22812
  return;
22607
22813
  }
22608
22814
  if (methodName && photon.methods) {
22609
- const [firstMethodName, secondMethodName] = methodName.split("+");
22815
+ const [firstMethodName, secondMethodName] = methodNames;
22610
22816
  const method = photon.methods.find((m3) => m3.name === firstMethodName);
22611
22817
  if (method) {
22612
22818
  if (Object.keys(sharedParams).length > 0) {
@@ -22617,11 +22823,13 @@ var BeamApp = class extends i4 {
22617
22823
  }
22618
22824
  this._selectedMethod = method;
22619
22825
  this._view = "form";
22826
+ if (photon.isApp && photon.appEntry?.name === method.name) {
22827
+ this._mainTab = "app";
22828
+ } else if (!photon.isApp) {
22829
+ this._mainTab = "methods";
22830
+ }
22620
22831
  this._maybeAutoInvoke(method);
22621
22832
  if (secondMethodName) {
22622
- const urlPath = location.pathname;
22623
- const methodPart = urlPath.split("/").pop() || "";
22624
- const methodNames = methodPart.split("+");
22625
22833
  for (let i7 = 1; i7 < methodNames.length; i7++) {
22626
22834
  const name2 = methodNames[i7];
22627
22835
  if (name2 === "source") {
@@ -22644,10 +22852,12 @@ var BeamApp = class extends i4 {
22644
22852
  }
22645
22853
  this._selectedMethod = photon.appEntry;
22646
22854
  this._view = "form";
22855
+ this._mainTab = "app";
22647
22856
  this._maybeAutoInvoke(photon.appEntry);
22648
22857
  } else {
22649
22858
  this._selectedMethod = null;
22650
22859
  this._view = "list";
22860
+ this._mainTab = "methods";
22651
22861
  }
22652
22862
  }
22653
22863
  }
@@ -22811,7 +23021,7 @@ var BeamApp = class extends i4 {
22811
23021
  this._handleRemove = async () => {
22812
23022
  this._closeSettingsMenu();
22813
23023
  if (this._selectedPhoton && this._mcpReady) {
22814
- if (await confirmDialog(`Remove ${this._selectedPhoton.name} from this workspace?`, {
23024
+ if (await confirmElicit(`Remove ${this._selectedPhoton.name} from this workspace?`, {
22815
23025
  confirm: "Remove",
22816
23026
  destructive: true
22817
23027
  })) {
@@ -22822,22 +23032,42 @@ var BeamApp = class extends i4 {
22822
23032
  }
22823
23033
  }
22824
23034
  };
22825
- this._handleCopyMCPConfig = async () => {
23035
+ this._copyConfigSnippet = async (transport) => {
22826
23036
  if (!this._selectedPhoton) return;
23037
+ const name2 = this._selectedPhoton.name;
22827
23038
  try {
22828
- const res = await fetch(
22829
- `/api/export/mcp-config?photon=${encodeURIComponent(this._selectedPhoton.name)}`,
22830
- {
22831
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23039
+ let config3;
23040
+ if (transport === "url") {
23041
+ const beamUrl = `${location.protocol}//${location.host}/mcp`;
23042
+ config3 = { mcpServers: { [name2]: { url: beamUrl } } };
23043
+ } else {
23044
+ const res = await fetch("/api/export/mcp-config", {
23045
+ signal: AbortSignal.timeout(3e3)
23046
+ });
23047
+ if (res.ok) {
23048
+ const all = await res.json();
23049
+ const entry = all.mcpServers?.[name2];
23050
+ if (entry) {
23051
+ config3 = { mcpServers: { [name2]: entry } };
23052
+ } else {
23053
+ config3 = {
23054
+ mcpServers: {
23055
+ [name2]: { command: "npx", args: ["-y", "@portel/photon", "mcp", name2] }
23056
+ }
23057
+ };
23058
+ }
23059
+ } else {
23060
+ config3 = {
23061
+ mcpServers: { [name2]: { command: "npx", args: ["-y", "@portel/photon", "mcp", name2] } }
23062
+ };
22832
23063
  }
22833
- );
22834
- if (!res.ok) throw new Error("Failed to fetch config");
22835
- const config3 = await res.json();
23064
+ }
22836
23065
  await navigator.clipboard.writeText(JSON.stringify(config3, null, 2));
22837
- showToast("MCP config copied \u2014 paste into Claude Desktop settings", "success");
23066
+ const label = transport === "url" ? "HTTP config" : "Claude Desktop config";
23067
+ showToast(`${label} copied to clipboard`, "success");
22838
23068
  } catch (error2) {
22839
23069
  console.warn("Copy MCP config failed:", error2);
22840
- showToast("Failed to copy MCP config", "error");
23070
+ showToast("Failed to copy config", "error");
22841
23071
  }
22842
23072
  };
22843
23073
  this._handleUpgrade = async () => {
@@ -22847,7 +23077,7 @@ var BeamApp = class extends i4 {
22847
23077
  try {
22848
23078
  const res = await fetch("/api/marketplace/add", {
22849
23079
  method: "POST",
22850
- headers: { "Content-Type": "application/json" },
23080
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
22851
23081
  body: JSON.stringify({ name: name2 }),
22852
23082
  signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
22853
23083
  });
@@ -22876,15 +23106,19 @@ var BeamApp = class extends i4 {
22876
23106
  this._showForkDialog = false;
22877
23107
  this._forkPhotonName = "";
22878
23108
  this._forkOriginRepo = "";
23109
+ this._forkRequireNewName = false;
23110
+ this._forkSuggestedName = "";
22879
23111
  this._forkTargets = [];
22880
23112
  this._handleFork = async () => {
22881
23113
  if (!this._selectedPhoton) return;
22882
- this._forkPhotonName = this._selectedPhoton.name;
23114
+ this._forkPhotonName = this._selectedPhoton.qualifiedName || this._selectedPhoton.name;
22883
23115
  this._forkOriginRepo = this._selectedPhoton.installSource?.marketplace || "";
23116
+ this._forkRequireNewName = !this._selectedPhoton.installSource;
23117
+ this._forkSuggestedName = `${this._selectedPhoton.shortName || this._selectedPhoton.name}-copy`;
22884
23118
  await this._openForkDialog();
22885
23119
  };
22886
23120
  this._handleForkConfirm = async (e8) => {
22887
- const { target: target2 } = e8.detail;
23121
+ const { target: target2, newName } = e8.detail;
22888
23122
  const name2 = this._forkPhotonName;
22889
23123
  if (!name2) return;
22890
23124
  this._showForkDialog = false;
@@ -22892,8 +23126,8 @@ var BeamApp = class extends i4 {
22892
23126
  try {
22893
23127
  const res = await fetch("/api/marketplace/fork", {
22894
23128
  method: "POST",
22895
- headers: { "Content-Type": "application/json" },
22896
- body: JSON.stringify({ name: name2, target: target2 }),
23129
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
23130
+ body: JSON.stringify({ name: name2, target: target2, newName }),
22897
23131
  signal: AbortSignal.timeout(3e4)
22898
23132
  });
22899
23133
  const result = await res.json();
@@ -22920,6 +23154,8 @@ var BeamApp = class extends i4 {
22920
23154
  const { name: name2 } = e8.detail;
22921
23155
  this._forkPhotonName = name2;
22922
23156
  this._forkOriginRepo = "";
23157
+ this._forkRequireNewName = false;
23158
+ this._forkSuggestedName = `${name2}-copy`;
22923
23159
  await this._openForkDialog();
22924
23160
  };
22925
23161
  this._handleContribute = async () => {
@@ -22929,7 +23165,7 @@ var BeamApp = class extends i4 {
22929
23165
  try {
22930
23166
  const res = await fetch("/api/marketplace/contribute", {
22931
23167
  method: "POST",
22932
- headers: { "Content-Type": "application/json" },
23168
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
22933
23169
  body: JSON.stringify({ name: name2 }),
22934
23170
  signal: AbortSignal.timeout(6e4)
22935
23171
  });
@@ -23023,7 +23259,8 @@ var BeamApp = class extends i4 {
23023
23259
  const data = mcpClient.parseToolResult(result);
23024
23260
  if (data && data.code) {
23025
23261
  this._sourceData = data;
23026
- this._showSourceModal = true;
23262
+ this._mainTab = "source";
23263
+ this._view = "source";
23027
23264
  } else {
23028
23265
  showToast("No source code returned", "error");
23029
23266
  }
@@ -23035,14 +23272,18 @@ var BeamApp = class extends i4 {
23035
23272
  };
23036
23273
  /** Navigate to inline source view (Phase 2) */
23037
23274
  this._handleViewSourceInline = async () => {
23038
- if (this._view === "source") {
23039
- this._view = "studio";
23275
+ if (this._view === "source" || this._view === "studio") {
23040
23276
  return;
23041
23277
  }
23042
- await this._handleViewSource();
23043
- if (this._sourceData) {
23044
- this._showSourceModal = false;
23045
- this._view = "source";
23278
+ const isEditable = this._selectedPhoton?.editable && !this._selectedPhoton?.isExternalMCP;
23279
+ this._mainTab = "source";
23280
+ if (isEditable) {
23281
+ this._view = "studio";
23282
+ } else {
23283
+ await this._handleViewSource();
23284
+ if (this._sourceData) {
23285
+ this._view = "source";
23286
+ }
23046
23287
  }
23047
23288
  };
23048
23289
  /** Open settings for the current photon (Phase 3) */
@@ -23112,12 +23353,15 @@ var BeamApp = class extends i4 {
23112
23353
  const newName = detail.cloneName;
23113
23354
  if (!newName) return;
23114
23355
  try {
23115
- const res = await fetch(`/api/instances/${photonName}/${detail.instance}/clone`, {
23116
- method: "POST",
23117
- headers: { "Content-Type": "application/json" },
23118
- body: JSON.stringify({ newName }),
23119
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23120
- });
23356
+ const res = await fetch(
23357
+ `/api/instances/${encodeURIComponent(photonName)}/${encodeURIComponent(detail.instance)}/clone`,
23358
+ {
23359
+ method: "POST",
23360
+ headers: { "Content-Type": "application/json" },
23361
+ body: JSON.stringify({ newName }),
23362
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23363
+ }
23364
+ );
23121
23365
  if (res.ok) {
23122
23366
  await this._fetchInstances(photonName);
23123
23367
  showToast(`Cloned as: ${newName}`, "success");
@@ -23134,12 +23378,15 @@ var BeamApp = class extends i4 {
23134
23378
  const newName = detail.newName;
23135
23379
  if (!newName) return;
23136
23380
  try {
23137
- const res = await fetch(`/api/instances/${photonName}/${detail.instance}/rename`, {
23138
- method: "POST",
23139
- headers: { "Content-Type": "application/json" },
23140
- body: JSON.stringify({ newName }),
23141
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23142
- });
23381
+ const res = await fetch(
23382
+ `/api/instances/${encodeURIComponent(photonName)}/${encodeURIComponent(detail.instance)}/rename`,
23383
+ {
23384
+ method: "POST",
23385
+ headers: { "Content-Type": "application/json" },
23386
+ body: JSON.stringify({ newName }),
23387
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23388
+ }
23389
+ );
23143
23390
  if (res.ok) {
23144
23391
  await mcpClient.callTool(`${photonName}/_use`, { name: newName });
23145
23392
  this._setCurrentInstance(photonName, newName);
@@ -23161,10 +23408,13 @@ var BeamApp = class extends i4 {
23161
23408
  return;
23162
23409
  }
23163
23410
  try {
23164
- const res = await fetch(`/api/instances/${photonName}/${instanceToDelete}`, {
23165
- method: "DELETE",
23166
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23167
- });
23411
+ const res = await fetch(
23412
+ `/api/instances/${encodeURIComponent(photonName)}/${encodeURIComponent(instanceToDelete)}`,
23413
+ {
23414
+ method: "DELETE",
23415
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
23416
+ }
23417
+ );
23168
23418
  if (res.ok) {
23169
23419
  await mcpClient.callTool(`${photonName}/_use`, { name: "default" });
23170
23420
  this._setCurrentInstance(photonName, "default");
@@ -23183,7 +23433,7 @@ var BeamApp = class extends i4 {
23183
23433
  };
23184
23434
  this._handleDeletePhoton = async () => {
23185
23435
  this._closeSettingsMenu();
23186
- if (await confirmDialog(`Remove "${this._selectedPhoton?.name}"? It will be moved to trash.`, {
23436
+ if (await confirmElicit(`Remove "${this._selectedPhoton?.name}"? It will be moved to trash.`, {
23187
23437
  confirm: "Remove",
23188
23438
  destructive: true
23189
23439
  })) {
@@ -23369,22 +23619,35 @@ var BeamApp = class extends i4 {
23369
23619
  this._broadcastThemeToIframes();
23370
23620
  };
23371
23621
  this._handleOklchThemeReset = () => {
23372
- this._oklchEnabled = false;
23373
- const cssVars = beamThemeToCSS(
23622
+ const oldVars = beamThemeToCSS(
23374
23623
  generateBeamThemeColors({ hue: 0, chroma: 0, lightness: 0.5, theme: "dark" })
23375
23624
  );
23376
- for (const prop of Object.keys(cssVars)) {
23625
+ for (const prop of Object.keys(oldVars)) {
23377
23626
  this.style.removeProperty(prop);
23378
23627
  }
23379
- this._applyTheme();
23628
+ const theme3 = this._theme || "dark";
23629
+ const defaultViolet = { hue: 260, chroma: 0.15, lightness: 0.65, theme: theme3 };
23630
+ this._oklchEnabled = true;
23631
+ this._applyOklchTheme(defaultViolet);
23380
23632
  this._broadcastThemeToIframes();
23381
23633
  showToast("Theme reset to default", "info");
23382
23634
  };
23635
+ this._handleLocalElicit = (e8) => {
23636
+ const { data, resolve: resolve2 } = e8.detail;
23637
+ this._localElicitResolve = resolve2;
23638
+ this._elicitationData = { ...data };
23639
+ this._showElicitation = true;
23640
+ };
23383
23641
  this._handleElicitationSubmit = async (e8) => {
23384
23642
  const { value } = e8.detail;
23385
23643
  const elicitationId = this._elicitationData?.elicitationId;
23386
23644
  this._showElicitation = false;
23387
23645
  this._elicitationData = null;
23646
+ if (this._localElicitResolve) {
23647
+ this._localElicitResolve({ action: "accept", value });
23648
+ this._localElicitResolve = void 0;
23649
+ return;
23650
+ }
23388
23651
  const pendingWindow = elicitationId ? this._pendingBridgeCalls.get(elicitationId) : null;
23389
23652
  if (pendingWindow) {
23390
23653
  this._pendingBridgeCalls.delete(elicitationId);
@@ -23411,6 +23674,11 @@ var BeamApp = class extends i4 {
23411
23674
  this._showElicitation = false;
23412
23675
  this._elicitationData = null;
23413
23676
  this._isExecuting = false;
23677
+ if (this._localElicitResolve) {
23678
+ this._localElicitResolve({ action: "cancel" });
23679
+ this._localElicitResolve = void 0;
23680
+ return;
23681
+ }
23414
23682
  const pendingWindow = elicitationId ? this._pendingBridgeCalls.get(elicitationId) : null;
23415
23683
  if (pendingWindow) {
23416
23684
  this._pendingBridgeCalls.delete(elicitationId);
@@ -23426,6 +23694,18 @@ var BeamApp = class extends i4 {
23426
23694
  this._log("info", "Input cancelled");
23427
23695
  showToast("Input cancelled", "info");
23428
23696
  };
23697
+ this._handleApprovalResponse = async (e8) => {
23698
+ const { approvalId, photon, approved } = e8.detail;
23699
+ this._pendingApprovalsList = this._pendingApprovalsList.filter((a5) => a5.id !== approvalId);
23700
+ if (this._pendingApprovalsList.length === 0) {
23701
+ this._showApprovals = false;
23702
+ }
23703
+ const result = await mcpClient.sendApprovalResponse(approvalId, photon, approved);
23704
+ if (!result.success) {
23705
+ showToast("Failed to send approval response", "error");
23706
+ void this._fetchPendingApprovals();
23707
+ }
23708
+ };
23429
23709
  this._handleOAuthComplete = async (e8) => {
23430
23710
  const { elicitationId, success: success2 } = e8.detail;
23431
23711
  this._showElicitation = false;
@@ -23479,16 +23759,9 @@ var BeamApp = class extends i4 {
23479
23759
  this._showHelp = false;
23480
23760
  return;
23481
23761
  }
23482
- if (this._showPhotonHelp) {
23483
- this._showPhotonHelp = false;
23484
- return;
23485
- }
23486
- if (this._view === "source") {
23487
- this._view = "list";
23488
- return;
23489
- }
23490
- if (this._showSourceModal) {
23491
- this._closeSourceModal();
23762
+ if (this._mainTab === "help" || this._mainTab === "source") {
23763
+ this._mainTab = "methods";
23764
+ if (this._view === "source") this._view = "list";
23492
23765
  return;
23493
23766
  }
23494
23767
  if (this._view === "form" && this._selectedMethod) {
@@ -23603,6 +23876,26 @@ var BeamApp = class extends i4 {
23603
23876
  this._photonHelpLoading = false;
23604
23877
  }
23605
23878
  };
23879
+ /** Load help content for inline help tab view */
23880
+ this._loadPhotonHelp = async () => {
23881
+ if (!this._selectedPhoton) return;
23882
+ this._photonHelpMarkdown = "";
23883
+ this._photonHelpLoading = true;
23884
+ const markdown = await mcpClient.getPhotonHelp(this._selectedPhoton.name);
23885
+ if (markdown) {
23886
+ this._photonHelpMarkdown = markdown;
23887
+ } else {
23888
+ this._photonHelpMarkdown = this._generatePhotonHelpMarkdown();
23889
+ }
23890
+ this._photonHelpLoading = false;
23891
+ if (this._view === "source" || this._view === "studio") {
23892
+ if (this._selectedMethod) {
23893
+ this._view = "form";
23894
+ } else {
23895
+ this._view = "list";
23896
+ }
23897
+ }
23898
+ };
23606
23899
  this._toggleFocusMode = () => {
23607
23900
  this._focusMode = !this._focusMode;
23608
23901
  if (this._focusMode) {
@@ -23645,7 +23938,7 @@ var BeamApp = class extends i4 {
23645
23938
  this._handleReconfigure();
23646
23939
  break;
23647
23940
  case "copy-config":
23648
- void this._handleCopyMCPConfig();
23941
+ void this._copyConfigSnippet("stdio");
23649
23942
  break;
23650
23943
  case "upgrade":
23651
23944
  void this._handleUpgrade();
@@ -23706,7 +23999,8 @@ var BeamApp = class extends i4 {
23706
23999
  void this._handleRemove();
23707
24000
  break;
23708
24001
  case "help":
23709
- void this._showPhotonHelpModal();
24002
+ this._mainTab = "help";
24003
+ void this._loadPhotonHelp();
23710
24004
  break;
23711
24005
  case "fullscreen":
23712
24006
  this._handleFullscreen();
@@ -23936,6 +24230,28 @@ var BeamApp = class extends i4 {
23936
24230
  this._showError("Photon not found", `Method '${action}' not found on ${targetName}`);
23937
24231
  }
23938
24232
  }
24233
+ async _handleCreatePhoton(filename, template = "blank") {
24234
+ try {
24235
+ const res = await fetch("/api/create-photon", {
24236
+ method: "POST",
24237
+ headers: { "Content-Type": "application/json" },
24238
+ body: JSON.stringify({ filename, template })
24239
+ });
24240
+ if (!res.ok) {
24241
+ const err = await res.json().catch(() => ({ error: "Failed to create photon" }));
24242
+ this._showError("Create failed", err.error);
24243
+ return;
24244
+ }
24245
+ const { name: name2 } = await res.json();
24246
+ showToast(`Created ${filename}`, "success");
24247
+ this._pendingStudioOpen = true;
24248
+ setTimeout(() => {
24249
+ this._sidebar?.scrollPhotonIntoView(name2);
24250
+ }, 1500);
24251
+ } catch (err) {
24252
+ this._showError("Create failed", err.message);
24253
+ }
24254
+ }
23939
24255
  /**
23940
24256
  * Collect static methods from all internal photons for global display
23941
24257
  */
@@ -24019,6 +24335,7 @@ var BeamApp = class extends i4 {
24019
24335
  this._verboseLogging = true;
24020
24336
  }
24021
24337
  document.addEventListener("click", this._handleDocumentClick);
24338
+ document.addEventListener("beam:elicit-local", this._handleLocalElicit);
24022
24339
  void this._connectMCP();
24023
24340
  this._setupNotificationHandlers();
24024
24341
  window.addEventListener("popstate", this._handleRouteChange);
@@ -24063,6 +24380,7 @@ var BeamApp = class extends i4 {
24063
24380
  window.removeEventListener("message", this._handleBridgeMessage);
24064
24381
  window.removeEventListener("keydown", this._handleKeydown);
24065
24382
  document.removeEventListener("click", this._handleDocumentClick);
24383
+ document.removeEventListener("beam:elicit-local", this._handleLocalElicit);
24066
24384
  this._cleanupCollectionSubscriptions();
24067
24385
  }
24068
24386
  willUpdate(changedProperties) {
@@ -24186,6 +24504,7 @@ var BeamApp = class extends i4 {
24186
24504
  }
24187
24505
  this._initialConnectDone = true;
24188
24506
  void this._checkForUpdates();
24507
+ this._startApprovalsPolling();
24189
24508
  if (window.location.pathname !== "/") {
24190
24509
  void this._handleRouteChange();
24191
24510
  } else if (!this._selectedPhoton && this._photons.length > 0) {
@@ -24212,6 +24531,7 @@ var BeamApp = class extends i4 {
24212
24531
  this._connected = false;
24213
24532
  this._reconnecting = true;
24214
24533
  this._reconnectAttempt++;
24534
+ this._stopApprovalsPolling();
24215
24535
  showToast("Connection lost. Reconnecting...", "warning");
24216
24536
  });
24217
24537
  mcpClient.on("tools-changed", () => {
@@ -24240,8 +24560,12 @@ var BeamApp = class extends i4 {
24240
24560
  }
24241
24561
  }
24242
24562
  if (!this._selectedPhoton && window.location.pathname !== "/") {
24243
- const pathPhotonName = window.location.pathname.slice(1).split("/")[0];
24244
- const routePhoton = pathPhotonName ? this._photons.find((p5) => p5.name === pathPhotonName) : null;
24563
+ const { photonName: pathPhotonName } = parseBeamRoutePath(
24564
+ window.location.pathname,
24565
+ this._photons,
24566
+ this._externalMCPs
24567
+ );
24568
+ const routePhoton = pathPhotonName ? this._photons.find((p5) => p5.name === pathPhotonName) || this._externalMCPs.find((p5) => p5.name === pathPhotonName) : null;
24245
24569
  if (routePhoton) {
24246
24570
  void this._handleRouteChange();
24247
24571
  } else {
@@ -24263,18 +24587,15 @@ var BeamApp = class extends i4 {
24263
24587
  });
24264
24588
  mcpClient.on("progress", (data) => {
24265
24589
  this._log("info", data.message || "Processing...");
24266
- if (typeof data.progress === "number") {
24267
- if (data.progress > 0) {
24268
- this._progress = {
24269
- value: data.total ? data.progress / data.total : data.progress,
24270
- message: data.message || "Processing..."
24271
- };
24272
- } else {
24273
- this._progress = {
24274
- value: -1,
24275
- message: data.message || "Processing..."
24276
- };
24277
- }
24590
+ const panelId = data.progressToken != null ? this._panelProgressTokens.get(data.progressToken) : void 0;
24591
+ const progressValue = typeof data.progress === "number" ? data.progress > 0 ? {
24592
+ value: data.total ? data.progress / data.total : data.progress,
24593
+ message: data.message || "Processing..."
24594
+ } : { value: -1, message: data.message || "Processing..." } : null;
24595
+ if (panelId && progressValue) {
24596
+ this._updatePanel(panelId, { progress: progressValue });
24597
+ } else if (progressValue) {
24598
+ this._progress = progressValue;
24278
24599
  }
24279
24600
  });
24280
24601
  mcpClient.on("toast", (data) => {
@@ -24369,6 +24690,31 @@ var BeamApp = class extends i4 {
24369
24690
  this._photons = data.photons.map(
24370
24691
  (p5) => updateFlags.has(p5.name) ? { ...p5, hasUpdate: true } : p5
24371
24692
  );
24693
+ if (this._pendingStudioOpen) {
24694
+ const newPhoton = this._photons.find((p5) => !p5.internal && !prevNames.has(p5.name));
24695
+ if (newPhoton) {
24696
+ this._pendingStudioOpen = false;
24697
+ this._selectedPhoton = newPhoton;
24698
+ this._view = "studio";
24699
+ if (this._pendingTemplateSource) {
24700
+ const tpl = this._pendingTemplateSource;
24701
+ this._pendingTemplateSource = void 0;
24702
+ requestAnimationFrame(() => {
24703
+ const studio = this.shadowRoot?.querySelector("photon-studio");
24704
+ if (studio?.applyTemplate) {
24705
+ studio.applyTemplate({
24706
+ source: tpl,
24707
+ id: "custom",
24708
+ name: "",
24709
+ description: "",
24710
+ icon: ""
24711
+ });
24712
+ }
24713
+ });
24714
+ }
24715
+ this._updateRoute(true);
24716
+ }
24717
+ }
24372
24718
  if (this._selectedPhoton) {
24373
24719
  const updated = this._photons.find((p5) => p5.name === this._selectedPhoton?.name);
24374
24720
  if (updated) {
@@ -24382,28 +24728,7 @@ var BeamApp = class extends i4 {
24382
24728
  if (newUserPhoton) {
24383
24729
  this._selectedPhoton = newUserPhoton;
24384
24730
  this._welcomePhase = "welcome";
24385
- if (this._pendingStudioOpen) {
24386
- this._pendingStudioOpen = false;
24387
- this._view = "studio";
24388
- if (this._pendingTemplateSource) {
24389
- const tpl = this._pendingTemplateSource;
24390
- this._pendingTemplateSource = void 0;
24391
- requestAnimationFrame(() => {
24392
- const studio = this.shadowRoot?.querySelector("photon-studio");
24393
- if (studio?.applyTemplate) {
24394
- studio.applyTemplate({
24395
- source: tpl,
24396
- id: "custom",
24397
- name: "",
24398
- description: "",
24399
- icon: ""
24400
- });
24401
- }
24402
- });
24403
- }
24404
- } else {
24405
- this._view = "list";
24406
- }
24731
+ this._view = "list";
24407
24732
  this._updateRoute(true);
24408
24733
  }
24409
24734
  }
@@ -24472,6 +24797,26 @@ var BeamApp = class extends i4 {
24472
24797
  this._log("info", `Input required: ${data.message || elicitationData.ask}`);
24473
24798
  }
24474
24799
  });
24800
+ mcpClient.on("elicitation-deferred", (data) => {
24801
+ if (data) {
24802
+ if (this._elicitationData && this._elicitationData.elicitationId === data.elicitationId) {
24803
+ this._showElicitation = false;
24804
+ this._elicitationData = null;
24805
+ }
24806
+ void this._fetchPendingApprovals();
24807
+ this._log("info", `Moved to pending approvals: ${data.message || "Approval required"}`);
24808
+ }
24809
+ });
24810
+ mcpClient.on("approval-resolved", (data) => {
24811
+ if (data) {
24812
+ this._pendingApprovalsList = this._pendingApprovalsList.filter(
24813
+ (a5) => a5.id !== data.approvalId
24814
+ );
24815
+ if (this._pendingApprovalsList.length === 0) {
24816
+ this._showApprovals = false;
24817
+ }
24818
+ }
24819
+ });
24475
24820
  mcpClient.on("channel-event", (data) => {
24476
24821
  this._forwardToIframes({
24477
24822
  jsonrpc: "2.0",
@@ -24576,17 +24921,16 @@ var BeamApp = class extends i4 {
24576
24921
  } else if (!this._selectedPhoton) {
24577
24922
  path = "/";
24578
24923
  } else {
24579
- path = "/" + this._selectedPhoton.name;
24580
- if (this._selectedMethod) {
24581
- path += `/${this._selectedMethod.name}`;
24582
- for (const panel of this._splitPanels) {
24583
- if (panel.type === "method" && panel.method) {
24584
- path += `+${panel.method.name}`;
24585
- } else if (panel.type === "source") {
24586
- path += `+source`;
24587
- }
24588
- }
24589
- }
24924
+ const splitPanelMethodNames = this._selectedMethod ? this._splitPanels.map((panel) => {
24925
+ if (panel.type === "method" && panel.method) return panel.method.name;
24926
+ if (panel.type === "source") return "source";
24927
+ return null;
24928
+ }).filter((name2) => !!name2) : [];
24929
+ path = buildBeamRoutePath(
24930
+ this._selectedPhoton,
24931
+ this._selectedMethod?.name,
24932
+ splitPanelMethodNames
24933
+ );
24590
24934
  }
24591
24935
  if (replace2) {
24592
24936
  history.replaceState(null, "", path);
@@ -24975,7 +25319,7 @@ var BeamApp = class extends i4 {
24975
25319
 
24976
25320
  <nav
24977
25321
  class="sidebar-area glass-panel ${this._sidebarVisible ? "visible" : ""}"
24978
- style="margin: var(--space-sm); border-radius: var(--radius-md);"
25322
+ style="margin: var(--space-sm); border-radius: var(--radius-md); --sidebar-width: ${this._sidebarWidth}px;"
24979
25323
  aria-label="Photon navigation"
24980
25324
  >
24981
25325
  <beam-sidebar
@@ -24986,22 +25330,81 @@ var BeamApp = class extends i4 {
24986
25330
  .connected=${this._connected}
24987
25331
  .reconnecting=${this._reconnecting}
24988
25332
  .updatesAvailable=${this._updatesAvailable.length}
25333
+ .pendingApprovals=${this._pendingApprovalsList.length}
25334
+ .mainTab=${this._mainTab}
25335
+ .isApp=${!!(this._selectedPhoton?.isApp || this._selectedPhoton?.isExternalMCP && this._selectedPhoton?.hasMcpApp)}
25336
+ .hasSettings=${!!(this._selectedPhoton?.hasSettings && !this._selectedPhoton?.isExternalMCP)}
25337
+ .isExternalMCP=${!!this._selectedPhoton?.isExternalMCP}
25338
+ .hasPath=${!!this._selectedPhoton?.path}
25339
+ @tab-change=${(e8) => {
25340
+ const tab = e8.detail.tab;
25341
+ this._mainTab = tab;
25342
+ if (tab === "methods") {
25343
+ this._closeSecondPanel();
25344
+ this._selectedMethod = null;
25345
+ this._view = "list";
25346
+ this._updateRoute();
25347
+ return;
25348
+ }
25349
+ if (tab === "source") {
25350
+ void this._handleViewSourceInline();
25351
+ return;
25352
+ }
25353
+ if (tab === "help") {
25354
+ void this._loadPhotonHelp();
25355
+ return;
25356
+ }
25357
+ if (this._view === "source" || this._view === "studio") {
25358
+ if (this._selectedMethod) {
25359
+ this._view = "form";
25360
+ } else {
25361
+ this._view = "list";
25362
+ }
25363
+ }
25364
+ if (tab === "settings" && this._selectedPhoton) {
25365
+ const settingsMethod = this._selectedPhoton.methods?.find(
25366
+ (m3) => m3.name === "settings"
25367
+ );
25368
+ if (settingsMethod) {
25369
+ this._selectedMethod = settingsMethod;
25370
+ this._view = "form";
25371
+ this._maybeAutoInvoke(settingsMethod);
25372
+ }
25373
+ return;
25374
+ }
25375
+ if (tab === "app" && this._selectedPhoton?.isExternalMCP && this._selectedPhoton?.hasMcpApp) {
25376
+ this._view = "mcp-app";
25377
+ }
25378
+ if (tab === "app" && this._selectedPhoton?.isApp && this._selectedPhoton?.appEntry) {
25379
+ this._selectedMethod = this._selectedPhoton.appEntry;
25380
+ this._view = "form";
25381
+ this._maybeAutoInvoke(this._selectedPhoton.appEntry);
25382
+ }
25383
+ }}
25384
+ @toggle-focus=${() => this._toggleFocusMode()}
24989
25385
  @home=${this._goHome}
24990
25386
  @select=${(e8) => this._handlePhotonSelectMobile(e8)}
24991
25387
  @marketplace=${() => this._handleMarketplaceMobile()}
24992
25388
  @theme-change=${this._handleThemeChange}
24993
25389
  @open-theme-settings=${() => this._showThemeSettings = true}
24994
25390
  @show-shortcuts=${this._showHelpModal}
25391
+ @show-approvals=${() => {
25392
+ this._showApprovals = true;
25393
+ void this._fetchPendingApprovals();
25394
+ }}
24995
25395
  @reconnect-mcp=${(e8) => {
24996
25396
  void this._handleReconnectMCP(e8);
24997
25397
  }}
24998
25398
  @diagnostics=${() => {
24999
25399
  this._view = "diagnostics";
25000
25400
  this._updateRoute();
25401
+ }}
25402
+ @create-photon=${(e8) => {
25403
+ void this._handleCreatePhoton(e8.detail.name, e8.detail.template);
25001
25404
  }}
25002
25405
  @open-studio=${(e8) => {
25003
25406
  const photon = this._photons.find((p5) => p5.name === e8.detail.photonName);
25004
- if (photon) {
25407
+ if (photon?.editable && !photon?.isExternalMCP) {
25005
25408
  this._selectedPhoton = photon;
25006
25409
  this._view = "studio";
25007
25410
  }
@@ -25015,61 +25418,20 @@ var BeamApp = class extends i4 {
25015
25418
  }
25016
25419
  }}
25017
25420
  ></beam-sidebar>
25421
+ <div
25422
+ class="sidebar-resize-handle"
25423
+ @pointerdown=${(e8) => this._handleSidebarResizeStart(e8)}
25424
+ ></div>
25018
25425
  </nav>
25019
25426
 
25020
- <main
25021
- class="main-area"
25022
- id="main-content"
25023
- tabindex="-1"
25024
- aria-label="Main content"
25025
- style="${this._splitViewEnabled ? "overflow: hidden !important;" : ""}"
25026
- >
25027
- ${this._focusMode && this._selectedPhoton ? b2`<div class="focus-toolbar">
25028
- ${this._selectedMethod && !this._selectedPhoton.isApp ? b2`<button
25029
- class="focus-toolbar-back"
25030
- @click=${() => this._handleBackFromMethod()}
25031
- @mouseenter=${(e8) => {
25032
- e8.target.style.color = "var(--t-primary)";
25033
- e8.target.style.borderColor = "var(--accent-primary)";
25034
- }}
25035
- @mouseleave=${(e8) => {
25036
- e8.target.style.color = "var(--t-muted)";
25037
- e8.target.style.borderColor = "var(--border-glass)";
25038
- }}
25039
- title="Back to ${this._selectedPhoton.name}"
25040
- >
25041
- <svg
25042
- width="16"
25043
- height="16"
25044
- viewBox="0 0 24 24"
25045
- fill="none"
25046
- stroke="currentColor"
25047
- stroke-width="2"
25048
- stroke-linecap="round"
25049
- stroke-linejoin="round"
25050
- >
25051
- <path d="m15 18-6-6 6-6" />
25052
- </svg>
25053
- </button>` : ""}
25054
- <button
25055
- @click=${this._toggleFocusMode}
25056
- @mouseenter=${(e8) => {
25057
- e8.target.style.color = "var(--t-primary)";
25058
- e8.target.style.borderColor = "var(--accent-primary)";
25059
- }}
25060
- @mouseleave=${(e8) => {
25061
- e8.target.style.color = "var(--t-muted)";
25062
- e8.target.style.borderColor = "var(--border-glass)";
25063
- }}
25064
- title="Exit focus mode"
25065
- >
25066
- ${collapse}
25067
- </button>
25068
- </div>` : ""}
25069
- ${this._selectedPhoton ? b2`<div class="main-toolbar">
25070
- <div>
25427
+ <main class="main-area" id="main-content" tabindex="-1" aria-label="Main content">
25428
+ <div
25429
+ class="main-content-scroll"
25430
+ 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;" : ""}"
25431
+ >
25432
+ ${this._focusMode && this._selectedPhoton ? b2`<div class="focus-toolbar">
25071
25433
  ${this._selectedMethod && !this._selectedPhoton.isApp ? b2`<button
25072
- class="beam-back-btn"
25434
+ class="focus-toolbar-back"
25073
25435
  @click=${() => this._handleBackFromMethod()}
25074
25436
  @mouseenter=${(e8) => {
25075
25437
  e8.target.style.color = "var(--t-primary)";
@@ -25094,31 +25456,7 @@ var BeamApp = class extends i4 {
25094
25456
  <path d="m15 18-6-6 6-6" />
25095
25457
  </svg>
25096
25458
  </button>` : ""}
25097
- </div>
25098
- <div style="display: flex; gap: 4px; align-items: center;">
25099
- ${this._selectedPhoton.isApp ? b2`<div style="position: relative;">
25100
- <button
25101
- class="beam-fullscreen-btn"
25102
- @click=${() => {
25103
- this._methodPickerOpen = !this._methodPickerOpen;
25104
- this._methodPickerPanelId = null;
25105
- }}
25106
- @mouseenter=${(e8) => {
25107
- e8.target.style.color = "var(--accent-secondary)";
25108
- e8.target.style.borderColor = "var(--accent-secondary)";
25109
- }}
25110
- @mouseleave=${(e8) => {
25111
- e8.target.style.color = "var(--t-muted)";
25112
- e8.target.style.borderColor = "var(--border-glass)";
25113
- }}
25114
- title="Add panel"
25115
- >
25116
- +
25117
- </button>
25118
- ${this._methodPickerOpen && this._methodPickerPanelId === null ? this._renderMethodPickerPopover() : ""}
25119
- </div>` : ""}
25120
25459
  <button
25121
- class="beam-fullscreen-btn"
25122
25460
  @click=${this._toggleFocusMode}
25123
25461
  @mouseenter=${(e8) => {
25124
25462
  e8.target.style.color = "var(--t-primary)";
@@ -25128,18 +25466,21 @@ var BeamApp = class extends i4 {
25128
25466
  e8.target.style.color = "var(--t-muted)";
25129
25467
  e8.target.style.borderColor = "var(--border-glass)";
25130
25468
  }}
25131
- title=${this._focusMode ? "Exit focus mode" : "Focus mode"}
25469
+ title="Exit focus mode"
25132
25470
  >
25133
- ${this._focusMode ? collapse : expand}
25471
+ ${collapse}
25134
25472
  </button>
25135
- </div>
25136
- </div>` : ""}
25137
- ${this._renderContent()}
25138
- <activity-log
25139
- .items=${this._activityLog}
25140
- .filter=${this._selectedPhoton?.name}
25141
- @clear=${() => this._activityLog = []}
25142
- ></activity-log>
25473
+ </div>` : ""}
25474
+ ${this._selectedPhoton && !this._selectedMethod && this._mainTab === "methods" && this._view !== "studio" ? b2`<div class="main-toolbar">
25475
+ <div style="flex: 1; min-width: 0;">${this._renderPhotonToolbar()}</div>
25476
+ </div>` : ""}
25477
+ ${this._mainTab === "log" ? b2`<activity-log
25478
+ .items=${this._activityLog}
25479
+ .filter=${this._selectedPhoton?.name}
25480
+ .fullscreen=${true}
25481
+ @clear=${() => this._activityLog = []}
25482
+ ></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()}
25483
+ </div>
25143
25484
  </main>
25144
25485
 
25145
25486
  <toast-manager></toast-manager>
@@ -25160,13 +25501,13 @@ var BeamApp = class extends i4 {
25160
25501
  </div>
25161
25502
  ` : ""}
25162
25503
  ${this._showHelp ? this._renderHelpModal() : ""}
25163
- ${this._showPhotonHelp ? this._renderPhotonHelpModal() : ""}
25164
- ${this._showSourceModal ? this._renderSourceModal() : ""}
25165
25504
  ${this._selectedPrompt?.content ? this._renderPromptModal() : ""}
25166
25505
  ${this._selectedResource?.content ? this._renderResourceModal() : ""}
25167
25506
  ${this._showForkDialog ? b2`<fork-dialog
25168
25507
  .photonName=${this._forkPhotonName}
25169
25508
  .originRepo=${this._forkOriginRepo}
25509
+ .requireNewName=${this._forkRequireNewName}
25510
+ .suggestedName=${this._forkSuggestedName}
25170
25511
  .targets=${this._forkTargets}
25171
25512
  @fork-confirm=${this._handleForkConfirm}
25172
25513
  @fork-cancel=${() => {
@@ -25181,6 +25522,54 @@ var BeamApp = class extends i4 {
25181
25522
  @cancel=${this._handleElicitationCancel}
25182
25523
  @oauth-complete=${this._handleOAuthComplete}
25183
25524
  ></elicitation-modal>
25525
+
25526
+ ${this._showApprovals ? b2`
25527
+ <div class="approvals-overlay" @click=${() => this._showApprovals = false}></div>
25528
+ <div class="approvals-panel glass-panel">
25529
+ <pending-approvals
25530
+ .approvals=${this._pendingApprovalsList}
25531
+ @approval-response=${this._handleApprovalResponse}
25532
+ @close=${() => this._showApprovals = false}
25533
+ ></pending-approvals>
25534
+ </div>
25535
+ ` : ""}
25536
+ `;
25537
+ }
25538
+ _renderMethodsBentoOnly() {
25539
+ if (!this._selectedPhoton) return b2``;
25540
+ const methods = this._getVisibleMethods();
25541
+ if (methods.length === 0)
25542
+ return b2`<p style="color: var(--t-muted); padding: var(--space-md);">
25543
+ No methods available.
25544
+ </p>`;
25545
+ const hasTools = methods.some((m3) => !m3.isTemplate);
25546
+ const hasPrompts = methods.some((m3) => m3.isTemplate);
25547
+ const title = hasTools && hasPrompts ? "Methods & Prompts" : hasPrompts ? "Prompts" : "Methods";
25548
+ return b2`
25549
+ ${this._renderAnchorNav()}
25550
+ <div id="photon-methods" class="bento-methods">
25551
+ <h3 class="bento-section-title">${title}</h3>
25552
+ <div class="cards-grid">
25553
+ ${methods.map(
25554
+ (method) => b2`
25555
+ <method-card
25556
+ .method=${method}
25557
+ .photonName=${this._selectedPhoton.name}
25558
+ .selected=${this._selectedMethod?.name === method.name}
25559
+ @select=${(e8) => {
25560
+ this._selectedMethod = e8.detail.method;
25561
+ this._view = "form";
25562
+ this._mainTab = "methods";
25563
+ this._updateRoute();
25564
+ }}
25565
+ ></method-card>
25566
+ `
25567
+ )}
25568
+ </div>
25569
+ </div>
25570
+ <div id="photon-prompts" class="bento-bottom-grid">
25571
+ ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25572
+ </div>
25184
25573
  `;
25185
25574
  }
25186
25575
  _renderContent() {
@@ -25191,6 +25580,7 @@ var BeamApp = class extends i4 {
25191
25580
  return b2`<photon-studio
25192
25581
  .photonName=${this._selectedPhoton?.name || ""}
25193
25582
  .theme=${this._theme}
25583
+ .hideCloseButton=${true}
25194
25584
  @studio-close=${() => this._view = "list"}
25195
25585
  @studio-saved=${async () => {
25196
25586
  const tools = await mcpClient.listTools();
@@ -25740,62 +26130,72 @@ ${photon.errorMessage || "Unknown error"}</pre
25740
26130
  ` : ""}
25741
26131
  <div
25742
26132
  class="glass-panel"
25743
- style="padding: 0; overflow: hidden; min-height: calc(100vh - 80px); position: relative; ${hasMultipleUIs ? "border-radius: 0 0 var(--radius-md) var(--radius-md);" : ""}"
26133
+ 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);" : ""}"
25744
26134
  >
25745
26135
  <mcp-app-renderer
25746
26136
  .mcpName=${this._selectedPhoton.name}
25747
26137
  .appUri=${currentUri}
25748
26138
  .linkedTool=${linkedMethod?.name || ""}
25749
26139
  .theme=${this._theme}
25750
- style="height: calc(100vh - ${hasMultipleUIs ? "120px" : "80px"});"
26140
+ style="${this._mainTab === "app" ? "flex: 1; height: 100%;" : `height: calc(100vh - ${hasMultipleUIs ? "120px" : "80px"});`}"
25751
26141
  ></mcp-app-renderer>
25752
26142
  </div>
25753
26143
 
25754
- ${this._renderPhotonToolbar()} ${this._renderAnchorNav()}
25755
- <div id="photon-methods" class="bento-methods">
25756
- <h3 class="bento-section-title">
25757
- ${(() => {
26144
+ ${this._mainTab !== "app" ? b2`
26145
+ ${this._renderAnchorNav()}
26146
+ <div id="photon-methods" class="bento-methods">
26147
+ <h3 class="bento-section-title">
26148
+ ${(() => {
25758
26149
  const visible = this._getVisibleMethods();
25759
26150
  const hasTools = visible.some((m3) => !m3.isTemplate);
25760
26151
  const hasPrompts = visible.some((m3) => m3.isTemplate);
25761
26152
  return hasTools && hasPrompts ? "Methods & Prompts" : hasPrompts ? "Prompts" : "Methods";
25762
26153
  })()}
25763
- </h3>
25764
- ${this._getVisibleMethods().length > 0 ? b2`
25765
- <div class="cards-grid">
25766
- ${this._getVisibleMethods().map(
26154
+ </h3>
26155
+ ${this._getVisibleMethods().length > 0 ? b2`
26156
+ <div class="cards-grid">
26157
+ ${this._getVisibleMethods().map(
25767
26158
  (method) => b2`
25768
- <method-card
25769
- .method=${method}
25770
- .photonName=${this._selectedPhoton.name}
25771
- .selected=${this._selectedMethod?.name === method.name}
25772
- @select=${(e8) => {
26159
+ <method-card
26160
+ .method=${method}
26161
+ .photonName=${this._selectedPhoton.name}
26162
+ .selected=${this._selectedMethod?.name === method.name}
26163
+ @select=${(e8) => {
25773
26164
  this._selectedMethod = e8.detail.method;
25774
26165
  this._view = "form";
25775
26166
  this._updateRoute();
25776
26167
  }}
25777
- ></method-card>
25778
- `
26168
+ ></method-card>
26169
+ `
25779
26170
  )}
25780
- </div>
25781
- ` : ""}
25782
- </div>
25783
- <div id="photon-prompts" class="bento-bottom-grid">
25784
- ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25785
- </div>
26171
+ </div>
26172
+ ` : ""}
26173
+ </div>
26174
+ <div id="photon-prompts" class="bento-bottom-grid">
26175
+ ${this._renderPromptsSection()} ${this._renderResourcesSection()}
26176
+ </div>
26177
+ ` : ""}
25786
26178
  `;
25787
26179
  }
25788
26180
  if (this._view === "form" && this._selectedMethod) {
25789
26181
  const isAppMain = this._selectedPhoton.isApp && this._selectedMethod.name === "main";
25790
26182
  if (isAppMain && !this._selectedMethod.linkedUi) {
25791
26183
  const otherMethods = this._getVisibleMethods().filter((m3) => m3.name !== "main");
26184
+ const appTabActive = this._mainTab === "app";
25792
26185
  return b2`
25793
26186
  <app-layout
25794
26187
  .photonName=${this._selectedPhoton.name}
25795
26188
  .photonIcon=${this._selectedPhoton.appEntry?.icon || "\u{1F4F1}"}
26189
+ .hideBelow=${appTabActive}
25796
26190
  >
25797
- <div slot="app" style="min-height: calc(100vh - 140px);">
25798
- <div class="glass-panel" style="min-height: calc(100vh - 140px); overflow: hidden;">
26191
+ <div
26192
+ slot="app"
26193
+ style="${appTabActive ? "height: calc(100vh - 80px);" : "min-height: calc(100vh - 140px);"}"
26194
+ >
26195
+ <div
26196
+ class="glass-panel"
26197
+ style="${appTabActive ? "height: calc(100vh - 80px);" : "min-height: calc(100vh - 140px);"} overflow: hidden;"
26198
+ >
25799
26199
  ${this._renderMethodBody({
25800
26200
  photon: this._selectedPhoton,
25801
26201
  method: this._selectedMethod,
@@ -25810,44 +26210,45 @@ ${photon.errorMessage || "Unknown error"}</pre
25810
26210
  </div>
25811
26211
  </div>
25812
26212
  <div slot="popout" style="height: 100%;"></div>
25813
- <div slot="below-fold">
25814
- ${this._renderPhotonToolbar()} ${this._renderAnchorNav()}
25815
- ${otherMethods.length > 0 ? b2`
25816
- <div id="photon-methods" class="bento-methods">
25817
- <h3 class="bento-section-title">
25818
- ${(() => {
26213
+ ${appTabActive ? b2`<div slot="below-fold"></div>` : b2`<div slot="below-fold">
26214
+ ${this._renderAnchorNav()}
26215
+ ${otherMethods.length > 0 ? b2`
26216
+ <div id="photon-methods" class="bento-methods">
26217
+ <h3 class="bento-section-title">
26218
+ ${(() => {
25819
26219
  const hasTools = otherMethods.some((m3) => !m3.isTemplate);
25820
26220
  const hasPrompts = otherMethods.some((m3) => m3.isTemplate);
25821
26221
  return hasTools && hasPrompts ? "Methods & Prompts" : hasPrompts ? "Prompts" : "Methods";
25822
26222
  })()}
25823
- </h3>
25824
- <div class="cards-grid">
25825
- ${otherMethods.map(
26223
+ </h3>
26224
+ <div class="cards-grid">
26225
+ ${otherMethods.map(
25826
26226
  (method) => b2`
25827
- <method-card
25828
- .method=${method}
25829
- .photonName=${this._selectedPhoton.name}
25830
- @select=${(e8) => this._handleMethodSelect(e8)}
25831
- @update-metadata=${this._handleMethodMetadataUpdate}
25832
- ></method-card>
25833
- `
26227
+ <method-card
26228
+ .method=${method}
26229
+ .photonName=${this._selectedPhoton.name}
26230
+ @select=${(e8) => this._handleMethodSelect(e8)}
26231
+ @update-metadata=${this._handleMethodMetadataUpdate}
26232
+ ></method-card>
26233
+ `
25834
26234
  )}
25835
- </div>
25836
- </div>
25837
- ` : ""}
25838
- <div id="photon-prompts" class="bento-bottom-grid">
25839
- ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25840
- </div>
25841
- </div>
26235
+ </div>
26236
+ </div>
26237
+ ` : ""}
26238
+ <div id="photon-prompts" class="bento-bottom-grid">
26239
+ ${this._renderPromptsSection()} ${this._renderResourcesSection()}
26240
+ </div>
26241
+ </div>`}
25842
26242
  </app-layout>
25843
26243
  `;
25844
26244
  }
25845
26245
  if (this._selectedMethod.linkedUi) {
25846
26246
  const otherMethods = isAppMain ? this._getVisibleMethods().filter((m3) => m3.name !== "main") : [];
25847
26247
  const isExternalMCP = this._selectedPhoton.isExternalMCP;
26248
+ const appFillStyle = this._mainTab === "app" && isAppMain ? "height: 100%; min-height: 0;" : "height: calc(100vh - 140px);";
25848
26249
  const appRenderer = this._isExecuting ? b2`
25849
26250
  <div
25850
- style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; height: calc(100vh - 140px);"
26251
+ style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; ${appFillStyle}"
25851
26252
  >
25852
26253
  <span class="spinner"></span>
25853
26254
  <span style="color: var(--t-muted); font-size: 13px;">
@@ -25860,7 +26261,7 @@ ${photon.errorMessage || "Unknown error"}</pre
25860
26261
  .appUri=${`ui://${this._selectedPhoton.name}/${this._selectedMethod.linkedUi}`}
25861
26262
  .linkedTool=${this._selectedMethod.name}
25862
26263
  .theme=${this._theme}
25863
- style="height: calc(100vh - 140px);"
26264
+ style="${appFillStyle}"
25864
26265
  ></mcp-app-renderer>
25865
26266
  ` : b2`
25866
26267
  <custom-ui-renderer
@@ -25870,7 +26271,7 @@ ${photon.errorMessage || "Unknown error"}</pre
25870
26271
  .theme=${this._theme}
25871
26272
  .initialResult=${this._lastResult}
25872
26273
  .revision=${this._customUiRevision}
25873
- style="height: calc(100vh - 140px);"
26274
+ style="${appFillStyle}"
25874
26275
  ></custom-ui-renderer>
25875
26276
  `;
25876
26277
  if (isAppMain) {
@@ -25888,7 +26289,7 @@ ${photon.errorMessage || "Unknown error"}</pre
25888
26289
  ${this._splitPanels.map(
25889
26290
  (panel) => b2`
25890
26291
  <div
25891
- style="flex: 1; min-width: 0; min-height: 0; overflow: auto; background: var(--bg-panel);"
26292
+ style="flex: 1; min-width: 0; min-height: 0; overflow: hidden; background: var(--bg-panel);"
25892
26293
  >
25893
26294
  ${panel.type === "method" ? this._renderSinglePanel(this._buildAdditionalPanelOpts(panel)) : this._renderSourcePanel(panel.id)}
25894
26295
  </div>
@@ -25897,46 +26298,54 @@ ${photon.errorMessage || "Unknown error"}</pre
25897
26298
  </div>
25898
26299
  `;
25899
26300
  }
26301
+ const appTabActive2 = this._mainTab === "app";
25900
26302
  return b2`
25901
26303
  <app-layout
25902
26304
  .photonName=${this._selectedPhoton.name}
25903
26305
  .photonIcon=${this._selectedPhoton.appEntry?.icon || "\u{1F4F1}"}
26306
+ .hideBelow=${appTabActive2}
25904
26307
  >
25905
- <div slot="app" style="min-height: calc(100vh - 140px);">${appRenderer}</div>
26308
+ <div
26309
+ slot="app"
26310
+ style="${appTabActive2 ? "height: 100%; min-height: 0; display: flex; flex-direction: column;" : "min-height: calc(100vh - 140px);"}"
26311
+ >
26312
+ ${appRenderer}
26313
+ </div>
25906
26314
  <!-- Popout slot is lazily populated when app-layout toggles popout mode.
25907
26315
  Eagerly creating a second renderer causes Safari to load two
25908
26316
  iframes simultaneously (one with zero dimensions), leading to
25909
26317
  blank screens. -->
25910
26318
  <div slot="popout" style="height: 100%;"></div>
25911
- <div slot="below-fold">
25912
- ${this._renderPhotonToolbar()} ${this._renderAnchorNav()}
25913
- ${otherMethods.length > 0 ? b2`
25914
- <div id="photon-methods" class="bento-methods">
25915
- <h3 class="bento-section-title">
25916
- ${(() => {
26319
+ ${appTabActive2 ? b2`<div slot="below-fold"></div>` : b2`<div slot="below-fold">
26320
+ ${this._renderAnchorNav()}
26321
+ ${otherMethods.length > 0 ? b2`
26322
+ <div id="photon-methods" class="bento-methods">
26323
+ <h3 class="bento-section-title">
26324
+ ${(() => {
25917
26325
  const hasTools = otherMethods.some((m3) => !m3.isTemplate);
25918
26326
  const hasPrompts = otherMethods.some((m3) => m3.isTemplate);
25919
26327
  return hasTools && hasPrompts ? "Methods & Prompts" : hasPrompts ? "Prompts" : "Methods";
25920
26328
  })()}
25921
- </h3>
25922
- <div class="cards-grid">
25923
- ${otherMethods.map(
26329
+ </h3>
26330
+ <div class="cards-grid">
26331
+ ${otherMethods.map(
25924
26332
  (method) => b2`
25925
- <method-card
25926
- .method=${method}
25927
- .photonName=${this._selectedPhoton.name}
25928
- @select=${(e8) => this._handleMethodSelect(e8)}
25929
- @update-metadata=${this._handleMethodMetadataUpdate}
25930
- ></method-card>
25931
- `
26333
+ <method-card
26334
+ .method=${method}
26335
+ .photonName=${this._selectedPhoton.name}
26336
+ .editable=${!!this._selectedPhoton.editable && !this._selectedPhoton.isExternalMCP}
26337
+ @select=${(e8) => this._handleMethodSelect(e8)}
26338
+ @update-metadata=${this._handleMethodMetadataUpdate}
26339
+ ></method-card>
26340
+ `
25932
26341
  )}
25933
- </div>
25934
- </div>
25935
- ` : ""}
25936
- <div id="photon-prompts" class="bento-bottom-grid">
25937
- ${this._renderPromptsSection()} ${this._renderResourcesSection()}
25938
- </div>
25939
- </div>
26342
+ </div>
26343
+ </div>
26344
+ ` : ""}
26345
+ <div id="photon-prompts" class="bento-bottom-grid">
26346
+ ${this._renderPromptsSection()} ${this._renderResourcesSection()}
26347
+ </div>
26348
+ </div>`}
25940
26349
  </app-layout>
25941
26350
  `;
25942
26351
  }
@@ -25976,7 +26385,7 @@ ${photon.errorMessage || "Unknown error"}</pre
25976
26385
  ${this._splitPanels.map(
25977
26386
  (panel) => b2`
25978
26387
  <div
25979
- style="flex: 1; min-width: 0; min-height: 0; overflow: auto; background: var(--bg-panel);"
26388
+ style="flex: 1; min-width: 0; min-height: 0; overflow: hidden; background: var(--bg-panel);"
25980
26389
  >
25981
26390
  ${panel.type === "method" ? this._renderSinglePanel(this._buildAdditionalPanelOpts(panel)) : this._renderSourcePanel(panel.id)}
25982
26391
  </div>
@@ -26012,8 +26421,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26012
26421
  return b2` ${this._renderMethodContent()} `;
26013
26422
  }
26014
26423
  return b2`
26015
- ${this._renderPhotonToolbar()} ${this._editingIcon ? this._renderEmojiPicker() : ""}
26016
- ${this._renderAnchorNav()}
26424
+ ${this._editingIcon ? this._renderEmojiPicker() : ""} ${this._renderAnchorNav()}
26017
26425
 
26018
26426
  <div id="photon-methods" class="bento-methods">
26019
26427
  <h3 class="bento-section-title">
@@ -26086,6 +26494,50 @@ ${photon.errorMessage || "Unknown error"}</pre
26086
26494
  _closeSidebar() {
26087
26495
  this._sidebarVisible = false;
26088
26496
  }
26497
+ _handleSplitResizeStart(e8) {
26498
+ e8.preventDefault();
26499
+ const divider = e8.currentTarget;
26500
+ divider.setPointerCapture(e8.pointerId);
26501
+ divider.classList.add("dragging");
26502
+ const container = divider.parentElement;
26503
+ const containerRect = container.getBoundingClientRect();
26504
+ const startX = e8.clientX;
26505
+ const primaryPanel = divider.previousElementSibling;
26506
+ const startWidth = primaryPanel.getBoundingClientRect().width;
26507
+ const onMove = (moveEvent) => {
26508
+ const delta = moveEvent.clientX - startX;
26509
+ const minWidth = 200;
26510
+ const maxWidth = containerRect.width - 200 - 5;
26511
+ this._splitPrimaryWidth = Math.min(maxWidth, Math.max(minWidth, startWidth + delta));
26512
+ };
26513
+ const onUp = () => {
26514
+ divider.classList.remove("dragging");
26515
+ divider.removeEventListener("pointermove", onMove);
26516
+ divider.removeEventListener("pointerup", onUp);
26517
+ };
26518
+ divider.addEventListener("pointermove", onMove);
26519
+ divider.addEventListener("pointerup", onUp);
26520
+ }
26521
+ _handleSidebarResizeStart(e8) {
26522
+ e8.preventDefault();
26523
+ const handle = e8.currentTarget;
26524
+ handle.setPointerCapture(e8.pointerId);
26525
+ handle.classList.add("dragging");
26526
+ const startX = e8.clientX;
26527
+ const startWidth = this._sidebarWidth;
26528
+ const onMove = (moveEvent) => {
26529
+ const newWidth = Math.min(500, Math.max(200, startWidth + moveEvent.clientX - startX));
26530
+ this._sidebarWidth = newWidth;
26531
+ };
26532
+ const onUp = () => {
26533
+ handle.classList.remove("dragging");
26534
+ localStorage.setItem("beam-sidebar-width", String(this._sidebarWidth));
26535
+ handle.removeEventListener("pointermove", onMove);
26536
+ handle.removeEventListener("pointerup", onUp);
26537
+ };
26538
+ handle.addEventListener("pointermove", onMove);
26539
+ handle.addEventListener("pointerup", onUp);
26540
+ }
26089
26541
  _handlePhotonSelectMobile(e8) {
26090
26542
  this._closeSidebar();
26091
26543
  void this._handlePhotonSelect(e8);
@@ -26152,6 +26604,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26152
26604
  }
26153
26605
  if (this._selectedPhoton.isExternalMCP && this._selectedPhoton.hasMcpApp) {
26154
26606
  this._view = "mcp-app";
26607
+ this._mainTab = "app";
26155
26608
  this._updateRoute();
26156
26609
  return;
26157
26610
  }
@@ -26179,18 +26632,20 @@ ${photon.errorMessage || "Unknown error"}</pre
26179
26632
  }
26180
26633
  this._selectedMethod = this._selectedPhoton.appEntry;
26181
26634
  this._view = "form";
26635
+ this._mainTab = "app";
26182
26636
  this._updateRoute();
26183
26637
  this._maybeAutoInvoke(this._selectedPhoton.appEntry);
26184
26638
  return;
26185
26639
  } else {
26186
26640
  this._view = "list";
26641
+ this._mainTab = "methods";
26187
26642
  }
26188
26643
  this._updateRoute();
26189
26644
  }
26190
26645
  /** Fetch available instances for a stateful photon from the server */
26191
26646
  async _fetchInstances(photonName) {
26192
26647
  try {
26193
- const res = await fetch(`/api/instances/${photonName}`, {
26648
+ const res = await fetch(`/api/instances/${encodeURIComponent(photonName)}`, {
26194
26649
  signal: AbortSignal.timeout(1e4)
26195
26650
  });
26196
26651
  if (res.ok) {
@@ -26316,6 +26771,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26316
26771
  return b2`<p>${cleaned}</p>`;
26317
26772
  }
26318
26773
  _renderMethodContent() {
26774
+ const showBackButton = this._mainTab === "methods" || !this._selectedPhoton?.isApp;
26319
26775
  if (this._isHtmlUiMode()) {
26320
26776
  return b2`
26321
26777
  <div class="glass-panel html-ui-panel" style="padding: 0; overflow: hidden;">
@@ -26336,10 +26792,10 @@ ${photon.errorMessage || "Unknown error"}</pre
26336
26792
  }
26337
26793
  if (this._splitPanels.length > 0) {
26338
26794
  return b2`
26339
- <div style="display: flex; gap: 1px; height: 100%; overflow: hidden; width: 100%;">
26795
+ <div style="display: flex; height: 100%; overflow: hidden; width: 100%;">
26340
26796
  <!-- Primary Panel -->
26341
26797
  <div
26342
- style="flex: 1; min-width: 0; min-height: 0; overflow: auto; background: var(--bg-panel);"
26798
+ 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);"
26343
26799
  >
26344
26800
  ${this._renderSinglePanel({
26345
26801
  photon: this._selectedPhoton,
@@ -26368,7 +26824,9 @@ ${photon.errorMessage || "Unknown error"}</pre
26368
26824
  showDelete: false,
26369
26825
  showHelp: !this._selectedPhoton?.isExternalMCP
26370
26826
  }),
26371
- onOverflowSelect: (id2) => this._handleOverflowAction(id2)
26827
+ onOverflowSelect: (id2) => this._handleOverflowAction(id2),
26828
+ onBack: showBackButton ? () => void this._handleBackFromMethod() : void 0,
26829
+ backLabel: this._selectedPhoton?.name
26372
26830
  })}
26373
26831
  </div>
26374
26832
 
@@ -26376,7 +26834,11 @@ ${photon.errorMessage || "Unknown error"}</pre
26376
26834
  ${this._splitPanels.map(
26377
26835
  (panel) => b2`
26378
26836
  <div
26379
- style="flex: 1; min-width: 0; min-height: 0; overflow: auto; background: var(--bg-panel);"
26837
+ class="split-divider"
26838
+ @pointerdown=${(e8) => this._handleSplitResizeStart(e8)}
26839
+ ></div>
26840
+ <div
26841
+ style="flex: 1; min-width: 0; min-height: 0; overflow: hidden; background: var(--bg-panel);"
26380
26842
  >
26381
26843
  ${panel.type === "method" ? this._renderSinglePanel(this._buildAdditionalPanelOpts(panel)) : this._renderSourcePanel(panel.id)}
26382
26844
  </div>
@@ -26421,7 +26883,9 @@ ${photon.errorMessage || "Unknown error"}</pre
26421
26883
  showDelete: false,
26422
26884
  showHelp: !this._selectedPhoton?.isExternalMCP
26423
26885
  }),
26424
- onOverflowSelect: (id2) => this._handleOverflowAction(id2)
26886
+ onOverflowSelect: (id2) => this._handleOverflowAction(id2),
26887
+ onBack: showBackButton ? () => void this._handleBackFromMethod() : void 0,
26888
+ backLabel: this._selectedPhoton?.name
26425
26889
  });
26426
26890
  }
26427
26891
  /** Render a single panel with self-contained header */
@@ -26437,6 +26901,33 @@ ${photon.errorMessage || "Unknown error"}</pre
26437
26901
  class="panel-header"
26438
26902
  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;"
26439
26903
  >
26904
+ <!-- Back button -->
26905
+ ${opts.onBack ? b2`<button
26906
+ @click=${() => opts.onBack()}
26907
+ 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;"
26908
+ @mouseenter=${(e8) => {
26909
+ e8.target.style.color = "var(--t-primary)";
26910
+ e8.target.style.borderColor = "var(--accent-primary)";
26911
+ }}
26912
+ @mouseleave=${(e8) => {
26913
+ e8.target.style.color = "var(--t-muted)";
26914
+ e8.target.style.borderColor = "var(--border-glass)";
26915
+ }}
26916
+ title="Back to ${opts.backLabel || "methods"}"
26917
+ >
26918
+ <svg
26919
+ width="14"
26920
+ height="14"
26921
+ viewBox="0 0 24 24"
26922
+ fill="none"
26923
+ stroke="currentColor"
26924
+ stroke-width="2"
26925
+ stroke-linecap="round"
26926
+ stroke-linejoin="round"
26927
+ >
26928
+ <path d="m15 18-6-6 6-6" />
26929
+ </svg>
26930
+ </button>` : ""}
26440
26931
  <!-- LED dot (stateful/live indicator) -->
26441
26932
  ${opts.isStateful ? b2`<span
26442
26933
  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"};"
@@ -26517,9 +27008,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26517
27008
  _renderMethodBody(opts) {
26518
27009
  const hasParams = !!opts.method?.params?.properties && Object.keys(opts.method.params.properties).length > 0;
26519
27010
  return b2`
26520
- <div
26521
- style="display: flex; flex-direction: column; flex: 1; min-height: 0; overflow-y: auto; scrollbar-gutter: stable;"
26522
- >
27011
+ <div style="display: flex; flex-direction: column; flex: 1; min-height: 0;">
26523
27012
  ${opts.appSurface ? "" : this._renderDescription(opts.method.description)}
26524
27013
  ${opts.appSurface && !hasParams ? "" : b2`
26525
27014
  <invoke-form
@@ -26629,6 +27118,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26629
27118
  /** Close all split panels and return to single-panel mode */
26630
27119
  _closeSecondPanel() {
26631
27120
  this._splitPanels = [];
27121
+ this._splitPrimaryWidth = null;
26632
27122
  this._methodPickerOpen = false;
26633
27123
  this._methodPickerPanelId = null;
26634
27124
  this._updateRoute();
@@ -26676,17 +27166,11 @@ ${photon.errorMessage || "Unknown error"}</pre
26676
27166
  const panel = this._splitPanels.find((p5) => p5.id === panelId);
26677
27167
  if (!panel || panel.type !== "method" || !panel.method) return;
26678
27168
  this._updatePanel(panelId, { executing: true, result: null, progress: null, formParams: args });
27169
+ const progressToken = `panel_${panelId}_${Date.now()}`;
27170
+ this._panelProgressTokens.set(progressToken, panelId);
26679
27171
  try {
26680
27172
  const toolName = `${this._selectedPhoton.name}/${panel.method.name}`;
26681
- const result = await mcpClient.callTool(
26682
- toolName,
26683
- args,
26684
- void 0,
26685
- panel.instance || this._currentInstance,
26686
- (progress) => {
26687
- this._updatePanel(panelId, { progress });
26688
- }
26689
- );
27173
+ const result = await mcpClient.callTool(toolName, args, progressToken);
26690
27174
  this._updatePanel(panelId, {
26691
27175
  result: mcpClient.parseToolResult(result),
26692
27176
  executing: false,
@@ -26699,6 +27183,8 @@ ${photon.errorMessage || "Unknown error"}</pre
26699
27183
  executing: false,
26700
27184
  progress: null
26701
27185
  });
27186
+ } finally {
27187
+ this._panelProgressTokens.delete(progressToken);
26702
27188
  }
26703
27189
  }
26704
27190
  /** Change the method in a split panel */
@@ -26804,8 +27290,15 @@ ${photon.errorMessage || "Unknown error"}</pre
26804
27290
  case "run-tests":
26805
27291
  void this._runTests();
26806
27292
  break;
27293
+ case "copy-config-stdio":
27294
+ void this._copyConfigSnippet("stdio");
27295
+ break;
27296
+ case "copy-config-url":
27297
+ void this._copyConfigSnippet("url");
27298
+ break;
26807
27299
  case "help":
26808
- this._showPhotonHelp = true;
27300
+ this._mainTab = "help";
27301
+ void this._loadPhotonHelp();
26809
27302
  break;
26810
27303
  default:
26811
27304
  this._handleContextAction(new CustomEvent("context-action", { detail: { action: id2 } }));
@@ -26941,7 +27434,7 @@ ${photon.errorMessage || "Unknown error"}</pre
26941
27434
  }
26942
27435
  async _handleBackFromMethod() {
26943
27436
  const form = this.shadowRoot?.querySelector("invoke-form");
26944
- if (form?.isDirty && !await confirmDialog("You have unsaved changes. Discard them?", {
27437
+ if (form?.isDirty && !await confirmElicit("You have unsaved changes. Discard them?", {
26945
27438
  confirm: "Discard",
26946
27439
  destructive: true
26947
27440
  })) {
@@ -27388,6 +27881,21 @@ ${photon.errorMessage || "Unknown error"}</pre
27388
27881
  this.style.setProperty(prop, value);
27389
27882
  }
27390
27883
  }
27884
+ async _fetchPendingApprovals() {
27885
+ if (!this._mcpReady) return;
27886
+ this._pendingApprovalsList = await mcpClient.fetchPendingApprovals();
27887
+ }
27888
+ _startApprovalsPolling() {
27889
+ this._stopApprovalsPolling();
27890
+ void this._fetchPendingApprovals();
27891
+ this._approvalsRefreshInterval = setInterval(() => void this._fetchPendingApprovals(), 6e4);
27892
+ }
27893
+ _stopApprovalsPolling() {
27894
+ if (this._approvalsRefreshInterval) {
27895
+ clearInterval(this._approvalsRefreshInterval);
27896
+ this._approvalsRefreshInterval = void 0;
27897
+ }
27898
+ }
27391
27899
  _applyTheme() {
27392
27900
  this.setAttribute("data-theme", this._theme);
27393
27901
  }
@@ -27474,6 +27982,61 @@ ${photon.errorMessage || "Unknown error"}</pre
27474
27982
  _closePhotonHelp() {
27475
27983
  this._showPhotonHelp = false;
27476
27984
  }
27985
+ /** Render the inline help view (used as a tab, not a modal) */
27986
+ _renderPhotonHelpView() {
27987
+ const markdown = this._photonHelpLoading ? this._generatePhotonHelpMarkdown() : this._photonHelpMarkdown || this._generatePhotonHelpMarkdown();
27988
+ let htmlContent = markdown;
27989
+ if (window.marked) {
27990
+ const mermaidBlocks = [];
27991
+ let processed = markdown.replace(
27992
+ /```mermaid\s*\n([\s\S]*?)```/g,
27993
+ (_match, code) => {
27994
+ const id2 = `help-mermaid-${Math.random().toString(36).substr(2, 9)}`;
27995
+ mermaidBlocks.push({ id: id2, code: code.trim() });
27996
+ 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>`;
27997
+ }
27998
+ );
27999
+ htmlContent = window.marked.parse(processed);
28000
+ if (mermaidBlocks.length > 0 && window.mermaid) {
28001
+ const mermaid = window.mermaid;
28002
+ const isDark = this.getAttribute("data-theme") !== "light";
28003
+ mermaid.initialize({ startOnLoad: false, theme: isDark ? "dark" : "default" });
28004
+ requestAnimationFrame(() => {
28005
+ for (const { id: id2, code } of mermaidBlocks) {
28006
+ const el2 = this.shadowRoot?.querySelector(`[data-mermaid-id="${id2}"]`);
28007
+ if (el2) {
28008
+ mermaid.render(id2 + "-svg", code).then(({ svg: svg2 }) => {
28009
+ el2.innerHTML = svg2;
28010
+ el2.style.minHeight = "";
28011
+ el2.style.background = isDark ? "hsla(220, 15%, 18%, 0.8)" : "hsla(0, 0%, 97%, 0.8)";
28012
+ el2.style.borderRadius = "8px";
28013
+ el2.style.padding = "12px";
28014
+ }).catch(() => {
28015
+ el2.textContent = "Diagram rendering failed";
28016
+ });
28017
+ }
28018
+ }
28019
+ });
28020
+ }
28021
+ }
28022
+ return b2`
28023
+ <div
28024
+ style="display: flex; flex-direction: column; height: 100%; overflow: auto; padding: var(--space-lg);"
28025
+ >
28026
+ <div style="max-width: 700px; width: 100%;">
28027
+ <h2 class="text-gradient" style="margin: 0 0 var(--space-md) 0;">
28028
+ Help
28029
+ ${this._photonHelpLoading ? b2`<span style="font-size: 0.7em; opacity: 0.6; margin-left: 8px;"
28030
+ >Loading...</span
28031
+ >` : ""}
28032
+ </h2>
28033
+ <div class="markdown-body" style="color: var(--t-default);">
28034
+ ${window.marked ? b2`${o5(htmlContent)}` : b2`<pre style="white-space: pre-wrap;">${markdown}</pre>`}
28035
+ </div>
28036
+ </div>
28037
+ </div>
28038
+ `;
28039
+ }
27477
28040
  _generatePhotonHelpMarkdown() {
27478
28041
  if (!this._selectedPhoton) return "";
27479
28042
  const photon = this._selectedPhoton;
@@ -27607,7 +28170,8 @@ ${photon.errorMessage || "Unknown error"}</pre
27607
28170
  const hasInstallSource = !!this._selectedPhoton?.installSource;
27608
28171
  const isStateful = !!this._selectedPhoton?.stateful;
27609
28172
  const hasSettings = !!this._selectedPhoton?.hasSettings;
27610
- const sourceMode = isExternalMCP ? "hidden" : this._view === "source" ? "edit" : hasPath && !this._selectedPhoton?.internal ? "source" : "hidden";
28173
+ const isEditable = !!this._selectedPhoton?.editable && !isExternalMCP;
28174
+ const sourceMode = isExternalMCP ? "hidden" : this._view === "source" ? "edit" : hasPath && !this._selectedPhoton?.internal && isEditable ? "source" : "hidden";
27611
28175
  return b2`
27612
28176
  <context-bar
27613
28177
  .photon=${this._selectedPhoton}
@@ -27619,17 +28183,17 @@ ${photon.errorMessage || "Unknown error"}</pre
27619
28183
  .instances=${this._instances}
27620
28184
  .instanceSelectorMode=${this._instanceSelectorMode}
27621
28185
  .autoInstance=${this._autoInstance}
27622
- .sourceMode=${sourceMode}
27623
- .hasSettings=${hasSettings && !isExternalMCP}
28186
+ .sourceMode=${"hidden"}
28187
+ .hasSettings=${false}
27624
28188
  .overflowItems=${this._buildOverflowItems({
27625
28189
  showRefresh: !isExternalMCP,
27626
28190
  showEdit: false,
27627
28191
  showUpgrade: !!this._selectedPhoton?.hasUpdate,
27628
- showRename: !isExternalMCP,
28192
+ showRename: isEditable,
27629
28193
  showViewSource: false,
27630
- showFork: hasInstallSource && !isExternalMCP,
28194
+ showFork: !isEditable && !isExternalMCP,
27631
28195
  showContribute: hasInstallSource && !isExternalMCP,
27632
- showDelete: !isExternalMCP,
28196
+ showDelete: isEditable,
27633
28197
  showHelp: !isExternalMCP
27634
28198
  })}
27635
28199
  @context-action=${this._handleContextAction}
@@ -27699,6 +28263,17 @@ ${photon.errorMessage || "Unknown error"}</pre
27699
28263
  toggle: true,
27700
28264
  toggleActive: this._verboseLogging
27701
28265
  });
28266
+ items.push({
28267
+ id: "copy-config-stdio",
28268
+ label: "Copy Config (Claude Desktop)",
28269
+ iconSvg: iconSvgString(iconPaths.clone),
28270
+ dividerBefore: true
28271
+ });
28272
+ items.push({
28273
+ id: "copy-config-url",
28274
+ label: "Copy Config (HTTP)",
28275
+ iconSvg: iconSvgString(iconPaths.clone)
28276
+ });
27702
28277
  if (showInstallApp) {
27703
28278
  items.push({
27704
28279
  id: "install-app",
@@ -27773,6 +28348,7 @@ ${photon.errorMessage || "Unknown error"}</pre
27773
28348
  _renderPhotonHeader() {
27774
28349
  if (!this._selectedPhoton) return "";
27775
28350
  const isApp = this._selectedPhoton.isApp;
28351
+ const isEditable = !!this._selectedPhoton.editable && !this._selectedPhoton.isExternalMCP;
27776
28352
  const methods = this._selectedPhoton.methods || [];
27777
28353
  const templateCount = methods.filter((m3) => m3.isTemplate).length;
27778
28354
  const toolCount = methods.filter((m3) => !m3.isTemplate).length;
@@ -27785,42 +28361,42 @@ ${photon.errorMessage || "Unknown error"}</pre
27785
28361
  const displayIcon = customIcon || defaultIcon;
27786
28362
  return b2`
27787
28363
  <header class="photon-header">
27788
- <button
27789
- type="button"
27790
- class="photon-icon-large editable ${isApp ? "" : "mcp-icon"}"
27791
- @click=${this._startEditingIcon}
27792
- title="Click to change icon"
27793
- aria-label="Change icon"
27794
- >
27795
- ${displayIcon}
27796
- </button>
28364
+ ${isEditable ? b2`<button
28365
+ type="button"
28366
+ class="photon-icon-large editable ${isApp ? "" : "mcp-icon"}"
28367
+ @click=${this._startEditingIcon}
28368
+ title="Click to change icon"
28369
+ aria-label="Change icon"
28370
+ >
28371
+ ${displayIcon}
28372
+ </button>` : b2`<span class="photon-icon-large ${isApp ? "" : "mcp-icon"}">${displayIcon}</span>`}
27797
28373
  ${this._editingIcon ? this._renderEmojiPicker() : ""}
27798
28374
  <div class="photon-header-info">
27799
28375
  <h1 class="photon-header-name">${this._selectedPhoton.name}</h1>
27800
- ${this._editingDescription ? b2`
27801
- <p class="photon-header-desc editable editing">
27802
- <input
27803
- class="editable-input"
27804
- type="text"
27805
- .value=${this._editedDescription}
27806
- placeholder="Add a description..."
27807
- @input=${(e8) => this._editedDescription = e8.target.value}
27808
- @blur=${this._saveDescription}
27809
- @keydown=${this._handleDescriptionKeydown}
27810
- autofocus
27811
- />
27812
- </p>
27813
- ` : b2`
27814
- <button
27815
- type="button"
27816
- class="photon-header-desc editable ${isGenericDesc ? "placeholder" : ""}"
27817
- @click=${this._startEditingDescription}
27818
- title="Click to edit description"
27819
- aria-label="Edit description"
27820
- >
27821
- ${isGenericDesc ? "Click to add a description..." : description}
27822
- </button>
27823
- `}
28376
+ ${isEditable ? this._editingDescription ? b2`
28377
+ <p class="photon-header-desc editable editing">
28378
+ <input
28379
+ class="editable-input"
28380
+ type="text"
28381
+ .value=${this._editedDescription}
28382
+ placeholder="Add a description..."
28383
+ @input=${(e8) => this._editedDescription = e8.target.value}
28384
+ @blur=${this._saveDescription}
28385
+ @keydown=${this._handleDescriptionKeydown}
28386
+ autofocus
28387
+ />
28388
+ </p>
28389
+ ` : b2`
28390
+ <button
28391
+ type="button"
28392
+ class="photon-header-desc editable ${isGenericDesc ? "placeholder" : ""}"
28393
+ @click=${this._startEditingDescription}
28394
+ title="Click to edit description"
28395
+ aria-label="Edit description"
28396
+ >
28397
+ ${isGenericDesc ? "Click to add a description..." : description}
28398
+ </button>
28399
+ ` : b2`<p class="photon-header-desc">${description}</p>`}
27824
28400
  <div class="photon-header-meta">
27825
28401
  ${isApp ? b2`<span class="photon-badge app">App</span>` : b2`<span class="photon-badge">MCP</span>`}
27826
28402
  ${templateCount > 0 && toolCount === 0 ? b2`<span class="photon-badge"
@@ -28286,14 +28862,133 @@ ${photon.errorMessage || "Unknown error"}</pre
28286
28862
  </div>
28287
28863
  `;
28288
28864
  }
28865
+ /** Render the settings view — a professional two-column settings panel */
28866
+ _renderSettingsView() {
28867
+ const photon = this._selectedPhoton;
28868
+ if (!photon) return "";
28869
+ const settingsMethod = photon.methods?.find((m3) => m3.name === "settings");
28870
+ if (!settingsMethod)
28871
+ return b2`<div style="padding: var(--space-xl); color: var(--t-muted); text-align: center;">
28872
+ No settings available for this photon.
28873
+ </div>`;
28874
+ const params = settingsMethod.params;
28875
+ const properties = params?.properties || {};
28876
+ const propEntries = Object.entries(properties);
28877
+ const hasResult = this._lastResult !== null;
28878
+ let statusEntries = [];
28879
+ if (hasResult) {
28880
+ try {
28881
+ 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;
28882
+ if (resultData && typeof resultData === "object" && !Array.isArray(resultData)) {
28883
+ statusEntries = Object.entries(resultData).filter(([, v2]) => v2 !== null && v2 !== void 0).map(([k3, v2]) => [k3, String(v2)]);
28884
+ }
28885
+ } catch {
28886
+ }
28887
+ }
28888
+ return b2`
28889
+ <div style="padding: var(--space-lg); max-width: 900px; margin: 0 auto; width: 100%;">
28890
+ <!-- Settings Header -->
28891
+ <div style="margin-bottom: var(--space-xl);">
28892
+ <h2
28893
+ style="font-family: var(--font-display); font-size: var(--text-xl); font-weight: 700; color: var(--t-primary); margin: 0 0 4px 0;"
28894
+ >
28895
+ ${photon.name} Settings
28896
+ </h2>
28897
+ ${settingsMethod.description ? b2`<p
28898
+ style="color: var(--t-muted); font-size: var(--text-sm); margin: 0; line-height: 1.5;"
28899
+ >
28900
+ View or update photon configuration. Changes are applied immediately.
28901
+ </p>` : ""}
28902
+ </div>
28903
+
28904
+ <!-- Configuration Section -->
28905
+ ${propEntries.length > 0 ? b2`
28906
+ <div class="glass-panel" style="margin-bottom: var(--space-lg); overflow: hidden;">
28907
+ <div
28908
+ style="padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--border-glass); background: var(--bg-glass);"
28909
+ >
28910
+ <span
28911
+ 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;"
28912
+ >Configuration</span
28913
+ >
28914
+ </div>
28915
+ <div class="method-detail" style="padding: 0;">
28916
+ <invoke-form
28917
+ .params=${params}
28918
+ .loading=${this._isExecuting}
28919
+ .photonName=${photon.name}
28920
+ .methodName=${"settings"}
28921
+ .rememberValues=${this._rememberFormValues}
28922
+ .sharedValues=${this._sharedFormParams ?? this._lastFormParams}
28923
+ .settingsLayout=${true}
28924
+ @submit=${(e8) => void this._handleExecute(e8)}
28925
+ @cancel=${() => {
28926
+ }}
28927
+ ></invoke-form>
28928
+ <div
28929
+ style="display: flex; justify-content: flex-end; padding: var(--space-sm) var(--space-md); border-top: 1px solid var(--border-glass);"
28930
+ >
28931
+ <button
28932
+ class="btn-primary"
28933
+ style="font-size: var(--text-sm); padding: 6px 20px;"
28934
+ @click=${(e8) => {
28935
+ const panel = e8.target.closest(".glass-panel");
28936
+ const form = panel?.querySelector("invoke-form");
28937
+ form?.handleSubmit();
28938
+ }}
28939
+ ?disabled=${this._isExecuting}
28940
+ >
28941
+ ${this._isExecuting ? b2`<span class="btn-loading"
28942
+ ><span class="spinner"></span>Saving...</span
28943
+ >` : "Save Settings"}
28944
+ </button>
28945
+ </div>
28946
+ </div>
28947
+ </div>
28948
+ ` : ""}
28949
+
28950
+ <!-- Status Section (from last result) -->
28951
+ ${statusEntries.length > 0 ? b2`
28952
+ <div class="glass-panel" style="overflow: hidden;">
28953
+ <div
28954
+ style="padding: var(--space-sm) var(--space-md); border-bottom: 1px solid var(--border-glass); background: var(--bg-glass);"
28955
+ >
28956
+ <span
28957
+ 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;"
28958
+ >Status</span
28959
+ >
28960
+ </div>
28961
+ <div style="padding: 0;">
28962
+ ${statusEntries.map(
28963
+ ([key, value], i7) => b2`
28964
+ <div
28965
+ style="display: grid; grid-template-columns: 200px 1fr; border-bottom: ${i7 < statusEntries.length - 1 ? "1px solid var(--border-glass)" : "none"};"
28966
+ >
28967
+ <div
28968
+ 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);"
28969
+ >
28970
+ ${key.replace(/([A-Z])/g, " $1").replace(/_/g, " ").trim()}
28971
+ </div>
28972
+ <div
28973
+ style="padding: 10px var(--space-md); font-size: var(--text-sm); color: var(--t-primary); word-break: break-word;"
28974
+ >
28975
+ ${value}
28976
+ </div>
28977
+ </div>
28978
+ `
28979
+ )}
28980
+ </div>
28981
+ </div>
28982
+ ` : ""}
28983
+ </div>
28984
+ `;
28985
+ }
28289
28986
  /** Render source code as an inline view (not a modal) — Phase 2 */
28290
28987
  _renderSourceView() {
28291
28988
  if (!this._sourceData) {
28292
28989
  return b2`
28293
- ${this._renderPhotonToolbar({ showConfigure: false, showCopyConfig: false })}
28294
28990
  <div
28295
- class="glass-panel"
28296
- style="padding: var(--space-xl); text-align: center; color: var(--t-muted);"
28991
+ style="display: flex; align-items: center; justify-content: center; height: 100%; color: var(--t-muted);"
28297
28992
  >
28298
28993
  Loading source...
28299
28994
  </div>
@@ -28324,26 +29019,56 @@ ${photon.errorMessage || "Unknown error"}</pre
28324
29019
  if (Prism && Prism.languages[language2]) {
28325
29020
  highlightedCode = Prism.highlight(this._sourceData.code, Prism.languages[language2], language2);
28326
29021
  }
29022
+ const isProtected = !this._selectedPhoton?.editable;
28327
29023
  return b2`
28328
- ${this._renderPhotonToolbar({ showConfigure: false, showCopyConfig: false })}
28329
- <div
28330
- class="glass-panel"
28331
- style="margin-top: var(--space-md); display: flex; flex-direction: column; max-height: calc(100vh - 120px);"
28332
- >
29024
+ <div style="display: flex; flex-direction: column; height: 100%;">
28333
29025
  <div
28334
- 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;"
29026
+ 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);"
28335
29027
  >
28336
- <div style="font-family: var(--font-mono); font-size: 0.85rem; color: var(--t-muted);">
28337
- ${filename}
29028
+ <div style="display: flex; align-items: center; gap: 8px;">
29029
+ <div style="font-family: var(--font-mono); font-size: 0.85rem; color: var(--t-muted);">
29030
+ ${filename}
29031
+ </div>
29032
+ ${isProtected ? b2`<span
29033
+ 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;"
29034
+ >Protected</span
29035
+ >` : ""}
29036
+ </div>
29037
+ <div style="display: flex; gap: 6px; align-items: center;">
29038
+ ${isProtected ? b2`<button
29039
+ class="action-btn"
29040
+ 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);"
29041
+ @click=${this._handleFork}
29042
+ title="Fork to create an editable local copy"
29043
+ >
29044
+ <svg
29045
+ width="12"
29046
+ height="12"
29047
+ viewBox="0 0 24 24"
29048
+ fill="none"
29049
+ stroke="currentColor"
29050
+ stroke-width="2"
29051
+ stroke-linecap="round"
29052
+ stroke-linejoin="round"
29053
+ style="margin-right: 3px;"
29054
+ >
29055
+ <circle cx="12" cy="18" r="3" />
29056
+ <circle cx="6" cy="6" r="3" />
29057
+ <circle cx="18" cy="6" r="3" />
29058
+ <path d="M18 9v2c0 .6-.4 1-1 1H7c-.6 0-1-.4-1-1V9" />
29059
+ <path d="M12 12v3" />
29060
+ </svg>
29061
+ Fork
29062
+ </button>` : ""}
29063
+ <button
29064
+ class="action-btn"
29065
+ 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);"
29066
+ @click=${this._copySourceCode}
29067
+ title="Copy source code"
29068
+ >
29069
+ ${clipboard} Copy
29070
+ </button>
28338
29071
  </div>
28339
- <button
28340
- class="action-btn"
28341
- 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);"
28342
- @click=${this._copySourceCode}
28343
- title="Copy source code"
28344
- >
28345
- ${clipboard} Copy
28346
- </button>
28347
29072
  </div>
28348
29073
  <pre
28349
29074
  class="language-${language2}"
@@ -28358,7 +29083,6 @@ ${photon.errorMessage || "Unknown error"}</pre
28358
29083
  font-size: 0.85rem;
28359
29084
  line-height: 1.6;
28360
29085
  tab-size: 2;
28361
- border-radius: 0 0 var(--radius-md) var(--radius-md);
28362
29086
  "
28363
29087
  ><code class="language-${language2}" style="display: block; overflow-x: visible;">${Prism ? o5(highlightedCode) : this._sourceData.code}</code></pre>
28364
29088
  </div>
@@ -28417,7 +29141,7 @@ ${photon.errorMessage || "Unknown error"}</pre
28417
29141
  </div>
28418
29142
  </div>
28419
29143
  <div style="display: flex; gap: var(--space-sm);">
28420
- ${this._selectedPhoton?.path && !this._selectedPhoton?.isExternalMCP ? b2`
29144
+ ${this._selectedPhoton?.editable && !this._selectedPhoton?.isExternalMCP ? b2`
28421
29145
  <button
28422
29146
  class="toolbar-btn"
28423
29147
  style="padding: 6px 12px; font-size: 0.85rem; background: var(--accent-primary); border-color: var(--accent-primary); color: white;"
@@ -28612,11 +29336,31 @@ BeamApp.styles = [
28612
29336
  }
28613
29337
 
28614
29338
  .sidebar-area {
28615
- width: 300px;
29339
+ width: var(--sidebar-width, 300px);
28616
29340
  flex-shrink: 0;
28617
29341
  z-index: 10;
28618
29342
  display: flex;
28619
29343
  flex-direction: column;
29344
+ position: relative;
29345
+ overflow: visible;
29346
+ }
29347
+
29348
+ .sidebar-resize-handle {
29349
+ position: absolute;
29350
+ right: -3px;
29351
+ top: 0;
29352
+ bottom: 0;
29353
+ width: 6px;
29354
+ cursor: col-resize;
29355
+ z-index: 20;
29356
+ background: transparent;
29357
+ transition: background 0.15s;
29358
+ }
29359
+
29360
+ .sidebar-resize-handle:hover,
29361
+ .sidebar-resize-handle.dragging {
29362
+ background: var(--accent-primary);
29363
+ opacity: 0.5;
28620
29364
  }
28621
29365
 
28622
29366
  :host(.focus-mode) .sidebar-area {
@@ -28842,10 +29586,20 @@ BeamApp.styles = [
28842
29586
  flex: 1;
28843
29587
  min-width: 0;
28844
29588
  position: relative;
29589
+ display: flex;
29590
+ flex-direction: column;
29591
+ overflow: hidden;
29592
+ }
29593
+
29594
+ .main-content-scroll {
29595
+ flex: 1;
29596
+ min-height: 0;
28845
29597
  overflow-y: auto;
28846
29598
  overflow-x: hidden;
28847
29599
  padding: var(--space-lg);
28848
29600
  scrollbar-gutter: stable;
29601
+ display: flex;
29602
+ flex-direction: column;
28849
29603
  }
28850
29604
 
28851
29605
  /* Page transition when switching photons */
@@ -28866,9 +29620,9 @@ BeamApp.styles = [
28866
29620
 
28867
29621
  .main-toolbar {
28868
29622
  display: flex;
28869
- justify-content: space-between;
28870
29623
  align-items: center;
28871
- margin: calc(-1 * var(--space-lg) + 4px) calc(-1 * var(--space-lg) + 4px) 4px;
29624
+ gap: var(--space-sm);
29625
+ margin-bottom: 8px;
28872
29626
  flex-shrink: 0;
28873
29627
  }
28874
29628
 
@@ -28897,9 +29651,22 @@ BeamApp.styles = [
28897
29651
  margin-left: auto;
28898
29652
  }
28899
29653
 
29654
+ .beam-tab-btn.active {
29655
+ color: var(--accent-secondary);
29656
+ border-color: var(--accent-secondary);
29657
+ }
29658
+
29659
+ .tab-group-divider {
29660
+ width: 1px;
29661
+ height: 16px;
29662
+ background: var(--border-glass);
29663
+ margin: 0 2px;
29664
+ align-self: center;
29665
+ }
29666
+
28900
29667
  .cards-grid {
28901
29668
  display: grid;
28902
- grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
29669
+ grid-template-columns: repeat(auto-fill, minmax(280px, min(100%, 380px)));
28903
29670
  gap: var(--space-md);
28904
29671
  align-items: stretch;
28905
29672
  }
@@ -28951,7 +29718,7 @@ BeamApp.styles = [
28951
29718
  .anchor-nav {
28952
29719
  display: flex;
28953
29720
  gap: var(--space-md);
28954
- margin: var(--space-md) 0 var(--space-lg);
29721
+ margin: 0 0 var(--space-md);
28955
29722
  }
28956
29723
 
28957
29724
  .anchor-link {
@@ -28997,7 +29764,7 @@ BeamApp.styles = [
28997
29764
  display: flex;
28998
29765
  align-items: flex-start;
28999
29766
  gap: var(--space-lg);
29000
- margin-bottom: var(--space-xl);
29767
+ margin-bottom: var(--space-md);
29001
29768
  }
29002
29769
 
29003
29770
  .photon-icon-large {
@@ -30058,7 +30825,8 @@ BeamApp.styles = [
30058
30825
  }
30059
30826
 
30060
30827
  /* ===== Theme Settings Panel ===== */
30061
- .theme-settings-overlay {
30828
+ .theme-settings-overlay,
30829
+ .approvals-overlay {
30062
30830
  position: fixed;
30063
30831
  inset: 0;
30064
30832
  background: rgba(0, 0, 0, 0.3);
@@ -30077,6 +30845,29 @@ BeamApp.styles = [
30077
30845
  animation: slideInRight 0.2s ease;
30078
30846
  }
30079
30847
 
30848
+ .approvals-panel {
30849
+ position: fixed;
30850
+ bottom: var(--space-xl);
30851
+ left: var(--space-md);
30852
+ width: 340px;
30853
+ max-height: 60vh;
30854
+ z-index: 1001;
30855
+ overflow-y: auto;
30856
+ border-radius: var(--radius-md);
30857
+ animation: slideInUp 0.2s ease;
30858
+ }
30859
+
30860
+ @keyframes slideInUp {
30861
+ from {
30862
+ transform: translateY(20px);
30863
+ opacity: 0;
30864
+ }
30865
+ to {
30866
+ transform: translateY(0);
30867
+ opacity: 1;
30868
+ }
30869
+ }
30870
+
30080
30871
  @keyframes slideInRight {
30081
30872
  from {
30082
30873
  transform: translateX(20px);
@@ -30159,6 +30950,34 @@ BeamApp.styles = [
30159
30950
  margin-top: var(--space-md);
30160
30951
  }
30161
30952
 
30953
+ .split-divider {
30954
+ width: 5px;
30955
+ flex-shrink: 0;
30956
+ cursor: col-resize;
30957
+ background: var(--border-glass);
30958
+ position: relative;
30959
+ transition: background 0.15s;
30960
+ }
30961
+
30962
+ .split-divider::after {
30963
+ content: '';
30964
+ position: absolute;
30965
+ top: 50%;
30966
+ left: 50%;
30967
+ transform: translate(-50%, -50%);
30968
+ width: 1px;
30969
+ height: 32px;
30970
+ background: var(--t-muted);
30971
+ border-radius: 2px;
30972
+ opacity: 0.4;
30973
+ }
30974
+
30975
+ .split-divider:hover,
30976
+ .split-divider.dragging {
30977
+ background: var(--accent-primary);
30978
+ opacity: 0.6;
30979
+ }
30980
+
30162
30981
  .method-detail h2 {
30163
30982
  margin-top: 0;
30164
30983
  }
@@ -30394,6 +31213,9 @@ __decorateClass([
30394
31213
  __decorateClass([
30395
31214
  r5()
30396
31215
  ], BeamApp.prototype, "_sidebarVisible", 2);
31216
+ __decorateClass([
31217
+ r5()
31218
+ ], BeamApp.prototype, "_sidebarWidth", 2);
30397
31219
  __decorateClass([
30398
31220
  r5()
30399
31221
  ], BeamApp.prototype, "_focusMode", 2);
@@ -30475,6 +31297,12 @@ __decorateClass([
30475
31297
  __decorateClass([
30476
31298
  r5()
30477
31299
  ], BeamApp.prototype, "_showElicitation", 2);
31300
+ __decorateClass([
31301
+ r5()
31302
+ ], BeamApp.prototype, "_showApprovals", 2);
31303
+ __decorateClass([
31304
+ r5()
31305
+ ], BeamApp.prototype, "_pendingApprovalsList", 2);
30478
31306
  __decorateClass([
30479
31307
  r5()
30480
31308
  ], BeamApp.prototype, "_protocolMode", 2);
@@ -30553,6 +31381,12 @@ __decorateClass([
30553
31381
  __decorateClass([
30554
31382
  r5()
30555
31383
  ], BeamApp.prototype, "_methodPickerPanelId", 2);
31384
+ __decorateClass([
31385
+ r5()
31386
+ ], BeamApp.prototype, "_splitPrimaryWidth", 2);
31387
+ __decorateClass([
31388
+ r5()
31389
+ ], BeamApp.prototype, "_mainTab", 2);
30556
31390
  __decorateClass([
30557
31391
  e7("beam-sidebar")
30558
31392
  ], BeamApp.prototype, "_sidebar", 2);
@@ -30568,6 +31402,12 @@ __decorateClass([
30568
31402
  __decorateClass([
30569
31403
  r5()
30570
31404
  ], BeamApp.prototype, "_forkOriginRepo", 2);
31405
+ __decorateClass([
31406
+ r5()
31407
+ ], BeamApp.prototype, "_forkRequireNewName", 2);
31408
+ __decorateClass([
31409
+ r5()
31410
+ ], BeamApp.prototype, "_forkSuggestedName", 2);
30571
31411
  __decorateClass([
30572
31412
  r5()
30573
31413
  ], BeamApp.prototype, "_forkTargets", 2);
@@ -30587,11 +31427,21 @@ var BeamSidebar = class extends i4 {
30587
31427
  this.reconnecting = false;
30588
31428
  this.updatesAvailable = 0;
30589
31429
  this.pendingApprovals = 0;
31430
+ this.mainTab = "methods";
31431
+ this.isApp = false;
31432
+ this.hasSettings = false;
31433
+ this.isExternalMCP = false;
31434
+ this.hasPath = false;
30590
31435
  this._searchQuery = "";
30591
31436
  this._showFavoritesOnly = false;
30592
31437
  this._favorites = /* @__PURE__ */ new Set();
30593
31438
  this._collapsedSections = /* @__PURE__ */ new Set();
31439
+ /** Live recency list — saved to localStorage but NOT used for rendering.
31440
+ * Only applied on next page load via _initialRecentOrder. */
30594
31441
  this._recentPhotons = [];
31442
+ /** Snapshot of recency order captured at page load — used for sorting.
31443
+ * Stays stable during the session so the sidebar doesn't jump around. */
31444
+ this._initialRecentOrder = [];
30595
31445
  this._notificationWarmth = /* @__PURE__ */ new Map();
30596
31446
  }
30597
31447
  connectedCallback() {
@@ -30614,7 +31464,10 @@ var BeamSidebar = class extends i4 {
30614
31464
  _loadRecent() {
30615
31465
  try {
30616
31466
  const stored = localStorage.getItem(BeamSidebar.RECENT_KEY);
30617
- if (stored) this._recentPhotons = JSON.parse(stored);
31467
+ if (stored) {
31468
+ this._recentPhotons = JSON.parse(stored);
31469
+ this._initialRecentOrder = [...this._recentPhotons];
31470
+ }
30618
31471
  } catch {
30619
31472
  }
30620
31473
  }
@@ -30676,6 +31529,11 @@ var BeamSidebar = class extends i4 {
30676
31529
  super.updated(changedProps);
30677
31530
  if (changedProps.has("selectedPhoton")) {
30678
31531
  this._ensureActiveSectionOpen();
31532
+ if (this.selectedPhoton) {
31533
+ this._scrollPhotonIntoView(this.selectedPhoton, false);
31534
+ } else {
31535
+ this._scrollSidebarToTop();
31536
+ }
30679
31537
  }
30680
31538
  }
30681
31539
  get _filteredPhotons() {
@@ -30716,9 +31574,10 @@ var BeamSidebar = class extends i4 {
30716
31574
  get _nonAppExternalMCPs() {
30717
31575
  return this._filteredExternalMCPs.filter((m3) => !m3.hasMcpApp);
30718
31576
  }
30719
- /** Sort items by recency — recently used items float to the top */
31577
+ /** Sort items by recency — uses the order snapshot from page load,
31578
+ * so the list stays stable during the session and only reorders on refresh. */
30720
31579
  _sortByRecency(items) {
30721
- const recentIndex = new Map(this._recentPhotons.map((name2, i7) => [name2, i7]));
31580
+ const recentIndex = new Map(this._initialRecentOrder.map((name2, i7) => [name2, i7]));
30722
31581
  return [...items].sort((a5, b3) => {
30723
31582
  const aIdx = recentIndex.get(a5.name);
30724
31583
  const bIdx = recentIndex.get(b3.name);
@@ -30751,16 +31610,46 @@ var BeamSidebar = class extends i4 {
30751
31610
  title="${this.connected ? "Connected" : this.reconnecting ? "Reconnecting..." : "Disconnected"}"
30752
31611
  ></span>
30753
31612
  </button>
31613
+ <button
31614
+ class="sidebar-minimize-btn"
31615
+ @click=${() => this.dispatchEvent(new CustomEvent("toggle-focus"))}
31616
+ title="Hide sidebar"
31617
+ >
31618
+ <svg
31619
+ width="18"
31620
+ height="18"
31621
+ viewBox="0 0 24 24"
31622
+ fill="none"
31623
+ stroke="currentColor"
31624
+ stroke-width="2"
31625
+ stroke-linecap="round"
31626
+ stroke-linejoin="round"
31627
+ >
31628
+ <rect width="18" height="18" x="3" y="3" rx="2" />
31629
+ <path d="M9 3v18" />
31630
+ <path d="m16 15-3-3 3-3" />
31631
+ </svg>
31632
+ </button>
30754
31633
  </div>
30755
- <div class="search-box" role="search">
30756
- <input
30757
- type="search"
30758
- placeholder="Search photons... (⌘K)"
30759
- .value=${this._searchQuery}
30760
- @input=${(e8) => this._handleSearch(e8)}
30761
- @keydown=${(e8) => this._handleSearchKeydown(e8)}
30762
- aria-label="Search photons"
30763
- />
31634
+ <div class="search-row">
31635
+ <div class="search-box" role="search">
31636
+ <input
31637
+ type="search"
31638
+ placeholder="Search photons... (⌘K)"
31639
+ .value=${this._searchQuery}
31640
+ @input=${(e8) => this._handleSearch(e8)}
31641
+ @keydown=${(e8) => this._handleSearchKeydown(e8)}
31642
+ aria-label="Search photons"
31643
+ />
31644
+ </div>
31645
+ <button
31646
+ class="sidebar-minimize-btn create-btn"
31647
+ @click=${() => this._createPhoton()}
31648
+ title="Create new photon"
31649
+ aria-label="Create new photon"
31650
+ >
31651
+ ${plus}
31652
+ </button>
30764
31653
  </div>
30765
31654
  <div class="filter-row" role="group" aria-label="Filter options">
30766
31655
  <button
@@ -30783,29 +31672,30 @@ var BeamSidebar = class extends i4 {
30783
31672
  </div>
30784
31673
  </div>
30785
31674
 
30786
- ${(() => {
31675
+ <div class="sidebar-scroll">
31676
+ ${(() => {
30787
31677
  const apps = this._sortByRecency(this._apps);
30788
31678
  const configured = this._sortByRecency(this._configured);
30789
31679
  return b2`
30790
- ${apps.length > 0 ? this._renderSection(
31680
+ ${apps.length > 0 ? this._renderSection(
30791
31681
  "apps",
30792
31682
  "APPS",
30793
31683
  apps,
30794
31684
  (p5) => p5.isExternalMCP ? this._renderExternalMCPItem(p5) : this._renderPhotonItem(p5, "app")
30795
31685
  ) : ""}
30796
- ${configured.length > 0 ? this._renderSection(
31686
+ ${configured.length > 0 ? this._renderSection(
30797
31687
  "photons",
30798
31688
  "PHOTONS",
30799
31689
  configured,
30800
31690
  (p5) => this._renderPhotonItem(p5, "configured")
30801
31691
  ) : ""}
30802
- `;
31692
+ `;
30803
31693
  })()}
30804
- ${(() => {
31694
+ ${(() => {
30805
31695
  const needsConfig = this._needsSetup.filter((p5) => p5.errorReason !== "load-error");
30806
31696
  const loadErrors = this._needsSetup.filter((p5) => p5.errorReason === "load-error");
30807
31697
  return b2`
30808
- ${needsConfig.length > 0 ? this._renderSection(
31698
+ ${needsConfig.length > 0 ? this._renderSection(
30809
31699
  "config",
30810
31700
  "NEEDS CONFIGURATION",
30811
31701
  needsConfig,
@@ -30813,7 +31703,7 @@ var BeamSidebar = class extends i4 {
30813
31703
  "attention",
30814
31704
  warning
30815
31705
  ) : ""}
30816
- ${loadErrors.length > 0 ? this._renderSection(
31706
+ ${loadErrors.length > 0 ? this._renderSection(
30817
31707
  "errors",
30818
31708
  "LOAD ERRORS",
30819
31709
  loadErrors,
@@ -30821,58 +31711,50 @@ var BeamSidebar = class extends i4 {
30821
31711
  "attention",
30822
31712
  xMark
30823
31713
  ) : ""}
30824
- `;
31714
+ `;
30825
31715
  })()}
30826
- ${this._nonAppExternalMCPs.length > 0 ? this._renderSection(
31716
+ ${this._nonAppExternalMCPs.length > 0 ? this._renderSection(
30827
31717
  "mcps",
30828
31718
  "MCPS",
30829
31719
  this._sortByRecency(this._nonAppExternalMCPs),
30830
31720
  (mcp) => this._renderExternalMCPItem(mcp)
30831
31721
  ) : ""}
30832
- ${this._apps.length === 0 && this._configured.length === 0 && this._needsSetup.length === 0 && this._nonAppExternalMCPs.length === 0 ? b2`
30833
- <div class="empty-state">
30834
- ${this._searchQuery.trim() ? b2`
30835
- <div class="empty-icon">${search}</div>
30836
- <div class="empty-title">No results</div>
30837
- <div class="empty-hint">No photons match "${this._searchQuery}"</div>
30838
- ` : b2`
30839
- <div class="empty-icon">${packageBox}</div>
30840
- <div class="empty-title">No photons yet</div>
30841
- <div class="empty-hint">
30842
- Add photons from the marketplace or create your own
30843
- </div>
30844
- <button
30845
- class="empty-action"
30846
- @click=${() => this.dispatchEvent(new CustomEvent("marketplace"))}
30847
- >
30848
- ${marketplace} Browse Marketplace
30849
- </button>
30850
- `}
30851
- </div>
30852
- ` : ""}
31722
+ ${this._apps.length === 0 && this._configured.length === 0 && this._needsSetup.length === 0 && this._nonAppExternalMCPs.length === 0 ? b2`
31723
+ <div class="empty-state">
31724
+ ${this._searchQuery.trim() ? b2`
31725
+ <div class="empty-icon">${search}</div>
31726
+ <div class="empty-title">No results</div>
31727
+ <div class="empty-hint">No photons match "${this._searchQuery}"</div>
31728
+ ` : b2`
31729
+ <div class="empty-icon">${packageBox}</div>
31730
+ <div class="empty-title">No photons yet</div>
31731
+ <div class="empty-hint">
31732
+ Add photons from the marketplace or create your own
31733
+ </div>
31734
+ <button
31735
+ class="empty-action"
31736
+ @click=${() => this.dispatchEvent(new CustomEvent("marketplace"))}
31737
+ >
31738
+ ${marketplace} Browse Marketplace
31739
+ </button>
31740
+ `}
31741
+ </div>
31742
+ ` : ""}
31743
+ </div>
30853
31744
  </nav>
30854
31745
 
30855
31746
  <div class="sidebar-footer">
30856
- ${this.pendingApprovals > 0 ? b2`
30857
- <button
30858
- class="footer-link approval-badge-btn"
30859
- @click=${() => this.dispatchEvent(
31747
+ <button
31748
+ class="footer-link approval-badge-btn ${this.pendingApprovals === 0 ? "disabled" : ""}"
31749
+ @click=${() => this.pendingApprovals > 0 && this.dispatchEvent(
30860
31750
  new CustomEvent("show-approvals", { bubbles: true, composed: true })
30861
31751
  )}
30862
- title="Pending approvals (${this.pendingApprovals})"
30863
- aria-label="Show pending approvals"
30864
- >
30865
- ${shieldCheck}
30866
- <span class="approval-badge">${this.pendingApprovals}</span>
30867
- </button>
30868
- ` : ""}
30869
- <button
30870
- class="footer-link"
30871
- @click=${() => this.dispatchEvent(new CustomEvent("diagnostics", { bubbles: true, composed: true }))}
30872
- title="Server diagnostics"
30873
- aria-label="Show diagnostics"
31752
+ title="${this.pendingApprovals > 0 ? `Pending approvals (${this.pendingApprovals})` : "No pending approvals"}"
31753
+ aria-label="Show pending approvals"
31754
+ ?disabled=${this.pendingApprovals === 0}
30874
31755
  >
30875
- ${activity}
31756
+ ${shieldCheck}
31757
+ <span class="approval-badge">${this.pendingApprovals}</span>
30876
31758
  </button>
30877
31759
  <button
30878
31760
  class="footer-link"
@@ -30908,6 +31790,41 @@ var BeamSidebar = class extends i4 {
30908
31790
  _showShortcuts() {
30909
31791
  this.dispatchEvent(new CustomEvent("show-shortcuts", { bubbles: true, composed: true }));
30910
31792
  }
31793
+ async _createPhoton() {
31794
+ const result = await elicit({
31795
+ ask: "form",
31796
+ icon: "\u2728",
31797
+ message: "Create a new photon",
31798
+ description: "Give your photon a name and we\u2019ll set up everything for you. Use lowercase letters and hyphens \u2014 like my-api or weather-bot.",
31799
+ submitLabel: "Create",
31800
+ cancelLabel: "Cancel",
31801
+ fields: [
31802
+ { name: "name", label: "Name", placeholder: "e.g. my-api", required: true },
31803
+ {
31804
+ name: "template",
31805
+ label: "Template",
31806
+ type: "text",
31807
+ enum: ["Hello World", "API Tool", "Stateful", "App"],
31808
+ default: "Hello World"
31809
+ }
31810
+ ]
31811
+ });
31812
+ if (result.action === "cancel") return;
31813
+ const form = result.value;
31814
+ if (!form?.name?.trim()) return;
31815
+ let filename = form.name.trim().toLowerCase().replace(/[^a-z0-9.-]/g, "-");
31816
+ if (!filename.endsWith(".photon.ts")) {
31817
+ filename = filename.replace(/\.photon$/, "") + ".photon.ts";
31818
+ }
31819
+ const template = (form.template || "Blank").toLowerCase().replace(/\s+/g, "-");
31820
+ this.dispatchEvent(
31821
+ new CustomEvent("create-photon", {
31822
+ detail: { name: filename, template },
31823
+ bubbles: true,
31824
+ composed: true
31825
+ })
31826
+ );
31827
+ }
30911
31828
  _openStudio(photonName) {
30912
31829
  this.dispatchEvent(
30913
31830
  new CustomEvent("open-studio", {
@@ -30950,7 +31867,7 @@ var BeamSidebar = class extends i4 {
30950
31867
  class="photon-list motion-stagger ${collapsed ? "collapsed" : ""}"
30951
31868
  role="listbox"
30952
31869
  aria-labelledby=${headerId}
30953
- style="max-height: ${collapsed ? "0" : items.length * 52 + "px"}"
31870
+ style="max-height: ${collapsed ? "0" : this._estimateSectionHeight(items) + "px"}"
30954
31871
  >
30955
31872
  ${items.map(renderItem)}
30956
31873
  </ul>
@@ -30974,11 +31891,12 @@ var BeamSidebar = class extends i4 {
30974
31891
  const isLight = this.theme === "light";
30975
31892
  initialsStyle = isLight ? `background: hsl(${hue2}, 30%, 90%); color: hsl(${hue2}, 50%, 35%);` : `background: hsl(${hue2}, 35%, 22%); color: hsl(${hue2}, 60%, 75%);`;
30976
31893
  }
31894
+ const isSelected = this.selectedPhoton === photon.name;
30977
31895
  return b2`
30978
31896
  <li
30979
- class="photon-item ${this.selectedPhoton === photon.name ? "active" : ""} ${photon.internal ? "internal" : ""} ${this._isPhotonWarm(photon.name) ? "warmth" : ""}"
31897
+ class="photon-item ${isSelected ? "active" : ""} ${photon.internal ? "internal" : ""} ${this._isPhotonWarm(photon.name) ? "warmth" : ""}"
30980
31898
  role="option"
30981
- aria-selected="${this.selectedPhoton === photon.name}"
31899
+ aria-selected="${isSelected}"
30982
31900
  tabindex="0"
30983
31901
  @click=${() => this._selectPhoton(photon)}
30984
31902
  @keydown=${(e8) => e8.key === "Enter" && this._selectPhoton(photon)}
@@ -30992,23 +31910,27 @@ ${photon.path}` : ""}"
30992
31910
  >
30993
31911
  ${displayIcon}
30994
31912
  </div>
30995
- <div class="photon-info">
30996
- <div class="photon-name">${photon.name}</div>
30997
- ${photon.internal ? b2`<span class="internal-badge">System</span>` : ""}
31913
+ <div class="photon-item-body">
31914
+ <div class="photon-main-row">
31915
+ <div class="photon-info">
31916
+ <div class="photon-name">${photon.name}</div>
31917
+ ${photon.internal ? b2`<span class="internal-badge">System</span>` : ""}
31918
+ </div>
31919
+ <button
31920
+ class="star-btn ${isFavorited ? "favorited" : ""}"
31921
+ @click=${(e8) => this._toggleFavorite(e8, photon.name)}
31922
+ title="${isFavorited ? "Remove from favorites" : "Add to favorites"}"
31923
+ aria-label="${isFavorited ? `Remove ${photon.name} from favorites` : `Add ${photon.name} to favorites`}"
31924
+ aria-pressed="${isFavorited}"
31925
+ >
31926
+ ${isFavorited ? starFilled : starOutline}
31927
+ </button>
31928
+ ${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"
31929
+ >?</span
31930
+ >` : this._renderCountsPill(photon, methodCount)}
31931
+ </div>
31932
+ ${isSelected ? this._renderInlineViewTabs() : ""}
30998
31933
  </div>
30999
- ${""}
31000
- <button
31001
- class="star-btn ${isFavorited ? "favorited" : ""}"
31002
- @click=${(e8) => this._toggleFavorite(e8, photon.name)}
31003
- title="${isFavorited ? "Remove from favorites" : "Add to favorites"}"
31004
- aria-label="${isFavorited ? `Remove ${photon.name} from favorites` : `Add ${photon.name} to favorites`}"
31005
- aria-pressed="${isFavorited}"
31006
- >
31007
- ${isFavorited ? starFilled : starOutline}
31008
- </button>
31009
- ${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"
31010
- >?</span
31011
- >` : this._renderCountsPill(photon, methodCount)}
31012
31934
  </li>
31013
31935
  `;
31014
31936
  }
@@ -31017,11 +31939,12 @@ ${photon.path}` : ""}"
31017
31939
  const isConnected = mcp.connected !== false;
31018
31940
  const displayIcon = mcp.icon || plug;
31019
31941
  const isFavorited = this._favorites.has(mcp.name);
31942
+ const isSelected = this.selectedPhoton === mcp.name;
31020
31943
  return b2`
31021
31944
  <li
31022
- class="photon-item ${this.selectedPhoton === mcp.name ? "active" : ""} ${!isConnected ? "disconnected" : ""}"
31945
+ class="photon-item ${isSelected ? "active" : ""} ${!isConnected ? "disconnected" : ""}"
31023
31946
  role="option"
31024
- aria-selected="${this.selectedPhoton === mcp.name}"
31947
+ aria-selected="${isSelected}"
31025
31948
  tabindex="0"
31026
31949
  @click=${() => this._selectPhoton(mcp)}
31027
31950
  @keydown=${(e8) => e8.key === "Enter" && this._selectPhoton(mcp)}
@@ -31029,34 +31952,107 @@ ${photon.path}` : ""}"
31029
31952
  \u26A0\uFE0F ${mcp.errorMessage}` : ""}"
31030
31953
  >
31031
31954
  <div class="photon-icon external-mcp-icon" aria-hidden="true">${displayIcon}</div>
31032
- <div class="photon-info">
31033
- <div class="photon-name">${mcp.name}</div>
31955
+ <div class="photon-item-body">
31956
+ <div class="photon-main-row">
31957
+ <div class="photon-info">
31958
+ <div class="photon-name">${mcp.name}</div>
31959
+ </div>
31960
+ <button
31961
+ class="star-btn ${isFavorited ? "favorited" : ""}"
31962
+ @click=${(e8) => this._toggleFavorite(e8, mcp.name)}
31963
+ title="${isFavorited ? "Remove from favorites" : "Add to favorites"}"
31964
+ aria-label="${isFavorited ? `Remove ${mcp.name} from favorites` : `Add ${mcp.name} to favorites`}"
31965
+ aria-pressed="${isFavorited}"
31966
+ >
31967
+ ${isFavorited ? starFilled : starOutline}
31968
+ </button>
31969
+ ${!isConnected ? b2`
31970
+ <span class="disconnect-badge" title="${mcp.errorMessage || "Disconnected"}"
31971
+ >Offline</span
31972
+ >
31973
+ <button
31974
+ class="reconnect-btn"
31975
+ @click=${(e8) => this._reconnectMCP(e8, mcp.name)}
31976
+ title="Reconnect"
31977
+ aria-label="Reconnect ${mcp.name}"
31978
+ >
31979
+
31980
+ </button>
31981
+ ` : this._renderCountsPill(mcp, methodCount)}
31982
+ </div>
31983
+ ${isSelected ? this._renderInlineViewTabs() : ""}
31034
31984
  </div>
31035
- <button
31036
- class="star-btn ${isFavorited ? "favorited" : ""}"
31037
- @click=${(e8) => this._toggleFavorite(e8, mcp.name)}
31038
- title="${isFavorited ? "Remove from favorites" : "Add to favorites"}"
31039
- aria-label="${isFavorited ? `Remove ${mcp.name} from favorites` : `Add ${mcp.name} to favorites`}"
31040
- aria-pressed="${isFavorited}"
31041
- >
31042
- ${isFavorited ? starFilled : starOutline}
31043
- </button>
31044
- ${!isConnected ? b2`
31045
- <span class="disconnect-badge" title="${mcp.errorMessage || "Disconnected"}"
31046
- >Offline</span
31047
- >
31048
- <button
31049
- class="reconnect-btn"
31050
- @click=${(e8) => this._reconnectMCP(e8, mcp.name)}
31051
- title="Reconnect"
31052
- aria-label="Reconnect ${mcp.name}"
31053
- >
31054
-
31055
- </button>
31056
- ` : this._renderCountsPill(mcp, methodCount)}
31057
31985
  </li>
31058
31986
  `;
31059
31987
  }
31988
+ _renderInlineViewTabs() {
31989
+ const appTabIcon = b2`<svg
31990
+ width="14"
31991
+ height="14"
31992
+ viewBox="0 0 24 24"
31993
+ fill="none"
31994
+ stroke="currentColor"
31995
+ stroke-width="2"
31996
+ stroke-linecap="round"
31997
+ stroke-linejoin="round"
31998
+ aria-hidden="true"
31999
+ >
32000
+ <rect x="3" y="3" width="18" height="18" rx="2" />
32001
+ <path d="M3 9h18" />
32002
+ <path d="M9 21V9" />
32003
+ </svg>`;
32004
+ const methodsTabIcon = b2`<svg
32005
+ width="14"
32006
+ height="14"
32007
+ viewBox="0 0 24 24"
32008
+ fill="none"
32009
+ stroke="currentColor"
32010
+ stroke-width="2"
32011
+ stroke-linecap="round"
32012
+ stroke-linejoin="round"
32013
+ aria-hidden="true"
32014
+ >
32015
+ <rect x="3" y="3" width="7" height="7" />
32016
+ <rect x="14" y="3" width="7" height="7" />
32017
+ <rect x="3" y="14" width="7" height="7" />
32018
+ <rect x="14" y="14" width="7" height="7" />
32019
+ </svg>`;
32020
+ const tabs = [
32021
+ ...this.isApp ? [{ id: "app", label: "App", icon: appTabIcon }] : [],
32022
+ { id: "methods", label: "Methods", icon: methodsTabIcon },
32023
+ { id: "log", label: "Activity", icon: activity },
32024
+ ...this.hasSettings ? [{ id: "settings", label: "Settings", icon: settings }] : [],
32025
+ ...this.hasPath && !this.isExternalMCP ? [{ id: "source", label: "Source", icon: source }] : [],
32026
+ { id: "help", label: "Help", icon: docs }
32027
+ ];
32028
+ return b2`
32029
+ <div class="photon-view-tabs" role="tablist" aria-label="Selected photon views">
32030
+ ${tabs.map(
32031
+ (tab) => b2`
32032
+ <button
32033
+ class="photon-view-tab ${this.mainTab === tab.id ? "active" : ""}"
32034
+ role="tab"
32035
+ aria-selected=${String(this.mainTab === tab.id)}
32036
+ title=${tab.label}
32037
+ aria-label=${tab.label}
32038
+ @click=${(e8) => {
32039
+ e8.stopPropagation();
32040
+ this._emitTabChange(tab.id);
32041
+ }}
32042
+ >
32043
+ ${tab.icon}
32044
+ </button>
32045
+ `
32046
+ )}
32047
+ </div>
32048
+ `;
32049
+ }
32050
+ _estimateSectionHeight(items) {
32051
+ return items.reduce((height, item) => {
32052
+ const isSelected = item.name === this.selectedPhoton;
32053
+ return height + (isSelected ? 92 : 52);
32054
+ }, 0);
32055
+ }
31060
32056
  _reconnectMCP(e8, mcpName) {
31061
32057
  e8.stopPropagation();
31062
32058
  this.dispatchEvent(
@@ -31102,6 +32098,9 @@ ${photon.path}` : ""}"
31102
32098
  })
31103
32099
  );
31104
32100
  }
32101
+ _emitTabChange(tab) {
32102
+ this.dispatchEvent(new CustomEvent("tab-change", { detail: { tab } }));
32103
+ }
31105
32104
  _handleSearch(e8) {
31106
32105
  this._searchQuery = e8.target.value;
31107
32106
  }
@@ -31159,6 +32158,9 @@ ${photon.path}` : ""}"
31159
32158
  return this._showFavoritesOnly;
31160
32159
  }
31161
32160
  scrollPhotonIntoView(name2) {
32161
+ this._scrollPhotonIntoView(name2, true);
32162
+ }
32163
+ _scrollPhotonIntoView(name2, flashHighlight) {
31162
32164
  void this.updateComplete.then(() => {
31163
32165
  const items = this.shadowRoot?.querySelectorAll(".photon-item");
31164
32166
  if (!items) return;
@@ -31166,13 +32168,23 @@ ${photon.path}` : ""}"
31166
32168
  const nameEl = item.querySelector(".photon-name");
31167
32169
  if (nameEl?.textContent?.trim() === name2) {
31168
32170
  item.scrollIntoView({ behavior: "smooth", block: "nearest" });
31169
- item.classList.add("flash-highlight");
31170
- setTimeout(() => item.classList.remove("flash-highlight"), 600);
32171
+ if (flashHighlight) {
32172
+ item.classList.add("flash-highlight");
32173
+ setTimeout(() => item.classList.remove("flash-highlight"), 600);
32174
+ }
31171
32175
  break;
31172
32176
  }
31173
32177
  }
31174
32178
  });
31175
32179
  }
32180
+ _scrollSidebarToTop() {
32181
+ void this.updateComplete.then(() => {
32182
+ const scrollEl = this.shadowRoot?.querySelector(".sidebar-scroll");
32183
+ if (scrollEl) {
32184
+ scrollEl.scrollTo({ top: 0, behavior: "smooth" });
32185
+ }
32186
+ });
32187
+ }
31176
32188
  /**
31177
32189
  * Check if a photon currently has a warmth indicator (notification received within last 5 seconds)
31178
32190
  */
@@ -31206,9 +32218,17 @@ BeamSidebar.styles = [
31206
32218
  flex-direction: column;
31207
32219
  height: 100%;
31208
32220
  color: var(--t-primary);
32221
+ overflow: visible;
31209
32222
  }
31210
32223
 
31211
32224
  .sidebar-content {
32225
+ flex: 1;
32226
+ overflow: hidden;
32227
+ display: flex;
32228
+ flex-direction: column;
32229
+ }
32230
+
32231
+ .sidebar-scroll {
31212
32232
  flex: 1;
31213
32233
  overflow-y: auto;
31214
32234
  padding-right: 4px;
@@ -31300,6 +32320,7 @@ BeamSidebar.styles = [
31300
32320
  .header {
31301
32321
  padding: var(--space-md);
31302
32322
  border-bottom: 1px solid var(--border-glass);
32323
+ flex-shrink: 0;
31303
32324
  }
31304
32325
 
31305
32326
  .header-row {
@@ -31328,32 +32349,32 @@ BeamSidebar.styles = [
31328
32349
  }
31329
32350
 
31330
32351
  .status-indicator {
31331
- width: 8px;
31332
- height: 8px;
32352
+ width: 9px;
32353
+ height: 9px;
31333
32354
  border-radius: 50%;
31334
32355
  flex-shrink: 0;
31335
32356
  }
31336
32357
 
31337
32358
  .status-indicator.connected {
31338
- background: var(--color-success);
32359
+ background: #22dd44;
31339
32360
  box-shadow:
31340
- 0 0 4px 1px var(--color-success-glow),
31341
- 0 0 8px 2px var(--color-success-glow);
32361
+ 0 0 4px 2px rgba(34, 221, 68, 0.6),
32362
+ 0 0 10px 4px rgba(34, 221, 68, 0.3);
31342
32363
  }
31343
32364
 
31344
32365
  .status-indicator.reconnecting {
31345
- background: var(--color-warning);
32366
+ background: #ffbb33;
31346
32367
  box-shadow:
31347
- 0 0 4px 1px var(--color-warning-glow),
31348
- 0 0 8px 2px var(--color-warning-glow);
32368
+ 0 0 4px 2px rgba(255, 187, 51, 0.6),
32369
+ 0 0 10px 4px rgba(255, 187, 51, 0.3);
31349
32370
  animation: pulse 1s ease-in-out infinite;
31350
32371
  }
31351
32372
 
31352
32373
  .status-indicator.disconnected {
31353
- background: var(--color-error);
32374
+ background: #ff4444;
31354
32375
  box-shadow:
31355
- 0 0 4px 1px rgba(248, 113, 113, 0.5),
31356
- 0 0 8px 2px rgba(248, 113, 113, 0.3);
32376
+ 0 0 4px 2px rgba(255, 68, 68, 0.6),
32377
+ 0 0 10px 4px rgba(255, 68, 68, 0.3);
31357
32378
  }
31358
32379
 
31359
32380
  @keyframes pulse {
@@ -31404,26 +32425,61 @@ BeamSidebar.styles = [
31404
32425
  background: var(--bg-glass-strong);
31405
32426
  }
31406
32427
 
31407
- .search-box {
32428
+ .search-row {
32429
+ display: flex;
32430
+ align-items: center;
32431
+ gap: var(--space-xs);
31408
32432
  margin-top: var(--space-md);
32433
+ }
32434
+
32435
+ .search-box {
32436
+ flex: 1;
31409
32437
  position: relative;
31410
32438
  }
31411
32439
 
32440
+ .create-btn {
32441
+ flex-shrink: 0;
32442
+ margin-top: 0 !important;
32443
+ }
32444
+
32445
+ .sidebar-minimize-btn {
32446
+ width: 32px;
32447
+ height: 32px;
32448
+ border-radius: var(--radius-sm);
32449
+ background: var(--bg-glass);
32450
+ border: 1px solid var(--border-glass);
32451
+ color: var(--t-muted);
32452
+ cursor: pointer;
32453
+ display: flex;
32454
+ align-items: center;
32455
+ justify-content: center;
32456
+ transition: all 0.15s ease;
32457
+ padding: 0;
32458
+ flex-shrink: 0;
32459
+ }
32460
+
32461
+ .sidebar-minimize-btn:hover {
32462
+ color: var(--t-primary);
32463
+ background: var(--bg-glass-strong);
32464
+ border-color: color-mix(in srgb, var(--accent-primary) 30%, var(--border-glass));
32465
+ }
32466
+
31412
32467
  input {
31413
32468
  padding: var(--space-sm) var(--space-md);
31414
32469
  }
31415
32470
 
31416
32471
  .section-header {
31417
32472
  font-family: var(--font-display);
31418
- padding: var(--space-sm) var(--space-md);
31419
- font-size: var(--text-xs);
32473
+ padding: var(--space-xs) var(--space-md);
32474
+ font-size: 10px;
31420
32475
  font-weight: 600;
31421
32476
  text-transform: uppercase;
31422
- letter-spacing: 0.1em;
32477
+ letter-spacing: 0.12em;
31423
32478
  color: var(--t-muted);
31424
- margin-top: var(--space-sm);
31425
- border-left: 2px solid var(--accent-primary);
31426
- background: var(--bg-glass-strong);
32479
+ opacity: 0.75;
32480
+ margin-top: var(--space-md);
32481
+ border-left: none;
32482
+ background: color-mix(in srgb, var(--t-muted) 8%, transparent);
31427
32483
  cursor: pointer;
31428
32484
  user-select: none;
31429
32485
  display: flex;
@@ -31432,18 +32488,17 @@ BeamSidebar.styles = [
31432
32488
  }
31433
32489
 
31434
32490
  .section-header:hover {
32491
+ opacity: 1;
31435
32492
  color: var(--t-primary);
31436
- background: var(--bg-panel);
31437
32493
  }
31438
32494
 
31439
32495
  .section-header.attention {
31440
32496
  color: var(--color-warning);
31441
- border-left-color: var(--color-warning);
31442
32497
  }
31443
32498
 
31444
32499
  .section-header.attention:hover {
31445
32500
  color: var(--color-warning);
31446
- opacity: 0.85;
32501
+ opacity: 1;
31447
32502
  }
31448
32503
 
31449
32504
  .section-label {
@@ -31502,9 +32557,12 @@ BeamSidebar.styles = [
31502
32557
  border-left: 2px solid var(--accent-primary);
31503
32558
  color: var(--accent-primary);
31504
32559
  font-weight: 500;
32560
+ align-items: center;
32561
+ padding-top: calc(var(--space-sm) + 2px);
32562
+ padding-bottom: calc(var(--space-sm) + 2px);
31505
32563
  }
31506
32564
 
31507
- .photon-item.flash-highlight {
32565
+ .photon-item.flash-highlight:not(.active) {
31508
32566
  animation: flash-highlight 0.6s ease-out;
31509
32567
  }
31510
32568
 
@@ -31517,7 +32575,7 @@ BeamSidebar.styles = [
31517
32575
  }
31518
32576
  }
31519
32577
 
31520
- .photon-item.warmth {
32578
+ .photon-item.warmth:not(.active) {
31521
32579
  animation: warmth-fade 5s ease-out forwards;
31522
32580
  }
31523
32581
 
@@ -31543,6 +32601,10 @@ BeamSidebar.styles = [
31543
32601
  color: var(--t-primary);
31544
32602
  flex-shrink: 0;
31545
32603
  letter-spacing: 0.5px;
32604
+ transition:
32605
+ width 0.25s ease,
32606
+ height 0.25s ease,
32607
+ font-size 0.25s ease;
31546
32608
  }
31547
32609
 
31548
32610
  .photon-icon.emoji-icon {
@@ -31551,6 +32613,17 @@ BeamSidebar.styles = [
31551
32613
  overflow: hidden;
31552
32614
  }
31553
32615
 
32616
+ /* Scale icon up when the row is expanded with view tabs */
32617
+ .photon-item.active .photon-icon {
32618
+ width: 42px;
32619
+ height: 42px;
32620
+ font-size: 15px;
32621
+ }
32622
+
32623
+ .photon-item.active .photon-icon.emoji-icon {
32624
+ font-size: 30px;
32625
+ }
32626
+
31554
32627
  .photon-item.internal {
31555
32628
  opacity: 0.85;
31556
32629
  }
@@ -31571,6 +32644,25 @@ BeamSidebar.styles = [
31571
32644
  flex: 1;
31572
32645
  }
31573
32646
 
32647
+ .photon-item-body {
32648
+ min-width: 0;
32649
+ flex: 1;
32650
+ display: flex;
32651
+ flex-direction: column;
32652
+ gap: 8px;
32653
+ }
32654
+
32655
+ .photon-main-row {
32656
+ display: flex;
32657
+ align-items: center;
32658
+ gap: var(--space-sm);
32659
+ min-width: 0;
32660
+ }
32661
+
32662
+ .photon-main-row .photon-info {
32663
+ min-width: 0;
32664
+ }
32665
+
31574
32666
  .photon-name {
31575
32667
  font-family: var(--font-display);
31576
32668
  font-weight: 600;
@@ -31587,6 +32679,44 @@ BeamSidebar.styles = [
31587
32679
  text-overflow: ellipsis;
31588
32680
  }
31589
32681
 
32682
+ .photon-view-tabs {
32683
+ display: flex;
32684
+ align-items: center;
32685
+ gap: 4px;
32686
+ }
32687
+
32688
+ .photon-view-tab {
32689
+ width: 26px;
32690
+ height: 26px;
32691
+ display: inline-flex;
32692
+ align-items: center;
32693
+ justify-content: center;
32694
+ border: 1px solid var(--border-glass);
32695
+ background: color-mix(in srgb, var(--bg-glass-strong) 82%, transparent);
32696
+ color: var(--t-muted);
32697
+ border-radius: var(--radius-sm);
32698
+ padding: 0;
32699
+ cursor: pointer;
32700
+ transition: all 0.15s ease;
32701
+ }
32702
+
32703
+ .photon-view-tab svg {
32704
+ width: 13px;
32705
+ height: 13px;
32706
+ }
32707
+
32708
+ .photon-view-tab:hover {
32709
+ color: var(--t-primary);
32710
+ border-color: color-mix(in srgb, var(--accent-primary) 38%, var(--border-glass));
32711
+ background: color-mix(in srgb, var(--accent-primary) 10%, var(--bg-glass-strong));
32712
+ }
32713
+
32714
+ .photon-view-tab.active {
32715
+ color: white;
32716
+ border-color: var(--accent-primary);
32717
+ background: color-mix(in srgb, var(--accent-primary) 78%, black 22%);
32718
+ }
32719
+
31590
32720
  .method-count {
31591
32721
  font-size: var(--text-2xs);
31592
32722
  padding: 2px 6px;
@@ -31688,6 +32818,16 @@ BeamSidebar.styles = [
31688
32818
  position: relative;
31689
32819
  }
31690
32820
 
32821
+ .approval-badge-btn.disabled {
32822
+ opacity: 0.4;
32823
+ cursor: default;
32824
+ }
32825
+
32826
+ .approval-badge-btn.disabled:hover {
32827
+ color: var(--t-muted);
32828
+ background: none;
32829
+ }
32830
+
31691
32831
  .approval-badge {
31692
32832
  position: absolute;
31693
32833
  top: -2px;
@@ -31887,6 +33027,10 @@ BeamSidebar.styles = [
31887
33027
  min-height: 44px;
31888
33028
  }
31889
33029
 
33030
+ .photon-view-tabs {
33031
+ margin-left: 0;
33032
+ }
33033
+
31890
33034
  .photon-item .star-btn {
31891
33035
  padding: var(--space-sm);
31892
33036
  opacity: 0.4;
@@ -31941,6 +33085,21 @@ __decorateClass([
31941
33085
  __decorateClass([
31942
33086
  n4({ type: Number })
31943
33087
  ], BeamSidebar.prototype, "pendingApprovals", 2);
33088
+ __decorateClass([
33089
+ n4({ type: String })
33090
+ ], BeamSidebar.prototype, "mainTab", 2);
33091
+ __decorateClass([
33092
+ n4({ type: Boolean })
33093
+ ], BeamSidebar.prototype, "isApp", 2);
33094
+ __decorateClass([
33095
+ n4({ type: Boolean })
33096
+ ], BeamSidebar.prototype, "hasSettings", 2);
33097
+ __decorateClass([
33098
+ n4({ type: Boolean })
33099
+ ], BeamSidebar.prototype, "isExternalMCP", 2);
33100
+ __decorateClass([
33101
+ n4({ type: Boolean })
33102
+ ], BeamSidebar.prototype, "hasPath", 2);
31944
33103
  __decorateClass([
31945
33104
  r5()
31946
33105
  ], BeamSidebar.prototype, "_searchQuery", 2);
@@ -31956,9 +33115,6 @@ __decorateClass([
31956
33115
  __decorateClass([
31957
33116
  r5()
31958
33117
  ], BeamSidebar.prototype, "_collapsedSections", 2);
31959
- __decorateClass([
31960
- r5()
31961
- ], BeamSidebar.prototype, "_recentPhotons", 2);
31962
33118
  __decorateClass([
31963
33119
  r5()
31964
33120
  ], BeamSidebar.prototype, "_notificationWarmth", 2);
@@ -31971,6 +33127,7 @@ var MethodCard = class extends i4 {
31971
33127
  constructor() {
31972
33128
  super(...arguments);
31973
33129
  this.photonName = "";
33130
+ this.editable = false;
31974
33131
  this._editingDescription = false;
31975
33132
  this._editingIcon = false;
31976
33133
  this._editedDescription = "";
@@ -32034,20 +33191,20 @@ var MethodCard = class extends i4 {
32034
33191
  ${this.method.icon}
32035
33192
  </div>
32036
33193
  ` : ""}
32037
- <span class="editable">
33194
+ <span class="${this.editable ? "editable" : ""}">
32038
33195
  <h3 class="title">
32039
33196
  <span class="title-name">${this.method.name}</span>${this._renderParamSignature()}
32040
33197
  </h3>
32041
- <span
32042
- class="edit-pencil"
32043
- role="button"
32044
- tabindex="0"
32045
- @click=${(e8) => this._handleNameEditClick(e8)}
32046
- @keydown=${(e8) => (e8.key === "Enter" || e8.key === " ") && (e8.preventDefault(), this._handleNameEditClick(e8))}
32047
- title="Rename method"
32048
- aria-label="Rename method"
32049
- >${pencil}</span
32050
- >
33198
+ ${this.editable ? b2`<span
33199
+ class="edit-pencil"
33200
+ role="button"
33201
+ tabindex="0"
33202
+ @click=${(e8) => this._handleNameEditClick(e8)}
33203
+ @keydown=${(e8) => (e8.key === "Enter" || e8.key === " ") && (e8.preventDefault(), this._handleNameEditClick(e8))}
33204
+ title="Rename method"
33205
+ aria-label="Rename method"
33206
+ >${pencil}</span
33207
+ >` : ""}
32051
33208
  </span>
32052
33209
  </div>
32053
33210
  ${this.method.isTemplate ? b2`<span class="badge prompt">Prompt</span>` : ""}
@@ -32087,21 +33244,24 @@ var MethodCard = class extends i4 {
32087
33244
  <span class="char-counter">${this._editedDescription.length}/500</span>
32088
33245
  </div>
32089
33246
  ` : b2`
32090
- <div class="editable" style="flex:1; align-items: flex-start;">
33247
+ <div
33248
+ class="${this.editable ? "editable" : ""}"
33249
+ style="flex:1; align-items: flex-start;"
33250
+ >
32091
33251
  <div class="description ${hasDescription ? "" : "placeholder"}" style="flex:1;">
32092
- ${hasDescription ? this._renderDescription(this.method.description) : "Add description..."}
33252
+ ${hasDescription ? this._renderDescription(this.method.description) : this.editable ? "Add description..." : ""}
32093
33253
  </div>
32094
- <span
32095
- class="edit-pencil"
32096
- role="button"
32097
- tabindex="0"
32098
- @click=${(e8) => this._handleDescriptionEditClick(e8)}
32099
- @keydown=${(e8) => (e8.key === "Enter" || e8.key === " ") && (e8.preventDefault(), this._handleDescriptionEditClick(e8))}
32100
- title="Edit description"
32101
- aria-label="Edit description"
32102
- style="margin-top: 2px;"
32103
- >${pencil}</span
32104
- >
33254
+ ${this.editable ? b2`<span
33255
+ class="edit-pencil"
33256
+ role="button"
33257
+ tabindex="0"
33258
+ @click=${(e8) => this._handleDescriptionEditClick(e8)}
33259
+ @keydown=${(e8) => (e8.key === "Enter" || e8.key === " ") && (e8.preventDefault(), this._handleDescriptionEditClick(e8))}
33260
+ title="Edit description"
33261
+ aria-label="Edit description"
33262
+ style="margin-top: 2px;"
33263
+ >${pencil}</span
33264
+ >` : ""}
32105
33265
  </div>
32106
33266
  `}
32107
33267
  </div>
@@ -32698,6 +33858,9 @@ __decorateClass([
32698
33858
  __decorateClass([
32699
33859
  n4({ type: String })
32700
33860
  ], MethodCard.prototype, "photonName", 2);
33861
+ __decorateClass([
33862
+ n4({ type: Boolean })
33863
+ ], MethodCard.prototype, "editable", 2);
32701
33864
  __decorateClass([
32702
33865
  r5()
32703
33866
  ], MethodCard.prototype, "_editingDescription", 2);
@@ -32812,6 +33975,7 @@ var InvokeForm = class extends i4 {
32812
33975
  this.methodName = "";
32813
33976
  this.rememberValues = false;
32814
33977
  this.sharedValues = null;
33978
+ this.settingsLayout = false;
32815
33979
  this._values = {};
32816
33980
  this._initialValues = {};
32817
33981
  this._passwordVisible = {};
@@ -32917,12 +34081,13 @@ var InvokeForm = class extends i4 {
32917
34081
  const result = await mcpClient.callTool(`${this.photonName}/${toolName}`, {});
32918
34082
  let values = [];
32919
34083
  let data = result;
32920
- if (result && Array.isArray(result.content)) {
32921
- if (result.isError) {
34084
+ const mcpResult = result;
34085
+ if (result && Array.isArray(mcpResult.content)) {
34086
+ if (mcpResult.isError) {
32922
34087
  hasUnresolved = true;
32923
34088
  continue;
32924
34089
  }
32925
- const textBlock = result.content.find((c5) => c5.type === "text");
34090
+ const textBlock = mcpResult.content.find((c5) => c5.type === "text");
32926
34091
  if (textBlock?.text) {
32927
34092
  try {
32928
34093
  data = JSON.parse(textBlock.text);
@@ -33022,6 +34187,42 @@ var InvokeForm = class extends i4 {
33022
34187
  const isRequired = Array.isArray(requiredList) ? requiredList.includes(key) : !!schema.required;
33023
34188
  const error2 = this._errors[key];
33024
34189
  const inputId = `field-${key}`;
34190
+ if (this.settingsLayout) {
34191
+ const isBoolean = schema.type === "boolean" || schema.type === '"boolean"';
34192
+ return b2`
34193
+ <div
34194
+ style="display: grid; grid-template-columns: 200px 1fr; border-bottom: 1px solid var(--border-glass); min-height: 48px;"
34195
+ >
34196
+ <div
34197
+ style="padding: 12px var(--space-md); display: flex; flex-direction: column; justify-content: center; background: var(--bg-glass);"
34198
+ >
34199
+ <label
34200
+ for=${inputId}
34201
+ style="font-size: var(--text-sm); font-weight: 600; color: var(--t-primary); margin: 0;"
34202
+ >
34203
+ ${formatLabel(key)}
34204
+ </label>
34205
+ ${schema.description ? b2`<span
34206
+ style="font-size: var(--text-2xs); color: var(--t-muted); margin-top: 2px; line-height: 1.3;"
34207
+ >${this._cleanDescription(schema.description, schema)}</span
34208
+ >` : ""}
34209
+ </div>
34210
+ <div
34211
+ style="padding: ${isBoolean ? "8px" : "6px"} var(--space-md); display: flex; align-items: center;"
34212
+ >
34213
+ ${this._renderInput(key, schema, !!error2, inputId)}
34214
+ ${error2 ? b2`<div
34215
+ class="error-text"
34216
+ style="margin-left: 8px;"
34217
+ id="${inputId}-error"
34218
+ role="alert"
34219
+ >
34220
+ ${error2}
34221
+ </div>` : ""}
34222
+ </div>
34223
+ </div>
34224
+ `;
34225
+ }
33025
34226
  return b2`
33026
34227
  <div class="form-group">
33027
34228
  <label for=${inputId}>
@@ -34258,7 +35459,7 @@ var InvokeForm = class extends i4 {
34258
35459
  }
34259
35460
  /** Cancel with dirty check. Called by parent chrome wrapper. */
34260
35461
  async handleCancel() {
34261
- if (this.isDirty && !await confirmDialog("You have unsaved changes. Discard them?", {
35462
+ if (this.isDirty && !await confirmElicit("You have unsaved changes. Discard them?", {
34262
35463
  confirm: "Discard",
34263
35464
  destructive: true
34264
35465
  })) {
@@ -34826,6 +36027,9 @@ __decorateClass([
34826
36027
  __decorateClass([
34827
36028
  n4({ type: Object })
34828
36029
  ], InvokeForm.prototype, "sharedValues", 2);
36030
+ __decorateClass([
36031
+ n4({ type: Boolean })
36032
+ ], InvokeForm.prototype, "settingsLayout", 2);
34829
36033
  __decorateClass([
34830
36034
  r5()
34831
36035
  ], InvokeForm.prototype, "_values", 2);
@@ -34853,6 +36057,7 @@ var ActivityLog = class extends i4 {
34853
36057
  constructor() {
34854
36058
  super(...arguments);
34855
36059
  this.items = [];
36060
+ this.fullscreen = false;
34856
36061
  this._filterActive = false;
34857
36062
  this._collapsed = false;
34858
36063
  this._lastFilter = void 0;
@@ -35020,6 +36225,24 @@ ActivityLog.styles = [
35020
36225
  list-style: none;
35021
36226
  margin: 0;
35022
36227
  padding: 0;
36228
+ max-height: 180px;
36229
+ overflow-y: auto;
36230
+ }
36231
+
36232
+ :host([fullscreen]) {
36233
+ display: flex;
36234
+ flex-direction: column;
36235
+ flex: 1;
36236
+ min-height: 0;
36237
+ margin-top: 0;
36238
+ border-top: none;
36239
+ padding-top: 0;
36240
+ }
36241
+
36242
+ :host([fullscreen]) .log-list {
36243
+ max-height: none;
36244
+ flex: 1;
36245
+ min-height: 0;
35023
36246
  }
35024
36247
 
35025
36248
  .log-item {
@@ -35159,6 +36382,9 @@ __decorateClass([
35159
36382
  __decorateClass([
35160
36383
  n4({ type: String })
35161
36384
  ], ActivityLog.prototype, "filter", 2);
36385
+ __decorateClass([
36386
+ n4({ type: Boolean, reflect: true })
36387
+ ], ActivityLog.prototype, "fullscreen", 2);
35162
36388
  __decorateClass([
35163
36389
  r5()
35164
36390
  ], ActivityLog.prototype, "_filterActive", 2);
@@ -39718,33 +40944,32 @@ ${footerText || pageNum ? `<div class="slide-footer"><span>${footerText || ""}</
39718
40944
  }
39719
40945
  }
39720
40946
  _renderSlideFormat(target2, data, format) {
39721
- const win = window;
39722
40947
  const doRender = () => {
39723
- if (win._photonRenderers?.render) {
39724
- win._photonRenderers.render(target2, data, format);
40948
+ if (window._photonRenderers?.render) {
40949
+ window._photonRenderers.render(target2, data, format);
39725
40950
  } else {
39726
40951
  target2.textContent = typeof data === "object" ? JSON.stringify(data, null, 2) : String(data ?? "");
39727
40952
  }
39728
40953
  };
39729
- if (win._photonRenderers) {
40954
+ if (window._photonRenderers) {
39730
40955
  doRender();
39731
- } else if (win._photonRenderersLoading) {
39732
- win._photonRenderersQueue = win._photonRenderersQueue || [];
39733
- win._photonRenderersQueue.push(doRender);
40956
+ } else if (window._photonRenderersLoading) {
40957
+ window._photonRenderersQueue = window._photonRenderersQueue || [];
40958
+ window._photonRenderersQueue.push(doRender);
39734
40959
  } else {
39735
- win._photonRenderersLoading = true;
39736
- win._photonRenderersQueue = [doRender];
40960
+ window._photonRenderersLoading = true;
40961
+ window._photonRenderersQueue = [doRender];
39737
40962
  fetch("/api/photon-renderers.js").then((r7) => r7.text()).then((code) => {
39738
40963
  try {
39739
40964
  (0, eval)(code);
39740
40965
  } catch {
39741
40966
  }
39742
- const queue = win._photonRenderersQueue || [];
39743
- win._photonRenderersQueue = [];
40967
+ const queue = window._photonRenderersQueue || [];
40968
+ window._photonRenderersQueue = [];
39744
40969
  queue.forEach((fn2) => fn2());
39745
40970
  }).catch(() => {
39746
- const queue = win._photonRenderersQueue || [];
39747
- win._photonRenderersQueue = [];
40971
+ const queue = window._photonRenderersQueue || [];
40972
+ window._photonRenderersQueue = [];
39748
40973
  queue.forEach((fn2) => fn2());
39749
40974
  });
39750
40975
  }
@@ -45601,7 +46826,7 @@ var MarketplaceView = class extends i4 {
45601
46826
  this._items = items;
45602
46827
  }
45603
46828
  async _removeSource(name2) {
45604
- if (!await confirmDialog(`Remove marketplace "${name2}"? This will not uninstall any photons.`, {
46829
+ if (!await confirmElicit(`Remove marketplace "${name2}"? This will not uninstall any photons.`, {
45605
46830
  confirm: "Remove",
45606
46831
  destructive: true
45607
46832
  })) {
@@ -45610,7 +46835,7 @@ var MarketplaceView = class extends i4 {
45610
46835
  try {
45611
46836
  const res = await fetch("/api/marketplace/sources/remove", {
45612
46837
  method: "POST",
45613
- headers: { "Content-Type": "application/json" },
46838
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
45614
46839
  body: JSON.stringify({ name: name2 }),
45615
46840
  signal: AbortSignal.timeout(1e4)
45616
46841
  });
@@ -45641,6 +46866,7 @@ var MarketplaceView = class extends i4 {
45641
46866
  try {
45642
46867
  const res = await fetch("/api/marketplace/add", {
45643
46868
  method: "POST",
46869
+ headers: { "X-Photon-Request": "1" },
45644
46870
  body: JSON.stringify({ name: item.name }),
45645
46871
  signal: AbortSignal.timeout(3e4)
45646
46872
  // 30s for installation
@@ -45667,7 +46893,7 @@ var MarketplaceView = class extends i4 {
45667
46893
  }
45668
46894
  }
45669
46895
  async _remove(item) {
45670
- if (!await confirmDialog(`Remove "${item.name}"? This will delete the photon files.`, {
46896
+ if (!await confirmElicit(`Remove "${item.name}"? This will delete the photon files.`, {
45671
46897
  confirm: "Remove",
45672
46898
  destructive: true
45673
46899
  }))
@@ -45676,6 +46902,7 @@ var MarketplaceView = class extends i4 {
45676
46902
  try {
45677
46903
  const res = await fetch("/api/marketplace/remove", {
45678
46904
  method: "POST",
46905
+ headers: { "X-Photon-Request": "1" },
45679
46906
  body: JSON.stringify({ name: item.name }),
45680
46907
  signal: AbortSignal.timeout(1e4)
45681
46908
  });
@@ -45705,6 +46932,7 @@ var MarketplaceView = class extends i4 {
45705
46932
  try {
45706
46933
  const res = await fetch("/api/marketplace/add", {
45707
46934
  method: "POST",
46935
+ headers: { "X-Photon-Request": "1" },
45708
46936
  body: JSON.stringify({ name: item.name }),
45709
46937
  signal: AbortSignal.timeout(3e4)
45710
46938
  });
@@ -45784,7 +47012,7 @@ var MarketplaceView = class extends i4 {
45784
47012
  try {
45785
47013
  const res = await fetch("/api/marketplace/sources/add", {
45786
47014
  method: "POST",
45787
- headers: { "Content-Type": "application/json" },
47015
+ headers: { "Content-Type": "application/json", "X-Photon-Request": "1" },
45788
47016
  body: JSON.stringify({ source: source3 }),
45789
47017
  signal: AbortSignal.timeout(3e4)
45790
47018
  // 30s for adding repo
@@ -46737,6 +47965,23 @@ var beamTypographyTokens = {
46737
47965
  };
46738
47966
 
46739
47967
  // src/auto-ui/frontend/components/custom-ui-renderer.ts
47968
+ function getBeamThemeTokens(themeMode) {
47969
+ const tokens = getThemeTokens(themeMode);
47970
+ if (themeMode === "dark") {
47971
+ tokens["--color-surface"] = "hsl(220, 15%, 10%)";
47972
+ tokens["--color-surface-container"] = "hsl(220, 15%, 12%)";
47973
+ tokens["--color-surface-container-high"] = "hsl(220, 15%, 14%)";
47974
+ tokens["--color-surface-container-highest"] = "hsl(220, 15%, 16%)";
47975
+ tokens["--bg"] = "hsl(220, 15%, 10%)";
47976
+ } else {
47977
+ tokens["--color-surface"] = "#eae4dd";
47978
+ tokens["--color-surface-container"] = "#f8f5f1";
47979
+ tokens["--color-surface-container-high"] = "#f0ebe5";
47980
+ tokens["--color-surface-container-highest"] = "#e8e2db";
47981
+ tokens["--bg"] = "#eae4dd";
47982
+ }
47983
+ return tokens;
47984
+ }
46740
47985
  var CustomUiRenderer = class extends i4 {
46741
47986
  constructor() {
46742
47987
  super(...arguments);
@@ -46781,7 +48026,7 @@ var CustomUiRenderer = class extends i4 {
46781
48026
  }
46782
48027
  if (changedProperties.has("theme")) {
46783
48028
  if (this._iframeRef?.contentWindow) {
46784
- const themeTokens = getThemeTokens(this.theme);
48029
+ const themeTokens = getBeamThemeTokens(this.theme);
46785
48030
  this._iframeRef.contentWindow.postMessage(
46786
48031
  {
46787
48032
  jsonrpc: "2.0",
@@ -46826,6 +48071,7 @@ var CustomUiRenderer = class extends i4 {
46826
48071
  "sandbox",
46827
48072
  "allow-scripts allow-forms allow-same-origin allow-popups allow-modals"
46828
48073
  );
48074
+ iframe.setAttribute("allowtransparency", "true");
46829
48075
  iframe.addEventListener("load", (e8) => this._handleIframeLoad(e8));
46830
48076
  iframe.src = this._blobUrl;
46831
48077
  container.appendChild(iframe);
@@ -47064,7 +48310,7 @@ var CustomUiRenderer = class extends i4 {
47064
48310
  _handleIframeLoad(e8) {
47065
48311
  const iframe = e8.target;
47066
48312
  this._iframeRef = iframe;
47067
- const themeTokens = getThemeTokens(this.theme);
48313
+ const themeTokens = getBeamThemeTokens(this.theme);
47068
48314
  this._iframeRef?.contentWindow?.postMessage(
47069
48315
  {
47070
48316
  jsonrpc: "2.0",
@@ -47102,16 +48348,21 @@ var CustomUiRenderer = class extends i4 {
47102
48348
  this._contentResizeObserver?.disconnect();
47103
48349
  const body = iframe.contentDocument?.body;
47104
48350
  if (body) {
47105
- this._contentResizeObserver = new ResizeObserver(() => {
47106
- const scrollH = iframe.contentDocument?.body.scrollHeight ?? 0;
47107
- const containerH = this.offsetHeight || 500;
47108
- if (scrollH > containerH) {
47109
- iframe.style.height = scrollH + "px";
47110
- } else {
47111
- iframe.style.height = "";
47112
- }
47113
- });
47114
- this._contentResizeObserver.observe(body);
48351
+ const bodyOverflow = iframe.contentDocument?.defaultView ? getComputedStyle(iframe.contentDocument.body).overflow : "";
48352
+ const isFullHeightApp = bodyOverflow === "hidden";
48353
+ const hostHasExplicitHeight = this.style.height && this.style.height !== "auto";
48354
+ if (!isFullHeightApp && !hostHasExplicitHeight) {
48355
+ this._contentResizeObserver = new ResizeObserver(() => {
48356
+ const scrollH = iframe.contentDocument?.body.scrollHeight ?? 0;
48357
+ const containerH = this.offsetHeight || 500;
48358
+ if (scrollH > containerH) {
48359
+ iframe.style.height = scrollH + "px";
48360
+ } else {
48361
+ iframe.style.height = "";
48362
+ }
48363
+ });
48364
+ this._contentResizeObserver.observe(body);
48365
+ }
47115
48366
  }
47116
48367
  }
47117
48368
  disconnectedCallback() {
@@ -47135,7 +48386,7 @@ CustomUiRenderer.styles = [
47135
48386
  width: 100%;
47136
48387
  height: 100%;
47137
48388
  min-height: 500px;
47138
- background: var(--bg-panel, #0d0d0d);
48389
+ background: transparent;
47139
48390
  border-radius: var(--radius-md);
47140
48391
  overflow: visible;
47141
48392
  }
@@ -67115,6 +68366,23 @@ function X_(r7, i7) {
67115
68366
  }
67116
68367
 
67117
68368
  // src/auto-ui/frontend/components/mcp-app-renderer.ts
68369
+ function getBeamThemeTokens2(themeMode) {
68370
+ const tokens = getThemeTokens(themeMode);
68371
+ if (themeMode === "dark") {
68372
+ tokens["--color-surface"] = "hsl(220, 15%, 10%)";
68373
+ tokens["--color-surface-container"] = "hsl(220, 15%, 12%)";
68374
+ tokens["--color-surface-container-high"] = "hsl(220, 15%, 14%)";
68375
+ tokens["--color-surface-container-highest"] = "hsl(220, 15%, 16%)";
68376
+ tokens["--bg"] = "hsl(220, 15%, 10%)";
68377
+ } else {
68378
+ tokens["--color-surface"] = "#eae4dd";
68379
+ tokens["--color-surface-container"] = "#f8f5f1";
68380
+ tokens["--color-surface-container-high"] = "#f0ebe5";
68381
+ tokens["--color-surface-container-highest"] = "#e8e2db";
68382
+ tokens["--bg"] = "#eae4dd";
68383
+ }
68384
+ return tokens;
68385
+ }
67118
68386
  var VALID_STYLE_KEYS = /* @__PURE__ */ new Set([
67119
68387
  // Background colors
67120
68388
  "--color-background-primary",
@@ -67243,14 +68511,14 @@ var McpAppRenderer = class extends i4 {
67243
68511
  willUpdate(changedProperties) {
67244
68512
  if (changedProperties.has("theme")) {
67245
68513
  if (this._bridge) {
67246
- const specTokens = filterSpecVariables(getThemeTokens(this.theme));
68514
+ const specTokens = filterSpecVariables(getBeamThemeTokens2(this.theme));
67247
68515
  this._bridge.setHostContext({
67248
68516
  theme: this.theme,
67249
68517
  styles: { variables: specTokens }
67250
68518
  });
67251
68519
  }
67252
68520
  if (this._iframeRef?.contentWindow) {
67253
- const themeTokens = getThemeTokens(this.theme);
68521
+ const themeTokens = getBeamThemeTokens2(this.theme);
67254
68522
  this._iframeRef.contentWindow.postMessage(
67255
68523
  {
67256
68524
  jsonrpc: "2.0",
@@ -67306,6 +68574,7 @@ var McpAppRenderer = class extends i4 {
67306
68574
  "sandbox",
67307
68575
  "allow-scripts allow-forms allow-same-origin allow-popups allow-modals"
67308
68576
  );
68577
+ iframe.setAttribute("allowtransparency", "true");
67309
68578
  iframe.addEventListener("load", (e8) => this._handleIframeLoad(e8));
67310
68579
  iframe.src = this._blobUrl;
67311
68580
  container.appendChild(iframe);
@@ -67363,7 +68632,7 @@ var McpAppRenderer = class extends i4 {
67363
68632
  const iframe = e8.target;
67364
68633
  this._iframeRef = iframe;
67365
68634
  if (!iframe.contentWindow) return;
67366
- const themeTokens = getThemeTokens(this.theme);
68635
+ const themeTokens = getBeamThemeTokens2(this.theme);
67367
68636
  iframe.contentWindow.postMessage(
67368
68637
  {
67369
68638
  jsonrpc: "2.0",
@@ -67407,7 +68676,7 @@ var McpAppRenderer = class extends i4 {
67407
68676
  const msg = event.data;
67408
68677
  if (!msg || typeof msg !== "object") return;
67409
68678
  if (msg.jsonrpc === "2.0" && msg.method === "ui/initialize" && msg.id != null) {
67410
- const themeTokens2 = getThemeTokens(this.theme);
68679
+ const themeTokens2 = getBeamThemeTokens2(this.theme);
67411
68680
  iframe.contentWindow?.postMessage(
67412
68681
  {
67413
68682
  jsonrpc: "2.0",
@@ -67476,7 +68745,7 @@ var McpAppRenderer = class extends i4 {
67476
68745
  void asyncMessageHandler(event);
67477
68746
  };
67478
68747
  window.addEventListener("message", this._messageHandler);
67479
- const specTokens = filterSpecVariables(getThemeTokens(this.theme));
68748
+ const specTokens = filterSpecVariables(getBeamThemeTokens2(this.theme));
67480
68749
  this._bridge = new W_(
67481
68750
  null,
67482
68751
  { name: "Photon Beam", version: "1.0.0" },
@@ -67615,7 +68884,7 @@ McpAppRenderer.styles = [
67615
68884
  width: 100%;
67616
68885
  height: 100%;
67617
68886
  min-height: 500px;
67618
- background: var(--bg-panel, #0d0d0d);
68887
+ background: transparent;
67619
68888
  border-radius: var(--radius-md);
67620
68889
  overflow: visible;
67621
68890
  }
@@ -94326,6 +95595,7 @@ var PhotonStudio = class extends i4 {
94326
95595
  super(...arguments);
94327
95596
  this.photonName = "";
94328
95597
  this.theme = "dark";
95598
+ this.hideCloseButton = false;
94329
95599
  this._source = "";
94330
95600
  this._originalSource = "";
94331
95601
  this._dirty = false;
@@ -94817,7 +96087,7 @@ ${indent}* ` },
94817
96087
  return;
94818
96088
  }
94819
96089
  const currentName = seedPlan.symbolName.replace(/^\(alias\)\s*/, "").trim();
94820
- const nextName = window.prompt("Rename symbol to:", currentName);
96090
+ const nextName = await promptElicit("Rename symbol to:", currentName);
94821
96091
  if (!nextName || nextName === currentName) return;
94822
96092
  const renamePlan = await this._tsWorkerClient.rename(this._filePath, this._source, pos, nextName).catch((error2) => {
94823
96093
  showToast(error2 instanceof Error ? error2.message : String(error2), "error");
@@ -95233,7 +96503,7 @@ ${indent}* ` },
95233
96503
  }
95234
96504
  async _close() {
95235
96505
  if (this._dirty) {
95236
- if (!await confirmDialog("You have unsaved changes. Close anyway?", {
96506
+ if (!await confirmElicit("You have unsaved changes. Close anyway?", {
95237
96507
  confirm: "Close",
95238
96508
  destructive: true
95239
96509
  }))
@@ -95246,7 +96516,7 @@ ${indent}* ` },
95246
96516
  return b2`
95247
96517
  <div class="toolbar">
95248
96518
  <span class="toolbar-title">Studio</span>
95249
- <button class="close-btn" @click=${() => this._close()}>&times;</button>
96519
+ ${!this.hideCloseButton ? b2`<button class="close-btn" @click=${() => this._close()}>&times;</button>` : ""}
95250
96520
  </div>
95251
96521
  <div class="loading-state">Loading source...</div>
95252
96522
  `;
@@ -95254,8 +96524,8 @@ ${indent}* ` },
95254
96524
  if (this._error) {
95255
96525
  return b2`
95256
96526
  <div class="toolbar">
95257
- <span class="toolbar-title">Studio</span>
95258
- <button class="close-btn" @click=${() => this._close()}>&times;</button>
96527
+ <span class="toolbar-title">Studio Error</span>
96528
+ ${!this.hideCloseButton ? b2`<button class="close-btn" @click=${() => this._close()}>&times;</button>` : ""}
95259
96529
  </div>
95260
96530
  <div class="error-state">
95261
96531
  <span>${this._error}</span>
@@ -95330,9 +96600,9 @@ ${indent}* ` },
95330
96600
  ${this._saving ? "Saving..." : "Save"}
95331
96601
  </button>
95332
96602
 
95333
- <button class="close-btn" @click=${() => this._close()} title="Close Studio">
95334
- &times;
95335
- </button>
96603
+ ${!this.hideCloseButton ? b2`<button class="close-btn" @click=${() => this._close()} title="Close Studio">
96604
+ &times;
96605
+ </button>` : ""}
95336
96606
  </div>
95337
96607
 
95338
96608
  <div class="studio-body">
@@ -96376,6 +97646,9 @@ __decorateClass([
96376
97646
  __decorateClass([
96377
97647
  n4()
96378
97648
  ], PhotonStudio.prototype, "theme", 2);
97649
+ __decorateClass([
97650
+ n4({ type: Boolean })
97651
+ ], PhotonStudio.prototype, "hideCloseButton", 2);
96379
97652
  __decorateClass([
96380
97653
  r5()
96381
97654
  ], PhotonStudio.prototype, "_source", 2);
@@ -96918,7 +98191,11 @@ var ElicitationModal = class extends i4 {
96918
98191
  aria-label="${this.data?.message || "Input required"}"
96919
98192
  @click=${(e8) => e8.stopPropagation()}
96920
98193
  >
96921
- <h3>${this.data.message || "Input Required"}</h3>
98194
+ ${this.data.icon ? b2`<div class="modal-icon">${this.data.icon}</div>` : A}
98195
+ <h3 class="${this.data.description ? "has-description" : ""}">
98196
+ ${this.data.message || "Input Required"}
98197
+ </h3>
98198
+ ${this.data.description ? b2`<p class="modal-description">${this.data.description}</p>` : A}
96922
98199
  ${this._renderContent()}
96923
98200
  </div>
96924
98201
  `;
@@ -96958,8 +98235,12 @@ var ElicitationModal = class extends i4 {
96958
98235
  />
96959
98236
  </div>
96960
98237
  <div class="actions">
96961
- <button class="btn-secondary" @click=${() => this._cancel()}>Cancel</button>
96962
- <button class="btn-primary" @click=${() => this._submit()}>Submit</button>
98238
+ <button class="btn-secondary" @click=${() => this._cancel()}>
98239
+ ${this.data?.cancelLabel || "Cancel"}
98240
+ </button>
98241
+ <button class="btn-primary" @click=${() => this._submit()}>
98242
+ ${this.data?.submitLabel || "Submit"}
98243
+ </button>
96963
98244
  </div>
96964
98245
  `;
96965
98246
  }
@@ -97456,13 +98737,31 @@ ElicitationModal.styles = [
97456
98737
  animation-delay: 0.05s;
97457
98738
  }
97458
98739
 
98740
+ .modal-icon {
98741
+ font-size: 2.5rem;
98742
+ text-align: center;
98743
+ margin-bottom: var(--space-sm);
98744
+ line-height: 1;
98745
+ }
98746
+
97459
98747
  h3 {
97460
- margin: 0 0 var(--space-lg) 0;
98748
+ margin: 0 0 var(--space-sm) 0;
97461
98749
  font-size: var(--text-xl);
97462
98750
  font-weight: 600;
97463
98751
  color: var(--t-primary);
97464
98752
  }
97465
98753
 
98754
+ .modal-description {
98755
+ margin: 0 0 var(--space-lg) 0;
98756
+ font-size: var(--text-md);
98757
+ color: var(--t-muted);
98758
+ line-height: 1.5;
98759
+ }
98760
+
98761
+ h3:not(.has-description) {
98762
+ margin-bottom: var(--space-lg);
98763
+ }
98764
+
97466
98765
  .actions {
97467
98766
  display: flex;
97468
98767
  gap: var(--space-sm);
@@ -99074,9 +100373,7 @@ var ContextBar = class extends i4 {
99074
100373
  ${this.showConfigure && !p5.isExternalMCP ? b2`<button class="action-btn" @click=${() => this._emit("configure")}>
99075
100374
  Reconfigure
99076
100375
  </button>` : ""}
99077
- ${this.showCopyConfig ? b2`<button class="action-btn" @click=${() => this._emit("copy-config")}>
99078
- ${clipboard} Copy MCP Config
99079
- </button>` : ""}
100376
+ ${""}<!-- Copy MCP Config moved to overflow menu -->
99080
100377
  ${this.overflowItems.length > 0 ? b2`<overflow-menu
99081
100378
  .items=${this.overflowItems}
99082
100379
  @menu-select=${(e8) => this._emit("overflow", e8.detail)}
@@ -99608,15 +100905,21 @@ var ForkDialog = class extends i4 {
99608
100905
  super(...arguments);
99609
100906
  this.photonName = "";
99610
100907
  this.originRepo = "";
100908
+ this.requireNewName = false;
100909
+ this.suggestedName = "";
99611
100910
  this.targets = [];
99612
100911
  this._selectedTarget = "local";
99613
100912
  this._newRepoName = "";
100913
+ this._newPhotonName = "";
99614
100914
  }
99615
100915
  render() {
99616
100916
  return b2`
99617
100917
  <div class="modal-content" @click=${(e8) => e8.stopPropagation()}>
99618
100918
  <h3>Fork ${this.photonName}</h3>
99619
100919
  ${this.originRepo ? b2`<div class="origin-info">From ${this.originRepo}</div>` : ""}
100920
+ <div class="origin-info">
100921
+ ${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."}
100922
+ </div>
99620
100923
 
99621
100924
  <div class="target-list">
99622
100925
  ${this.targets.map(
@@ -99668,16 +100971,26 @@ var ForkDialog = class extends i4 {
99668
100971
  <div class="target-radio"></div>
99669
100972
  <div class="target-info">
99670
100973
  <div class="target-name">Local only</div>
99671
- <div class="target-repo">Remove marketplace tracking, keep file as-is</div>
100974
+ <div class="target-repo">Create or keep a local editable copy</div>
99672
100975
  </div>
99673
100976
  </div>
99674
100977
  </div>
99675
100978
 
100979
+ <input
100980
+ class="create-repo-input"
100981
+ type="text"
100982
+ placeholder=${this.suggestedName || (this.requireNewName ? "new-local-name" : "Optional local name")}
100983
+ .value=${this._newPhotonName}
100984
+ @input=${(e8) => {
100985
+ this._newPhotonName = e8.target.value;
100986
+ }}
100987
+ />
100988
+
99676
100989
  <div class="actions">
99677
100990
  <button class="btn" @click=${() => this._cancel()}>Cancel</button>
99678
100991
  <button
99679
100992
  class="btn btn-primary"
99680
- ?disabled=${this._selectedTarget === "create" && !this._newRepoName.trim()}
100993
+ ?disabled=${this._selectedTarget === "create" && !this._newRepoName.trim() || this.requireNewName && !this._newPhotonName.trim()}
99681
100994
  @click=${() => this._confirm()}
99682
100995
  >
99683
100996
  Fork
@@ -99695,7 +101008,7 @@ var ForkDialog = class extends i4 {
99695
101008
  }
99696
101009
  this.dispatchEvent(
99697
101010
  new CustomEvent("fork-confirm", {
99698
- detail: { target: target2 },
101011
+ detail: { target: target2, newName: this._newPhotonName.trim() || void 0 },
99699
101012
  bubbles: true,
99700
101013
  composed: true
99701
101014
  })
@@ -99879,6 +101192,12 @@ __decorateClass([
99879
101192
  __decorateClass([
99880
101193
  n4()
99881
101194
  ], ForkDialog.prototype, "originRepo", 2);
101195
+ __decorateClass([
101196
+ n4({ type: Boolean })
101197
+ ], ForkDialog.prototype, "requireNewName", 2);
101198
+ __decorateClass([
101199
+ n4()
101200
+ ], ForkDialog.prototype, "suggestedName", 2);
99882
101201
  __decorateClass([
99883
101202
  n4({ type: Array })
99884
101203
  ], ForkDialog.prototype, "targets", 2);
@@ -99888,6 +101207,9 @@ __decorateClass([
99888
101207
  __decorateClass([
99889
101208
  r5()
99890
101209
  ], ForkDialog.prototype, "_newRepoName", 2);
101210
+ __decorateClass([
101211
+ r5()
101212
+ ], ForkDialog.prototype, "_newPhotonName", 2);
99891
101213
  ForkDialog = __decorateClass([
99892
101214
  t4("fork-dialog")
99893
101215
  ], ForkDialog);
@@ -99898,6 +101220,7 @@ var AppLayout = class extends i4 {
99898
101220
  super(...arguments);
99899
101221
  this.photonName = "";
99900
101222
  this.photonIcon = "";
101223
+ this.hideBelow = false;
99901
101224
  this._poppedOut = false;
99902
101225
  this._handleKeydown = (e8) => {
99903
101226
  if (e8.key === "Escape" && this._poppedOut) {
@@ -99955,6 +101278,34 @@ AppLayout.styles = [
99955
101278
  display: block;
99956
101279
  }
99957
101280
 
101281
+ :host([hide-below]) .scroll-divider,
101282
+ :host([hide-below]) .below-fold {
101283
+ display: none;
101284
+ }
101285
+
101286
+ /* App tab mode: fill the available flex height instead of using min-height */
101287
+ :host([hide-below]) {
101288
+ flex: 1;
101289
+ min-height: 0;
101290
+ height: 100%;
101291
+ }
101292
+
101293
+ :host([hide-below]) .app-viewport {
101294
+ min-height: unset;
101295
+ height: 100%;
101296
+ display: flex;
101297
+ flex-direction: column;
101298
+ /* Remove rounded corners and clipping — we fill the full viewport */
101299
+ border-radius: 0;
101300
+ overflow: visible;
101301
+ }
101302
+
101303
+ :host([hide-below]) .app-content {
101304
+ overflow: hidden;
101305
+ flex: 1;
101306
+ min-height: 0;
101307
+ }
101308
+
99958
101309
  .app-viewport {
99959
101310
  min-height: calc(100vh - 140px);
99960
101311
  border-radius: var(--radius-md);
@@ -100064,6 +101415,9 @@ __decorateClass([
100064
101415
  __decorateClass([
100065
101416
  n4({ type: String })
100066
101417
  ], AppLayout.prototype, "photonIcon", 2);
101418
+ __decorateClass([
101419
+ n4({ type: Boolean, reflect: true, attribute: "hide-below" })
101420
+ ], AppLayout.prototype, "hideBelow", 2);
100067
101421
  __decorateClass([
100068
101422
  r5()
100069
101423
  ], AppLayout.prototype, "_poppedOut", 2);