claude-code-marketplace 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/app.js +53 -2
- package/public/style.css +33 -0
- package/server.js +18 -5
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -123,6 +123,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
123
123
|
updateThemeColor(savedTheme !== 'dark');
|
|
124
124
|
|
|
125
125
|
document.addEventListener('keydown', handleKeydown);
|
|
126
|
+
|
|
127
|
+
document.getElementById('treeContainer').addEventListener('click', (e) => {
|
|
128
|
+
const row = e.target.closest('.tree-row');
|
|
129
|
+
if (!row?.dataset.rowId) return;
|
|
130
|
+
const rowId = row.dataset.rowId;
|
|
131
|
+
const rows = getVisibleRows();
|
|
132
|
+
const idx = rows.findIndex((r) => r.dataset.rowId === rowId);
|
|
133
|
+
if (idx >= 0) setFocusedRow(idx, rows);
|
|
134
|
+
});
|
|
126
135
|
});
|
|
127
136
|
|
|
128
137
|
function syncHljsTheme() {
|
|
@@ -467,6 +476,7 @@ async function showDetail(pluginId) {
|
|
|
467
476
|
<div class="detail-section">
|
|
468
477
|
<p class="detail-desc">${esc(plugin.description || 'No description')}</p>
|
|
469
478
|
${metaRow}
|
|
479
|
+
${renderPluginMetadata(plugin)}
|
|
470
480
|
</div>
|
|
471
481
|
${scopeSection}
|
|
472
482
|
<div class="detail-section">
|
|
@@ -515,6 +525,42 @@ function renderScopeMatrix(plugin) {
|
|
|
515
525
|
.join('')}</div>`;
|
|
516
526
|
}
|
|
517
527
|
|
|
528
|
+
function shortUrl(url) {
|
|
529
|
+
return url
|
|
530
|
+
.replace(/^https?:\/\/(www\.)?/, '')
|
|
531
|
+
.replace(/\.git$/, '')
|
|
532
|
+
.replace(/\/$/, '');
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function renderPluginMetadata(plugin) {
|
|
536
|
+
const meta = plugin.metadata || {};
|
|
537
|
+
const chips = [];
|
|
538
|
+
if (meta.category) chips.push(`<span class="meta-tag">${esc(meta.category)}</span>`);
|
|
539
|
+
if (meta.author) {
|
|
540
|
+
const name = typeof meta.author === 'object' ? meta.author.name : meta.author;
|
|
541
|
+
if (name) chips.push(`<span class="meta-chip">${esc(name)}</span>`);
|
|
542
|
+
}
|
|
543
|
+
if (meta.tags?.length) {
|
|
544
|
+
for (const t of meta.tags) chips.push(`<span class="meta-tag">${esc(t)}</span>`);
|
|
545
|
+
}
|
|
546
|
+
const links = [];
|
|
547
|
+
if (meta.homepage) {
|
|
548
|
+
links.push(
|
|
549
|
+
`<a class="meta-link" href="${esc(meta.homepage)}" target="_blank" rel="noopener">${esc(shortUrl(meta.homepage))}</a>`,
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
if (plugin.source && typeof plugin.source === 'string' && plugin.source.startsWith('http')) {
|
|
553
|
+
const href = plugin.source.replace(/\.git$/, '');
|
|
554
|
+
if (!meta.homepage || !plugin.source.includes(meta.homepage)) {
|
|
555
|
+
links.push(
|
|
556
|
+
`<a class="meta-link" href="${esc(href)}" target="_blank" rel="noopener">${esc(shortUrl(plugin.source))}</a>`,
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
if (!chips.length && !links.length) return '';
|
|
561
|
+
return `<div class="plugin-meta-bar">${chips.join('')}${links.join('')}</div>`;
|
|
562
|
+
}
|
|
563
|
+
|
|
518
564
|
function renderDetailComponents(pluginId, comps, hasDirAccess) {
|
|
519
565
|
const configFiles = comps._configFiles || {};
|
|
520
566
|
const entries = Object.entries(comps).filter(
|
|
@@ -1016,7 +1062,11 @@ function filterPlugins(plugins) {
|
|
|
1016
1062
|
}
|
|
1017
1063
|
if (searchFilter) {
|
|
1018
1064
|
result = result.filter(
|
|
1019
|
-
(p) =>
|
|
1065
|
+
(p) =>
|
|
1066
|
+
p.name.toLowerCase().includes(searchFilter) ||
|
|
1067
|
+
(p.description || '').toLowerCase().includes(searchFilter) ||
|
|
1068
|
+
(p.metadata?.category || '').toLowerCase().includes(searchFilter) ||
|
|
1069
|
+
(p.metadata?.tags || []).some((t) => t.toLowerCase().includes(searchFilter)),
|
|
1020
1070
|
);
|
|
1021
1071
|
}
|
|
1022
1072
|
return result;
|
|
@@ -1157,7 +1207,8 @@ function handleKeydown(e) {
|
|
|
1157
1207
|
}
|
|
1158
1208
|
return;
|
|
1159
1209
|
}
|
|
1160
|
-
if ((tag === 'BUTTON' || tag === 'A') && (e.key === 'Enter' || e.key === ' '))
|
|
1210
|
+
if ((tag === 'BUTTON' || tag === 'A') && (e.key === 'Enter' || e.key === ' ') && !e.target.closest('#treeContainer'))
|
|
1211
|
+
return;
|
|
1161
1212
|
|
|
1162
1213
|
const openModal = document.querySelector('.modal-overlay.open');
|
|
1163
1214
|
if (openModal) {
|
package/public/style.css
CHANGED
|
@@ -781,6 +781,39 @@ body.light .scope-toggle.local {
|
|
|
781
781
|
letter-spacing: 0.03em;
|
|
782
782
|
}
|
|
783
783
|
|
|
784
|
+
.plugin-meta-bar {
|
|
785
|
+
display: flex;
|
|
786
|
+
align-items: center;
|
|
787
|
+
gap: 6px;
|
|
788
|
+
flex-wrap: wrap;
|
|
789
|
+
margin-top: 8px;
|
|
790
|
+
}
|
|
791
|
+
.meta-tag {
|
|
792
|
+
font-size: 9px;
|
|
793
|
+
padding: 2px 8px;
|
|
794
|
+
border-radius: 10px;
|
|
795
|
+
border: 1px solid var(--border);
|
|
796
|
+
color: var(--text-muted);
|
|
797
|
+
letter-spacing: 0.02em;
|
|
798
|
+
}
|
|
799
|
+
.meta-chip {
|
|
800
|
+
font-size: 10px;
|
|
801
|
+
color: var(--text-muted);
|
|
802
|
+
}
|
|
803
|
+
.meta-link {
|
|
804
|
+
font-size: 10px;
|
|
805
|
+
color: var(--text-muted);
|
|
806
|
+
text-decoration: none;
|
|
807
|
+
overflow: hidden;
|
|
808
|
+
text-overflow: ellipsis;
|
|
809
|
+
white-space: nowrap;
|
|
810
|
+
max-width: 260px;
|
|
811
|
+
}
|
|
812
|
+
.meta-link:hover {
|
|
813
|
+
color: var(--accent);
|
|
814
|
+
text-decoration: underline;
|
|
815
|
+
}
|
|
816
|
+
|
|
784
817
|
/* === SCOPE MATRIX === */
|
|
785
818
|
|
|
786
819
|
.scope-matrix {
|
package/server.js
CHANGED
|
@@ -218,11 +218,22 @@ function loadMarketplaces() {
|
|
|
218
218
|
const srcDir = path.resolve(installLocation, rawSource);
|
|
219
219
|
if (fs.existsSync(srcDir)) originDir = srcDir;
|
|
220
220
|
}
|
|
221
|
+
if (!originDir && typeof rawSource === 'object' && rawSource?.path) {
|
|
222
|
+
const srcDir = path.resolve(installLocation, rawSource.path);
|
|
223
|
+
if (fs.existsSync(srcDir)) originDir = srcDir;
|
|
224
|
+
}
|
|
221
225
|
if (!originDir) {
|
|
222
226
|
const pluginSubdir = path.join(installLocation, 'plugins', pd.name);
|
|
223
227
|
if (fs.existsSync(pluginSubdir)) originDir = pluginSubdir;
|
|
224
228
|
else if ((mData.plugins || []).length === 1) originDir = installLocation;
|
|
225
229
|
}
|
|
230
|
+
if (!originDir) {
|
|
231
|
+
const cacheDir = path.join(PLUGINS_DIR, 'cache', name, pd.name);
|
|
232
|
+
if (fs.existsSync(cacheDir)) {
|
|
233
|
+
const latest = findLatestVersionDir(cacheDir);
|
|
234
|
+
if (latest) originDir = latest;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
226
237
|
}
|
|
227
238
|
|
|
228
239
|
// Resolve plugin dir for filesystem-based component counts
|
|
@@ -250,11 +261,13 @@ function loadMarketplaces() {
|
|
|
250
261
|
.find(d => d?.version && d.version !== 'unknown')?.version || null;
|
|
251
262
|
|
|
252
263
|
let availableVersion = pd.version || null;
|
|
253
|
-
if (!availableVersion
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
264
|
+
if (!availableVersion) {
|
|
265
|
+
const versionDir = pluginDir || originDir;
|
|
266
|
+
if (versionDir) {
|
|
267
|
+
const pluginJson = path.join(versionDir, '.claude-plugin', 'plugin.json');
|
|
268
|
+
const pjData = readJsonSafe(pluginJson);
|
|
269
|
+
if (pjData?.version) availableVersion = pjData.version;
|
|
270
|
+
}
|
|
258
271
|
}
|
|
259
272
|
const hasUpdate = isInstalled && semverNewer(availableVersion, installedVersion);
|
|
260
273
|
|