@cloudinary/asset-management-mcp 0.9.1 → 0.9.2

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 (47) hide show
  1. package/README.md +12 -15
  2. package/bin/mcp-server.js +209 -359
  3. package/bin/mcp-server.js.map +13 -13
  4. package/esm/landing-page.d.ts.map +1 -1
  5. package/esm/landing-page.js +9 -3
  6. package/esm/landing-page.js.map +1 -1
  7. package/esm/lib/config.d.ts +3 -3
  8. package/esm/lib/config.js +3 -3
  9. package/esm/mcp-server/apps/app-shared.d.ts +5 -4
  10. package/esm/mcp-server/apps/app-shared.d.ts.map +1 -1
  11. package/esm/mcp-server/apps/app-shared.js +79 -12
  12. package/esm/mcp-server/apps/app-shared.js.map +1 -1
  13. package/esm/mcp-server/apps/asset-details-app.d.ts.map +1 -1
  14. package/esm/mcp-server/apps/asset-details-app.js +7 -14
  15. package/esm/mcp-server/apps/asset-details-app.js.map +1 -1
  16. package/esm/mcp-server/apps/asset-gallery-app.d.ts.map +1 -1
  17. package/esm/mcp-server/apps/asset-gallery-app.js +75 -298
  18. package/esm/mcp-server/apps/asset-gallery-app.js.map +1 -1
  19. package/esm/mcp-server/apps/asset-upload-app.d.ts.map +1 -1
  20. package/esm/mcp-server/apps/asset-upload-app.js +29 -24
  21. package/esm/mcp-server/apps/asset-upload-app.js.map +1 -1
  22. package/esm/mcp-server/apps/config.d.ts.map +1 -1
  23. package/esm/mcp-server/apps/config.js +1 -2
  24. package/esm/mcp-server/apps/config.js.map +1 -1
  25. package/esm/mcp-server/apps/extensions.d.ts.map +1 -1
  26. package/esm/mcp-server/apps/extensions.js +6 -1
  27. package/esm/mcp-server/apps/extensions.js.map +1 -1
  28. package/esm/mcp-server/cli/serve/impl.js +1 -1
  29. package/esm/mcp-server/cli/serve/impl.js.map +1 -1
  30. package/esm/mcp-server/mcp-server.js +1 -1
  31. package/esm/mcp-server/server.js +1 -1
  32. package/esm/types/bigint.d.ts.map +1 -1
  33. package/esm/types/bigint.js +4 -3
  34. package/esm/types/bigint.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/landing-page.ts +9 -3
  37. package/src/lib/config.ts +3 -3
  38. package/src/mcp-server/apps/app-shared.ts +80 -12
  39. package/src/mcp-server/apps/asset-details-app.ts +7 -13
  40. package/src/mcp-server/apps/asset-gallery-app.ts +75 -297
  41. package/src/mcp-server/apps/asset-upload-app.ts +29 -23
  42. package/src/mcp-server/apps/config.ts +1 -2
  43. package/src/mcp-server/apps/extensions.ts +6 -1
  44. package/src/mcp-server/cli/serve/impl.ts +1 -1
  45. package/src/mcp-server/mcp-server.ts +1 -1
  46. package/src/mcp-server/server.ts +1 -1
  47. package/src/types/bigint.ts +18 -17
package/bin/mcp-server.js CHANGED
@@ -13960,9 +13960,9 @@ var init_config = __esm(() => {
13960
13960
  SDK_METADATA = {
13961
13961
  language: "typescript",
13962
13962
  openapiDocVersion: "0.5.1",
13963
- sdkVersion: "0.9.1",
13964
- genVersion: "2.881.4",
13965
- userAgent: "speakeasy-sdk/mcp-typescript 0.9.1 2.881.4 0.5.1 @cloudinary/asset-management-mcp"
13963
+ sdkVersion: "0.9.2",
13964
+ genVersion: "2.885.1",
13965
+ userAgent: "speakeasy-sdk/mcp-typescript 0.9.2 2.885.1 0.5.1 @cloudinary/asset-management-mcp"
13966
13966
  };
13967
13967
  });
13968
13968
 
@@ -14021,7 +14021,7 @@ var init_config2 = __esm(() => {
14021
14021
  "asset-details",
14022
14022
  "asset-upload"
14023
14023
  ];
14024
- DEFAULT_MCP_APPS = [];
14024
+ DEFAULT_MCP_APPS = [...MCP_APPS];
14025
14025
  });
14026
14026
 
14027
14027
  // src/mcp-server/console-logger.ts
