@ww_nero/skills 2.4.6 → 3.0.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.
@@ -30,6 +30,46 @@ def hex_to_rgb(hex_color):
30
30
  hex_color = ''.join([c*2 for c in hex_color])
31
31
  return RGBColor(int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16))
32
32
 
33
+ def _overwrite_alpha(srgbClr, alpha_float):
34
+ """覆盖 srgbClr 下的透明度节点"""
35
+ if srgbClr is None:
36
+ return
37
+ for a in list(srgbClr.findall(qn("a:alpha"))):
38
+ srgbClr.remove(a)
39
+ alpha = OxmlElement('a:alpha')
40
+ alpha.set('val', str(int(alpha_float * 100000)))
41
+ srgbClr.append(alpha)
42
+
43
+ def _clear_fill_elements(parent):
44
+ """移除已有填充定义,避免冲突"""
45
+ for tag in ('a:solidFill', 'a:gradFill', 'a:noFill'):
46
+ existing = parent.find(qn(tag))
47
+ if existing is not None:
48
+ parent.remove(existing)
49
+
50
+ def _make_grad_stop(pos, hex_color, alpha=None):
51
+ gs = OxmlElement('a:gs')
52
+ gs.set('pos', str(pos))
53
+ srgbClr = OxmlElement('a:srgbClr')
54
+ srgbClr.set('val', hex_color.lstrip('#'))
55
+ if alpha is not None and alpha < 1.0:
56
+ _overwrite_alpha(srgbClr, alpha)
57
+ gs.append(srgbClr)
58
+ return gs
59
+
60
+ def _build_linear_gradient(color1, alpha1, color2, alpha2, angle_deg=0, scaled='1', rot_with_shape='1'):
61
+ gradFill = OxmlElement('a:gradFill')
62
+ gradFill.set('rotWithShape', rot_with_shape)
63
+ gsLst = OxmlElement('a:gsLst')
64
+ gsLst.append(_make_grad_stop(0, color1, alpha1))
65
+ gsLst.append(_make_grad_stop(100000, color2, alpha2))
66
+ lin = OxmlElement('a:lin')
67
+ lin.set('ang', str(int(angle_deg * 60000)))
68
+ lin.set('scaled', scaled)
69
+ gradFill.append(gsLst)
70
+ gradFill.append(lin)
71
+ return gradFill
72
+
33
73
  def _catmull_rom_spline(points, segments_per_curve=20):
34
74
  """Catmull-Rom 样条插值,生成平滑曲线点"""
35
75
  if len(points) < 2:
@@ -64,26 +104,7 @@ def set_slide_background_gradient(slide, color1, color2):
64
104
  else:
65
105
  bg.clear()
66
106
  bgPr = OxmlElement('p:bgPr')
67
- gradFill = OxmlElement('a:gradFill')
68
- gradFill.set('rotWithShape', '1')
69
- gsLst = OxmlElement('a:gsLst')
70
-
71
- def add_stop(pos, hex_c):
72
- gs = OxmlElement('a:gs')
73
- gs.set('pos', str(pos))
74
- srgbClr = OxmlElement('a:srgbClr')
75
- srgbClr.set('val', hex_c.lstrip('#'))
76
- gs.append(srgbClr)
77
- gsLst.append(gs)
78
-
79
- add_stop(0, color1)
80
- add_stop(100000, color2)
81
-
82
- lin = OxmlElement('a:lin')
83
- lin.set('ang', '2700000')
84
- lin.set('scaled', '0')
85
- gradFill.append(gsLst)
86
- gradFill.append(lin)
107
+ gradFill = _build_linear_gradient(color1, None, color2, None, angle_deg=45, scaled='0')
87
108
  bgPr.append(gradFill)
88
109
  effectLst = OxmlElement('a:effectLst')
89
110
  bgPr.append(effectLst)
@@ -97,12 +118,7 @@ def set_transparency(shape, alpha_float, is_line=True):
97
118
  if hasattr(fore_color, '_xFill'):
98
119
  elm = fore_color._xFill
99
120
  if hasattr(elm, "srgbClr"):
100
- clr = elm.srgbClr
101
- for a in clr.findall(qn("a:alpha")):
102
- clr.remove(a)
103
- alpha = OxmlElement('a:alpha')
104
- alpha.set('val', str(int(alpha_float * 100000)))
105
- clr.append(alpha)
121
+ _overwrite_alpha(elm.srgbClr, alpha_float)
106
122
 
