@xenterprises/nuxt-x-marketing 1.0.0 → 1.0.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.
@@ -1,240 +1,187 @@
1
1
  <template>
2
- <article>
3
- <!-- Hero -->
4
- <header class="mb-12">
5
- <div class="max-w-3xl mx-auto text-center mb-8">
6
- <UBadge
7
- v-if="post.category"
8
- :label="post.category"
9
- class="mb-4"
10
- />
11
- <h1 class="xText-headline xText-balance text-neutral-900 dark:text-white">
12
- {{ post.title }}
13
- </h1>
14
- <p
15
- v-if="post.description"
16
- class="mt-4 text-xl text-neutral-600 dark:text-neutral-400"
17
- >
18
- {{ post.description }}
19
- </p>
2
+ <article class="blog-detail">
3
+ <!-- Hero -->
4
+ <header class="mb-16 lg:mb-20">
5
+ <div class="max-w-3xl mx-auto text-center mb-10">
6
+ <UBadge
7
+ v-if="post.category"
8
+ :label="post.category"
9
+ color="primary"
10
+ variant="subtle"
11
+ class="mb-6"
12
+ />
13
+ <h1
14
+ class="text-3xl sm:text-4xl lg:text-5xl font-bold leading-tight tracking-tight text-neutral-900 dark:text-white"
15
+ >
16
+ {{ post.title }}
17
+ </h1>
18
+ <p
19
+ v-if="post.description"
20
+ class="mt-6 text-lg sm:text-xl text-neutral-600 dark:text-neutral-400 leading-relaxed max-w-2xl mx-auto"
21
+ >
22
+ {{ post.description }}
23
+ </p>
20
24
 
21
- <!-- Meta -->
22
- <div class="mt-6 flex items-center justify-center gap-4 flex-wrap">
23
- <!-- Author -->
24
- <div v-if="post.author" class="flex items-center gap-2">
25
- <img
26
- v-if="post.author.avatar"
27
- :src="post.author.avatar"
28
- :alt="post.author.name"
29
- class="w-8 h-8 rounded-full object-cover"
30
- />
31
- <span class="font-medium text-neutral-900 dark:text-white">
32
- {{ post.author.name }}
33
- </span>
34
- </div>
35
- <span class="text-neutral-300 dark:text-neutral-700">·</span>
36
- <time class="text-neutral-500" :datetime="post.date">
37
- {{ formattedDate }}
38
- </time>
39
- <span class="text-neutral-300 dark:text-neutral-700">·</span>
40
- <span class="text-neutral-500">{{ post.readingTime }} min read</span>
41
- </div>
42
- </div>
25
+ <!-- Meta -->
26
+ <div
27
+ class="mt-8 flex items-center justify-center gap-3 sm:gap-4 flex-wrap text-sm"
28
+ >
29
+ <!-- Author -->
30
+ <div v-if="post.author" class="flex items-center gap-2.5">
31
+ <img
32
+ v-if="post.author.avatar"
33
+ :src="post.author.avatar"
34
+ :alt="post.author.name"
35
+ class="w-10 h-10 rounded-full object-cover ring-2 ring-white dark:ring-neutral-800"
36
+ />
37
+ <span class="font-medium text-neutral-900 dark:text-white">
38
+ {{ post.author.name }}
39
+ </span>
40
+ </div>
41
+ <span class="text-neutral-300 dark:text-neutral-600">•</span>
42
+ <time
43
+ class="text-neutral-500 dark:text-neutral-400"
44
+ :datetime="post.date"
45
+ >
46
+ {{ formattedDate }}
47
+ </time>
48
+ <span class="text-neutral-300 dark:text-neutral-600">•</span>
49
+ <span class="text-neutral-500 dark:text-neutral-400">{{
50
+ post.readingTime
51
+ }}</span>
52
+ </div>
53
+ </div>
43
54
 
