claude-code-marketplace 0.6.0 → 0.7.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 +62 -8
- package/public/index.html +2 -0
- package/public/style.css +29 -20
- package/server.js +24 -1
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -48,11 +48,14 @@ ICONS.readme = SVG(
|
|
|
48
48
|
);
|
|
49
49
|
ICONS.settings = ICONS.gear;
|
|
50
50
|
ICONS.claudeMd = ICONS.readme;
|
|
51
|
+
ICONS.agentsMd = ICONS.readme;
|
|
52
|
+
ICONS.agentSkills = ICONS.skills;
|
|
51
53
|
ICONS.openEditor =
|
|
52
54
|
'<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M17.583 2.207a1.1 1.1 0 0 1 1.541.033l2.636 2.636a1.1 1.1 0 0 1 .033 1.541L10.68 17.53a1.1 1.1 0 0 1-.345.247l-4.56 1.903a.55.55 0 0 1-.725-.725l1.903-4.56a1.1 1.1 0 0 1 .247-.345zm.902 1.87-8.794 8.793-.946 2.268 2.268-.946 8.794-8.793z"/></svg>';
|
|
53
55
|
ICONS.copyPath =
|
|
54
56
|
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
|
|
55
|
-
const
|
|
57
|
+
const COMP_DIR_MAP = { skills: 'skills', commands: 'commands', agents: 'agents', agentSkills: '~agents' };
|
|
58
|
+
const COMP_HAS_DIR = new Set(Object.keys(COMP_DIR_MAP));
|
|
56
59
|
const COMP_LABELS = {
|
|
57
60
|
skills: 'Skills',
|
|
58
61
|
commands: 'Commands',
|
|
@@ -62,10 +65,13 @@ const COMP_LABELS = {
|
|
|
62
65
|
lspServers: 'LSP Servers',
|
|
63
66
|
settings: 'Settings',
|
|
64
67
|
claudeMd: 'CLAUDE.md',
|
|
68
|
+
agentsMd: 'AGENTS.md',
|
|
69
|
+
agentSkills: 'Agent Skills (not-supported)',
|
|
65
70
|
readme: 'README',
|
|
66
71
|
};
|
|
67
72
|
|
|
68
73
|
const VIRTUAL_ROOT_PREFIX = '~root/';
|
|
74
|
+
const VIRTUAL_AGENTS_PREFIX = '~agents/';
|
|
69
75
|
|
|
70
76
|
function encodePathSegments(p) {
|
|
71
77
|
return p.split('/').map(encodeURIComponent).join('/');
|
|
@@ -81,6 +87,12 @@ function claudeMdLabel(name, count) {
|
|
|
81
87
|
return count > 1 ? 'CLAUDE.md (.claude/)' : name;
|
|
82
88
|
}
|
|
83
89
|
|
|
90
|
+
function compItemLabel(type, name, count) {
|
|
91
|
+
if (type === 'claudeMd') return claudeMdLabel(name, count);
|
|
92
|
+
if (type === 'agentsMd' && name.startsWith(VIRTUAL_ROOT_PREFIX)) return name.slice(VIRTUAL_ROOT_PREFIX.length);
|
|
93
|
+
return name;
|
|
94
|
+
}
|
|
95
|
+
|
|
84
96
|
function updateArrow(p) {
|
|
85
97
|
if (!p.hasUpdate) return '';
|
|
86
98
|
const title =
|
|
@@ -203,7 +215,12 @@ async function loadData() {
|
|
|
203
215
|
}
|
|
204
216
|
|
|
205
217
|
renderTree();
|
|
206
|
-
if (selectedPluginId)
|
|
218
|
+
if (selectedPluginId) {
|
|
219
|
+
showDetail(selectedPluginId);
|
|
220
|
+
} else {
|
|
221
|
+
const userCustom = marketplaces.flatMap((m) => m.plugins).find((p) => p.fullId === '_custom/user');
|
|
222
|
+
if (userCustom) showDetail('_custom/user');
|
|
223
|
+
}
|
|
207
224
|
|
|
208
225
|
// Prefetch components for all plugins in background
|
|
209
226
|
for (const m of marketplaces) {
|
|
@@ -603,7 +620,8 @@ function renderDetailComponents(pluginId, comps, hasDirAccess) {
|
|
|
603
620
|
.map(([type, items]) => {
|
|
604
621
|
const names = Array.isArray(items) ? items : [];
|
|
605
622
|
const count = names.length || items;
|
|
606
|
-
|
|
623
|
+
const groupCls = type === 'agentSkills' || type === 'agentsMd' ? ' view-only' : '';
|
|
624
|
+
let html = `<div class="detail-comp-group${groupCls}">
|
|
607
625
|
<div class="detail-comp-header">
|
|
608
626
|
<span class="comp-icon">${ICONS[type] || ''}</span>
|
|
609
627
|
${COMP_LABELS[type] || type}
|
|
@@ -612,7 +630,7 @@ function renderDetailComponents(pluginId, comps, hasDirAccess) {
|
|
|
612
630
|
|
|
613
631
|
if (names.length) {
|
|
614
632
|
const configFile = configFiles[type];
|
|
615
|
-
const dir =
|
|
633
|
+
const dir = COMP_DIR_MAP[type] || null;
|
|
616
634
|
html += '<div class="detail-comp-items">';
|
|
617
635
|
for (const name of names) {
|
|
618
636
|
const clickPath = configFile || (dir ? `${dir}/${name}` : name);
|
|
@@ -620,9 +638,10 @@ function renderDetailComponents(pluginId, comps, hasDirAccess) {
|
|
|
620
638
|
const click = hasDirAccess
|
|
621
639
|
? ` onclick="openContentModal('${escJs(pluginId)}', '${escJs(clickPath)}', '${escJs(type)}')"`
|
|
622
640
|
: '';
|
|
641
|
+
const isFolder = type === 'skills' || type === 'agentSkills';
|
|
623
642
|
html += `<div class="detail-comp-item${cls}"${click}>
|
|
624
|
-
<span class="icon">${
|
|
625
|
-
${esc(type
|
|
643
|
+
<span class="icon">${isFolder ? ICONS.folder : ICONS.file}</span>
|
|
644
|
+
${esc(compItemLabel(type, name, names.length))}
|
|
626
645
|
</div>`;
|
|
627
646
|
}
|
|
628
647
|
html += '</div>';
|
|
@@ -732,10 +751,12 @@ async function copyToClipboard(text, btn) {
|
|
|
732
751
|
async function copyContentPath(event) {
|
|
733
752
|
if (!_contentPluginDir) return;
|
|
734
753
|
const relativePath = getContentRelativePath();
|
|
754
|
+
const parentDir = _contentPluginDir.replace(/\/[^/]+\/?$/, '');
|
|
735
755
|
let full;
|
|
736
756
|
if (relativePath.startsWith(VIRTUAL_ROOT_PREFIX)) {
|
|
737
|
-
const parentDir = _contentPluginDir.replace(/\/[^/]+\/?$/, '');
|
|
738
757
|
full = `${parentDir}/${relativePath.slice(VIRTUAL_ROOT_PREFIX.length)}`;
|
|
758
|
+
} else if (relativePath.startsWith(VIRTUAL_AGENTS_PREFIX)) {
|
|
759
|
+
full = `${parentDir}/.agents/skills/${relativePath.slice(VIRTUAL_AGENTS_PREFIX.length)}`;
|
|
739
760
|
} else {
|
|
740
761
|
full = relativePath ? `${_contentPluginDir}/${relativePath}` : _contentPluginDir;
|
|
741
762
|
}
|
|
@@ -798,6 +819,15 @@ async function loadContentTree(pluginId, treePath, container, depth, autoSelect)
|
|
|
798
819
|
const data = await res.json();
|
|
799
820
|
|
|
800
821
|
if (data.type === 'directory') {
|
|
822
|
+
if (!data.entries.length) {
|
|
823
|
+
container.innerHTML =
|
|
824
|
+
'<div style="color:var(--text-dim);font-size:11px;padding:8px 12px">(empty directory)</div>';
|
|
825
|
+
if (autoSelect) {
|
|
826
|
+
const codeEl = getContentCodeEl();
|
|
827
|
+
codeEl.innerHTML = '<span style="color:var(--text-dim)">No files in this directory</span>';
|
|
828
|
+
}
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
801
831
|
let firstFile = null;
|
|
802
832
|
let preferredFile = null;
|
|
803
833
|
for (const entry of data.entries) {
|
|
@@ -843,7 +873,11 @@ async function loadContentTree(pluginId, treePath, container, depth, autoSelect)
|
|
|
843
873
|
async function loadContentFile(pluginId, filePath) {
|
|
844
874
|
const codeEl = getContentCodeEl();
|
|
845
875
|
const pathEl = document.getElementById('contentViewerPath');
|
|
846
|
-
pathEl.textContent = filePath.startsWith(VIRTUAL_ROOT_PREFIX)
|
|
876
|
+
pathEl.textContent = filePath.startsWith(VIRTUAL_ROOT_PREFIX)
|
|
877
|
+
? filePath.slice(VIRTUAL_ROOT_PREFIX.length)
|
|
878
|
+
: filePath.startsWith(VIRTUAL_AGENTS_PREFIX)
|
|
879
|
+
? `.agents/skills/${filePath.slice(VIRTUAL_AGENTS_PREFIX.length)}`
|
|
880
|
+
: filePath;
|
|
847
881
|
pathEl.dataset.rawPath = filePath;
|
|
848
882
|
codeEl.innerHTML = '<span style="color:var(--text-dim)">Loading...</span>';
|
|
849
883
|
|
|
@@ -1320,6 +1354,13 @@ function handleKeydown(e) {
|
|
|
1320
1354
|
return;
|
|
1321
1355
|
}
|
|
1322
1356
|
|
|
1357
|
+
if (matchKey(e, 'u') || matchKey(e, 'p')) {
|
|
1358
|
+
e.preventDefault();
|
|
1359
|
+
const scope = matchKey(e, 'u') ? 'user' : 'project';
|
|
1360
|
+
openCustomClaudeMd(scope);
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1323
1364
|
const rows = getVisibleRows();
|
|
1324
1365
|
const idx = getFocusedIndex(rows);
|
|
1325
1366
|
|
|
@@ -1382,6 +1423,19 @@ function handleKeydown(e) {
|
|
|
1382
1423
|
}
|
|
1383
1424
|
}
|
|
1384
1425
|
|
|
1426
|
+
async function openCustomClaudeMd(scope) {
|
|
1427
|
+
const pluginId = `_custom/${scope}`;
|
|
1428
|
+
const plugin = findPlugin(pluginId);
|
|
1429
|
+
if (!plugin) return;
|
|
1430
|
+
const comps = (await fetchComponents(pluginId)) || {};
|
|
1431
|
+
const files = comps.claudeMd;
|
|
1432
|
+
if (!files?.length) return;
|
|
1433
|
+
// prefer the root CLAUDE.md over the .claude/ one
|
|
1434
|
+
const file = files.find((f) => !f.startsWith('~root/')) || files[0];
|
|
1435
|
+
showDetail(pluginId);
|
|
1436
|
+
openContentModal(pluginId, file, 'claudeMd');
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1385
1439
|
let _helpModalHandler = null;
|
|
1386
1440
|
|
|
1387
1441
|
function showHelpModal() {
|
package/public/index.html
CHANGED
|
@@ -136,6 +136,8 @@
|
|
|
136
136
|
<tr><td><kbd>E</kbd></td><td>Expand / Collapse all</td></tr>
|
|
137
137
|
<tr><td><kbd>R</kbd></td><td>Refresh data</td></tr>
|
|
138
138
|
<tr><td><kbd>T</kbd></td><td>Toggle theme</td></tr>
|
|
139
|
+
<tr><td><kbd>U</kbd></td><td>Open user CLAUDE.md</td></tr>
|
|
140
|
+
<tr><td><kbd>P</kbd></td><td>Open project CLAUDE.md</td></tr>
|
|
139
141
|
<tr><td><kbd>Esc</kbd></td><td>Close panel / blur input</td></tr>
|
|
140
142
|
</table>
|
|
141
143
|
</div>
|
package/public/style.css
CHANGED
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
--accent-text: #f0a070;
|
|
15
15
|
--accent-dim: rgba(232, 111, 51, 0.22);
|
|
16
16
|
--accent-glow: rgba(232, 111, 51, 0.55);
|
|
17
|
+
--gold: #d9b667;
|
|
17
18
|
--success: #3ecf8e;
|
|
18
19
|
--success-dim: rgba(62, 207, 142, 0.18);
|
|
19
20
|
--warning: #f0b429;
|
|
20
21
|
--warning-dim: rgba(240, 180, 41, 0.18);
|
|
21
|
-
--error: #
|
|
22
|
-
--error-dim: rgba(239,
|
|
23
|
-
--team: #
|
|
24
|
-
--team-dim: rgba(
|
|
22
|
+
--error: #ef5350;
|
|
23
|
+
--error-dim: rgba(239, 83, 80, 0.18);
|
|
24
|
+
--team: #60a5fa;
|
|
25
|
+
--team-dim: rgba(96, 165, 250, 0.18);
|
|
25
26
|
--plan: #86a886;
|
|
26
27
|
--plan-dim: rgba(134, 168, 134, 0.18);
|
|
27
28
|
--mono: 'IBM Plex Mono', monospace;
|
|
@@ -37,23 +38,24 @@
|
|
|
37
38
|
|
|
38
39
|
body.light {
|
|
39
40
|
--bg-deep: #e8e6e3;
|
|
40
|
-
--bg-surface: #
|
|
41
|
-
--bg-elevated: #
|
|
41
|
+
--bg-surface: #efede9;
|
|
42
|
+
--bg-elevated: #f7f4f0;
|
|
42
43
|
--bg-hover: #d2d0cc;
|
|
43
|
-
--border: #
|
|
44
|
+
--border: #cfcbc4;
|
|
44
45
|
--text-primary: #0a0a0a;
|
|
45
|
-
--text-secondary: #
|
|
46
|
-
--text-tertiary: #
|
|
47
|
-
--text-muted: #
|
|
46
|
+
--text-secondary: #444444;
|
|
47
|
+
--text-tertiary: #666666;
|
|
48
|
+
--text-muted: #888888;
|
|
48
49
|
--accent-text: #b85a20;
|
|
49
50
|
--accent-dim: rgba(232, 111, 51, 0.18);
|
|
50
51
|
--accent-glow: rgba(232, 111, 51, 0.5);
|
|
52
|
+
--gold: #a8842f;
|
|
51
53
|
--success: #1a8a5a;
|
|
52
54
|
--success-dim: rgba(26, 138, 90, 0.15);
|
|
53
55
|
--warning: #b07d0a;
|
|
54
56
|
--warning-dim: rgba(176, 125, 10, 0.15);
|
|
55
|
-
--error: #
|
|
56
|
-
--error-dim: rgba(
|
|
57
|
+
--error: #c0392b;
|
|
58
|
+
--error-dim: rgba(192, 57, 43, 0.15);
|
|
57
59
|
--plan: #5a7a5a;
|
|
58
60
|
--plan-dim: rgba(90, 122, 90, 0.15);
|
|
59
61
|
|
|
@@ -156,14 +158,14 @@ body {
|
|
|
156
158
|
display: flex;
|
|
157
159
|
align-items: center;
|
|
158
160
|
gap: 6px;
|
|
159
|
-
background: var(--bg-
|
|
161
|
+
background: var(--bg-deep);
|
|
160
162
|
border: 1px solid var(--border);
|
|
161
163
|
border-radius: 6px;
|
|
162
164
|
padding: 6px 10px;
|
|
163
|
-
transition:
|
|
165
|
+
transition: box-shadow 0.15s ease;
|
|
164
166
|
}
|
|
165
167
|
.topbar-search:focus-within {
|
|
166
|
-
|
|
168
|
+
box-shadow: 0 0 0 2px var(--accent-dim);
|
|
167
169
|
}
|
|
168
170
|
.topbar-search svg {
|
|
169
171
|
color: var(--text-muted);
|
|
@@ -183,7 +185,7 @@ body {
|
|
|
183
185
|
}
|
|
184
186
|
|
|
185
187
|
.topbar-select {
|
|
186
|
-
background: var(--bg-
|
|
188
|
+
background: var(--bg-deep);
|
|
187
189
|
border: 1px solid var(--border);
|
|
188
190
|
border-radius: 6px;
|
|
189
191
|
color: var(--text-secondary);
|
|
@@ -194,7 +196,7 @@ body {
|
|
|
194
196
|
cursor: pointer;
|
|
195
197
|
}
|
|
196
198
|
.topbar-select:focus {
|
|
197
|
-
|
|
199
|
+
box-shadow: 0 0 0 2px var(--accent-dim);
|
|
198
200
|
}
|
|
199
201
|
.topbar-select option {
|
|
200
202
|
background: var(--bg-surface);
|
|
@@ -1177,17 +1179,17 @@ body.light .scope-toggle.local {
|
|
|
1177
1179
|
.modal-field input[type='text'] {
|
|
1178
1180
|
width: 100%;
|
|
1179
1181
|
padding: 8px 10px;
|
|
1180
|
-
background: var(--bg-
|
|
1182
|
+
background: var(--bg-deep);
|
|
1181
1183
|
border: 1px solid var(--border);
|
|
1182
1184
|
border-radius: 6px;
|
|
1183
1185
|
color: var(--text-primary);
|
|
1184
1186
|
font-family: var(--mono);
|
|
1185
1187
|
font-size: 12px;
|
|
1186
1188
|
outline: none;
|
|
1187
|
-
transition:
|
|
1189
|
+
transition: box-shadow 0.15s ease;
|
|
1188
1190
|
}
|
|
1189
1191
|
.modal-field input[type='text']:focus {
|
|
1190
|
-
|
|
1192
|
+
box-shadow: 0 0 0 2px var(--accent-dim);
|
|
1191
1193
|
}
|
|
1192
1194
|
.modal-field input[type='text']::placeholder {
|
|
1193
1195
|
color: var(--text-muted);
|
|
@@ -1389,3 +1391,10 @@ kbd {
|
|
|
1389
1391
|
color: var(--text-muted);
|
|
1390
1392
|
opacity: 0.6;
|
|
1391
1393
|
}
|
|
1394
|
+
|
|
1395
|
+
.detail-comp-group.view-only {
|
|
1396
|
+
opacity: 0.55;
|
|
1397
|
+
}
|
|
1398
|
+
.detail-comp-group.view-only:hover {
|
|
1399
|
+
opacity: 0.85;
|
|
1400
|
+
}
|
package/server.js
CHANGED
|
@@ -478,6 +478,21 @@ function rescanVirtualComponents(basePath, scope) {
|
|
|
478
478
|
}
|
|
479
479
|
if (claudeMdFiles.length) components.claudeMd = claudeMdFiles;
|
|
480
480
|
|
|
481
|
+
if (scope === 'project') {
|
|
482
|
+
const parentAgents = path.join(basePath, '..', 'AGENTS.md');
|
|
483
|
+
if (fs.existsSync(parentAgents)) components.agentsMd = ['~root/AGENTS.md'];
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const agentSkillsDir = path.join(basePath, '..', '.agents', 'skills');
|
|
487
|
+
if (fs.existsSync(agentSkillsDir) && fs.statSync(agentSkillsDir).isDirectory()) {
|
|
488
|
+
try {
|
|
489
|
+
const dirs = fs.readdirSync(agentSkillsDir).filter(d => {
|
|
490
|
+
try { return fs.statSync(path.join(agentSkillsDir, d)).isDirectory(); } catch { return false; }
|
|
491
|
+
});
|
|
492
|
+
if (dirs.length) components.agentSkills = dirs;
|
|
493
|
+
} catch {}
|
|
494
|
+
}
|
|
495
|
+
|
|
481
496
|
return components;
|
|
482
497
|
}
|
|
483
498
|
|
|
@@ -585,6 +600,9 @@ function resolvePluginDir(fullId, marketplaces) {
|
|
|
585
600
|
}
|
|
586
601
|
|
|
587
602
|
function resolveVirtualRelPath(pluginId, relPath) {
|
|
603
|
+
if ((pluginId === '_custom/user' || pluginId === '_custom/project') && relPath.startsWith('~agents/')) {
|
|
604
|
+
return path.join('..', '.agents', 'skills', relPath.slice('~agents/'.length));
|
|
605
|
+
}
|
|
588
606
|
return pluginId === '_custom/project' && relPath.startsWith('~root/')
|
|
589
607
|
? path.join('..', relPath.slice(6))
|
|
590
608
|
: relPath;
|
|
@@ -592,8 +610,13 @@ function resolveVirtualRelPath(pluginId, relPath) {
|
|
|
592
610
|
|
|
593
611
|
function isPathAllowed(fullPath, pluginDir, pluginId) {
|
|
594
612
|
if (fullPath.startsWith(path.resolve(pluginDir))) return true;
|
|
613
|
+
const parent = path.resolve(pluginDir, '..');
|
|
595
614
|
if (pluginId === '_custom/project') {
|
|
596
|
-
|
|
615
|
+
if (fullPath === path.join(parent, 'CLAUDE.md') || fullPath === path.join(parent, 'AGENTS.md')) return true;
|
|
616
|
+
}
|
|
617
|
+
if (pluginId === '_custom/user' || pluginId === '_custom/project') {
|
|
618
|
+
const agentsRoot = path.join(parent, '.agents', 'skills');
|
|
619
|
+
if (fullPath === agentsRoot || fullPath.startsWith(agentsRoot + path.sep)) return true;
|
|
597
620
|
}
|
|
598
621
|
return false;
|
|
599
622
|
}
|