107
123
  def set_shape_transparency(shape, alpha_float):
108
124
  """设置形状填充透明度"""
@@ -110,53 +126,13 @@ def set_shape_transparency(shape, alpha_float):
110
126
  solidFill = spPr.find(qn('a:solidFill'))
111
127
  if solidFill is not None:
112
128
  srgbClr = solidFill.find(qn('a:srgbClr'))
113
- if srgbClr is not None:
114
- for a in srgbClr.findall(qn("a:alpha")):
115
- srgbClr.remove(a)
116
- alpha = OxmlElement('a:alpha')
117
- alpha.set('val', str(int(alpha_float * 100000)))
118
- srgbClr.append(alpha)
129
+ _overwrite_alpha(srgbClr, alpha_float)
119
130
 
120
131
  def set_shape_gradient_fill(shape, color1, alpha1, color2, alpha2, angle=0):
121
132
  """设置形状渐变填充"""
122
133
  spPr = shape._sp.spPr
123
- for tag in ['a:solidFill', 'a:gradFill', 'a:noFill']:
124
- existing = spPr.find(qn(tag))
125
- if existing is not None:
126
- spPr.remove(existing)
127
-
128
- gradFill = OxmlElement('a:gradFill')
129
- gradFill.set('rotWithShape', '1')
130
- gsLst = OxmlElement('a:gsLst')
131
-
132
- gs1 = OxmlElement('a:gs')
133
- gs1.set('pos', '0')
134
- srgbClr1 = OxmlElement('a:srgbClr')
135
- srgbClr1.set('val', color1.lstrip('#'))
136
- if alpha1 < 1.0:
137
- alpha_elem1 = OxmlElement('a:alpha')
138
- alpha_elem1.set('val', str(int(alpha1 * 100000)))
139
- srgbClr1.append(alpha_elem1)
140
- gs1.append(srgbClr1)
141
- gsLst.append(gs1)
142
-
143
- gs2 = OxmlElement('a:gs')
144
- gs2.set('pos', '100000')
145
- srgbClr2 = OxmlElement('a:srgbClr')
146
- srgbClr2.set('val', color2.lstrip('#'))
147
- if alpha2 < 1.0:
148
- alpha_elem2 = OxmlElement('a:alpha')
149
- alpha_elem2.set('val', str(int(alpha2 * 100000)))
150
- srgbClr2.append(alpha_elem2)
151
- gs2.append(srgbClr2)
152
- gsLst.append(gs2)
153
-
154
- lin = OxmlElement('a:lin')
155
- lin.set('ang', str(int(angle * 60000)))
156
- lin.set('scaled', '1')
157
-
158
- gradFill.append(gsLst)
159
- gradFill.append(lin)
134
+ _clear_fill_elements(spPr)
135
+ gradFill = _build_linear_gradient(color1, alpha1, color2, alpha2, angle)
160
136
  spPr.append(gradFill)
161
137
 
162
138
  def set_line_transparency(connector, alpha_float):
@@ -170,12 +146,7 @@ def set_line_transparency(connector, alpha_float):
170
146
  solidFill = ln.find(qn('a:solidFill'))
171
147
  if solidFill is not None:
172
148
  srgbClr = solidFill.find(qn('a:srgbClr'))
173
- if srgbClr is not None:
174
- for a in srgbClr.findall(qn("a:alpha")):
175
- srgbClr.remove(a)
176
- alpha = OxmlElement('a:alpha')
177
- alpha.set('val', str(int(alpha_float * 100000)))
178
- srgbClr.append(alpha)
149
+ _overwrite_alpha(srgbClr, alpha_float)
179
150
 
180
151
  def set_line_stroke_transparency(shape, alpha_float):
181
152
  """设置形状边框透明度"""
@@ -187,55 +158,19 @@ def set_line_stroke_transparency(shape, alpha_float):
187
158
  solidFill = ln.find(qn('a:solidFill'))
188
159
  if solidFill is not None:
189
160
  srgbClr = solidFill.find(qn('a:srgbClr'))