@@ -65624,6 +65624,7 @@ var _infoSchema, _uploadSchema, TOOLTIP_MAP_JSON, SHARED_CSS_TOKENS = `
65624
65624
  [data-theme="dark"] .status-warn, .dark .status-warn { background: #854d0e; color: #fef08a; }
65625
65625
  [data-theme="dark"] .status-err, .dark .status-err { background: #991b1b; color: #fecaca; }
65626
65626
 
65627
+ html { overflow: hidden; }
65627
65628
  body {
65628
65629
  font-family: var(--cld-font);
65629
65630
  background: var(--cld-bg);
@@ -65634,16 +65635,35 @@ body {
65634
65635
  position: relative;
65635
65636
  }
65636
65637
  .theme-btn {
65637
- position: absolute; top: 4px; right: 4px; z-index: 900;
65638
65638
  width: 22px; height: 22px; border-radius: 50%;
65639
65639
  border: 1px solid transparent; background: transparent;
65640
65640
  color: var(--cld-text3); cursor: pointer;
65641
65641
  display: flex; align-items: center; justify-content: center;
65642
65642
  padding: 0; transition: background 0.15s, color 0.15s, border-color 0.15s;
65643
- opacity: 0.5;
65643
+ opacity: 0.5; flex-shrink: 0;
65644
65644
  }
65645
65645
  .theme-btn:hover { background: var(--cld-bg3); color: var(--cld-text); border-color: var(--cld-border); opacity: 1; }
65646
65646
  .theme-btn svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
65647
+ /* Shared icon-button — square pill, same family as theme-btn */
65648
+ .icon-btn {
65649
+ display: inline-flex; align-items: center; justify-content: center; gap: 5px;
65650
+ background: none; border: 1px solid var(--cld-border); border-radius: var(--cld-radius-sm);
65651
+ color: var(--cld-text2); cursor: pointer; padding: 4px 8px;
65652
+ font-size: 12px; font-weight: 500; font-family: inherit; line-height: 1;
65653
+ transition: background 0.15s, color 0.15s, border-color 0.15s;
65654
+ white-space: nowrap; flex-shrink: 0;
65655
+ }
65656
+ .icon-btn:hover { background: var(--cld-bg3); color: var(--cld-text); border-color: var(--cld-border2); }
65657
+ .icon-btn svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
65658
+ /* icon-only variant (no text label) */
65659
+ .icon-btn.icon-only { padding: 4px; width: 28px; height: 28px; }
65660
+ /* header state icon (decorative, not a button) */
65661
+ .upload-header-icon { display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
65662
+ .upload-header-icon svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
65663
+ .upload-header-icon.icon-success { color: var(--cld-success); }
65664
+ .upload-header-icon.icon-error { color: var(--cld-error); }
65665
+ .upload-header-icon.icon-warning { color: var(--cld-warning); }
65666
+ .upload-header-icon.icon-accent { color: var(--cld-accent); }
65647
65667
  `, SHARED_CSS_COMPONENTS = `
65648
65668
  .link { cursor: pointer; }
65649
65669
  .link:hover { color: var(--cld-accent); text-decoration: underline; }
@@ -65894,7 +65914,8 @@ details.detail-section > summary.detail-section-title::-webkit-details-marker {
65894
65914
  }
65895
65915
  .upload-zone:hover { border-color: var(--cld-accent); background: var(--cld-accent-bg); }
65896
65916
  .upload-zone.dragover { border-color: var(--cld-accent); background: var(--cld-accent-bg); }
65897
- .upload-zone-icon { font-size: 36px; margin-bottom: 8px; color: var(--cld-text3); }
65917
+ .upload-zone-icon { margin-bottom: 8px; color: var(--cld-text3); display: flex; align-items: center; justify-content: center; }
65918
+ .upload-zone-icon svg { width: 36px; height: 36px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
65898
65919
  .upload-zone-text { font-size: 14px; color: var(--cld-text2); margin-bottom: 4px; }
65899
65920
  .upload-zone-hint { font-size: 12px; color: var(--cld-text3); }
65900
65921
  .upload-zone-btn {
@@ -65940,8 +65961,9 @@ details.detail-section > summary.detail-section-title::-webkit-details-marker {
65940
65961
  .upload-preview-icon {
65941
65962
  width: 56px; height: 56px; border-radius: var(--cld-radius-sm);
65942
65963
  background: var(--cld-bg3); flex-shrink: 0; display: flex;
65943
- align-items: center; justify-content: center; font-size: 24px; color: var(--cld-text3);
65964
+ align-items: center; justify-content: center; color: var(--cld-text3);
65944
65965
  }
65966
+ .upload-preview-icon svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
65945
65967
  .upload-preview-info { flex: 1; min-width: 0; }
65946
65968
  .upload-preview-name { font-size: 13px; font-weight: 600; color: var(--cld-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
65947
65969
  .upload-preview-meta { font-size: 11px; color: var(--cld-text3); margin-top: 2px; }
@@ -66090,19 +66112,15 @@ details.upload-section > .upload-form { margin: 0; padding: 10px 12px; }
66090
66112
  background: var(--cld-accent-bg); border: 1px solid var(--cld-accent);
66091
66113
  border-radius: var(--cld-radius); margin-bottom: 4px; position: relative;
66092
66114
  }
66093
- .upload-staged-icon { font-size: 24px; flex-shrink: 0; }
66115
+ .upload-staged-icon { flex-shrink: 0; display: flex; align-items: center; color: var(--cld-accent); }
66116
+ .upload-staged-icon svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
66094
66117
  .upload-staged-info { flex: 1; min-width: 0; }
66095
66118
  .upload-staged-name {
66096
66119
  font-size: 13px; font-weight: 600; color: var(--cld-text);
66097
66120
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
66098
66121
  }
66099
66122
  .upload-staged-meta { font-size: 11px; color: var(--cld-text3); margin-top: 2px; }
66100
- .upload-staged-clear {
66101
- background: none; border: none; cursor: pointer; font-size: 16px;
66102
- color: var(--cld-text3); padding: 4px 6px; border-radius: var(--cld-radius-sm);
66103
- transition: color 0.15s, background 0.15s; flex-shrink: 0;
66104
- }
66105
- .upload-staged-clear:hover { color: var(--cld-error); background: rgba(206,25,13,0.08); }
66123
+ .upload-staged-clear:hover { color: var(--cld-error); border-color: var(--cld-error); background: rgba(206,25,13,0.08); }
66106
66124
 
66107
66125
  /* Upload submit button */
66108
66126
  .upload-submit {
@@ -66148,6 +66166,21 @@ details.upload-section > .upload-form { margin: 0; padding: 10px 12px; }
66148
66166
  .json-bool { color: #a9e34b; }
66149
66167
  .json-null { color: #868e96; }
66150
66168
  }
66169
+ `, SHARED_JS_ICONS = `
66170
+ var IC = {
66171
+ refresh: '<svg viewBox="0 0 24 24"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M3 21v-5h5"/></svg>',
66172
+ chevronLeft:'<svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>',
66173
+ arrowDown: '<svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg>',
66174
+ x: '<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',
66175
+ zap: '<svg viewBox="0 0 24 24"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>',
66176
+ uploadCloud:'<svg viewBox="0 0 24 24"><polyline points="16 16 12 12 8 16"/><line x1="12" y1="12" x2="12" y2="21"/><path d="M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3"/></svg>',
66177
+ alertTriangle:'<svg viewBox="0 0 24 24"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
66178
+ folderOpen: '<svg viewBox="0 0 24 24"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/><polyline points="22 13 17 13 15 16 9 16 7 13 2 13"/></svg>',
66179
+ checkCircle:'<svg viewBox="0 0 24 24"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>',
66180
+ clock: '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>',
66181
+ file: '<svg viewBox="0 0 24 24"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>',
66182
+ image: '<svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>',
66183
+ };
66151
66184
  `, SHARED_JS_MCP_CLIENT = `
66152
66185
  var RPC_TIMEOUT_MS = 15000;
66153
66186
  var TOOL_CALL_TIMEOUT_MS = 30000;
@@ -66233,6 +66266,29 @@ class MCPApp {
66233
66266
  }
66234
66267
  }
66235
66268
  `, SHARED_JS_HELPERS = `
66269
+ function copyText(text) {
66270
+ if (navigator.clipboard && navigator.clipboard.writeText) {
66271
+ return navigator.clipboard.writeText(text).catch(function() { return _copyFallback(text); });
66272
+ }
66273
+ return _copyFallback(text);
66274
+ }
66275
+ function _copyFallback(text) {
66276
+ return new Promise(function(resolve, reject) {
66277
+ try {
66278
+ var ta = document.createElement("textarea");
66279
+ ta.value = text;
66280
+ ta.setAttribute("readonly", "");
66281
+ ta.style.position = "fixed"; ta.style.top = "0"; ta.style.left = "0";
66282
+ ta.style.opacity = "0"; ta.style.pointerEvents = "none";
66283
+ document.body.appendChild(ta);
66284
+ ta.select(); ta.setSelectionRange(0, text.length);
66285
+ var ok = document.execCommand("copy");
66286
+ document.body.removeChild(ta);
66287
+ if (ok) resolve(); else reject(new Error("Clipboard unavailable"));
66288
+ } catch (e) { reject(e); }
66289
+ });
66290
+ }
66291
+
66236
66292
  function fmtBytes(b) {
66237
66293
  if (!b) return "";
66238
66294
  var u = ["B","KB","MB","GB"], i = Math.min(Math.floor(Math.log(b)/Math.log(1024)), 3);
@@ -67456,7 +67512,16 @@ function renderThemeToggle() {
67456
67512
  applyTheme();
67457
67513
  renderThemeToggle();
67458
67514
  });
67459
- document.body.appendChild(btn);
67515
+ var slot = document.getElementById("header-actions");
67516
+ if (slot) {
67517
+ slot.appendChild(btn);
67518
+ } else {
67519
+ btn.style.position = "absolute";
67520
+ btn.style.top = "4px";
67521
+ btn.style.right = "4px";
67522
+ btn.style.zIndex = "900";
67523
+ document.body.appendChild(btn);
67524
+ }
67460
67525
  }
67461
67526
 
67462
67527
  function setupHostContext(app) {
@@ -67550,90 +67615,10 @@ var GALLERY_CSS = `
67550
67615
  font-size: var(--cld-font-xxs); color: var(--cld-text3); background: var(--cld-bg3);
67551
67616
  padding: 2px 8px; border-radius: 20px; font-weight: 500;
67552
67617
  }
