@pymodel/niblet 0.1.0 → 0.2.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/README.md +23 -5
- package/assets/niblet-logo-dark.svg +20 -0
- package/assets/niblet-logo-light.svg +20 -0
- package/package.json +1 -1
- package/skill/niblet/SKILL.md +1 -1
- package/src/server.mjs +136 -12
- package/src/skill.mjs +103 -0
- package/assets/niblet-banner.svg +0 -20
package/README.md
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/PyModel/niblet-skill-mcp/main/assets/niblet-logo-dark.svg">
|
|
4
|
+
<img alt="Niblet" src="https://raw.githubusercontent.com/PyModel/niblet-skill-mcp/main/assets/niblet-logo-light.svg" width="300">
|
|
5
|
+
</picture>
|
|
3
6
|
</p>
|
|
4
7
|
|
|
5
8
|
<h1 align="center">Niblet MCP</h1>
|
|
6
9
|
|
|
10
|
+
<p align="center">Real screen references and a design skill, for coding agents that build UI.</p>
|
|
11
|
+
|
|
7
12
|
<p align="center">
|
|
8
|
-
<
|
|
13
|
+
<a href="https://www.npmjs.com/package/@pymodel/niblet"><img alt="npm" src="https://img.shields.io/npm/v/%40pymodel%2Fniblet?logo=npm&logoColor=white&label=npm&color=e8a33d&labelColor=0f1110"></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/@pymodel/niblet"><img alt="Downloads" src="https://img.shields.io/npm/dm/%40pymodel%2Fniblet?logo=npm&logoColor=white&label=downloads&color=30363d&labelColor=0f1110"></a>
|
|
15
|
+
<a href="https://nodejs.org"><img alt="Node 24.15+" src="https://img.shields.io/badge/node-24.15%2B-30363d?logo=nodedotjs&logoColor=white&labelColor=0f1110"></a>
|
|
16
|
+
<a href="https://modelcontextprotocol.io"><img alt="MCP" src="https://img.shields.io/badge/mcp-server-30363d?logo=anthropic&logoColor=white&labelColor=0f1110"></a>
|
|
17
|
+
<a href="https://github.com/PyModel/niblet-skill-mcp/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/PyModel/niblet-skill-mcp?logo=github&logoColor=white&label=stars&color=30363d&labelColor=0f1110"></a>
|
|
18
|
+
<a href="https://github.com/PyModel/niblet-skill-mcp/blob/main/LICENSE"><img alt="License: Apache-2.0" src="https://img.shields.io/badge/license-Apache--2.0-30363d?labelColor=0f1110"></a>
|
|
19
|
+
<a href="https://hits.sh/github.com/PyModel/niblet-skill-mcp/"><img alt="Visitors" src="https://hits.sh/github.com/PyModel/niblet-skill-mcp.svg?label=visitors&color=30363d&labelColor=0f1110"></a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
<img src="https://raw.githubusercontent.com/PyModel/niblet-skill-mcp/main/assets/niblet-mascot.svg" alt="" width="96" height="96">
|
|
9
24
|
</p>
|
|
10
25
|
|
|
11
26
|
<p align="center">
|
|
@@ -25,7 +40,10 @@ Two tools, matching the hosted service exactly:
|
|
|
25
40
|
| `find_ui_references` | One concrete unresolved question about a layout, state, or interaction. Returns one to three real screens as inline images. |
|
|
26
41
|
| `find_ui_materials` | A named font, icon, or animated icon role your design system does not already cover. Returns the recorded license with each result. |
|
|
27
42
|
|
|
28
|
-
|
|
43
|
+
| `niblet_help` | “What can Niblet do?”, or choosing between commands. Lists the four surface modes and every command with its purpose; pass `command` for one entry. |
|
|
44
|
+
| `niblet_status` | Diagnosing the connection. Reports the configured origins, whether a usable token is present (never the token), which bundled documents are readable, and whether the API actually answers. |
|
|
45
|
+
|
|
46
|
+
The bundled documents are served as resources and need no token: `niblet://skill` for the workflow, plus `niblet://skill/commands`, `niblet://skill/connection`, `niblet://skill/evidence`, and `niblet://skill/native`. Their cross-links are rewritten to these URIs on the way out, so an agent reading them over MCP can follow every reference.
|
|
29
47
|
|
|
30
48
|
## Connect
|
|
31
49
|
|
|
@@ -64,7 +82,7 @@ Get a token from [niblet.com/docs](https://niblet.com/docs). Keep it in `.env` o
|
|
|
64
82
|
|
|
65
83
|
## The skill
|
|
66
84
|
|
|
67
|
-
<img src="assets/niblet-mascot-working.svg" alt="" width="72" height="72" align="right">
|
|
85
|
+
<img src="https://raw.githubusercontent.com/PyModel/niblet-skill-mcp/main/assets/niblet-mascot-working.svg" alt="" width="72" height="72" align="right">
|
|
68
86
|
|
|
69
87
|
Install it straight from the repository:
|
|
70
88
|
|
|
@@ -94,7 +112,7 @@ npm ci --ignore-scripts
|
|
|
94
112
|
cp .env.example .env # then put your token in NIBLET_TOKEN
|
|
95
113
|
```
|
|
96
114
|
|
|
97
|
-
`npm test` covers the tool contract and its failure boundaries. For anything touching startup or configuration, also connect a real MCP client and confirm the tool list and `niblet://skill
|
|
115
|
+
`npm test` covers the tool contract and its failure boundaries. For anything touching startup or configuration, also connect a real MCP client and confirm the tool list and every `niblet://skill` resource — a resource that registers but never appears in `resources/list` is the failure the unit tests cannot catch. For documentation, check that relative links resolve and that `npm pack --dry-run` still ships what you expect.
|
|
98
116
|
|
|
99
117
|
[AGENTS.md](AGENTS.md) has the details if you are pointing a coding agent at this repository.
|
|
100
118
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="106" viewBox="0 0 360 106" role="img" aria-labelledby="nb-title nb-desc">
|
|
3
|
+
<title id="nb-title">Niblet horizontal logo for dark backgrounds</title><desc id="nb-desc">Editable native SVG artwork. No embedded raster images.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="nb-hat" x1="0" y1="0.65" x2="0.9" y2="0.15" gradientUnits="objectBoundingBox"><stop stop-color="#115999"/><stop offset="0.46" stop-color="#1796B1"/><stop offset="0.8" stop-color="#25CBBB"/><stop offset="1" stop-color="#89F3D8"/></linearGradient>
|
|
6
|
+
<linearGradient id="nb-hat-fold" x1="0" y1="0.2" x2="1" y2="0.8"><stop stop-color="#0C5E8D"/><stop offset="0.62" stop-color="#117B90"/><stop offset="1" stop-color="#00A59F"/></linearGradient>
|
|
7
|
+
<linearGradient id="nb-brim" x1="0" y1="1" x2="1" y2="0"><stop stop-color="#2278D3"/><stop offset="0.5" stop-color="#28AADA"/><stop offset="1" stop-color="#67EAD0"/></linearGradient>
|
|
8
|
+
<radialGradient id="nb-face" cx="45%" cy="35%" r="70%"><stop stop-color="#FFF1CF"/><stop offset="0.65" stop-color="#FFDFBA"/><stop offset="1" stop-color="#F4AF91"/></radialGradient>
|
|
9
|
+
<linearGradient id="nb-ear" x1="0" y1="0" x2="0.8" y2="1"><stop stop-color="#FFD7B5"/><stop offset="1" stop-color="#F2A185"/></linearGradient>
|
|
10
|
+
<linearGradient id="nb-ear-inner" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#E98072"/><stop offset="1" stop-color="#F6B797"/></linearGradient>
|
|
11
|
+
<radialGradient id="nb-orb" cx="30%" cy="23%" r="80%"><stop stop-color="#ABFFEC"/><stop offset="0.4" stop-color="#16D7C5"/><stop offset="1" stop-color="#078899"/></radialGradient>
|
|
12
|
+
<linearGradient id="nb-cloak" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#169EAF"/><stop offset="0.5" stop-color="#08718D"/><stop offset="1" stop-color="#0A344F"/></linearGradient>
|
|
13
|
+
<linearGradient id="nb-app" x1="0" y1="1" x2="0.9" y2="0"><stop stop-color="#7360FF"/><stop offset="0.44" stop-color="#2E8BFF"/><stop offset="1" stop-color="#08DBC2"/></linearGradient>
|
|
14
|
+
<linearGradient id="nb-magic" x1="0" y1="1" x2="1" y2="0"><stop stop-color="#8B5CF6"/><stop offset="0.55" stop-color="#2E8BFF"/><stop offset="1" stop-color="#00D1B2"/></linearGradient>
|
|
15
|
+
<linearGradient id="nb-soft" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#EEF5FF"/><stop offset="0.6" stop-color="#F7F4FF"/><stop offset="1" stop-color="#E8FAF8"/></linearGradient>
|
|
16
|
+
<linearGradient id="nb-dark-surface" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#142A42"/><stop offset="1" stop-color="#0A1628"/></linearGradient>
|
|
17
|
+
<radialGradient id="nb-halo"><stop stop-color="#A8EEE7" stop-opacity="0.55"/><stop offset="1" stop-color="#DFEFFE" stop-opacity="0"/></radialGradient>
|
|
18
|
+
</defs>
|
|
19
|
+
<g transform="translate(12 9) scale(1)" ><g transform="translate(-5 -8) scale(0.17)" ><g id="mascot-cloak"><path d="M170 359C187 378 220 389 255 388C288 389 322 378 343 360L349 400L310 426L299 464L268 454L239 466L218 454L186 459L183 423L153 401Z" fill="url(#nb-cloak)" /><path d="M169 382Q244 432 335 384L320 411Q242 447 177 407Z" fill="#084E67" /><path d="M188 427L238 445L212 453L188 449Z" fill="#20A9B1" /><path d="M268 426L288 460L264 449L242 460L244 441Z" fill="#0D405E" /></g><g id="mascot-ears"><path d="M153 282C126 264 98 251 59 248C65 285 91 320 127 334L161 316Z" fill="url(#nb-ear)" /><path d="M350 277C377 248 404 232 448 221C441 267 418 306 380 326L350 311Z" fill="url(#nb-ear)" /><path d="M137 292Q115 273 79 264Q94 295 132 314Z" fill="url(#nb-ear-inner)" /><path d="M371 285Q395 255 429 240Q417 281 382 307Z" fill="url(#nb-ear-inner)" /></g><g id="mascot-hood"><path d="M118 276C127 219 151 166 183 112C217 55 258 29 303 44C344 58 365 87 386 109C359 101 337 112 325 137C331 177 361 210 367 248C392 276 391 320 368 353C345 390 304 407 252 407C191 405 149 388 126 353C109 327 108 299 118 276Z" fill="url(#nb-hat)" /><path d="M183 113C216 65 253 35 295 52C250 57 222 100 217 139C207 178 225 207 234 228L136 260C143 216 160 166 183 113Z" fill="#72E5D4" opacity="0.18"/><path d="M284 59C328 61 358 89 384 109C358 100 337 113 325 138C325 167 348 203 359 228C319 209 292 170 282 129C275 98 277 77 284 59Z" fill="url(#nb-hat-fold)" /><path d="M179 117C205 75 234 52 263 47" fill="none" stroke="#C2FFF0" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.66"/><path d="M135 256C197 224 296 222 362 255" fill="none" stroke="#076E91" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" /></g><g id="mascot-face"><path d="M137 290C153 265 189 252 245 251C301 247 340 260 362 288L365 325C361 371 315 397 253 397C192 397 146 375 139 337Z" fill="url(#nb-face)" /></g><g id="mascot-hatband"><path d="M120 279C142 245 181 228 239 224C292 219 336 231 364 252L369 289C333 261 293 251 245 255C191 256 150 273 131 308Z" fill="url(#nb-brim)" /><path d="M136 276C166 248 207 238 251 236C295 235 330 245 351 260" fill="none" stroke="#A5FBE8" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.65"/><path d="M225 254L242 268L257 252Z" fill="#19C6B8" /></g><g id="mascot-expression"><ellipse cx="203" cy="312" rx="12" ry="19" fill="#0A1628"/><ellipse cx="295" cy="312" rx="12" ry="19" fill="#0A1628"/><circle cx="200" cy="305" r="4.1" fill="#FFFFFF" /><circle cx="292" cy="305" r="4.1" fill="#FFFFFF" /><path d="M187 280Q199 271 211 279M285 278Q297 268 309 278" fill="none" stroke="#0A1628" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M232 343Q252 362 274 340" fill="none" stroke="#0A1628" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round" /><ellipse cx="178" cy="343" rx="17" ry="10" fill="#F58E85" opacity="0.38"/><ellipse cx="321" cy="341" rx="17" ry="10" fill="#F58E85" opacity="0.38"/><path d="M250 322Q256 328 250 330" fill="none" stroke="#ECA58E" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" /></g><g id="mascot-hat-orb"><path d="M382 108Q392 111 394 121" fill="none" stroke="#148E9D" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" /><circle cx="395" cy="126" r="18" fill="url(#nb-orb)" /><path d="M385 117Q392 110 402 116" fill="none" stroke="#D1FFF5" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.8"/></g></g><g fill="#FFFFFF" transform="translate(85 57) scale(0.0288086 -0.0288086)"><path d="M111 0H419V691C419 755 418 882 412 1038C496 887 572 758 615 690L1049 0H1374V1490H1067V753C1067 690 1068 567 1072 452C1013 559 949 672 914 728L435 1490H111Z" transform="translate(0 0)"/><path d="M104 0H399V1056H104ZM251 1189C348 1189 419 1256 419 1346C419 1436 348 1503 251 1503C154 1503 83 1436 83 1346C83 1256 154 1189 251 1189Z" transform="translate(1413.32 0)"/><path d="M709 -22C985 -22 1166 198 1166 529C1166 853 981 1078 711 1078C574 1078 468 1024 400 910H399V1490H104V0H395V162H396C457 39 570 -22 709 -22ZM633 218C484 218 385 340 385 529C385 717 484 840 633 840C776 840 869 727 869 529C869 331 776 218 633 218Z" transform="translate(1844.64 0)"/><path d="M399 1490H104V0H399Z" transform="translate(2996.96 0)"/><path d="M586 -24C842 -24 1046 122 1085 332H816C789 250 710 197 595 197C440 197 350 298 345 454H1096V533C1096 855 887 1080 576 1080C273 1080 58 849 58 527C58 206 266 -24 586 -24ZM347 642C363 774 450 856 582 856C715 856 803 774 818 642Z" transform="translate(3428.28 0)"/><path d="M711 1056H495V1344H200V1056H18V825H200V280C200 88 307 0 539 0H711V231H598C518 231 495 254 495 326V825H711Z" transform="translate(4506.6 0)"/></g><path d="M249.514296875 11C251.014296875 19.0 251.514296875 19.5 259.514296875 21C251.514296875 22.5 251.014296875 23.0 249.514296875 31C248.014296875 23.0 247.514296875 22.5 239.514296875 21C247.514296875 19.5 248.014296875 19.0 249.514296875 11Z" fill="url(#nb-magic)" /><g fill="#A8B7CB" transform="translate(88 85) scale(0.00537109 -0.00537109)"><path d="M645 0C1099 0 1356 282 1356 748C1356 1210 1099 1490 664 1490H180V0ZM370 168V1322H651C996 1322 1172 1106 1172 748C1172 386 996 168 633 168Z" transform="translate(0 0)"/><path d="M180 0H1097V168H370V668H1039V836H370V1322H1088V1490H180Z" transform="translate(1826.16 0)"/><path d="M657 -26C1001 -26 1198 162 1198 406C1198 684 936 774 776 818L627 859C518 889 343 944 343 1100C343 1240 471 1342 664 1342C841 1342 975 1259 992 1114H1178C1169 1339 964 1510 670 1510C382 1510 158 1343 158 1091C158 893 298 770 538 702L718 651C877 606 1013 553 1013 409C1013 250 859 144 657 144C482 144 326 221 311 390H116C133 140 334 -26 657 -26Z" transform="translate(3405.32 0)"/><path d="M370 1490H180V0H370Z" transform="translate(5067.48 0)"/><path d="M789 -20C1144 -20 1400 216 1400 586V749H828V583H1214C1209 321 1038 156 789 156C515 156 307 364 307 744C307 1127 516 1334 778 1334C989 1334 1132 1214 1193 1023H1389C1335 1312 1092 1510 777 1510C395 1510 122 1217 122 744C122 273 391 -20 789 -20Z" transform="translate(5965.64 0)"/><path d="M180 0H371V850C371 922 364 1071 356 1262C472 1055 529 955 597 848L1137 0H1363V1490H1173V576C1173 496 1174 369 1186 225C1118 360 1050 474 1010 537L404 1490H180Z" transform="translate(7841.8 0)"/><path d="M180 0H1097V168H370V668H1039V836H370V1322H1088V1490H180Z" transform="translate(9732.96 0)"/><path d="M180 0H370V578H691C703 578 714 578 726 579L1036 0H1256L922 613C1110 679 1198 832 1198 1030C1198 1296 1038 1490 690 1490H180ZM370 747V1323H680C917 1323 1009 1207 1009 1030C1009 855 917 747 682 747Z" transform="translate(11312.1 0)"/><path d="M180 0H361V851C361 966 357 1142 354 1284C413 1109 471 935 504 851L842 0H1007L1340 851C1374 938 1436 1117 1490 1287C1486 1132 1483 961 1483 851V0H1670V1490H1399L1037 550C1008 475 962 328 927 211C892 332 845 478 817 550L450 1490H180Z" transform="translate(13902.4 0)"/><path d="M783 -20C1088 -20 1332 166 1384 469H1194C1152 266 978 156 783 156C516 156 307 363 307 744C307 1126 515 1334 783 1334C977 1334 1152 1225 1194 1021H1384C1331 1328 1085 1510 783 1510C401 1510 122 1217 122 744C122 272 401 -20 783 -20Z" transform="translate(16100.6 0)"/><path d="M180 0H370V539H691C1038 539 1198 750 1198 1016C1198 1281 1038 1490 690 1490H180ZM370 706V1323H680C918 1323 1009 1192 1009 1016C1009 839 918 706 682 706Z" transform="translate(17944.8 0)"/><path d="M657 -26C1001 -26 1198 162 1198 406C1198 684 936 774 776 818L627 859C518 889 343 944 343 1100C343 1240 471 1342 664 1342C841 1342 975 1259 992 1114H1178C1169 1339 964 1510 670 1510C382 1510 158 1343 158 1091C158 893 298 770 538 702L718 651C877 606 1013 553 1013 409C1013 250 859 144 657 144C482 144 326 221 311 390H116C133 140 334 -26 657 -26Z" transform="translate(20525.1 0)"/><path d="M180 0H370V489L585 716L1094 0H1319L716 845L1318 1490H1069L624 1009C533 911 450 813 367 706L370 980V1490H180Z" transform="translate(22187.2 0)"/><path d="M370 1490H180V0H370Z" transform="translate(23911.4 0)"/><path d="M180 0H1060V168H370V1490H180Z" transform="translate(24809.6 0)"/><path d="M180 0H1060V168H370V1490H180Z" transform="translate(26315.7 0)"/></g></g>
|
|
20
|
+
</svg>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="106" viewBox="0 0 360 106" role="img" aria-labelledby="nb-title nb-desc">
|
|
3
|
+
<title id="nb-title">Niblet horizontal logo for light backgrounds</title><desc id="nb-desc">Editable native SVG artwork. No embedded raster images.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="nb-hat" x1="0" y1="0.65" x2="0.9" y2="0.15" gradientUnits="objectBoundingBox"><stop stop-color="#115999"/><stop offset="0.46" stop-color="#1796B1"/><stop offset="0.8" stop-color="#25CBBB"/><stop offset="1" stop-color="#89F3D8"/></linearGradient>
|
|
6
|
+
<linearGradient id="nb-hat-fold" x1="0" y1="0.2" x2="1" y2="0.8"><stop stop-color="#0C5E8D"/><stop offset="0.62" stop-color="#117B90"/><stop offset="1" stop-color="#00A59F"/></linearGradient>
|
|
7
|
+
<linearGradient id="nb-brim" x1="0" y1="1" x2="1" y2="0"><stop stop-color="#2278D3"/><stop offset="0.5" stop-color="#28AADA"/><stop offset="1" stop-color="#67EAD0"/></linearGradient>
|
|
8
|
+
<radialGradient id="nb-face" cx="45%" cy="35%" r="70%"><stop stop-color="#FFF1CF"/><stop offset="0.65" stop-color="#FFDFBA"/><stop offset="1" stop-color="#F4AF91"/></radialGradient>
|
|
9
|
+
<linearGradient id="nb-ear" x1="0" y1="0" x2="0.8" y2="1"><stop stop-color="#FFD7B5"/><stop offset="1" stop-color="#F2A185"/></linearGradient>
|
|
10
|
+
<linearGradient id="nb-ear-inner" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#E98072"/><stop offset="1" stop-color="#F6B797"/></linearGradient>
|
|
11
|
+
<radialGradient id="nb-orb" cx="30%" cy="23%" r="80%"><stop stop-color="#ABFFEC"/><stop offset="0.4" stop-color="#16D7C5"/><stop offset="1" stop-color="#078899"/></radialGradient>
|
|
12
|
+
<linearGradient id="nb-cloak" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#169EAF"/><stop offset="0.5" stop-color="#08718D"/><stop offset="1" stop-color="#0A344F"/></linearGradient>
|
|
13
|
+
<linearGradient id="nb-app" x1="0" y1="1" x2="0.9" y2="0"><stop stop-color="#7360FF"/><stop offset="0.44" stop-color="#2E8BFF"/><stop offset="1" stop-color="#08DBC2"/></linearGradient>
|
|
14
|
+
<linearGradient id="nb-magic" x1="0" y1="1" x2="1" y2="0"><stop stop-color="#8B5CF6"/><stop offset="0.55" stop-color="#2E8BFF"/><stop offset="1" stop-color="#00D1B2"/></linearGradient>
|
|
15
|
+
<linearGradient id="nb-soft" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#EEF5FF"/><stop offset="0.6" stop-color="#F7F4FF"/><stop offset="1" stop-color="#E8FAF8"/></linearGradient>
|
|
16
|
+
<linearGradient id="nb-dark-surface" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#142A42"/><stop offset="1" stop-color="#0A1628"/></linearGradient>
|
|
17
|
+
<radialGradient id="nb-halo"><stop stop-color="#A8EEE7" stop-opacity="0.55"/><stop offset="1" stop-color="#DFEFFE" stop-opacity="0"/></radialGradient>
|
|
18
|
+
</defs>
|
|
19
|
+
<g transform="translate(12 9) scale(1)" ><g transform="translate(-5 -8) scale(0.17)" ><g id="mascot-cloak"><path d="M170 359C187 378 220 389 255 388C288 389 322 378 343 360L349 400L310 426L299 464L268 454L239 466L218 454L186 459L183 423L153 401Z" fill="url(#nb-cloak)" /><path d="M169 382Q244 432 335 384L320 411Q242 447 177 407Z" fill="#084E67" /><path d="M188 427L238 445L212 453L188 449Z" fill="#20A9B1" /><path d="M268 426L288 460L264 449L242 460L244 441Z" fill="#0D405E" /></g><g id="mascot-ears"><path d="M153 282C126 264 98 251 59 248C65 285 91 320 127 334L161 316Z" fill="url(#nb-ear)" /><path d="M350 277C377 248 404 232 448 221C441 267 418 306 380 326L350 311Z" fill="url(#nb-ear)" /><path d="M137 292Q115 273 79 264Q94 295 132 314Z" fill="url(#nb-ear-inner)" /><path d="M371 285Q395 255 429 240Q417 281 382 307Z" fill="url(#nb-ear-inner)" /></g><g id="mascot-hood"><path d="M118 276C127 219 151 166 183 112C217 55 258 29 303 44C344 58 365 87 386 109C359 101 337 112 325 137C331 177 361 210 367 248C392 276 391 320 368 353C345 390 304 407 252 407C191 405 149 388 126 353C109 327 108 299 118 276Z" fill="url(#nb-hat)" /><path d="M183 113C216 65 253 35 295 52C250 57 222 100 217 139C207 178 225 207 234 228L136 260C143 216 160 166 183 113Z" fill="#72E5D4" opacity="0.18"/><path d="M284 59C328 61 358 89 384 109C358 100 337 113 325 138C325 167 348 203 359 228C319 209 292 170 282 129C275 98 277 77 284 59Z" fill="url(#nb-hat-fold)" /><path d="M179 117C205 75 234 52 263 47" fill="none" stroke="#C2FFF0" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.66"/><path d="M135 256C197 224 296 222 362 255" fill="none" stroke="#076E91" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" /></g><g id="mascot-face"><path d="M137 290C153 265 189 252 245 251C301 247 340 260 362 288L365 325C361 371 315 397 253 397C192 397 146 375 139 337Z" fill="url(#nb-face)" /></g><g id="mascot-hatband"><path d="M120 279C142 245 181 228 239 224C292 219 336 231 364 252L369 289C333 261 293 251 245 255C191 256 150 273 131 308Z" fill="url(#nb-brim)" /><path d="M136 276C166 248 207 238 251 236C295 235 330 245 351 260" fill="none" stroke="#A5FBE8" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.65"/><path d="M225 254L242 268L257 252Z" fill="#19C6B8" /></g><g id="mascot-expression"><ellipse cx="203" cy="312" rx="12" ry="19" fill="#0A1628"/><ellipse cx="295" cy="312" rx="12" ry="19" fill="#0A1628"/><circle cx="200" cy="305" r="4.1" fill="#FFFFFF" /><circle cx="292" cy="305" r="4.1" fill="#FFFFFF" /><path d="M187 280Q199 271 211 279M285 278Q297 268 309 278" fill="none" stroke="#0A1628" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M232 343Q252 362 274 340" fill="none" stroke="#0A1628" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round" /><ellipse cx="178" cy="343" rx="17" ry="10" fill="#F58E85" opacity="0.38"/><ellipse cx="321" cy="341" rx="17" ry="10" fill="#F58E85" opacity="0.38"/><path d="M250 322Q256 328 250 330" fill="none" stroke="#ECA58E" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" /></g><g id="mascot-hat-orb"><path d="M382 108Q392 111 394 121" fill="none" stroke="#148E9D" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" /><circle cx="395" cy="126" r="18" fill="url(#nb-orb)" /><path d="M385 117Q392 110 402 116" fill="none" stroke="#D1FFF5" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.8"/></g></g><g fill="#0A1628" transform="translate(85 57) scale(0.0288086 -0.0288086)"><path d="M111 0H419V691C419 755 418 882 412 1038C496 887 572 758 615 690L1049 0H1374V1490H1067V753C1067 690 1068 567 1072 452C1013 559 949 672 914 728L435 1490H111Z" transform="translate(0 0)"/><path d="M104 0H399V1056H104ZM251 1189C348 1189 419 1256 419 1346C419 1436 348 1503 251 1503C154 1503 83 1436 83 1346C83 1256 154 1189 251 1189Z" transform="translate(1413.32 0)"/><path d="M709 -22C985 -22 1166 198 1166 529C1166 853 981 1078 711 1078C574 1078 468 1024 400 910H399V1490H104V0H395V162H396C457 39 570 -22 709 -22ZM633 218C484 218 385 340 385 529C385 717 484 840 633 840C776 840 869 727 869 529C869 331 776 218 633 218Z" transform="translate(1844.64 0)"/><path d="M399 1490H104V0H399Z" transform="translate(2996.96 0)"/><path d="M586 -24C842 -24 1046 122 1085 332H816C789 250 710 197 595 197C440 197 350 298 345 454H1096V533C1096 855 887 1080 576 1080C273 1080 58 849 58 527C58 206 266 -24 586 -24ZM347 642C363 774 450 856 582 856C715 856 803 774 818 642Z" transform="translate(3428.28 0)"/><path d="M711 1056H495V1344H200V1056H18V825H200V280C200 88 307 0 539 0H711V231H598C518 231 495 254 495 326V825H711Z" transform="translate(4506.6 0)"/></g><path d="M249.514296875 11C251.014296875 19.0 251.514296875 19.5 259.514296875 21C251.514296875 22.5 251.014296875 23.0 249.514296875 31C248.014296875 23.0 247.514296875 22.5 239.514296875 21C247.514296875 19.5 248.014296875 19.0 249.514296875 11Z" fill="url(#nb-magic)" /><g fill="#516277" transform="translate(88 85) scale(0.00537109 -0.00537109)"><path d="M645 0C1099 0 1356 282 1356 748C1356 1210 1099 1490 664 1490H180V0ZM370 168V1322H651C996 1322 1172 1106 1172 748C1172 386 996 168 633 168Z" transform="translate(0 0)"/><path d="M180 0H1097V168H370V668H1039V836H370V1322H1088V1490H180Z" transform="translate(1826.16 0)"/><path d="M657 -26C1001 -26 1198 162 1198 406C1198 684 936 774 776 818L627 859C518 889 343 944 343 1100C343 1240 471 1342 664 1342C841 1342 975 1259 992 1114H1178C1169 1339 964 1510 670 1510C382 1510 158 1343 158 1091C158 893 298 770 538 702L718 651C877 606 1013 553 1013 409C1013 250 859 144 657 144C482 144 326 221 311 390H116C133 140 334 -26 657 -26Z" transform="translate(3405.32 0)"/><path d="M370 1490H180V0H370Z" transform="translate(5067.48 0)"/><path d="M789 -20C1144 -20 1400 216 1400 586V749H828V583H1214C1209 321 1038 156 789 156C515 156 307 364 307 744C307 1127 516 1334 778 1334C989 1334 1132 1214 1193 1023H1389C1335 1312 1092 1510 777 1510C395 1510 122 1217 122 744C122 273 391 -20 789 -20Z" transform="translate(5965.64 0)"/><path d="M180 0H371V850C371 922 364 1071 356 1262C472 1055 529 955 597 848L1137 0H1363V1490H1173V576C1173 496 1174 369 1186 225C1118 360 1050 474 1010 537L404 1490H180Z" transform="translate(7841.8 0)"/><path d="M180 0H1097V168H370V668H1039V836H370V1322H1088V1490H180Z" transform="translate(9732.96 0)"/><path d="M180 0H370V578H691C703 578 714 578 726 579L1036 0H1256L922 613C1110 679 1198 832 1198 1030C1198 1296 1038 1490 690 1490H180ZM370 747V1323H680C917 1323 1009 1207 1009 1030C1009 855 917 747 682 747Z" transform="translate(11312.1 0)"/><path d="M180 0H361V851C361 966 357 1142 354 1284C413 1109 471 935 504 851L842 0H1007L1340 851C1374 938 1436 1117 1490 1287C1486 1132 1483 961 1483 851V0H1670V1490H1399L1037 550C1008 475 962 328 927 211C892 332 845 478 817 550L450 1490H180Z" transform="translate(13902.4 0)"/><path d="M783 -20C1088 -20 1332 166 1384 469H1194C1152 266 978 156 783 156C516 156 307 363 307 744C307 1126 515 1334 783 1334C977 1334 1152 1225 1194 1021H1384C1331 1328 1085 1510 783 1510C401 1510 122 1217 122 744C122 272 401 -20 783 -20Z" transform="translate(16100.6 0)"/><path d="M180 0H370V539H691C1038 539 1198 750 1198 1016C1198 1281 1038 1490 690 1490H180ZM370 706V1323H680C918 1323 1009 1192 1009 1016C1009 839 918 706 682 706Z" transform="translate(17944.8 0)"/><path d="M657 -26C1001 -26 1198 162 1198 406C1198 684 936 774 776 818L627 859C518 889 343 944 343 1100C343 1240 471 1342 664 1342C841 1342 975 1259 992 1114H1178C1169 1339 964 1510 670 1510C382 1510 158 1343 158 1091C158 893 298 770 538 702L718 651C877 606 1013 553 1013 409C1013 250 859 144 657 144C482 144 326 221 311 390H116C133 140 334 -26 657 -26Z" transform="translate(20525.1 0)"/><path d="M180 0H370V489L585 716L1094 0H1319L716 845L1318 1490H1069L624 1009C533 911 450 813 367 706L370 980V1490H180Z" transform="translate(22187.2 0)"/><path d="M370 1490H180V0H370Z" transform="translate(23911.4 0)"/><path d="M180 0H1060V168H370V1490H180Z" transform="translate(24809.6 0)"/><path d="M180 0H1060V168H370V1490H180Z" transform="translate(26315.7 0)"/></g></g>
|
|
20
|
+
</svg>
|
package/package.json
CHANGED
package/skill/niblet/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: niblet
|
|
|
3
3
|
description: Keep interface work anchored to the product it belongs to instead of a generic template. Sets a short design contract, builds from the components and tokens already in the codebase, covers the states a surface can actually reach, and closes by looking at the rendered result. Use when building, reworking, or assessing a web or native interface. Trigger with "niblet", "niblet skill", "niblet designer ui", or "niblet review". Skip backend, CLI, data, and infrastructure work, prose-only tasks, and questions the product's own design system already settles.
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.2.0"
|
|
7
7
|
author: "Mohamed Elkholy (elkaix)"
|
|
8
8
|
organization: "PyModel"
|
|
9
9
|
source: "https://github.com/PyModel/niblet-skill-mcp"
|
package/src/server.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
2
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
4
3
|
import { z } from 'zod';
|
|
4
|
+
import { SKILL_DOCS, parseCommands, parseModes, readSkillDoc, uriFor } from './skill.mjs';
|
|
5
|
+
// The advertised server version is the package version; nothing else to keep in step.
|
|
6
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
5
7
|
|
|
6
8
|
const DEFAULT_API_ORIGIN = 'https://api.niblet.com';
|
|
7
9
|
const DEFAULT_MEDIA_ORIGIN = 'https://media.niblet.com';
|
|
@@ -138,7 +140,9 @@ function listOf(data, key) {
|
|
|
138
140
|
}
|
|
139
141
|
|
|
140
142
|
/**
|
|
141
|
-
* Create a local stdio server
|
|
143
|
+
* Create a local stdio server. It exposes the hosted service's two catalogue tools with
|
|
144
|
+
* identical contracts, plus local-only helpers that read bundled files and need no token:
|
|
145
|
+
* niblet_help, niblet_status, and every skill document as a resource.
|
|
142
146
|
* Token, origins, and fetch injection are for embedding and tests; they never widen the
|
|
143
147
|
* destination allowlist beyond the configured API and media origins.
|
|
144
148
|
*/
|
|
@@ -152,8 +156,8 @@ export function createServer({
|
|
|
152
156
|
const MEDIA_ORIGINS = new Set([originOf(mediaOrigin, DEFAULT_MEDIA_ORIGIN), API_ORIGIN]);
|
|
153
157
|
|
|
154
158
|
const server = new McpServer(
|
|
155
|
-
{ name: 'niblet', version:
|
|
156
|
-
{ instructions: `Read niblet://skill for the Niblet design workflow. ${UNTRUSTED_DATA}
|
|
159
|
+
{ name: 'niblet', version: pkg.version, websiteUrl: 'https://niblet.com' },
|
|
160
|
+
{ instructions: `Read niblet://skill for the Niblet design workflow; its reference documents are served alongside it (niblet://skill/commands, /connection, /evidence, /native). Call niblet_help to list the surface modes and every design command, or when asked what Niblet can do; call niblet_status to diagnose the connection before concluding the catalogue is empty. ${UNTRUSTED_DATA} The two catalogue tools require NIBLET_TOKEN; the bundled skill, niblet_help, and niblet_status do not. This server only reads ${API_ORIGIN}/v1 and does not provide a remote UI review service.` },
|
|
157
161
|
);
|
|
158
162
|
|
|
159
163
|
function credentialError() {
|
|
@@ -328,17 +332,137 @@ export function createServer({
|
|
|
328
332
|
return textResult([MATERIAL_PREAMBLE, '', ...materials.map(materialText)].join('\n'));
|
|
329
333
|
});
|
|
330
334
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
335
|
+
// Every bundled document is served, not just SKILL.md: SKILL.md directs the agent
|
|
336
|
+
// to the command playbook, the evidence policy, and the native guidance, and over
|
|
337
|
+
// stdio those relative paths are unresolvable unless each one is also a resource.
|
|
338
|
+
for (const [slug, { title, description }] of Object.entries(SKILL_DOCS)) {
|
|
339
|
+
server.registerResource(slug === 'skill' ? 'niblet-skill' : `niblet-skill-${slug}`, uriFor(slug), {
|
|
340
|
+
title,
|
|
341
|
+
description,
|
|
342
|
+
mimeType: 'text/markdown',
|
|
343
|
+
}, async (uri) => {
|
|
344
|
+
const text = await readSkillDoc(slug);
|
|
345
|
+
if (text === null) throw new McpError(ErrorCode.InternalError, 'The bundled Niblet skill could not be read. Reinstall the package.');
|
|
338
346
|
return { contents: [{ uri: uri.href, mimeType: 'text/markdown', text }] };
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const localAnnotations = { ...annotations, openWorldHint: false };
|
|
351
|
+
|
|
352
|
+
server.registerTool('niblet_help', {
|
|
353
|
+
title: 'Niblet help',
|
|
354
|
+
description: 'List everything Niblet offers: the surface modes, every design command with its purpose, and the reference documents available as resources. Use when asked what Niblet can do, which command fits, or to present the choice menu before making changes.',
|
|
355
|
+
inputSchema: z.object({
|
|
356
|
+
command: z.string().min(1).max(64).optional().describe('A command name, to locate its section and full playbook entry.'),
|
|
357
|
+
}).strict(),
|
|
358
|
+
annotations: localAnnotations,
|
|
359
|
+
}, async (input) => {
|
|
360
|
+
let skillDoc;
|
|
361
|
+
let commandsDoc;
|
|
362
|
+
try {
|
|
363
|
+
[skillDoc, commandsDoc] = await Promise.all([readSkillDoc('skill'), readSkillDoc('commands')]);
|
|
339
364
|
} catch {
|
|
340
|
-
|
|
365
|
+
return errorResult('The bundled Niblet documents could not be read. Reinstall the package.');
|
|
366
|
+
}
|
|
367
|
+
const sections = parseCommands(commandsDoc ?? '');
|
|
368
|
+
const all = sections.flatMap((s) => s.commands.map((c) => ({ ...c, section: s.section })));
|
|
369
|
+
|
|
370
|
+
if (input.command) {
|
|
371
|
+
const wanted = input.command.trim().toLowerCase().replace(/^\//, '');
|
|
372
|
+
const match = all.find((c) => c.names.some((n) => n.toLowerCase() === wanted));
|
|
373
|
+
if (!match) {
|
|
374
|
+
return textResult([
|
|
375
|
+
`No Niblet command named "${input.command}".`,
|
|
376
|
+
`Available: ${all.flatMap((c) => c.names).join(', ')}.`,
|
|
377
|
+
`Full playbook: ${uriFor('commands')}`,
|
|
378
|
+
].join('\n'));
|
|
379
|
+
}
|
|
380
|
+
return textResult([
|
|
381
|
+
`${match.names.map((n) => `\`${n}\``).join(' / ')} — ${match.purpose}`,
|
|
382
|
+
`Section: ${match.section}.`,
|
|
383
|
+
'',
|
|
384
|
+
`Read ${uriFor('commands')} for the full entry, and ${uriFor('skill')} for the design contract and finish gate every implementation command applies.`,
|
|
385
|
+
].join('\n'));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// A compact index rather than the whole playbook: SKILL.md's routing rule asks for
|
|
389
|
+
// a short menu and a choice, not a wall of text.
|
|
390
|
+
const modes = parseModes(skillDoc ?? '');
|
|
391
|
+
const lines = ['Niblet keeps interface work anchored to the product it belongs to. Pick a mode and a command, then work under a design contract.'];
|
|
392
|
+
if (modes.length) {
|
|
393
|
+
lines.push('', 'Surface modes — choose by the job of the surface:');
|
|
394
|
+
for (const m of modes) lines.push(` ${m.mode} — ${m.job} (${m.surfaces})`);
|
|
395
|
+
}
|
|
396
|
+
for (const section of sections) {
|
|
397
|
+
lines.push('', `${section.section}:`);
|
|
398
|
+
for (const c of section.commands) lines.push(` ${c.names.join(' / ')} — ${c.purpose}`);
|
|
399
|
+
}
|
|
400
|
+
lines.push('', 'Reference documents (read as MCP resources):');
|
|
401
|
+
for (const [slug, doc] of Object.entries(SKILL_DOCS)) lines.push(` ${uriFor(slug)} — ${doc.title}`);
|
|
402
|
+
lines.push('', 'Catalogue tools: find_ui_references (real full-screen references), find_ui_materials (license-recorded fonts and icons). Both need NIBLET_TOKEN; run niblet_status to check. Reference retrieval is optional and never a prerequisite to useful work.');
|
|
403
|
+
lines.push('With no target or command, present this menu and wait for a choice rather than making changes.');
|
|
404
|
+
return textResult(lines.join('\n'));
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
server.registerTool('niblet_status', {
|
|
408
|
+
title: 'Niblet status',
|
|
409
|
+
description: 'Diagnose this Niblet connection: configured origins, whether a usable token is present, the bundled documents, and whether the catalogue API actually answers. Use before concluding that the catalogue is empty or broken.',
|
|
410
|
+
inputSchema: z.object({
|
|
411
|
+
probe: z.boolean().default(true).describe('Contact the configured API to confirm it answers. Set false to report configuration only.'),
|
|
412
|
+
}).strict(),
|
|
413
|
+
// The probe is the reported result, so this one does reach the configured origin.
|
|
414
|
+
annotations,
|
|
415
|
+
}, async (input, extra) => {
|
|
416
|
+
const lines = ['Niblet MCP status.', '', `API origin: ${API_ORIGIN}`, `Media origins: ${[...MEDIA_ORIGINS].join(', ')}`];
|
|
417
|
+
|
|
418
|
+
// Presence and shape only — the playbook's doctor entry requires never displaying it.
|
|
419
|
+
const credential = credentialError();
|
|
420
|
+
if (typeof token !== 'string' || token.trim() === '') lines.push('Token: not configured. Set NIBLET_TOKEN in the MCP server environment.');
|
|
421
|
+
else if (credential) lines.push('Token: present but malformed for a bearer credential. Check NIBLET_TOKEN.');
|
|
422
|
+
else lines.push(`Token: present (${token.trim().length} characters, not shown).`);
|
|
423
|
+
|
|
424
|
+
const docs = await Promise.all(Object.keys(SKILL_DOCS).map(async (slug) => {
|
|
425
|
+
try {
|
|
426
|
+
return (await readSkillDoc(slug)) ? slug : null;
|
|
427
|
+
} catch {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
}));
|
|
431
|
+
const readable = docs.filter(Boolean);
|
|
432
|
+
lines.push(`Documents: ${readable.length}/${Object.keys(SKILL_DOCS).length} readable (${readable.map(uriFor).join(', ')}).`);
|
|
433
|
+
lines.push('Tools: find_ui_references, find_ui_materials, niblet_help, niblet_status.');
|
|
434
|
+
|
|
435
|
+
if (!input.probe) {
|
|
436
|
+
lines.push('', 'API not contacted (probe disabled).');
|
|
437
|
+
return textResult(lines.join('\n'));
|
|
438
|
+
}
|
|
439
|
+
if (credential) {
|
|
440
|
+
lines.push('', 'API not contacted: no usable token. The bundled documents and niblet_help remain available without one.');
|
|
441
|
+
return textResult(lines.join('\n'));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const result = await requestJson(['stats'], {}, extra.signal);
|
|
445
|
+
if (!result.ok) {
|
|
446
|
+
// Any HTTP status means the origin answered, which is what reachability asks.
|
|
447
|
+
// /v1/stats is not part of the hosted contract, so a 404 is a normal answer
|
|
448
|
+
// from a healthy deployment, not a failure.
|
|
449
|
+
if (result.status === 404) {
|
|
450
|
+
lines.push('', 'API check: reachable — the configured origin answered. It does not serve catalogue counts; use find_ui_references to confirm the catalogue itself.');
|
|
451
|
+
return textResult(lines.join('\n'));
|
|
452
|
+
}
|
|
453
|
+
if (result.status !== undefined) {
|
|
454
|
+
lines.push('', `API check: reachable, but the request was rejected — ${result.message}`);
|
|
455
|
+
return textResult(lines.join('\n'));
|
|
456
|
+
}
|
|
457
|
+
lines.push('', `API check: FAILED — ${result.message}`);
|
|
458
|
+
lines.push(`Check that the configured origin is correct and that the service is actually running, then read the connection guide at ${uriFor('connection')}.`);
|
|
459
|
+
return textResult(lines.join('\n'));
|
|
341
460
|
}
|
|
461
|
+
const counts = ['apps', 'screens', 'captioned', 'journeys']
|
|
462
|
+
.map((key) => (typeof result.data[key] === 'number' ? `${key} ${result.data[key]}` : null))
|
|
463
|
+
.filter(Boolean);
|
|
464
|
+
lines.push('', `API check: OK${counts.length ? ` — catalogue holds ${counts.join(', ')}.` : '.'}`);
|
|
465
|
+
return textResult(lines.join('\n'));
|
|
342
466
|
});
|
|
343
467
|
|
|
344
468
|
return server;
|
package/src/skill.mjs
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundled-skill access: reading the documents, making their cross-links usable
|
|
3
|
+
* over MCP, and deriving the command index from them.
|
|
4
|
+
*
|
|
5
|
+
* The same files are also loaded directly as a filesystem skill, where the
|
|
6
|
+
* relative links between them are correct. They are only wrong for a client that
|
|
7
|
+
* reads them over stdio and has no access to the package directory, so the
|
|
8
|
+
* rewrite happens on the way out rather than in the files themselves.
|
|
9
|
+
*/
|
|
10
|
+
import { readFile } from 'node:fs/promises';
|
|
11
|
+
|
|
12
|
+
/** slug -> { file, title, description }. `skill` is SKILL.md; the rest are its references. */
|
|
13
|
+
export const SKILL_DOCS = {
|
|
14
|
+
skill: {
|
|
15
|
+
file: 'SKILL.md',
|
|
16
|
+
title: 'Niblet design skill',
|
|
17
|
+
description: 'The bundled Niblet design workflow: modes, design contract, state coverage, and the rendered finish gate. Available without an API token.',
|
|
18
|
+
},
|
|
19
|
+
commands: {
|
|
20
|
+
file: 'references/commands.md',
|
|
21
|
+
title: 'Niblet command playbook',
|
|
22
|
+
description: 'Every Niblet command — what it does, its scope, and what completion means. Referenced by the design workflow.',
|
|
23
|
+
},
|
|
24
|
+
connection: {
|
|
25
|
+
file: 'references/connection.md',
|
|
26
|
+
title: 'Niblet connection guide',
|
|
27
|
+
description: 'Installing and invoking the MCP tools, diagnosing a connection, and the limits of host-dependent helpers.',
|
|
28
|
+
},
|
|
29
|
+
evidence: {
|
|
30
|
+
file: 'references/evidence.md',
|
|
31
|
+
title: 'Niblet evidence policy',
|
|
32
|
+
description: 'When to retrieve an external reference, and how to use one without copying it.',
|
|
33
|
+
},
|
|
34
|
+
native: {
|
|
35
|
+
file: 'references/native.md',
|
|
36
|
+
title: 'Niblet native platform guidance',
|
|
37
|
+
description: 'Platform constraints and the native finish-gate batch for iOS and other native work.',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const uriFor = (slug) => (slug === 'skill' ? 'niblet://skill' : `niblet://skill/${slug}`);
|
|
42
|
+
|
|
43
|
+
/** Relative markdown targets in the bundled docs -> the resource URI serving the same document. */
|
|
44
|
+
const LINK_REWRITES = [
|
|
45
|
+
[/\]\(\.\.\/SKILL\.md\)/g, `](${uriFor('skill')})`],
|
|
46
|
+
[/\]\(SKILL\.md\)/g, `](${uriFor('skill')})`],
|
|
47
|
+
...Object.entries(SKILL_DOCS)
|
|
48
|
+
.filter(([slug]) => slug !== 'skill')
|
|
49
|
+
.flatMap(([slug]) => [
|
|
50
|
+
[new RegExp(`\\]\\(references/${slug}\\.md\\)`, 'g'), `](${uriFor(slug)})`],
|
|
51
|
+
[new RegExp(`\\]\\(${slug}\\.md\\)`, 'g'), `](${uriFor(slug)})`],
|
|
52
|
+
]),
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Point a document's cross-links at the resources that serve them. Without this a
|
|
57
|
+
* client that reads niblet://skill is told to open `references/commands.md`, a path
|
|
58
|
+
* it has no way to resolve.
|
|
59
|
+
*/
|
|
60
|
+
export function rewriteLinks(text) {
|
|
61
|
+
return LINK_REWRITES.reduce((acc, [pattern, replacement]) => acc.replace(pattern, replacement), text);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function readSkillDoc(slug) {
|
|
65
|
+
const entry = SKILL_DOCS[slug];
|
|
66
|
+
if (!entry) return null;
|
|
67
|
+
const text = await readFile(new URL(`../skill/niblet/${entry.file}`, import.meta.url), 'utf8');
|
|
68
|
+
return rewriteLinks(text);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The command index, derived from commands.md so it cannot drift from the playbook.
|
|
73
|
+
* Headings are `## Section` and ``### `name` — purpose``.
|
|
74
|
+
*/
|
|
75
|
+
export function parseCommands(markdown) {
|
|
76
|
+
const sections = [];
|
|
77
|
+
let current = null;
|
|
78
|
+
for (const line of markdown.split('\n')) {
|
|
79
|
+
const section = /^##\s+(?!#)(.+?)\s*$/.exec(line);
|
|
80
|
+
if (section) {
|
|
81
|
+
current = { section: section[1], commands: [] };
|
|
82
|
+
sections.push(current);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const command = /^###\s+(.+?)\s+—\s+(.+?)\s*$/.exec(line);
|
|
86
|
+
if (command && current) {
|
|
87
|
+
// Names arrive as `polish`, or `pin` / `unpin` for a paired helper.
|
|
88
|
+
const names = [...command[1].matchAll(/`([^`]+)`/g)].map((m) => m[1]);
|
|
89
|
+
if (names.length) current.commands.push({ names, purpose: command[2] });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return sections.filter((s) => s.commands.length);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** The four surface modes, from the table in SKILL.md, for the same no-drift reason. */
|
|
96
|
+
export function parseModes(markdown) {
|
|
97
|
+
const modes = [];
|
|
98
|
+
for (const line of markdown.split('\n')) {
|
|
99
|
+
const row = /^\|\s*\*\*(.+?)\*\*\s*\|\s*(.+?)\s*\|\s*(.+?)\s*\|\s*(.+?)\s*\|\s*$/.exec(line);
|
|
100
|
+
if (row) modes.push({ mode: row[1], job: row[2], surfaces: row[4] });
|
|
101
|
+
}
|
|
102
|
+
return modes;
|
|
103
|
+
}
|
package/assets/niblet-banner.svg
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="1500" height="500" viewBox="0 0 1500 500" role="img" aria-labelledby="nb-title nb-desc">
|
|
3
|
-
<title id="nb-title">Niblet wide profile banner</title><desc id="nb-desc">Editable native SVG artwork. No embedded raster images.</desc>
|
|
4
|
-
<defs>
|
|
5
|
-
<linearGradient id="nb-hat" x1="0" y1="0.65" x2="0.9" y2="0.15" gradientUnits="objectBoundingBox"><stop stop-color="#115999"/><stop offset="0.46" stop-color="#1796B1"/><stop offset="0.8" stop-color="#25CBBB"/><stop offset="1" stop-color="#89F3D8"/></linearGradient>
|
|
6
|
-
<linearGradient id="nb-hat-fold" x1="0" y1="0.2" x2="1" y2="0.8"><stop stop-color="#0C5E8D"/><stop offset="0.62" stop-color="#117B90"/><stop offset="1" stop-color="#00A59F"/></linearGradient>
|
|
7
|
-
<linearGradient id="nb-brim" x1="0" y1="1" x2="1" y2="0"><stop stop-color="#2278D3"/><stop offset="0.5" stop-color="#28AADA"/><stop offset="1" stop-color="#67EAD0"/></linearGradient>
|
|
8
|
-
<radialGradient id="nb-face" cx="45%" cy="35%" r="70%"><stop stop-color="#FFF1CF"/><stop offset="0.65" stop-color="#FFDFBA"/><stop offset="1" stop-color="#F4AF91"/></radialGradient>
|
|
9
|
-
<linearGradient id="nb-ear" x1="0" y1="0" x2="0.8" y2="1"><stop stop-color="#FFD7B5"/><stop offset="1" stop-color="#F2A185"/></linearGradient>
|
|
10
|
-
<linearGradient id="nb-ear-inner" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#E98072"/><stop offset="1" stop-color="#F6B797"/></linearGradient>
|
|
11
|
-
<radialGradient id="nb-orb" cx="30%" cy="23%" r="80%"><stop stop-color="#ABFFEC"/><stop offset="0.4" stop-color="#16D7C5"/><stop offset="1" stop-color="#078899"/></radialGradient>
|
|
12
|
-
<linearGradient id="nb-cloak" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#169EAF"/><stop offset="0.5" stop-color="#08718D"/><stop offset="1" stop-color="#0A344F"/></linearGradient>
|
|
13
|
-
<linearGradient id="nb-app" x1="0" y1="1" x2="0.9" y2="0"><stop stop-color="#7360FF"/><stop offset="0.44" stop-color="#2E8BFF"/><stop offset="1" stop-color="#08DBC2"/></linearGradient>
|
|
14
|
-
<linearGradient id="nb-magic" x1="0" y1="1" x2="1" y2="0"><stop stop-color="#8B5CF6"/><stop offset="0.55" stop-color="#2E8BFF"/><stop offset="1" stop-color="#00D1B2"/></linearGradient>
|
|
15
|
-
<linearGradient id="nb-soft" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#EEF5FF"/><stop offset="0.6" stop-color="#F7F4FF"/><stop offset="1" stop-color="#E8FAF8"/></linearGradient>
|
|
16
|
-
<linearGradient id="nb-dark-surface" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#142A42"/><stop offset="1" stop-color="#0A1628"/></linearGradient>
|
|
17
|
-
<radialGradient id="nb-halo"><stop stop-color="#A8EEE7" stop-opacity="0.55"/><stop offset="1" stop-color="#DFEFFE" stop-opacity="0"/></radialGradient>
|
|
18
|
-
</defs>
|
|
19
|
-
<rect x="0" y="0" width="1500" height="500" rx="0" fill="#0A1628" /><circle cx="1130" cy="263" r="420" fill="url(#nb-halo)" /><g transform="translate(78 64) scale(0.77)" ><g transform="translate(-5 -8) scale(0.17)" ><g id="mascot-cloak"><path d="M170 359C187 378 220 389 255 388C288 389 322 378 343 360L349 400L310 426L299 464L268 454L239 466L218 454L186 459L183 423L153 401Z" fill="url(#nb-cloak)" /><path d="M169 382Q244 432 335 384L320 411Q242 447 177 407Z" fill="#084E67" /><path d="M188 427L238 445L212 453L188 449Z" fill="#20A9B1" /><path d="M268 426L288 460L264 449L242 460L244 441Z" fill="#0D405E" /></g><g id="mascot-ears"><path d="M153 282C126 264 98 251 59 248C65 285 91 320 127 334L161 316Z" fill="url(#nb-ear)" /><path d="M350 277C377 248 404 232 448 221C441 267 418 306 380 326L350 311Z" fill="url(#nb-ear)" /><path d="M137 292Q115 273 79 264Q94 295 132 314Z" fill="url(#nb-ear-inner)" /><path d="M371 285Q395 255 429 240Q417 281 382 307Z" fill="url(#nb-ear-inner)" /></g><g id="mascot-hood"><path d="M118 276C127 219 151 166 183 112C217 55 258 29 303 44C344 58 365 87 386 109C359 101 337 112 325 137C331 177 361 210 367 248C392 276 391 320 368 353C345 390 304 407 252 407C191 405 149 388 126 353C109 327 108 299 118 276Z" fill="url(#nb-hat)" /><path d="M183 113C216 65 253 35 295 52C250 57 222 100 217 139C207 178 225 207 234 228L136 260C143 216 160 166 183 113Z" fill="#72E5D4" opacity="0.18"/><path d="M284 59C328 61 358 89 384 109C358 100 337 113 325 138C325 167 348 203 359 228C319 209 292 170 282 129C275 98 277 77 284 59Z" fill="url(#nb-hat-fold)" /><path d="M179 117C205 75 234 52 263 47" fill="none" stroke="#C2FFF0" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.66"/><path d="M135 256C197 224 296 222 362 255" fill="none" stroke="#076E91" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" /></g><g id="mascot-face"><path d="M137 290C153 265 189 252 245 251C301 247 340 260 362 288L365 325C361 371 315 397 253 397C192 397 146 375 139 337Z" fill="url(#nb-face)" /></g><g id="mascot-hatband"><path d="M120 279C142 245 181 228 239 224C292 219 336 231 364 252L369 289C333 261 293 251 245 255C191 256 150 273 131 308Z" fill="url(#nb-brim)" /><path d="M136 276C166 248 207 238 251 236C295 235 330 245 351 260" fill="none" stroke="#A5FBE8" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.65"/><path d="M225 254L242 268L257 252Z" fill="#19C6B8" /></g><g id="mascot-expression"><ellipse cx="203" cy="312" rx="12" ry="19" fill="#0A1628"/><ellipse cx="295" cy="312" rx="12" ry="19" fill="#0A1628"/><circle cx="200" cy="305" r="4.1" fill="#FFFFFF" /><circle cx="292" cy="305" r="4.1" fill="#FFFFFF" /><path d="M187 280Q199 271 211 279M285 278Q297 268 309 278" fill="none" stroke="#0A1628" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M232 343Q252 362 274 340" fill="none" stroke="#0A1628" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round" /><ellipse cx="178" cy="343" rx="17" ry="10" fill="#F58E85" opacity="0.38"/><ellipse cx="321" cy="341" rx="17" ry="10" fill="#F58E85" opacity="0.38"/><path d="M250 322Q256 328 250 330" fill="none" stroke="#ECA58E" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" /></g><g id="mascot-hat-orb"><path d="M382 108Q392 111 394 121" fill="none" stroke="#148E9D" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" /><circle cx="395" cy="126" r="18" fill="url(#nb-orb)" /><path d="M385 117Q392 110 402 116" fill="none" stroke="#D1FFF5" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.8"/></g></g><g fill="#FFFFFF" transform="translate(85 57) scale(0.0288086 -0.0288086)"><path d="M111 0H419V691C419 755 418 882 412 1038C496 887 572 758 615 690L1049 0H1374V1490H1067V753C1067 690 1068 567 1072 452C1013 559 949 672 914 728L435 1490H111Z" transform="translate(0 0)"/><path d="M104 0H399V1056H104ZM251 1189C348 1189 419 1256 419 1346C419 1436 348 1503 251 1503C154 1503 83 1436 83 1346C83 1256 154 1189 251 1189Z" transform="translate(1413.32 0)"/><path d="M709 -22C985 -22 1166 198 1166 529C1166 853 981 1078 711 1078C574 1078 468 1024 400 910H399V1490H104V0H395V162H396C457 39 570 -22 709 -22ZM633 218C484 218 385 340 385 529C385 717 484 840 633 840C776 840 869 727 869 529C869 331 776 218 633 218Z" transform="translate(1844.64 0)"/><path d="M399 1490H104V0H399Z" transform="translate(2996.96 0)"/><path d="M586 -24C842 -24 1046 122 1085 332H816C789 250 710 197 595 197C440 197 350 298 345 454H1096V533C1096 855 887 1080 576 1080C273 1080 58 849 58 527C58 206 266 -24 586 -24ZM347 642C363 774 450 856 582 856C715 856 803 774 818 642Z" transform="translate(3428.28 0)"/><path d="M711 1056H495V1344H200V1056H18V825H200V280C200 88 307 0 539 0H711V231H598C518 231 495 254 495 326V825H711Z" transform="translate(4506.6 0)"/></g><path d="M249.514296875 11C251.014296875 19.0 251.514296875 19.5 259.514296875 21C251.514296875 22.5 251.014296875 23.0 249.514296875 31C248.014296875 23.0 247.514296875 22.5 239.514296875 21C247.514296875 19.5 248.014296875 19.0 249.514296875 11Z" fill="url(#nb-magic)" /></g><text x="77" y="263" font-family="Inter, Arial, sans-serif" font-size="70" font-weight="750" fill="#FFFFFF" text-anchor="start" letter-spacing="-2" >Design anything.</text><text x="77" y="345" font-family="Inter, Arial, sans-serif" font-size="70" font-weight="750" fill="#75B7FF" text-anchor="start" letter-spacing="-2" >With a little magic.</text><text x="81" y="428" font-family="Inter, Arial, sans-serif" font-size="15" font-weight="550" fill="#B1C4DA" text-anchor="start" letter-spacing="1.2" >UI / ICONS / ILLUSTRATIONS / BRAND ASSETS</text><g transform="translate(985 7) scale(0.94)" ><g id="mascot-cloak--instance-2"><path d="M170 359C187 378 220 389 255 388C288 389 322 378 343 360L349 400L310 426L299 464L268 454L239 466L218 454L186 459L183 423L153 401Z" fill="url(#nb-cloak)" /><path d="M169 382Q244 432 335 384L320 411Q242 447 177 407Z" fill="#084E67" /><path d="M188 427L238 445L212 453L188 449Z" fill="#20A9B1" /><path d="M268 426L288 460L264 449L242 460L244 441Z" fill="#0D405E" /></g><g id="mascot-ears--instance-2"><path d="M153 282C126 264 98 251 59 248C65 285 91 320 127 334L161 316Z" fill="url(#nb-ear)" /><path d="M350 277C377 248 404 232 448 221C441 267 418 306 380 326L350 311Z" fill="url(#nb-ear)" /><path d="M137 292Q115 273 79 264Q94 295 132 314Z" fill="url(#nb-ear-inner)" /><path d="M371 285Q395 255 429 240Q417 281 382 307Z" fill="url(#nb-ear-inner)" /></g><g id="mascot-hood--instance-2"><path d="M118 276C127 219 151 166 183 112C217 55 258 29 303 44C344 58 365 87 386 109C359 101 337 112 325 137C331 177 361 210 367 248C392 276 391 320 368 353C345 390 304 407 252 407C191 405 149 388 126 353C109 327 108 299 118 276Z" fill="url(#nb-hat)" /><path d="M183 113C216 65 253 35 295 52C250 57 222 100 217 139C207 178 225 207 234 228L136 260C143 216 160 166 183 113Z" fill="#72E5D4" opacity="0.18"/><path d="M284 59C328 61 358 89 384 109C358 100 337 113 325 138C325 167 348 203 359 228C319 209 292 170 282 129C275 98 277 77 284 59Z" fill="url(#nb-hat-fold)" /><path d="M179 117C205 75 234 52 263 47" fill="none" stroke="#C2FFF0" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.66"/><path d="M135 256C197 224 296 222 362 255" fill="none" stroke="#076E91" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" /></g><g id="mascot-face--instance-2"><path d="M137 290C153 265 189 252 245 251C301 247 340 260 362 288L365 325C361 371 315 397 253 397C192 397 146 375 139 337Z" fill="url(#nb-face)" /></g><g id="mascot-hatband--instance-2"><path d="M120 279C142 245 181 228 239 224C292 219 336 231 364 252L369 289C333 261 293 251 245 255C191 256 150 273 131 308Z" fill="url(#nb-brim)" /><path d="M136 276C166 248 207 238 251 236C295 235 330 245 351 260" fill="none" stroke="#A5FBE8" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.65"/><path d="M225 254L242 268L257 252Z" fill="#19C6B8" /></g><g id="mascot-expression--instance-2"><ellipse cx="203" cy="312" rx="12" ry="19" fill="#0A1628"/><ellipse cx="295" cy="312" rx="12" ry="19" fill="#0A1628"/><circle cx="200" cy="305" r="4.1" fill="#FFFFFF" /><circle cx="292" cy="305" r="4.1" fill="#FFFFFF" /><path d="M187 280Q199 271 211 279M285 278Q297 268 309 278" fill="none" stroke="#0A1628" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round" /><path d="M232 343Q252 362 274 340" fill="none" stroke="#0A1628" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round" /><ellipse cx="178" cy="343" rx="17" ry="10" fill="#F58E85" opacity="0.38"/><ellipse cx="321" cy="341" rx="17" ry="10" fill="#F58E85" opacity="0.38"/><path d="M250 322Q256 328 250 330" fill="none" stroke="#ECA58E" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" /></g><g id="mascot-hat-orb--instance-2"><path d="M382 108Q392 111 394 121" fill="none" stroke="#148E9D" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" /><circle cx="395" cy="126" r="18" fill="url(#nb-orb)" /><path d="M385 117Q392 110 402 116" fill="none" stroke="#D1FFF5" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" opacity="0.8"/></g><g id="mascot-magic"><path d="M85 165C87.1 176.2 87.8 176.9 99 179C87.8 181.1 87.1 181.8 85 193C82.9 181.8 82.2 181.1 71 179C82.2 176.9 82.9 176.2 85 165Z" fill="#F4B400" /><path d="M431 343C433.55 356.6 434.4 357.45 448 360C434.4 362.55 433.55 363.4 431 377C428.45 363.4 427.6 362.55 414 360C427.6 357.45 428.45 356.6 431 343Z" fill="#2E8BFF" /><path d="M390 188C391.2 194.4 391.6 194.8 398 196C391.6 197.2 391.2 197.6 390 204C388.8 197.6 388.4 197.2 382 196C388.4 194.8 388.8 194.4 390 188Z" fill="#00D1B2" /><circle cx="94" cy="380" r="3.5" fill="#00D1B2" /></g></g>
|
|
20
|
-
</svg>
|