44
- <!-- Featured Image -->
45
- <figure
46
- v-if="post.img?.src"
47
- class="aspect-[21/9] rounded-2xl overflow-hidden"
48
- >
49
- <img
50
- :src="post.img.src"
51
- :alt="post.img.alt || post.title"
52
- class="w-full h-full object-cover"
53
- />
54
- </figure>
55
- </header>
55
+ <!-- Featured Image -->
56
+ <figure
57
+ v-if="post.img?.src"
58
+ class="aspect-2/1 sm:aspect-21/9 rounded-2xl lg:rounded-3xl overflow-hidden shadow-xl"
59
+ >
60
+ <img
61
+ :src="post.img.src"
62
+ :alt="post.img.alt || post.title"
63
+ class="w-full h-full object-cover"
64
+ />
65
+ </figure>
66
+ </header>
56
67
 
57
- <!-- Content Grid -->
58
- <div class="grid lg:grid-cols-[1fr_280px] gap-12">
59
- <!-- Main Content -->
60
- <div class="max-w-3xl">
61
- <!-- Prose -->
62
- <div class="prose prose-lg dark:prose-invert prose-primary max-w-none">
63
- <slot />
64
- </div>
68
+ <!-- Content Grid -->
69
+ <div class="grid lg:grid-cols-[1fr_300px] gap-12 lg:gap-16">
70
+ <!-- Main Content -->
71
+ <div class="min-w-0">
72
+ <!-- Prose Content -->
73
+ <div
74
+ class="prose prose-lg prose-neutral dark:prose-invert max-w-none prose-headings:scroll-mt-20 prose-a:text-primary-600 dark:prose-a:text-primary-400 prose-a:no-underline hover:prose-a:underline prose-pre:bg-neutral-900 dark:prose-pre:bg-neutral-950 prose-pre:border prose-pre:border-neutral-800 prose-img:rounded-xl"
75
+ >
76
+ <slot />
77
+ </div>
65
78
 
66
- <!-- Tags -->
67
- <div v-if="post.tags?.length" class="mt-12 pt-8 border-t border-neutral-200 dark:border-neutral-800">
68
- <div class="flex flex-wrap gap-2">
69
- <UBadge
70
- v-for="tag in post.tags"
71
- :key="tag"
72
- :label="tag"
73
- variant="outline"
74
- />
75
- </div>
76
- </div>
79
+ <!-- Tags -->
80
+ <div
81
+ v-if="post.tags?.length"
82
+ class="mt-16 pt-10 border-t border-neutral-200 dark:border-neutral-800"
83
+ >
84
+ <h4
85
+ class="text-xs font-semibold uppercase tracking-wider text-neutral-500 mb-4"
86
+ >
87
+ Tags
88
+ </h4>
89
+ <div class="flex flex-wrap gap-2">
90
+ <UBadge
91
+ v-for="tag in post.tags"
92
+ :key="tag"
93
+ :label="tag"
94
+ variant="subtle"
95
+ color="neutral"
96
+ size="md"
97
+ />
98
+ </div>
99
+ </div>
77
100
 
78
- <!-- Author Bio -->
79
- <div
80
- v-if="post.author?.bio"
81
- class="mt-12 flex gap-6 p-6 rounded-2xl bg-neutral-100 dark:bg-neutral-900"
82
- >
83
- <img
84
- v-if="post.author.avatar"
85
- :src="post.author.avatar"
86
- :alt="post.author.name"
87
- class="w-20 h-20 rounded-full object-cover flex-shrink-0"
88
- />
89
- <div>
90
- <p class="font-semibold text-lg text-neutral-900 dark:text-white">
91
- {{ post.author.name }}
92
- </p>
93
- <p v-if="post.author.title" class="text-sm text-neutral-500 mb-3">
94
- {{ post.author.title }}
95
- </p>
96
- <p class="text-neutral-600 dark:text-neutral-400">
97
- {{ post.author.bio }}
98
- </p>
99
- <div v-if="post.author.social" class="flex gap-2 mt-4">
100
- <UButton
101
- v-for="(url, platform) in post.author.social"
102
- :key="platform"
103
- :to="url"
104
- :icon="getSocialIcon(platform)"
105
- variant="ghost"
106
- color="neutral"
107
- size="sm"
108
- target="_blank"
109
- :aria-label="platform"
110
- />
111
- </div>
112
- </div>
113
- </div>
101
+ <!-- Author Bio -->
102
+ <XMarkBlogAuthor
103
+ v-if="post.author"
104
+ :author="post.author"
105
+ variant="full"
106
+ class="mt-12"
107
+ />
114
108
 