67553
- .select-all-btn {
67554
- font-size: 12px; color: var(--cld-text2); background: none;
67555
- border: 1px solid var(--cld-border); border-radius: var(--cld-radius-sm);
67556
- padding: 4px 10px; cursor: pointer; font-family: inherit;
67557
- transition: color 0.15s, border-color 0.15s;
67558
- }
67559
- .select-all-btn:hover { color: var(--cld-accent); border-color: var(--cld-accent); }
67560
- .refresh-btn {
67561
- background: none; border: 1px solid var(--cld-border); border-radius: var(--cld-radius-sm);
67562
- color: var(--cld-text2); cursor: pointer; font-size: 14px; padding: 2px 7px;
67563
- line-height: 1; transition: background 0.15s, color 0.15s;
67564
- }
67565
- .refresh-btn:hover { background: var(--cld-bg3); color: var(--cld-text); }
67566
-
67567
- /* ── Filter bar ── */
67568
- .filter-row {
67569
- margin-bottom: var(--cld-sp-md); display: flex; gap: 8px; align-items: center;
67570
- }
67571
- .filter-text-wrap { position: relative; flex: 1; }
67572
- .filter-input {
67573
- width: 100%; height: 36px; padding: 0 12px 0 34px;
67574
- border: 1px solid var(--cld-border); border-radius: var(--cld-radius);
67575
- background: var(--cld-bg); font-size: 12.5px; color: var(--cld-text);
67576
- outline: none; font-family: inherit;
67577
- transition: border-color 0.18s, box-shadow 0.18s;
67578
- }
67579
- .filter-input::placeholder { color: var(--cld-text3); }
67580
- .filter-input:focus {
67581
- border-color: var(--cld-accent);
67582
- box-shadow: 0 0 0 3px rgba(52,72,197,0.1);
67583
- }
67584
- [data-theme="dark"] .filter-input:focus { box-shadow: 0 0 0 3px rgba(13,154,255,0.15); }
67585
- .filter-icon {
67586
- position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
67587
- color: var(--cld-text3); pointer-events: none; display: flex; align-items: center;
67588
- }
67589
- .filter-clear {
67590
- position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
67591
- background: none; border: none; color: var(--cld-text3); cursor: pointer;
67592
- font-size: 14px; line-height: 1; padding: 2px 4px; border-radius: 4px;
67593
- display: none; font-family: inherit;
67594
- }
67595
- .filter-clear:hover { color: var(--cld-text); background: var(--cld-border); }
67596
- .filter-clear.visible { display: block; }
67597
-
67598
- /* Aspect-ratio dropdown */
67599
- .aspect-dropdown { position: relative; flex-shrink: 0; user-select: none; }
67600
- .aspect-btn {
67601
- height: 36px; padding: 0 10px; border: 1px solid var(--cld-border);
67602
- border-radius: var(--cld-radius); background: var(--cld-bg);
67603
- font-size: 12.5px; color: var(--cld-text); cursor: pointer;
67604
- display: flex; align-items: center; gap: 6px; white-space: nowrap;
67605
- transition: border-color 0.18s, box-shadow 0.18s, background 0.18s;
67606
- font-family: inherit; outline: none;
67607
- }
67608
- .aspect-btn:hover { border-color: var(--cld-border2); }
67609
- .aspect-btn.active {
67610
- border-color: var(--cld-accent); background: var(--cld-accent-bg);
67611
- color: var(--cld-accent); font-weight: 600;
67612
- }
67613
- .aspect-btn-chevron { color: var(--cld-text3); flex-shrink: 0; transition: transform 0.18s; }
67614
- .aspect-btn.open .aspect-btn-chevron { transform: rotate(180deg); }
67615
- .aspect-menu {
67616
- position: absolute; top: calc(100% + 6px); right: 0;
67617
- background: var(--cld-bg); border: 1px solid var(--cld-border);
67618
- border-radius: 10px; box-shadow: var(--cld-shadow-md);
67619
- padding: 4px; min-width: 160px; z-index: 50; display: none;
67620
- }
67621
- .aspect-menu.open { display: block; }
67622
- .aspect-option {
67623
- display: flex; align-items: center; gap: 10px;
67624
- padding: 7px 10px; border-radius: 6px; font-size: 12.5px;
67625
- color: var(--cld-text); cursor: pointer; transition: background 0.18s;
67626
- }
67627
- .aspect-option:hover { background: var(--cld-bg3); }
67628
- .aspect-option.selected { color: var(--cld-accent); font-weight: 600; }
67629
- .aspect-opt-icon { color: var(--cld-text3); display: flex; align-items: center; flex-shrink: 0; }
67630
- .aspect-option.selected .aspect-opt-icon { color: var(--cld-accent); }
67631
- .aspect-check { margin-left: auto; color: var(--cld-accent); opacity: 0; }
67632
- .aspect-option.selected .aspect-check { opacity: 1; }
67633
- .no-results {
67634
- grid-column: 1 / -1; padding: 60px 20px;
67635
- text-align: center; color: var(--cld-text3); font-size: 13px;
67636
- }
67618
+ /* action-btn svg sizing */
67619
+ .action-btn svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
67620
+ /* select bar svg */
67621
+ .bar-btn svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
67637
67622
 
67638
67623
  /* ── Grid ── */
67639
67624
  .grid {
@@ -67692,18 +67677,11 @@ var GALLERY_CSS = `
67692
67677
  opacity: 0; transition: opacity 0.18s; z-index: 4; pointer-events: none;
67693
67678
  }
67694
67679
  .card:hover .tags-overlay { opacity: 1; }
67695
- .grid.filtering .tags-overlay { opacity: 1; }
67696
67680
  .tag-overlay {
67697
67681
  font-size: 10px; color: white;
67698
67682
  background: rgba(10, 12, 18, 0.55); padding: 2px 7px; border-radius: 20px;
67699
67683
  backdrop-filter: blur(6px); font-weight: 600; letter-spacing: 0.02em;
67700
67684
  }
67701
- .tag-overlay.tag-match { background: rgba(52, 72, 197, 0.82); }
67702
- .tag-overlay mark {
67703
- background: rgba(255, 213, 79, 0.5); color: white;
67704
- border-radius: 2px; padding: 0 1px;
67705
- }
67706
-
67707
67685
  /* Floating action buttons */
67708
67686
  .card-actions {
67709
67687
  position: absolute; bottom: 10px; left: 0; right: 0;
@@ -67778,7 +67756,6 @@ var GALLERY_CSS = `
67778
67756
  opacity: 0; pointer-events: none; z-index: 100; white-space: nowrap;
67779
67757
  }
67780
67758
  .select-bar.visible { transform: translateX(-50%) translateY(0); opacity: 1; pointer-events: all; }
67781
- .select-bar-spacer { height: 72px; }
67782
67759
  .select-count { font-size: 13px; font-weight: 600; margin-right: 8px; }
