claude-code-marketplace 0.4.3 → 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 +42 -1
- package/public/style.css +33 -0
- package/server.js +18 -5
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -476,6 +476,7 @@ async function showDetail(pluginId) {
|
|
|
476
476
|
<div class="detail-section">
|
|
477
477
|
<p class="detail-desc">${esc(plugin.description || 'No description')}</p>
|
|
478
478
|
${metaRow}
|
|
479
|
+
${renderPluginMetadata(plugin)}
|
|
479
480
|
</div>
|
|
480
481
|
${scopeSection}
|
|
481
482
|
<div class="detail-section">
|
|
@@ -524,6 +525,42 @@ function renderScopeMatrix(plugin) {
|
|
|
524
525
|
.join('')}</div>`;
|
|
525
526
|
}
|
|
526
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
|
+
|
|
527
564
|
function renderDetailComponents(pluginId, comps, hasDirAccess) {
|
|
528
565
|
const configFiles = comps._configFiles || {};
|
|
529
566
|
const entries = Object.entries(comps).filter(
|
|
@@ -1025,7 +1062,11 @@ function filterPlugins(plugins) {
|
|
|
1025
1062
|
}
|
|
1026
1063
|
if (searchFilter) {
|
|
1027
1064
|
result = result.filter(
|
|
1028
|
-
(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)),
|
|
1029
1070
|
);
|
|
1030
1071
|
}
|
|
1031
1072
|
return result;
|
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
|
|