190
- if srgbClr is not None:
191
- for a in srgbClr.findall(qn("a:alpha")):
192
- srgbClr.remove(a)
193
- alpha = OxmlElement('a:alpha')
194
- alpha.set('val', str(int(alpha_float * 100000)))
195
- srgbClr.append(alpha)
161
+ _overwrite_alpha(srgbClr, alpha_float)
196
162
 
197
163
  def apply_gradient_to_text(run, color1, color2):
198
164
  """应用渐变到文本"""
199
165
  rPr = run._r.get_or_add_rPr()
200
- for tag in ['a:solidFill', 'a:gradFill', 'a:noFill']:
201
- existing = rPr.find(qn(tag))
202
- if existing is not None:
203
- rPr.remove(existing)
204
-
205
- gradFill = OxmlElement('a:gradFill')
206
- gradFill.set('rotWithShape', '1')
207
-
208
- gsLst = OxmlElement('a:gsLst')
209
-
210
- gs1 = OxmlElement('a:gs')
211
- gs1.set('pos', '0')
212
- srgb1 = OxmlElement('a:srgbClr')
213
- srgb1.set('val', color1.lstrip('#'))
214
- gs1.append(srgb1)
215
- gsLst.append(gs1)
216
-
217
- gs2 = OxmlElement('a:gs')
218
- gs2.set('pos', '100000')
219
- srgb2 = OxmlElement('a:srgbClr')
220
- srgb2.set('val', color2.lstrip('#'))
221
- gs2.append(srgb2)
222
- gsLst.append(gs2)
223
-
224
- lin = OxmlElement('a:lin')
225
- lin.set('ang', '0')
226
- lin.set('scaled', '1')
227
-
228
- gradFill.append(gsLst)
229
- gradFill.append(lin)
166
+ _clear_fill_elements(rPr)
167
+ gradFill = _build_linear_gradient(color1, 1.0, color2, 1.0, 0)
230
168
  rPr.insert(0, gradFill)
231
169
 
232
170
  def set_text_color_xml(run, hex_color):
233
171
  """通过XML直接设置文字颜色,确保不被覆盖"""
234
172
  rPr = run._r.get_or_add_rPr()
235
- for tag in ['a:solidFill', 'a:gradFill', 'a:noFill']:
236
- existing = rPr.find(qn(tag))
237
- if existing is not None:
238
- rPr.remove(existing)
173
+ _clear_fill_elements(rPr)
239
174
  solidFill = OxmlElement('a:solidFill')
240
175
  srgbClr = OxmlElement('a:srgbClr')
241
176
  srgbClr.set('val', hex_color.lstrip('#'))
@@ -289,7 +224,7 @@ def add_text_box(slide, text, x, y, width, height, font_size, color, bold=False,
289
224
 
290
225
  return tb
291
226
 
292
- def add_rectangle(slide, x, y, width, height, fill_color, opacity=1.0, rx=0, stroke_color=None, stroke_width=0, stroke_opacity=None):
227
+ def add_rectangle(slide, x, y, width, height, fill_color, opacity=1.0, rx=0, stroke_color=None, stroke_width=0, stroke_opacity=None, has_shadow=False):
293
228
  """添加矩形"""
294
229
  shape = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE if rx > 0 else MSO_SHAPE.RECTANGLE,
295
230
  px(x), px(y), px(width), px(height))
@@ -304,15 +239,17 @@ def add_rectangle(slide, x, y, width, height, fill_color, opacity=1.0, rx=0, str
304
239
  if stroke_color and stroke_width > 0:
305
240
  shape.line.color.rgb = hex_to_rgb(stroke_color)
306
241
  shape.line.width = int(stroke_width * 9525)
307
- # 设置边框透明度
308
242
  if stroke_opacity is not None and stroke_opacity < 1.0:
309
243
  set_line_stroke_transparency(shape, stroke_opacity)
310
244
  else:
311
245
  shape.line.fill.background()
312
246
 
247
+ if not has_shadow:
248
+ remove_shadow(shape)
249
+
313
250
  return shape
314
251
 
315
- def add_gradient_rectangle(slide, x, y, width, height, color1, alpha1, color2, alpha2, angle=0, rx=0):
252
+ def add_gradient_rectangle(slide, x, y, width, height, color1, alpha1, color2, alpha2, angle=0, rx=0, has_shadow=False):
316
253
  """添加渐变矩形"""
317
254
  shape = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE if rx > 0 else MSO_SHAPE.RECTANGLE,
318
255
  px(x), px(y), px(width), px(height))