67783
67760
  .bar-btn {
67784
67761
  height: 36px; padding: 0 14px; border: none; border-radius: 30px;
@@ -67817,8 +67794,6 @@ var pendingCall = {
67817
67794
  args: null,
67818
67795
  };
67819
67796
  var selected = new Set();
67820
- var filterQuery = "";
67821
- var aspectFilter = "";
67822
67797
  var app = new MCPApp({ name: "Cloudinary Asset Gallery", version: "1.0.0" });
67823
67798
  setupHostContext(app);
67824
67799
 
@@ -67842,24 +67817,6 @@ function showToast(msg) {
67842
67817
  _toastTimer = setTimeout(function() { t.classList.remove("show"); }, 2000);
67843
67818
  }
67844
67819
 
67845
- function getAspect(r) {
67846
- if (!r.width || !r.height) return "";
67847
- var ratio = r.width / r.height;
67848
- if (ratio > 1.1) return "landscape";
67849
- if (ratio < 0.9) return "portrait";
67850
- return "square";
67851
- }
67852
-
67853
- function highlightText(text, query) {
67854
- if (!query) return esc(text);
67855
- var lo = text.toLowerCase();
67856
- var idx = lo.indexOf(query);
67857
- if (idx === -1) return esc(text);
67858
- return esc(text.slice(0, idx))
67859
- + "<mark>" + esc(text.slice(idx, idx + query.length)) + "</mark>"
67860
- + esc(text.slice(idx + query.length));
67861
- }
67862
-
67863
67820
  function updateSelectBar() {
67864
67821
  var bar = document.getElementById("select-bar");
67865
67822
  var countEl = document.getElementById("select-count");
@@ -67867,8 +67824,6 @@ function updateSelectBar() {
67867
67824
  var n = selected.size;
67868
67825
  countEl.textContent = n + " selected";
67869
67826
  bar.classList.toggle("visible", n > 0);
67870
- var spacer = document.getElementById("select-bar-spacer");
67871
- if (spacer) spacer.style.display = n > 0 ? "" : "none";
67872
67827
  var btn = document.getElementById("select-all-btn");
67873
67828
  if (btn) {
67874
67829
  var visible = getVisibleIndices();
@@ -67935,11 +67890,9 @@ function copyAssetUrl(type, idx) {
67935
67890
  var url = r.secure_url || r.url || "";
67936
67891
  var copyUrl = type === "optimized" ? optimizedUrl(url, r) : url;
67937
67892
  if (!copyUrl) return;
67938
- try {
67939
- navigator.clipboard.writeText(copyUrl).then(function() {
67940
- showToast(type === "optimized" ? "\\u2728 Optimized URL copied" : "URL copied");
67941
- });
67942
- } catch(e) { showError("Copy Failed", String(e)); }
67893
+ copyText(copyUrl).then(function() {
67894
+ showToast(type === "optimized" ? "\\u2728 Optimized URL copied" : "URL copied");
67895
+ }).catch(function(e) { showError("Copy Failed", e && e.message ? e.message : String(e)); });
67943
67896
  }
67944
67897
 
67945
67898
  function downloadOne(idx) {
@@ -67961,134 +67914,74 @@ function copySelectedUrls(type) {
67961
67914
  urls.push(type === "optimized" ? optimizedUrl(url, r) : url);
67962
67915
  });
67963
67916
  if (!urls.length) return;
67964
- try {
67965
- navigator.clipboard.writeText(urls.join("\\n")).then(function() {
67966
- showToast(urls.length + " " + (type === "optimized" ? "optimized " : "") + "URLs copied");
67967
- });
67968
- } catch(e) { showError("Copy Failed", String(e)); }
67917
+ copyText(urls.join("\\n")).then(function() {
67918
+ showToast(urls.length + " " + (type === "optimized" ? "optimized " : "") + "URLs copied");
67919
+ }).catch(function(e) { showError("Copy Failed", e && e.message ? e.message : String(e)); });
67969
67920
  }
67970
67921
 
67971
- function downloadSelected() {
67972
- var count = 0;
67922
+ async function downloadSelected() {
67923
+ if (selected.size === 0) return;
67924
+
67925
+ var picks = [];
67973
67926
  selected.forEach(function(i) {
67974
67927
  var r = allResources[i];
67975
- if (!r) return;
67976
- var url = r.secure_url || r.url || "";
67977
- var dl = downloadUrl(url, r);
67978
- if (dl) { app._rpc("ui/open-link", { url: dl }); count++; }
67928
+ if (r && r.public_id) picks.push(r);
67979
67929
  });
67980
- if (count) showToast("Downloading " + count + " asset" + (count > 1 ? "s" : ""));
67981
- }
67982
-
67983
- function handleFilter() {
67984
- var input = document.getElementById("filter-input");
67985
- filterQuery = input ? input.value.trim().toLowerCase() : "";
67930
+ if (!picks.length) return;
67986
67931
 
67987
- var clearBtn = document.getElementById("filter-clear");
67988
- if (clearBtn) clearBtn.classList.toggle("visible", filterQuery.length > 0);
67932
+ var requestBody = {
67933
+ mode: "create",
67934
+ target_format: "zip",
67935
+ keep_derived: true,
67936
+ target_public_id: "mcp-gallery-archive-" + Date.now(),
67937
+ fully_qualified_public_ids: picks.map(function(r) {
67938
+ return (r.resource_type || "image") + "/" + (r.type || "upload") + "/" + r.public_id;
67939
+ }),
67940
+ };
67989
67941
 
67990
- var aspectBtn = document.getElementById("aspect-btn");
67991
- if (aspectBtn) aspectBtn.classList.toggle("active", aspectFilter !== "");
67942
+ var btn = document.getElementById("bar-download");
67943
+ var origLabel = btn ? btn.innerHTML : "";
67944
+ if (btn) { btn.innerHTML = "Creating archive\\u2026"; btn.disabled = true; }
67992
67945
 
67993
- var anyFilter = filterQuery.length > 0 || aspectFilter !== "";
67994
- var grid = document.getElementById("gallery-grid");
67995
- if (grid) grid.classList.toggle("filtering", anyFilter);
67946
+ try {
67947
+ var res = await app.callServerTool({
67948
+ name: "generate-archive",
67949
+ arguments: {
67950
+ resource_type: "all",
67951
+ RequestBody: requestBody,
67952
+ },
67953
+ });
67996
67954
 
67997
- var visibleCount = 0;
67998
- for (var i = 0; i < allResources.length; i++) {
67999
- var r = allResources[i];
68000
- var card = document.getElementById("card-" + i);
68001
- if (!card) continue;
67955
+ var data = ingestResult(res);
67956
+ if (data && (data._error || data._parseError)) {
67957
+ showError("Archive Failed", unwrapApiError(data._message));
67958
+ return;
67959
+ }
67960
+ var archiveUrl = data && (data.secure_url || data.url);
67961
+ if (!archiveUrl) {
67962
+ showError("Archive Failed", "No delivery URL returned.");
67963
+ return;
67964
+ }
67965
+ try { await copyText(archiveUrl); } catch (e) { /* ignore */ }
67966
+ app._rpc("ui/open-link", { url: archiveUrl });
67967
+ showToast("Archive saved as raw in Cloudinary \\u2014 opening URL (" + picks.length + " asset" + (picks.length > 1 ? "s" : "") + ")");
67968
+ } catch (e) {
67969
+ showError("Archive Failed", unwrapApiError(e && e.message ? e.message : String(e)));
67970
+ } finally {
67971
+ if (btn) { btn.innerHTML = origLabel; btn.disabled = false; }
67972
+ }
67973
+ }
68002
67974
 
68003
- var name = (r.public_id || r.filename || "").toLowerCase();
68004
- var tags = r.tags || [];
68005
- var textMatch = !filterQuery
68006
- || name.indexOf(filterQuery) !== -1
68007
- || tags.some(function(t) { return t.toLowerCase().indexOf(filterQuery) !== -1; });
68008
-
68009
- var aspectMatch = !aspectFilter || getAspect(r) === aspectFilter;
68010
- var match = textMatch && aspectMatch;
68011
- card.style.display = match ? "" : "none";
68012
-
68013
- var tagsEl = document.getElementById("tags-overlay-" + i);
68014
- if (tagsEl && tags.length) {
68015
- var maxOv = 3;
68016
- var matchedTags = [];
68017
- var otherTags = [];
68018
- for (var ti = 0; ti < tags.length; ti++) {
68019
- var isMatch = filterQuery && tags[ti].toLowerCase().indexOf(filterQuery) !== -1;
68020
- if (isMatch) matchedTags.push(tags[ti]);
68021
- else otherTags.push(tags[ti]);
68022
- }
68023
- var shown = matchedTags.slice();
68024
- var remaining = maxOv - shown.length;
68025
- if (remaining > 0) shown = shown.concat(otherTags.slice(0, remaining));
68026
- var hidden = tags.length - shown.length;
68027
- var hiddenTags = tags.filter(function(t) { return shown.indexOf(t) === -1; });
68028
- tagsEl.innerHTML = shown.map(function(t) {
68029
- var matched = filterQuery && t.toLowerCase().indexOf(filterQuery) !== -1;
68030
- return '<span class="tag-overlay' + (matched ? ' tag-match' : '') + '">' + highlightText(t, filterQuery) + '</span>';
68031
- }).join("") + (hidden > 0 ? '<span class="tag-overlay" title="' + esc(hiddenTags.join(", ")) + '">+' + hidden + '</span>' : '');
68032
- }
68033
-
68034
- if (match) visibleCount++;
68035
- }
68036
-
68037
- var badge = document.getElementById("count-badge");
68038
- if (badge) {
68039
- badge.textContent = anyFilter
68040
- ? visibleCount + " of " + allResources.length
68041
- : allResources.length + (lastCursor ? "+" : "") + " items";
68042
- }
68043
-
68044
- var noRes = document.getElementById("no-results");
68045
- if (visibleCount === 0 && anyFilter) {
68046
- if (!noRes && grid) {
68047
- noRes = document.createElement("div");
68048
- noRes.id = "no-results";
68049
- noRes.className = "no-results";
68050
- grid.appendChild(noRes);
68051
- }
68052
- if (noRes) noRes.textContent = "No results" + (filterQuery ? ' for "' + filterQuery + '"' : "") + (aspectFilter ? " in " + aspectFilter + " images" : "");
68053
- } else if (noRes) {
68054
- noRes.remove();
68055
- }
68056
- }
68057
-
68058
- function clearFilter() {
68059
- var input = document.getElementById("filter-input");
68060
- if (input) input.value = "";
68061
- aspectFilter = "";
68062
- var label = document.getElementById("aspect-btn-label");
68063
- if (label) label.textContent = "All orientations";
68064
- document.querySelectorAll(".aspect-option").forEach(function(o) {
68065
- o.classList.toggle("selected", o.getAttribute("data-value") === "");
68066
- });
68067
- handleFilter();
68068
- }
68069
-
68070
- function toggleAspectMenu(e) {
68071
- e.stopPropagation();
68072
- var btn = document.getElementById("aspect-btn");
68073
- var menu = document.getElementById("aspect-menu");
68074
- if (!btn || !menu) return;
68075
- var open = menu.classList.toggle("open");
68076
- btn.classList.toggle("open", open);
68077
- }
68078
-
68079
- function selectAspect(val) {
68080
- aspectFilter = val;
68081
- var labels = { "": "All orientations", landscape: "Landscape", portrait: "Portrait", square: "Square" };
68082
- var label = document.getElementById("aspect-btn-label");
68083
- if (label) label.textContent = labels[aspectFilter] || "All orientations";
68084
- document.querySelectorAll(".aspect-option").forEach(function(o) {
68085
- o.classList.toggle("selected", o.getAttribute("data-value") === aspectFilter);
68086
- });
68087
- var menu = document.getElementById("aspect-menu");
68088
- var btn = document.getElementById("aspect-btn");
68089
- if (menu) menu.classList.remove("open");
68090
- if (btn) btn.classList.remove("open");
68091
- handleFilter();
67975
+ function unwrapApiError(raw) {
67976
+ if (!raw) return "Unknown error.";
67977
+ var msg = String(raw);
67978
+ try {
67979
+ if (msg.charAt(0) === "{") {
67980
+ var parsed = JSON.parse(msg);
67981
+ msg = (parsed && parsed.error && parsed.error.message) || msg;
67982
+ }
67983
+ } catch (e) { /* keep raw */ }
67984
+ return msg;
68092
67985
  }
68093
67986
 
68094
67987
  function render() {
@@ -68108,40 +68001,11 @@ function render() {
68108
68001
  h += '<h1>Results</h1>';
68109
68002
  h += '<span class="count-badge" id="count-badge">' + allResources.length + (lastCursor ? "+" : "") + ' items</span>';
68110
68003
  h += '</div>';
68111
- h += '<div style="display:flex;align-items:center;gap:8px">';
68112
- h += '<button class="select-all-btn" id="select-all-btn">Select all</button>';
68113
- h += '<button class="refresh-btn" id="refresh-gallery" title="Refresh">\\u21BB</button>';
68114
- h += '</div>';
68004
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:8px">';
68005
+ h += '<button class="icon-btn" id="select-all-btn">Select all</button>';
68006
+ h += '<button class="icon-btn icon-only" id="refresh-gallery" title="Refresh">' + IC.refresh + '</button>';
68115
68007
  h += '</div>';
68116
-
68117
- // Filter bar
68118
- h += '<div class="filter-row">';
68119
- h += '<div class="filter-text-wrap">';
68120
- h += '<span class="filter-icon"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="6.5" cy="6.5" r="4.5"/><path d="M10.5 10.5l3 3"/></svg></span>';
68121
- h += '<input class="filter-input" id="filter-input" type="text" placeholder="Filter by filename or tag\\u2026" autocomplete="off" spellcheck="false">';
68122
- h += '<button class="filter-clear" id="filter-clear">\\u2715</button>';
68123
68008
  h += '</div>';
68124
- h += '<div class="aspect-dropdown" id="aspect-dropdown">';
68125
- h += '<button class="aspect-btn" id="aspect-btn">';
68126
- h += '<span id="aspect-btn-label">All orientations</span>';
68127
- h += '<svg class="aspect-btn-chevron" width="11" height="11" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="2,4 6,8 10,4"/></svg>';
68128
- h += '</button>';
68129
- h += '<div class="aspect-menu" id="aspect-menu">';
68130
- var aspects = [
68131
- { val: "", label: "All orientations", icon: '<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="1" y="1" width="12" height="12" rx="1.5"/></svg>' },
68132
- { val: "landscape", label: "Landscape", icon: '<svg width="14" height="10" viewBox="0 0 14 10" fill="none" stroke="currentColor" stroke-width="1.5"><rect x=".75" y=".75" width="12.5" height="8.5" rx="1.5"/></svg>' },
68133
- { val: "portrait", label: "Portrait", icon: '<svg width="10" height="14" viewBox="0 0 10 14" fill="none" stroke="currentColor" stroke-width="1.5"><rect x=".75" y=".75" width="8.5" height="12.5" rx="1.5"/></svg>' },
68134
- { val: "square", label: "Square", icon: '<svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5"><rect x=".75" y=".75" width="10.5" height="10.5" rx="1.5"/></svg>' },
68135
- ];
68136
- for (var ai = 0; ai < aspects.length; ai++) {
68137
- var ao = aspects[ai];
68138
- h += '<div class="aspect-option' + (ao.val === aspectFilter ? ' selected' : '') + '" data-value="' + ao.val + '">';
68139
- h += '<span class="aspect-opt-icon">' + ao.icon + '</span>';
68140
- h += ao.label;
68141
- h += '<svg class="aspect-check" width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="2,6 5,9 10,3"/></svg>';
68142
- h += '</div>';
68143
- }
68144
- h += '</div></div></div>';
68145
68009
 
68146
68010
  // Grid
68147
68011
  h += '<div class="grid" id="gallery-grid">';
@@ -68191,8 +68055,8 @@ function render() {
68191
68055
  if (url) {
68192
68056
  h += '<div class="card-actions">';
68193
68057
  h += '<button class="action-btn act-original" data-copy-original="' + i + '">Copy URL</button>';
68194
- if (rt !== "raw") h += '<button class="action-btn act-optimized" data-copy-optimized="' + i + '">\\u2728 Optimized</button>';
68195
- h += '<button class="action-btn act-download" data-download="' + i + '" title="Download">\\u2193</button>';
68058
+ if (rt !== "raw") h += '<button class="action-btn act-optimized" data-copy-optimized="' + i + '">' + IC.zap + ' Optimized</button>';
68059
+ h += '<button class="action-btn act-download" data-download="' + i + '" title="Download">' + IC.arrowDown + '</button>';
68196
68060
  h += '</div>';
68197
68061
  }
68198
68062
 
@@ -68239,24 +68103,22 @@ function render() {
68239
68103
  h += "</div>";
68240
68104
  }
68241
68105
 
68242
- // Spacer so select bar doesn't cover Load More
68243
- h += '<div class="select-bar-spacer" id="select-bar-spacer" style="display:none"></div>';
68244
-
68245
68106
  // Multi-select bar
68246
68107
  h += '<div class="select-bar" id="select-bar">';
68247
68108
  h += '<span class="select-count" id="select-count">0 selected</span>';
68248
68109
  h += '<div class="bar-divider"></div>';
68249
- h += '<button class="bar-btn bar-primary" id="bar-copy-optimized" style="display:none">\\u2728 Copy Optimized</button>';
68110
+ h += '<button class="bar-btn bar-primary" id="bar-copy-optimized" style="display:none">' + IC.zap + ' Copy Optimized</button>';
68250
68111
  h += '<button class="bar-btn bar-secondary" id="bar-copy-original">Copy Original</button>';
68251
- h += '<button class="bar-btn bar-secondary" id="bar-download">\\u2193 Download All</button>';
68112
+ h += '<button class="bar-btn bar-secondary" id="bar-download">' + IC.arrowDown + ' Download Selected</button>';
68252
68113
  h += '<div class="bar-divider"></div>';
68253
- h += '<button class="bar-btn bar-ghost" id="bar-clear">\\u2715</button>';
68114
+ h += '<button class="bar-btn bar-ghost" id="bar-clear">' + IC.x + '</button>';
68254
68115
  h += '</div>';
68255
68116
 
68256
68117
  // Toast
68257
68118
  h += '<div class="gallery-toast" id="gallery-toast"></div>';
68258
68119
 
68259
68120
  root.innerHTML = h;
68121
+ renderThemeToggle();
68260
68122
 
68261
68123
  // Re-apply selection state
68262
68124
  selected.forEach(function(i) {
@@ -68290,37 +68152,16 @@ function attachEvents() {
68290
68152
  _eventsAttached = true;
68291
68153
  var root = document.getElementById("app");
68292
68154
 
68293
- root.addEventListener("input", function(e) {
68294
- if (e.target && e.target.id === "filter-input") handleFilter();
68295
- });
68296
-
68297
- document.addEventListener("click", function(e) {
68298
- var dd = document.getElementById("aspect-dropdown");
68299
- if (dd && !dd.contains(e.target)) {
68300
- var menu = document.getElementById("aspect-menu");
68301
- var btn = document.getElementById("aspect-btn");
68302
- if (menu) menu.classList.remove("open");
68303
- if (btn) btn.classList.remove("open");
68304
- }
68305
- });
68306
-
68307
68155
  root.addEventListener("click", function(e) {
68308
68156
  var el = e.target;
68309
68157
  while (el && el !== root) {
68310
68158
  if (el.id === "load-more-btn") { loadMore(); return; }
68311
68159
  if (el.id === "refresh-gallery") { refreshGallery(); return; }
68312
68160
  if (el.id === "select-all-btn") { toggleSelectAll(); return; }
68313
- if (el.id === "filter-clear") { clearFilter(); return; }
68314
68161
  if (el.id === "bar-copy-optimized") { copySelectedUrls("optimized"); return; }
68315
68162
  if (el.id === "bar-copy-original") { copySelectedUrls("original"); return; }
68316
68163
  if (el.id === "bar-download") { downloadSelected(); return; }
68317
68164
  if (el.id === "bar-clear") { clearSelection(); return; }
68318
- if (el.id === "aspect-btn" || el.parentElement && el.parentElement.id === "aspect-btn") {
68319
- toggleAspectMenu(e); return;
68320
- }
68321
- if (el.classList && el.classList.contains("aspect-option")) {
68322
- selectAspect(el.getAttribute("data-value") || ""); return;
68323
- }
68324
68165
  if (el.dataset && el.dataset.copyOriginal != null) {
68325
68166
  e.stopPropagation();
68326
68167
  copyAssetUrl("original", parseInt(el.dataset.copyOriginal, 10)); return;
@@ -68481,6 +68322,7 @@ function showFetchPrompt() {
68481
68322
  h += '<button class="prompt-btn prompt-btn-primary" id="fetch-direct-btn">Fetch Directly</button>';
68482
68323
  h += "</div></div>";
68483
68324
  root.innerHTML = h;
68325
+ renderThemeToggle();
68484
68326
  document.getElementById("fetch-direct-btn").addEventListener("click", function() { fetchDirect(); });
68485
68327
  }
68486
68328
 
@@ -68558,7 +68400,6 @@ function refreshGallery() {
68558
68400
  document.addEventListener("keydown", function(e) {
68559
68401
  if (e.key === "Escape") {
68560
68402
  if (document.querySelector(".modal-overlay")) { closeModal(); return; }
68561
- if (filterQuery || aspectFilter) { clearFilter(); return; }
68562
68403
  if (selected.size > 0) { clearSelection(); return; }
68563
68404
  }
68564
68405
  });
@@ -68590,6 +68431,7 @@ ${GALLERY_CSS}
68590
68431
  <div class="gallery-toast" id="gallery-toast"></div>
68591
68432
 
68592
68433
  <script>
68434
+ ${SHARED_JS_ICONS}
68593
68435
  ${SHARED_JS_MCP_CLIENT}
68594
68436
  ${SHARED_JS_HELPERS}
68595
68437
  ${SHARED_JS_TOOLTIPS}
@@ -68643,16 +68485,6 @@ var ASSET_DETAILS_CSS = `
68643
68485
  padding: 2px 7px; border-radius: 4px; border: 1px solid var(--cld-border);
68644
68486
  }
68645
68487
 
68646
- .open-link {
68647
- padding: 6px 14px; border-radius: var(--cld-radius-sm);
68648
- font-size: 12px; font-weight: 500; cursor: pointer;
68649
- border: 1px solid var(--cld-accent); background: transparent;
68650
- color: var(--cld-accent); font-family: inherit;
68651
- transition: background 0.15s;
68652
- white-space: nowrap; flex-shrink: 0;
68653
- }
68654
- .open-link:hover { background: var(--cld-accent-bg); }
68655
-
68656
68488
  .hero-container {
68657
68489
  position: relative; margin-bottom: var(--cld-sp-md);
68658
68490
  border-radius: var(--cld-radius); overflow: hidden;
@@ -68713,9 +68545,9 @@ function renderPage(r) {
68713
68545
  if (dur) h += '<span class="pill">' + dur + "</span>";
68714
68546
  if (size) h += '<span class="pill">' + size + "</span>";
68715
68547
  h += "</div></div>";
68716
- h += '<div style="display:flex;gap:6px;flex-shrink:0">';
68717
- h += '<button class="open-link" id="refresh-asset" title="Refresh">\\u21BB</button>';
68718
- if (url) h += '<button class="open-link" id="open-asset">Open</button>';
68548
+ h += '<div id="header-actions" style="display:flex;gap:8px;flex-shrink:0;align-items:center">';
68549
+ if (url) h += '<button class="icon-btn" id="open-asset">Open</button>';
68550
+ h += '<button class="icon-btn icon-only" id="refresh-asset" title="Refresh">' + IC.refresh + '</button>';
68719
68551
  h += "</div>";
68720
68552
  h += "</div>";
68721
68553
 
@@ -68757,6 +68589,7 @@ function renderPage(r) {
68757
68589
  h += "</div>";
68758
68590
 
68759
68591
  root.innerHTML = h;
68592
+ renderThemeToggle();
68760
68593
 
68761
68594
  // Event delegation
68762
68595
  root.addEventListener("click", function handler(e) {
@@ -68802,6 +68635,7 @@ function showFetchPrompt() {
68802
68635
  h += '<button class="prompt-btn prompt-btn-primary" id="fetch-direct-btn">Fetch Directly</button>';
68803
68636
  h += "</div></div>";
68804
68637
  root.innerHTML = h;
68638
+ renderThemeToggle();
68805
68639
  document.getElementById("fetch-direct-btn").addEventListener("click", function() { fetchDirect(); });
68806
68640
  }
68807
68641
 
@@ -68883,6 +68717,7 @@ ${ASSET_DETAILS_CSS}
68883
68717
  <div id="app"><div class="status">Loading asset details&hellip;</div></div>
68884
68718
 
68885
68719
  <script>
68720
+ ${SHARED_JS_ICONS}
68886
68721
  ${SHARED_JS_MCP_CLIENT}
68887
68722
  ${SHARED_JS_HELPERS}
68888
68723
  ${SHARED_JS_TOOLTIPS}
@@ -69122,15 +68957,8 @@ var uploadJsonSchema, rtJsonSchema, allSchemaProperties, rtCopy, SCHEMA_JSON, UP
69122
68957
  .upload-header h1 {
69123
68958
  font-size: var(--cld-font-sm); font-weight: 600; color: var(--cld-text);
69124
68959
  }
69125
- .upload-header-icon { font-size: 20px; }
69126
- .upload-header { position: relative; }
69127
- .back-link {
69128
- position: absolute; top: -2px; right: 0;
69129
- background: none; border: none; cursor: pointer;
69130
- color: var(--cld-accent); font-size: var(--cld-font-xs);
69131
- padding: 2px 6px; border-radius: 4px;
69132
- }
69133
- .back-link:hover { text-decoration: underline; background: var(--cld-accent-bg); }
68960
+ .upload-header-icon { display: flex; align-items: center; justify-content: center; }
68961
+ .upload-header-icon svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
69134
68962
 
69135
68963
  .upload-result .detail-section { padding: 14px 16px; }
69136
68964
  .upload-result .detail-section:first-child { padding-top: 0; }
@@ -69581,16 +69409,18 @@ function renderPicker() {
69581
69409
  var h = "";
69582
69410
 
69583
69411
  h += '<div class="upload-header">';
69412
+ h += '<span class="upload-header-icon icon-accent">' + IC.uploadCloud + '</span>';
69413
+ h += "<h1>Upload to Cloudinary</h1>";
69414
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto">';
69584
69415
  if (lastResult) {
69585
- h += '<button class="back-link" id="back-to-result-btn">\\u2190 Back to Result</button>';
69416
+ h += '<button class="icon-btn" id="back-to-result-btn">' + IC.chevronLeft + ' Back</button>';
69586
69417
  }
69587
- h += '<span class="upload-header-icon">\\u2B06\\uFE0F</span>';
69588
- h += "<h1>Upload to Cloudinary</h1>";
69418
+ h += '</div>';
69589
69419
  h += "</div>";
69590
69420
 
69591
69421
  if (stagedFile) {
69592
69422
  h += '<div class="upload-staged">';
69593
- h += '<div class="upload-staged-icon">\\u{1F4C4}</div>';
69423
+ h += '<div class="upload-staged-icon">' + IC.file + '</div>';
69594
69424
  h += '<div class="upload-staged-info">';
69595
69425
  h += '<div class="upload-staged-name">' + esc(stagedFile.name) + "</div>";
69596
69426
  if (stagedFile.size) {
@@ -69601,11 +69431,11 @@ function renderPicker() {
69601
69431
  h += '<div class="upload-staged-meta">Remote URL</div>';
69602
69432
  }
69603
69433
  h += "</div>";
69604
- h += '<button class="upload-staged-clear" id="clear-staged-btn" title="Remove">\\u2715</button>';
69434
+ h += '<button class="upload-staged-clear icon-btn icon-only" id="clear-staged-btn" title="Remove">' + IC.x + '</button>';
69605
69435
  h += "</div>";
69606
69436
  } else {
69607
69437
  h += '<div class="upload-zone" id="drop-zone">';
69608
- h += '<div class="upload-zone-icon">\\u{1F4C1}</div>';
69438
+ h += '<div class="upload-zone-icon">' + IC.folderOpen + '</div>';
69609
69439
  h += '<div class="upload-zone-text">Drag & drop a file here</div>';
69610
69440
  h += '<div class="upload-zone-hint">Images, videos, PDFs, and other files up to 60 MB</div>';
69611
69441
  h += '<button class="upload-zone-btn" id="browse-btn">Browse Files</button>';
@@ -69629,6 +69459,7 @@ function renderPicker() {
69629
69459
  }
69630
69460
 
69631
69461
  root.innerHTML = h;
69462
+ renderThemeToggle();
69632
69463
 
69633
69464
  var backBtn = document.getElementById("back-to-result-btn");
69634
69465
  if (backBtn && lastResult) {
@@ -69708,12 +69539,13 @@ function renderUploading(name, meta) {
69708
69539
  var h = "";
69709
69540
 
69710
69541
  h += '<div class="upload-header">';
69711
- h += '<span class="upload-header-icon">\\u2B06\\uFE0F</span>';
69712
- h += "<h1>Uploading\\u2026</h1>";
69542
+ h += '<span class="upload-header-icon icon-accent">' + IC.uploadCloud + '</span>';
69543
+ h += '<h1>Uploading…</h1>';
69544
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto"></div>';
69713
69545
  h += "</div>";
69714
69546
 
69715
69547
  h += '<div class="upload-preview">';
69716
- h += '<div class="upload-preview-icon">\\u{1F4C4}</div>';
69548
+ h += '<div class="upload-preview-icon">' + IC.file + '</div>';
69717
69549
  h += '<div class="upload-preview-info">';
69718
69550
  h += '<div class="upload-preview-name">' + esc(name) + "</div>";
69719
69551
  h += '<div class="upload-preview-meta">' + esc(meta) + "</div>";
@@ -69725,6 +69557,7 @@ function renderUploading(name, meta) {
69725
69557
  h += "</div>";
69726
69558
 
69727
69559
  root.innerHTML = h;
69560
+ renderThemeToggle();
69728
69561
  animateProgress();
69729
69562
  }
69730
69563
 
@@ -69778,7 +69611,7 @@ function renderUploadError(title, msg) {
69778
69611
  var header = document.querySelector(".upload-header h1");
69779
69612
  if (header) header.textContent = title;
69780
69613
  var icon = document.querySelector(".upload-header-icon");
69781
- if (icon) icon.textContent = "\\u26A0\\uFE0F";
69614
+ if (icon) { icon.innerHTML = IC.alertTriangle; icon.className = "upload-header-icon icon-warning"; }
69782
69615
 
69783
69616
  var safeMsg = esc(msg).replace(/\\n/g, "<br>");
69784
69617
  var h = '<div class="upload-error-msg">' + safeMsg + "</div>";
@@ -69790,14 +69623,16 @@ function renderUploadError(title, msg) {
69790
69623
  var root = document.getElementById("app");
69791
69624
  var safeMsg = esc(msg).replace(/\\n/g, "<br>");
69792
69625
  var h = '<div class="upload-header">';
69793
- h += '<span class="upload-header-icon">\\u26A0\\uFE0F</span>';
69626
+ h += '<span class="upload-header-icon icon-warning">' + IC.alertTriangle + '</span>';
69794
69627
  h += "<h1>" + esc(title) + "</h1>";
69628
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto"></div>';
69795
69629
  h += "</div>";
69796
69630
  h += '<div class="upload-error-msg">' + safeMsg + "</div>";
69797
69631
  h += '<div class="upload-another" style="margin-top:14px;text-align:center">';
69798
69632
  h += '<button class="prompt-btn prompt-btn-primary" id="retry-upload-btn">Try from App</button>';
69799
69633
  h += "</div>";
69800
69634
  root.innerHTML = h;
69635
+ renderThemeToggle();
69801
69636
  }
69802
69637
 
69803
69638
  var btn = document.getElementById("retry-upload-btn");
@@ -69842,8 +69677,9 @@ function renderLocalFileNeeded(expectedName, errMsg) {
69842
69677
  var classified = classifyFileError(errMsg);
69843
69678
  var root = document.getElementById("app");
69844
69679
  var h = '<div class="upload-header">';
69845
- h += '<span class="upload-header-icon">\\u{1F4C1}</span>';
69680
+ h += '<span class="upload-header-icon icon-accent">' + IC.folderOpen + '</span>';
69846
69681
  h += "<h1>" + esc(classified.title) + "</h1>";
69682
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto"></div>';
69847
69683
  h += "</div>";
69848
69684
  h += '<div class="prompt" style="margin-bottom:16px">';
69849
69685
  h += '<div class="prompt-desc">The file <strong>' + esc(expectedName)
@@ -69858,13 +69694,14 @@ function renderLocalFileNeeded(expectedName, errMsg) {
69858
69694
  }
69859
69695
  h += "</div>";
69860
69696
  h += '<div class="upload-zone" id="drop-zone">';
69861
- h += '<div class="upload-zone-icon">\\u{1F4C1}</div>';
69697
+ h += '<div class="upload-zone-icon">' + IC.folderOpen + '</div>';
69862
69698
  h += '<div class="upload-zone-text">Drop <strong>' + esc(expectedName) + "</strong> here</div>";
69863
69699
  h += '<div class="upload-zone-hint">Or click to browse your files</div>';
69864
69700
  h += '<button class="upload-zone-btn" id="browse-btn">Browse Files</button>';
69865
69701
  h += '<input type="file" id="file-input" style="display:none">';
69866
69702
  h += "</div>";
69867
69703
  root.innerHTML = h;
69704
+ renderThemeToggle();
69868
69705
 
69869
69706
  function onFileSelected(file) {
69870
69707
  var reader = new FileReader();
@@ -69977,8 +69814,9 @@ function renderResult(r) {
69977
69814
  var h = "";
69978
69815
 
69979
69816
  h += '<div class="upload-header">';
69980
- h += '<span class="upload-header-icon">' + (isPending ? "\\u23F3" : "\\u2705") + '</span>';
69817
+ h += '<span class="upload-header-icon ' + (isPending ? "icon-accent" : "icon-success") + '">' + (isPending ? IC.clock : IC.checkCircle) + '</span>';
69981
69818
  h += "<h1>" + (isPending ? "Upload Queued" : "Upload Complete") + "</h1>";
69819
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto"></div>';
69982
69820
  h += "</div>";
69983
69821
 
69984
69822
  h += '<div class="upload-result">';
@@ -70039,6 +69877,7 @@ function renderResult(r) {
70039
69877
  h += "</div></div>";
70040
69878
 
70041
69879
  root.innerHTML = h;
69880
+ renderThemeToggle();
70042
69881
 
70043
69882
  root.addEventListener("click", function handler(e) {
70044
69883
  var el = e.target;
@@ -70173,6 +70012,7 @@ ${UPLOAD_CSS}
70173
70012
  <div id="app"><div class="status">Preparing upload&hellip;</div></div>
70174
70013
 
70175
70014
  <script>
70015
+ ${SHARED_JS_ICONS}
70176
70016
  ${SHARED_JS_MCP_CLIENT}
70177
70017
  ${SHARED_JS_HELPERS}
70178
70018
  ${SHARED_JS_TOOLTIPS}
@@ -70192,7 +70032,12 @@ function appResourceContent(uri, html) {
70192
70032
  uri: uri.toString(),
70193
70033
  mimeType: MCP_APP_MIME_TYPE,
70194
70034
  text: html,
70195
- _meta: { ui: { csp: { resourceDomains: CSP_RESOURCE_DOMAINS } } }
70035
+ _meta: {
70036
+ ui: {
70037
+ csp: { resourceDomains: CSP_RESOURCE_DOMAINS },
70038
+ permissions: { clipboardWrite: {} }
70039
+ }
70040
+ }
70196
70041
  }]
70197
70042
  };
70198
70043
  }
@@ -74103,7 +73948,7 @@ A report on the status of product environment usage, including storage, credits,
74103
73948
  function createMCPServer(deps) {
74104
73949
  const server = new McpServer({
74105
73950
  name: "CloudinaryAssetMgmt",
74106
- version: "0.9.1"
73951
+ version: "0.9.2"
74107
73952
  });
74108
73953
  const getClient = deps.getSDK || (() => new CloudinaryAssetMgmtCore({
74109
73954
  security: deps.security,
@@ -74376,8 +74221,13 @@ This tool creates actual derived assets on Cloudinary using the explicit API.`
74376
74221
 
74377
74222
  // src/landing-page.ts
74378
74223
  function landingPageExpress(req, res) {
74379
- const origin = new URL(req.host).href;
74380
- res.type("html").send(landingPageHTML(origin));
74224
+ const proto = req.get("x-forwarded-proto")?.split(",")[0]?.trim() || req.protocol;
74225
+ const host = req.get("host");
74226
+ if (!host) {
74227
+ res.status(400).send("Missing Host header");
74228
+ return;
74229
+ }
74230
+ res.type("html").send(landingPageHTML(`${proto}://${host}`));
74381
74231
  }
74382
74232
  function landingPageHTML(origin) {
74383
74233
  const o = origin;
@@ -75280,7 +75130,7 @@ http_headers = { "api-key" = "YOUR_API_KEY", "api-secret" = "YOUR_API_SECRET", "
75280
75130
  <h1>Instructions</h1>
75281
75131
  <p>One-click installation for Claude Desktop users</p>
75282
75132
  <div class="instruction-item">
75283
- <a href="https://github.com/cloudinary/asset-management-mcp/releases/download/v0.9.1/mcp-server.mcpb" download="mcp-server.mcpb" class="action-button header-action" style="display: inline-flex; margin-bottom: 16px;">
75133
+ <a href="https://github.com/cloudinary/asset-management-mcp/releases/download/v0.9.2/mcp-server.mcpb" download="mcp-server.mcpb" class="action-button header-action" style="display: inline-flex; margin-bottom: 16px;">
75284
75134
  \uD83D\uDCE5 Download MCP Bundle
75285
75135
  </a>
75286
75136
  </div>
@@ -75442,7 +75292,7 @@ async function startStreamableHTTP(cliFlags) {
75442
75292
  app.use((req, res, next) => {
75443
75293
  res.header("Access-Control-Allow-Origin", "*");
75444
75294
  res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
75445
- res.header("Access-Control-Allow-Headers", "Content-Type, *");
75295
+ res.header("Access-Control-Allow-Headers", "*");
75446
75296
  if (req.method === "OPTIONS") {
75447
75297
  res.sendStatus(204);
75448
75298
  return;
@@ -77224,7 +77074,7 @@ var routes = ln({
77224
77074
  var app = _e(routes, {
77225
77075
  name: "mcp",
77226
77076
  versionInfo: {
77227
- currentVersion: "0.9.1"
77077
+ currentVersion: "0.9.2"
77228
77078
  }
77229
77079
  });
77230
77080
  Yt(app, process4.argv.slice(2), buildContext(process4));
@@ -77232,5 +77082,5 @@ export {
77232
77082
  app
77233
77083
  };
77234
77084
 
77235
- //# debugId=92BB3EDCF4CED14664756E2164756E21
77085
+ //# debugId=80B49656B4FCF52064756E2164756E21
77236
77086
  //# sourceMappingURL=mcp-server.js.map