115
- <!-- Navigation -->
116
- <nav
117
- v-if="previousPost || nextPost"
118
- class="mt-12 pt-8 border-t border-neutral-200 dark:border-neutral-800 grid sm:grid-cols-2 gap-4"
119
- >
120
- <!-- Previous -->
121
- <NuxtLink
122
- v-if="previousPost"
123
- :to="`/blog/${previousPost.slug}`"
124
- class="group flex items-center gap-4 p-4 rounded-xl hover:bg-neutral-100 dark:hover:bg-neutral-900 transition-colors"
125
- >
126
- <UIcon
127
- name="i-lucide-arrow-left"
128
- class="w-5 h-5 text-neutral-400 group-hover:text-primary-500 transition-colors"
129
- />
130
- <div>
131
- <span class="text-xs text-neutral-500 uppercase tracking-wide">Previous</span>
132
- <p class="font-medium text-neutral-900 dark:text-white group-hover:text-primary-500 transition-colors line-clamp-1">
133
- {{ previousPost.title }}
134
- </p>
135
- </div>
136
- </NuxtLink>
137
- <div v-else />
109
+ <!-- Navigation -->
110
+ <XMarkBlogNavigation
111
+ v-if="previousPost || nextPost"
112
+ :previous="previousPost"
113
+ :next="nextPost"
114
+ class="mt-12"
115
+ />
116
+ </div>
138
117
 
139
- <!-- Next -->
140
- <NuxtLink
141
- v-if="nextPost"
142
- :to="`/blog/${nextPost.slug}`"
143
- class="group flex items-center justify-end gap-4 p-4 rounded-xl hover:bg-neutral-100 dark:hover:bg-neutral-900 transition-colors text-right"
144
- >
145
- <div>
146
- <span class="text-xs text-neutral-500 uppercase tracking-wide">Next</span>
147
- <p class="font-medium text-neutral-900 dark:text-white group-hover:text-primary-500 transition-colors line-clamp-1">
148
- {{ nextPost.title }}
149
- </p>
150
- </div>
151
- <UIcon
152
- name="i-lucide-arrow-right"
153
- class="w-5 h-5 text-neutral-400 group-hover:text-primary-500 transition-colors"
154
- />
155
- </NuxtLink>
156
- </nav>
157
- </div>
118
+ <!-- Sidebar -->
119
+ <aside class="hidden lg:block">
120
+ <div class="sticky top-24 space-y-8">
121
+ <!-- Table of Contents -->
122
+ <div
123
+ v-if="toc?.length"
124
+ class="p-5 rounded-xl bg-neutral-50 dark:bg-neutral-900/50 border border-neutral-200/60 dark:border-neutral-800"
125
+ >
126
+ <h4
127
+ class="font-semibold text-neutral-900 dark:text-white mb-4 text-sm"
128
+ >
129
+ On this page
130
+ </h4>
131
+ <nav class="space-y-1">
132
+ <a
133
+ v-for="item in toc"
134
+ :key="item.id"
135
+ :href="`#${item.id}`"
136
+ class="block py-1.5 text-sm text-neutral-600 dark:text-neutral-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors leading-snug"
137
+ :class="{ 'pl-4 text-[13px]': item.depth > 2 }"
138
+ >
139
+ {{ item.text }}
140
+ </a>
141
+ </nav>
142
+ </div>
158
143
 
159
- <!-- Sidebar -->
160
- <aside class="hidden lg:block">
161
- <div class="sticky top-24 space-y-8">
162
- <!-- Table of Contents -->
163
- <div v-if="toc?.length">
164
- <h4 class="font-medium text-neutral-900 dark:text-white mb-4">On this page</h4>
165
- <nav class="space-y-2">
166
- <a
167
- v-for="item in toc"
168
- :key="item.id"
169
- :href="`#${item.id}`"
170
- class="block text-sm text-neutral-500 hover:text-primary-500 transition-colors"
171
- :class="{ 'pl-4': item.depth > 2 }"
172
- >
173
- {{ item.text }}
174
- </a>
175
- </nav>
176
- </div>
177
-
178
- <!-- Newsletter CTA -->
179
- <slot name="sidebar">
180
- <XMarkNewsletterForm
181
- variant="compact"
182
- title="Subscribe"
183
- description="Get notified about new posts."
184
- />
185
- </slot>
186
- </div>
187
- </aside>
188
- </div>
189
- </article>
144
+ <!-- Newsletter CTA -->
145
+ <slot name="sidebar">
146
+ <XMarkNewsletterForm
147
+ variant="compact"
148
+ title="Subscribe to our newsletter"
149
+ description="Get the latest posts and insights directly to your inbox."
150
+ />
151
+ </slot>
152
+ </div>
153
+ </aside>
154
+ </div>
155
+ </article>
190
156
  </template>