@@ -321,18 +258,27 @@ def add_gradient_rectangle(slide, x, y, width, height, color1, alpha1, color2, a
321
258
 
322
259
  set_shape_gradient_fill(shape, color1, alpha1, color2, alpha2, angle)
323
260
  shape.line.fill.background()
261
+
262
+ if not has_shadow:
263
+ remove_shadow(shape)
264
+
324
265
  return shape
325
266
 
326
- def remove_autoshape_shadow(shape):
327
- """移除自动形状阴影效果"""
328
- spPr = shape._sp.spPr
267
+ def remove_shadow(shape):
268
+ """移除形状阴影效果"""
269
+ if hasattr(shape, '_sp'):
270
+ spPr = shape._sp.spPr
271
+ else:
272
+ spPr = shape._element.find(qn('p:spPr'))
273
+ if spPr is None:
274
+ return
329
275
  effectLst = spPr.find(qn('a:effectLst'))
330
276
  if effectLst is not None:
331
277
  spPr.remove(effectLst)
332
278
  effectLst = OxmlElement('a:effectLst')
333
279
  spPr.append(effectLst)
334
280
 
335
- def add_circle(slide, cx, cy, r, fill_color=None, stroke_color=None, stroke_width=1, opacity=1.0, stroke_opacity=None):
281
+ def add_circle(slide, cx, cy, r, fill_color=None, stroke_color=None, stroke_width=1, opacity=1.0, stroke_opacity=None, has_shadow=False):
336
282
  """添加圆形"""
337
283
  shape = slide.shapes.add_shape(MSO_SHAPE.OVAL, px(cx-r), px(cy-r), px(r*2), px(r*2))
338
284
 
@@ -352,13 +298,12 @@ def add_circle(slide, cx, cy, r, fill_color=None, stroke_color=None, stroke_widt
352
298
  else:
353
299
  shape.line.fill.background()
354
300
 
355
- # 如果只有stroke没有fill,移除阴影
356
- if not fill_color and stroke_color:
357
- remove_autoshape_shadow(shape)
301
+ if not has_shadow:
302
+ remove_shadow(shape)
358
303
 
359
304
  return shape
360
305
 
361
- def add_ellipse(slide, cx, cy, rx, ry, fill_color=None, stroke_color=None, stroke_width=1, opacity=1.0, rotation=0, stroke_opacity=None):
306
+ def add_ellipse(slide, cx, cy, rx, ry, fill_color=None, stroke_color=None, stroke_width=1, opacity=1.0, rotation=0, stroke_opacity=None, has_shadow=False):
362
307
  """添加椭圆"""
363
308
  shape = slide.shapes.add_shape(MSO_SHAPE.OVAL, px(cx-rx), px(cy-ry), px(rx*2), px(ry*2))
364
309
 
@@ -373,7 +318,6 @@ def add_ellipse(slide, cx, cy, rx, ry, fill_color=None, stroke_color=None, strok
373
318
  if stroke_color:
374
319
  shape.line.color.rgb = hex_to_rgb(stroke_color)
375
320
  shape.line.width = int(stroke_width * 9525)
376
- # 设置边框透明度
377
321
  if stroke_opacity is not None and stroke_opacity < 1.0:
378
322
  set_line_stroke_transparency(shape, stroke_opacity)
379
323
  else:
@@ -382,18 +326,10 @@ def add_ellipse(slide, cx, cy, rx, ry, fill_color=None, stroke_color=None, strok
382
326
  if rotation != 0:
383
327
  shape.rotation = rotation
384
328
 
385
- return shape
329
+ if not has_shadow:
330
+ remove_shadow(shape)
386
331
 
387
- def remove_shape_shadow(shape):
388
- """移除形状阴影效果"""
389
- spPr = shape._element.find(qn('p:spPr'))
390
- if spPr is None:
391
- return
392
- effectLst = spPr.find(qn('a:effectLst'))
393
- if effectLst is not None:
394
- spPr.remove(effectLst)
395
- effectLst = OxmlElement('a:effectLst')
396
- spPr.append(effectLst)
332
+ return shape
397
333
 
398
334
  def add_line(slide, x1, y1, x2, y2, color, width=1, opacity=1.0, dash=False):
399
335
  """添加线条"""
@@ -404,10 +340,10 @@ def add_line(slide, x1, y1, x2, y2, color, width=1, opacity=1.0, dash=False):
404
340
  connector.line.dash_style = 2
405
341
  if opacity < 1.0:
406
342
  set_line_transparency(connector, opacity)
407
- remove_shape_shadow(connector)
343
+ remove_shadow(connector)
408
344
  return connector
409
345
 
410
- def add_triangle(slide, cx, cy, size, fill_color, opacity=1.0, rotation=0, stroke_color=None, stroke_width=0, stroke_opacity=None):
346
+ def add_triangle(slide, cx, cy, size, fill_color, opacity=1.0, rotation=0, stroke_color=None, stroke_width=0, stroke_opacity=None, has_shadow=False):
411
347
  """添加三角形"""
412
348
  shape = slide.shapes.add_shape(MSO_SHAPE.ISOSCELES_TRIANGLE,
413
349
  px(cx - size/2), px(cy - size/2), px(size), px(size))
@@ -420,11 +356,14 @@ def add_triangle(slide, cx, cy, size, fill_color, opacity=1.0, rotation=0, strok
420
356
  if stroke_color and stroke_width > 0:
421
357
  shape.line.color.rgb = hex_to_rgb(stroke_color)
422
358
  shape.line.width = int(stroke_width * 9525)
423
- # 设置边框透明度
424
359
  if stroke_opacity is not None and stroke_opacity < 1.0:
425
360
  set_line_stroke_transparency(shape, stroke_opacity)
426
361
  else:
427
362
  shape.line.fill.background()
363
+
364
+ if not has_shadow:
365
+ remove_shadow(shape)
366
+
428
367
  return shape
429
368
 
430
369
  def add_spline(slide, points, color, width=2, opacity=1.0, smooth=True):
@@ -448,16 +387,7 @@ def add_spline(slide, points, color, width=2, opacity=1.0, smooth=True):
448
387
  set_line_transparency(shape, opacity)
449
388
  return shape
450
389
 
451
- def remove_freeform_shadow(shape):
452
- """移除自由形状阴影效果"""
453
- spPr = shape._sp.spPr
454
- effectLst = spPr.find(qn('a:effectLst'))
455
- if effectLst is not None:
456
- spPr.remove(effectLst)
457
- effectLst = OxmlElement('a:effectLst')
458
- spPr.append(effectLst)
459
-
460
- def add_freeform_path(slide, points, fill_color=None, stroke_color=None, stroke_width=1, opacity=1.0, closed=False, stroke_opacity=None):
390
+ def add_freeform_path(slide, points, fill_color=None, stroke_color=None, stroke_width=1, opacity=1.0, closed=False, stroke_opacity=None, has_shadow=False):
461
391
  """添加自由形状路径"""
462
392
  if len(points) < 2:
463
393
  return None
@@ -485,9 +415,8 @@ def add_freeform_path(slide, points, fill_color=None, stroke_color=None, stroke_
485
415
  else:
486
416
  shape.line.fill.background()
487
417
 
488
- # 对于非封闭路径(线条类型),移除阴影
489
- if not closed:
490
- remove_freeform_shadow(shape)
418
+ if not has_shadow:
419
+ remove_shadow(shape)
491
420
 
492
421
  return shape
493
422
 
@@ -763,4 +692,4 @@ def main():
763
692
  print(f"成功生成: {output_path}")
764
693
 
765
694
  if __name__ == "__main__":
766
- main()
695
+ main()
package/index.js CHANGED
@@ -122,7 +122,7 @@ const SNIPPETS = {
122
122
  '【渐变透明度】每个渐变停止点的透明度需在对应 srgbClr 下追加 a:alpha 元素,val 值为透明度*100000(如 0.5 透明度对应 50000)。',
123
123
  '【曲线绘制】使用 build_freeform 绘制曲线时,起点坐标在构造器中指定,后续点通过 add_line_segments 添加。若需平滑曲线,可用 Catmull-Rom 样条插值生成中间点。',
124
124
  '【线宽单位换算】线条宽度不能使用 Pt,应使用 EMU 单位:width * 9525(1px 约等于 9525 EMU)。',
125
- '【移除阴影效果】对于线条、非封闭的 freeform path、以及只有 stroke 没有 fill circle,需要移除默认阴影效果,方法是在 spPr 下添加空的 a:effectLst 元素。',
125
+ '【移除阴影效果】如果 SVG 代码中没有显式设置阴影(如 box-shadow filter: drop-shadow),插入元素后需要移除默认阴影,方法是在 spPr 下添加空的 a:effectLst 元素。',
126
126
  '【Emoji 处理】Emoji 可以像普通文本一样直接插入到 PPT 中,使用 add_text_box 函数即可,无需特殊处理。'
127
127
  ]
128
128
  }
@@ -183,15 +183,15 @@ const GUIDES = {
183
183
  1. **规划PPT内容**,存储到markdown文件中:
184
184
  - 每页Slide的规划需要包含:内容、布局方式、插图(只有用户明确提出要求时才添加插图)
185
185
  - 不同页面应尽可能使用不同的布局方式,避免过于单调,可适当使用图表来呈现信息,例如折线图、柱状图、饼状图等;各正文页面背景和标题样式应保持一致
186
- - 如果用户未明确提出要求,则页面默认比例为宽1280px、高720px,默认背景为象牙白(#FFFFF0)、弱渐变、商务简约、扁平化风格
186
+ - 如果用户未明确提出要求,则页面默认比例为宽1280px、高720px,默认背景为弱渐变的浅灰蓝(#F2F4F7 → #FCFCFC)、商务简约、扁平化风格
187
187
  - 如果需要插入图片,则按照以下方式:
188
188
  - 收集图片素材,优先使用用户提供的图片;如未提供,则使用图片生成工具生成合适的图片
189
189
  - 将图片素材保存到\`images\`文件夹中,通过python脚本获取每个图片的宽高比例,然后对每张图片进行重命名,通过名称标识图片的内容及宽高比例,例如\`main_background_16_9.png\`表示该图片是主背景图,宽高比为16:9;对于用户提供的图片素材,可调用工具解读图片内容
190
190
 
191
191
  2. **通过SVG代码实现Slides的排版**:
192
- - 如需插图,统一使用\`rect\`或\`circle\`元素进行占位(必须符合图片宽高比例),占位元素应设置合适的位置,可添加浅色填充或边框以便预览时识别
193
- - 如需图标,优先使用Emoji,其次使用纯代码的方式绘制
194
- - 如需图表,如折线图、柱状图等,应使用纯代码的方式绘制,而不是使用图片占位元素
192
+ - 如需Image,统一使用\`rect\`或\`circle\`元素进行占位(必须符合图片宽高比例),占位元素应设置合适的位置,可添加浅色填充或边框以便预览时识别
193
+ - 如需Icon,优先使用Emoji,其次使用纯代码的方式绘制
194
+ - 如需Chart,如折线图、柱状图等,应使用纯代码的方式绘制,而不是使用图片占位元素
195
195
  - 所有Slide的页面共同保存在一个HTML文件中。
196
196
 
197
197
  3. **把SVG转成PPTX文件**:
@@ -284,7 +284,7 @@ const listTools = () => ({
284
284
  ]
285
285
  });
286
286
 
287
- const server = new Server({ name: 'skills', version: '2.4.6' }, { capabilities: { tools: {} } });
287
+ const server = new Server({ name: 'skills', version: '3.0.2' }, { capabilities: { tools: {} } });
288
288
 
289
289
  server.setRequestHandler(ListToolsRequestSchema, async () => listTools());
290
290
 
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
- {
2
- "name": "@ww_nero/skills",
3
- "version": "2.4.6",
4
- "description": "MCP server that returns Python reference snippets and skill guides",
5
- "main": "index.js",
6
- "bin": {
7
- "skills": "index.js"
8
- },
9
- "files": [
10
- "index.js",
11
- "assets"
12
- ],
13
- "dependencies": {
14
- "@modelcontextprotocol/sdk": "^1.22.0"
15
- }
16
- }
1
+ {
2
+ "name": "@ww_nero/skills",
3
+ "version": "3.0.2",
4
+ "description": "MCP server that returns Python reference snippets and skill guides",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "skills": "index.js"
8
+ },
9
+ "files": [
10
+ "index.js",
11
+ "assets"
12
+ ],
13
+ "dependencies": {
14
+ "@modelcontextprotocol/sdk": "^1.22.0"
15
+ }
16
+ }