191
157
 
192
158
  <script setup>
193
159
  const props = defineProps({
194
- /** Blog post object with img: { src, alt? } */
195
- post: {
196
- type: Object,
197
- required: true,
198
- },
199
- /** Previous post for navigation */
200
- previousPost: {
201
- type: Object,
202
- default: null,
203
- },
204
- /** Next post for navigation */
205
- nextPost: {
206
- type: Object,
207
- default: null,
208
- },
209
- /** Table of contents items */
210
- toc: {
211
- type: Array,
212
- default: () => [],
213
- },
160
+ post: {
161
+ type: Object,
162
+ required: true,
163
+ },
164
+ previousPost: {
165
+ type: Object,
166
+ default: null,
167
+ },
168
+ nextPost: {
169
+ type: Object,
170
+ default: null,
171
+ },
172
+ toc: {
173
+ type: Array,
174
+ default: () => [],
175
+ },
214
176
  });
215
177
 
216
178
  const formattedDate = computed(() => {
217
- if (!props.post.date) return '';
218
- const date = new Date(props.post.date);
219
- return date.toLocaleDateString('en-US', {
220
- year: 'numeric',
221
- month: 'long',
222
- day: 'numeric',
223
- });
179
+ if (!props.post.date) return "";
180
+ const date = new Date(props.post.date);
181
+ return date.toLocaleDateString("en-US", {
182
+ year: "numeric",
183
+ month: "long",
184
+ day: "numeric",
185
+ });
224
186
  });
225
-
226
- const getSocialIcon = (platform) => {
227
- const icons = {
228
- twitter: 'i-lucide-twitter',
229
- x: 'i-lucide-twitter',
230
- linkedin: 'i-lucide-linkedin',
231
- github: 'i-lucide-github',
232
- website: 'i-lucide-globe',
233
- instagram: 'i-lucide-instagram',
234
- facebook: 'i-lucide-facebook',
235
- youtube: 'i-lucide-youtube',
236
- email: 'i-lucide-mail',
237
- };
238
- return icons[platform.toLowerCase()] || 'i-lucide-link';
239
- };
240
187
  </script>
@@ -0,0 +1,69 @@
1
+ <template>
2
+ <div class="group relative my-6">
3
+ <!-- Language badge -->
4
+ <div
5
+ v-if="language"
6
+ class="absolute top-3 right-3 z-10 px-2 py-1 text-xs font-medium uppercase tracking-wider text-neutral-400 bg-neutral-800/80 rounded"
7
+ >
8
+ {{ language }}
9
+ </div>
10
+
11
+ <!-- Copy button -->
12
+ <UButton
13
+ v-if="showCopy"
14
+ :icon="copied ? 'i-lucide-check' : 'i-lucide-copy'"
15
+ :color="copied ? 'success' : 'neutral'"
16
+ variant="ghost"
17
+ size="xs"
18
+ class="absolute top-3 z-10"
19
+ :class="language ? 'right-28' : 'right-3'"
20
+ @click="copyCode"
21
+ :aria-label="copied ? 'Copied!' : 'Copy code'"
22
+ />
23
+
24
+ <!-- Shiki Highlighter - wrapped in ClientOnly for SSR compatibility -->
25
+ <ClientOnly>
26
+ <Shiki :code="code" :lang="(language as any)" />
27
+ <template #fallback>
28
+ <pre class="shiki-fallback"><code>{{ code }}</code></pre>
29
+ </template>
30
+ </ClientOnly>
31
+ </div>
32
+ </template>
33
+
34
+ <script setup lang="ts">
35
+ const props = defineProps<{
36
+ code: string;
37
+ language?: string;
38
+ showCopy?: boolean;
39
+ }>();
40
+
41
+ const copied = ref(false);
42
+
43
+ const copyCode = async () => {
44
+ try {
45
+ await navigator.clipboard.writeText(props.code);
46
+ copied.value = true;
47
+ setTimeout(() => {
48
+ copied.value = false;
49
+ }, 2000);
50
+ } catch (err) {
51
+ console.error("Failed to copy:", err);
52
+ }
53
+ };
54
+ </script>
55
+
56
+ <style scoped>
57
+ /* Fallback styling while Shiki loads */
58
+ .shiki-fallback {
59
+ margin: 0;
60
+ padding: 1.25rem 1.5rem;
61
+ border-radius: 0.75rem;
62
+ overflow-x: auto;
63
+ background-color: #0d1117;
64
+ color: #c9d1d9;
65
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
66
+ font-size: 0.875rem;
67
+ line-height: 1.7;
68
+ }
69
+ </style>
@@ -10,7 +10,9 @@
10
10
  class="fixed z-40"
11
11
  :class="placementClasses"
12
12
  >
13
- <div class="bg-white dark:bg-gray-900 rounded-xl shadow-lg border border-gray-200 dark:border-gray-800 p-4 flex items-center gap-3">
13
+ <div
14
+ class="bg-white dark:bg-gray-900 rounded-xl shadow-lg border border-gray-200 dark:border-gray-800 p-4 flex items-center gap-3"
15
+ >
14
16
  <!-- Avatar -->
15
17
  <img
16
18
  v-if="currentNotification.avatar"
@@ -38,10 +40,11 @@
38
40
  </p>
39
41
  </div>
40
42
 
41
- <!-- Verified badge -->
43
+ <!-- Status icon -->
42
44
  <UIcon
43
- name="i-lucide-badge-check"
44
- class="w-5 h-5 text-green-500 flex-shrink-0"
45
+ v-if="showIcon && iconName"
46
+ :name="iconName"
47
+ :class="iconClasses"
45
48
  />
46
49
  </div>
47
50
  </aside>
@@ -74,33 +77,75 @@ const props = defineProps({
74
77
  /** Toast placement */
75
78
  placement: {
76
79
  type: String,
77
- default: 'topRight',
78
- validator: (v) => ['topLeft', 'topRight', 'bottomLeft', 'bottomRight'].includes(v),
80
+ default: "topRight",
81
+ validator: (v) =>
82
+ ["topLeft", "topRight", "bottomLeft", "bottomRight"].includes(v),
83
+ },
84
+ /** Toast type - determines icon and color */
85
+ type: {
86
+ type: String,
87
+ default: "success",
88
+ validator: (v) => ["success", "error", "warning", "info"].includes(v),
89
+ },
90
+ /** Whether to show the status icon */
91
+ showIcon: {
92
+ type: Boolean,
93
+ default: true,
79
94
  },
80
95
  });
81
96
 
82
97
  const placementClasses = computed(() => {
83
98
  const placements = {
84
- topLeft: 'top-6 left-6',
85
- topRight: 'top-6 right-6',
86
- bottomLeft: 'bottom-6 left-6',
87
- bottomRight: 'bottom-6 right-6',
99
+ topLeft: "top-6 left-6",
100
+ topRight: "top-6 right-6",
101
+ bottomLeft: "bottom-6 left-6",
102
+ bottomRight: "bottom-6 right-6",
88
103
  };
89
104
  return placements[props.placement];
90
105
  });
91
106
 
107
+ const iconConfig = {
108
+ success: {
109
+ name: "i-lucide-badge-check",
110
+ color: "text-green-500",
111
+ },
112
+ error: {
113
+ name: "i-lucide-x-circle",
114
+ color: "text-red-500",
115
+ },
116
+ warning: {
117
+ name: "i-lucide-alert-triangle",
118
+ color: "text-yellow-500",
119
+ },
120
+ info: {
121
+ name: "i-lucide-info",
122
+ color: "text-blue-500",
123
+ },
124
+ };
125
+
126
+ const iconName = computed(() => {
127
+ if (!props.showIcon) return null;
128
+ return iconConfig[props.type]?.name || null;
129
+ });
130
+
131
+ const iconClasses = computed(() => {
132
+ const baseClasses = "w-5 h-5 flex-shrink-0";
133
+ const colorClass = iconConfig[props.type]?.color || "text-gray-500";
134
+ return `${baseClasses} ${colorClass}`;
135
+ });
136
+
92
137
  const enterFromClass = computed(() => {
93
- if (props.placement.includes('Left')) {
94
- return '-translate-x-full opacity-0';
138
+ if (props.placement.includes("Left")) {
139
+ return "-translate-x-full opacity-0";
95
140
  }
96
- return 'translate-x-full opacity-0';
141
+ return "translate-x-full opacity-0";
97
142
  });
98
143
 
99
144
  const leaveToClass = computed(() => {
100
- if (props.placement.includes('Left')) {
101
- return '-translate-x-full opacity-0';
145
+ if (props.placement.includes("Left")) {
146
+ return "-translate-x-full opacity-0";
102
147
  }
103
- return 'translate-x-full opacity-0';
148
+ return "translate-x-full opacity-0";
104
149
  });
105
150
 
106
151
  const currentNotification = ref(null);
package/nuxt.config.ts CHANGED
@@ -2,7 +2,6 @@
2
2
  import { resolve } from "path";
3
3
 
4
4
  export default defineNuxtConfig({
5
- compatibilityDate: "2026-01-04",
6
5
  ssr: true,
7
6
  devtools: { enabled: process.env.NODE_ENV === "development" },
8
7
  runtimeConfig: {
@@ -10,6 +9,16 @@ export default defineNuxtConfig({
10
9
 
11
10
  },
12
11
  },
13
- modules: ["@nuxt/ui"],
12
+ modules: ["@nuxt/ui", "nuxt-shiki"],
13
+ shiki: {
14
+ bundledThemes: ["github-dark-default", "github-light-default"],
15
+ bundledLangs: ["javascript", "typescript", "vue", "html", "css", "json", "yaml", "sql", "markdown", "bash", "shellscript"],
16
+ defaultTheme: "github-dark-default",
17
+ langAlias: {
18
+ shell: "bash",
19
+ sh: "bash",
20
+ zsh: "bash",
21
+ },
22
+ },
14
23
  css: [resolve(__dirname, "app/assets/css/x-marketing.css")],
15
- });
24
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xenterprises/nuxt-x-marketing",
3
3
  "type": "module",
4
- "version": "1.0.0",
4
+ "version": "1.0.1",
5
5
  "main": "./nuxt.config.ts",
6
6
  "scripts": {
7
7
  "dev": "nuxi dev .playground",
@@ -23,11 +23,13 @@
23
23
  "@axe-core/playwright": "^4.8.4",
24
24
  "@iconify-json/lucide": "^1.2.82",
25
25
  "@playwright/test": "^1.41.1",
26
+ "@tailwindcss/typography": "^0.5.19",
26
27
  "@vitejs/plugin-vue": "^5.0.3",
27
28
  "@vitest/coverage-v8": "^2.1.8",
28
29
  "@vue/test-utils": "^2.4.4",
29
30
  "happy-dom": "^13.3.8",
30
31
  "nuxt": "^4.2.1",
32
+ "nuxt-shiki": "^0.3.2",
31
33
  "typescript": "^5.6.3",
32
34
  "vitest": "^2.1.8",
33
35
  "vue": "latest"
@@ -37,4 +39,4 @@
37
39
  "@nuxt/ui": "^4.3.0",
38
40
  "zod": "^3.23.8"
39
41
  }
40
- }
42
+ }
@@ -1,22 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(curl:*)",
5
- "Bash(npm run dev:*)",
6
- "Bash(cat:*)",
7
- "Bash(npm install:*)",
8
- "Bash(find:*)",
9
- "Bash(ls:*)",
10
- "Skill(frontend-design)",
11
- "Bash(git log:*)",
12
- "Bash(test:*)",
13
- "Bash(timeout 300 npx playwright test:*)",
14
- "Bash(npx playwright test:*)",
15
- "Bash(npx playwright install:*)",
16
- "Bash({} ;)",
17
- "mcp__plugin_context7_context7__resolve-library-id",
18
- "mcp__plugin_context7_context7__query-docs",
19
- "Bash(git reset:*)"
20
- ]
21
- }
22
- }