sheleg-design-skill 1.54.0 → 1.54.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.
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,61 @@ follow [SemVer](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.54.1] - 2026-08-29
|
|
10
|
+
|
|
11
|
+
### The installer refuses the shadow it documents
|
|
12
|
+
|
|
13
|
+
Both installers write a plain skill copy on request, and on a machine where
|
|
14
|
+
`sheleg-design` is installed as a Claude Code plugin, a write to that home's
|
|
15
|
+
`~/.claude/skills/sheleg-design` is a copy that shadows the plugin and serves
|
|
16
|
+
this frozen version forever. Neither installer checked the plugin channel at
|
|
17
|
+
all, and CI tested a fresh HOME only, so the plugin-present case had never run
|
|
18
|
+
anywhere. Canon: make-skill v0.25.0, `references/distribution.md` §"The
|
|
19
|
+
installer must refuse the shadow it documents"; family audit SHD-07/UM-03.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `bin/cli.js` and `install.sh` now consult the **target home's**
|
|
24
|
+
`~/.claude/plugins/installed_plugins.json` before any write to that home's
|
|
25
|
+
`~/.claude/skills/sheleg-design`, and refuse with **exit 3** when the plugin
|
|
26
|
+
channel owns the skill. The refusal names the real spec read from the JSON
|
|
27
|
+
(`sheleg-design@<marketplace>` — the marketplace name differs from the
|
|
28
|
+
plugin name here, and a remedy that guesses it sends the operator to a
|
|
29
|
+
marketplace that does not exist), prints the plugin-channel remedy
|
|
30
|
+
(`claude plugin marketplace update` + `claude plugin update <spec>`, plus
|
|
31
|
+
the family launcher line), and offers `--force` as the deliberate override.
|
|
32
|
+
The `plugins/marketplaces/` directory is read only as the fallback signal —
|
|
33
|
+
it under-reports (a `directory`-sourced marketplace has no dir there), which
|
|
34
|
+
is the fail-open class the canon names. A missing or unparsable JSON reads
|
|
35
|
+
as "no plugin": fail open, never crash. Only the Claude Code channel is
|
|
36
|
+
gated — `.cursor/` and every other agent's install are untouched, and a
|
|
37
|
+
project-level `.claude/` falls open naturally because a project holds no
|
|
38
|
+
plugin registry.
|
|
39
|
+
- `install.sh` accepts `--force` (the override for the gate above) and refuses
|
|
40
|
+
unknown flags with exit 2 instead of treating them as a target directory.
|
|
41
|
+
- `test/installer_test.js` — thirteen cases against throwaway HOMEs, wired
|
|
42
|
+
into `npm test` and CI: plugin-present (exit 3 + remedy + nothing written,
|
|
43
|
+
all three asserted), the differently-named marketplace spec carried into the
|
|
44
|
+
remedy, `--force` installing, corrupt JSON installing, a prefix-collider
|
|
45
|
+
(`sheleg-design-extra@x`) not falsely refused, marketplaces-dir-only still
|
|
46
|
+
refusing, fresh HOME still installing, the `.cursor` channel untouched by
|
|
47
|
+
the gate, and the install.sh mirrors of the same. Watched failing first: run
|
|
48
|
+
against the pre-fix installers, 7 cases red.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- Both installers now end a successful install by saying how the next version
|
|
53
|
+
arrives (`npx sheleg-design-skill@latest --force`, or the family launcher) —
|
|
54
|
+
an installer that never mentions updates has still chosen an update model:
|
|
55
|
+
never.
|
|
56
|
+
- `bin/cli.js --help` documents the exit-code contract, including the new
|
|
57
|
+
exit 3.
|
|
58
|
+
- CONTRIBUTING: release tags must be **annotated** (`git tag -a`) — v1.53.0
|
|
59
|
+
and v1.54.0 were lightweight, and `git submodule status` describes a pinned
|
|
60
|
+
commit with `git describe`, which ignores lightweight tags, so the family
|
|
61
|
+
umbrella misreported the member's version (SHD-07/UM-03). Applies from this
|
|
62
|
+
release forward; the old tags are not re-cut.
|
|
63
|
+
|
|
9
64
|
## [1.54.0] - 2026-08-29
|
|
10
65
|
|
|
11
66
|
### The thirty-eighth pack — the terrain is mapped
|
package/bin/cli.js
CHANGED
|
@@ -225,6 +225,13 @@ ${c("bold", "Default")}
|
|
|
225
225
|
Auto-detects: uses .cursor/ if present, else .claude/ if present,
|
|
226
226
|
otherwise creates .cursor/skills/${SKILL_SLUG}/.
|
|
227
227
|
|
|
228
|
+
${c("bold", "Exit codes")}
|
|
229
|
+
0 installed or skipped 2 usage error
|
|
230
|
+
1 packaging bug, or 3 refused: the sheleg-design PLUGIN is installed
|
|
231
|
+
overwrite refused in the target home — a plain copy in
|
|
232
|
+
~/.claude/skills would shadow it and serve this
|
|
233
|
+
frozen version forever (--force overrides)
|
|
234
|
+
|
|
228
235
|
${c("bold", "What it installs")}
|
|
229
236
|
SKILL.md the agent-facing skill (discovery + principles)
|
|
230
237
|
SHELEG_DESIGN.md the full reference (architecture, recipes, why it works)
|
|
@@ -328,6 +335,112 @@ function resolveTargetDir(opts, cwd) {
|
|
|
328
335
|
return path.join(cwd, ".cursor", "skills", SKILL_SLUG);
|
|
329
336
|
}
|
|
330
337
|
|
|
338
|
+
// Exit codes are the contract: 0 installed or skipped, 1 packaging bug or
|
|
339
|
+
// overwrite refusal, 2 usage error, 3 refused — the plugin channel owns the
|
|
340
|
+
// target home's Claude Code install (--force overrides).
|
|
341
|
+
const EXIT_PLUGIN_PRESENT = 3;
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* The home whose Claude Code channel this write would land in, or null.
|
|
345
|
+
*
|
|
346
|
+
* Only the Claude Code channel is gated: a write to `<H>/.claude/skills/
|
|
347
|
+
* sheleg-design` is the shape that can shadow a plugin installed in `<H>`.
|
|
348
|
+
* `.cursor/` and every other agent's skill directory have no plugin channel,
|
|
349
|
+
* so installs there are untouched by the check. A project-level `.claude/`
|
|
350
|
+
* matches this shape too, and falls open naturally: a project holds no
|
|
351
|
+
* `plugins/installed_plugins.json`, so the gate reads "no plugin" and the
|
|
352
|
+
* install proceeds.
|
|
353
|
+
*/
|
|
354
|
+
function claudeHomeOf(targetDir) {
|
|
355
|
+
const parts = path.resolve(targetDir).split(path.sep);
|
|
356
|
+
const tail = parts.slice(-3).join("/");
|
|
357
|
+
if (tail !== `.claude/skills/${SKILL_SLUG}`) return null;
|
|
358
|
+
return parts.slice(0, -3).join(path.sep) || path.sep;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* The plugin spec (`<name>@<marketplace>`) installed for sheleg-design in
|
|
363
|
+
* this home, or null.
|
|
364
|
+
*
|
|
365
|
+
* `installed_plugins.json` is the record of what is actually installed. The
|
|
366
|
+
* `plugins/marketplaces/<name>` directory under-reports: a marketplace added
|
|
367
|
+
* from a local `directory` source has no dir there at all, and plugin names
|
|
368
|
+
* differ from marketplace names — this very plugin is `sheleg-design` shipped
|
|
369
|
+
* from the `sheleg-design-skill` marketplace — so a check keyed on the dir
|
|
370
|
+
* alone stays green while the shadow lands. Absence and corruption both read
|
|
371
|
+
* as "no plugin": the fresh HOME is the common case, and an installer that
|
|
372
|
+
* crashes on a parse error refuses the machines that need it most.
|
|
373
|
+
*/
|
|
374
|
+
function installedPluginSpec(home) {
|
|
375
|
+
try {
|
|
376
|
+
const raw = fs.readFileSync(
|
|
377
|
+
path.join(home, ".claude", "plugins", "installed_plugins.json"),
|
|
378
|
+
"utf8",
|
|
379
|
+
);
|
|
380
|
+
const parsed = JSON.parse(raw);
|
|
381
|
+
const plugins =
|
|
382
|
+
parsed &&
|
|
383
|
+
typeof parsed === "object" &&
|
|
384
|
+
parsed.plugins &&
|
|
385
|
+
typeof parsed.plugins === "object"
|
|
386
|
+
? parsed.plugins
|
|
387
|
+
: parsed;
|
|
388
|
+
if (!plugins || typeof plugins !== "object") return null;
|
|
389
|
+
for (const spec of Object.keys(plugins)) {
|
|
390
|
+
if (spec === SKILL_SLUG) return `${SKILL_SLUG}@${SKILL_SLUG}`;
|
|
391
|
+
if (spec.startsWith(SKILL_SLUG + "@")) return spec;
|
|
392
|
+
}
|
|
393
|
+
} catch {
|
|
394
|
+
// missing or corrupt = no plugin — fail open on absence, never crash
|
|
395
|
+
}
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* One channel per agent. A plain `<H>/.claude/skills/sheleg-design` beside an
|
|
401
|
+
* installed plugin is two listings of the same skill, and the stale copy wins
|
|
402
|
+
* — the exact shadow the family canon forbids (make-skill
|
|
403
|
+
* references/distribution.md §"The installer must refuse the shadow it
|
|
404
|
+
* documents"). Refuse rather than create it, and refuse LOUDLY: a refusal
|
|
405
|
+
* that exits 0 reads as success to every script above it. Reproduced live
|
|
406
|
+
* 2026-08-29: a bare `npx @ssheleg/telegram-dev` shipped three shadows past a
|
|
407
|
+
* marketplace-dir-only check while the plugin was enabled.
|
|
408
|
+
*/
|
|
409
|
+
function refuseIfPluginOwnsChannel(targetDir, force) {
|
|
410
|
+
const home = claudeHomeOf(targetDir);
|
|
411
|
+
if (!home || force) return;
|
|
412
|
+
const spec = installedPluginSpec(home);
|
|
413
|
+
const marketplaces = path.join(home, ".claude", "plugins", "marketplaces");
|
|
414
|
+
const mktDir = [SKILL_SLUG, "sheleg-design-skill"]
|
|
415
|
+
.map((n) => path.join(marketplaces, n))
|
|
416
|
+
.find((p) => fs.existsSync(p));
|
|
417
|
+
if (!spec && !mktDir) return;
|
|
418
|
+
|
|
419
|
+
const remedySpec = spec || "sheleg-design@sheleg-design-skill";
|
|
420
|
+
const remedyMarketplace = remedySpec.split("@")[1];
|
|
421
|
+
const found = spec
|
|
422
|
+
? `installed as the Claude Code plugin ${spec}\n` +
|
|
423
|
+
` (declared in ${path.join(home, ".claude", "plugins", "installed_plugins.json")})`
|
|
424
|
+
: `registered as a Claude Code marketplace\n (${mktDir})`;
|
|
425
|
+
console.error(
|
|
426
|
+
c("yellow", `refused: ${SKILL_SLUG} is already ${found}.`) +
|
|
427
|
+
`\n A plain copy in ${path.join(home, ".claude", "skills", SKILL_SLUG)}\n` +
|
|
428
|
+
` would shadow the plugin and serve this frozen version forever.\n` +
|
|
429
|
+
` Update the plugin channel instead:\n` +
|
|
430
|
+
` ${c("bold", `claude plugin marketplace update ${remedyMarketplace}`)}\n` +
|
|
431
|
+
` ${c("bold", `claude plugin update ${remedySpec}`)}\n` +
|
|
432
|
+
` Family launcher (updates every member, prunes shadow copies):\n` +
|
|
433
|
+
` ${c("bold", "npx --yes sshlg-skills@latest update")}\n` +
|
|
434
|
+
` Pass --force to write the plain copy anyway — a deliberate choice\n` +
|
|
435
|
+
` to run two channels, where the stale one wins.`,
|
|
436
|
+
);
|
|
437
|
+
// Offered on the refusal path too: the skill IS present on this machine —
|
|
438
|
+
// as the plugin — so the routing block is exactly as wanted as on the
|
|
439
|
+
// install path.
|
|
440
|
+
offerRouters();
|
|
441
|
+
process.exit(EXIT_PLUGIN_PRESENT);
|
|
442
|
+
}
|
|
443
|
+
|
|
331
444
|
function main() {
|
|
332
445
|
const opts = parseArgs(process.argv.slice(2));
|
|
333
446
|
|
|
@@ -354,6 +467,10 @@ function main() {
|
|
|
354
467
|
|
|
355
468
|
const targetDir = resolveTargetDir(opts, cwd);
|
|
356
469
|
|
|
470
|
+
// Before any write to a home's ~/.claude/skills/sheleg-design: if that
|
|
471
|
+
// home's plugin channel already owns this skill, refuse (exit 3).
|
|
472
|
+
refuseIfPluginOwnsChannel(targetDir, opts.force);
|
|
473
|
+
|
|
357
474
|
// Verify the bundle is intact before touching the filesystem.
|
|
358
475
|
for (const f of CORE_FILES) {
|
|
359
476
|
if (!fs.existsSync(path.join(SKILL_DIR, f))) {
|
|
@@ -398,6 +515,16 @@ function main() {
|
|
|
398
515
|
);
|
|
399
516
|
|
|
400
517
|
offerRouters();
|
|
518
|
+
|
|
519
|
+
// The last line says how the next version arrives — "installed" is not a
|
|
520
|
+
// complete sentence. Auto-update is off on purpose: this member composes
|
|
521
|
+
// with its family, and per-marketplace autoUpdate moves each member on its
|
|
522
|
+
// own clock, into combinations nobody tested together.
|
|
523
|
+
console.log(
|
|
524
|
+
`Updates: rerun ${c("bold", "npx sheleg-design-skill@latest --force")}, or refresh the\n` +
|
|
525
|
+
`whole family with ${c("bold", "npx --yes sshlg-skills@latest update")} (every channel,\n` +
|
|
526
|
+
`and it prunes plain copies that would shadow a plugin).\n`,
|
|
527
|
+
);
|
|
401
528
|
}
|
|
402
529
|
|
|
403
530
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sheleg-design-skill",
|
|
3
|
-
"version": "1.54.
|
|
3
|
+
"version": "1.54.1",
|
|
4
4
|
"description": "Design taste as an installable agent skill. Cinematic scroll-driven landing pages built on one scroll clock and layered degrade-to-calm motion, a motion doctrine that decides whether to animate before it decides how, three calibration dials, and thirty-eight locked style packs with ready-made design tokens — instrument-console, editorial-luxury, workbench, briefing-room, atrium, orchard, outrank, babylove, patchbay, nameplate, field-notes, cyclorama, showroom, blueprint, prism, maquette, scoreboard, datasheet, manpage, pigeonhole, roster, ora, tenor, paperclip, ledger, router, daylight, notation, almanac, vitrine, proscenium, awning, bulletin, rimlight, onionskin and deskmate, test-drive, surveyor. Colour, slop and fork-reciprocity gates run as scripts, not opinions. Works with Cursor, Claude Code and any agent that reads a SKILL.md.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sheleg-design-skill": "bin/cli.js"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"node": ">=16"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
|
-
"test": "python3 test/validate.py && python3 test/validate_palette.py && python3 test/sloplint.py && node --check bin/cli.js && npm run selftest",
|
|
22
|
+
"test": "python3 test/validate.py && python3 test/validate_palette.py && python3 test/sloplint.py && node --check bin/cli.js && node test/installer_test.js && npm run selftest",
|
|
23
23
|
"validate": "python3 test/validate.py && python3 test/validate_palette.py && python3 test/sloplint.py",
|
|
24
24
|
"smoke": "node bin/cli.js --help",
|
|
25
25
|
"palette": "python3 test/validate_palette.py",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "sheleg-design",
|
|
3
3
|
"displayName": "SHELEG Design",
|
|
4
4
|
"description": "SHELEG Design methodology: cinematic scroll-driven landing pages (single scroll clock, layered degrade-to-calm motion, WebGL particle formations), a motion doctrine that decides whether to animate before it decides how, and thirty-eight pluggable visual style packs — instrument-console (dark console), editorial-luxury (warm editorial), workbench (light/dark product UI for dashboards and tools), briefing-room (dark 16:9 deck), atrium (warm consumer health), orchard, outrank, babylove (friendly consumer biotech), patchbay (a dark live schematic: one mint-cyan, 8% hairlines and no shadow, and an architecture diagram whose cords carry SMIL particles), field-notes (warm paper for dev tools sold on auditability), cyclorama (a pastel field on a 32s cycle), showroom (the product as the exhibit), blueprint (a drawing sheet, zero radius), prism (one iridescent wash over mono body), maquette (cream axonometric models on a dark table), scoreboard (warm paper, pixel numerals, a dark ledger of results), datasheet (an off-white spec sheet whose live instrument goes dark when it detects the reader is hiding), manpage (a developer landing page set in the reader's own system monospace on cream paper, with coral label chips that are real headings and a dark code frame as the argument), pigeonhole (a white sorting wall whose nine pastel categories are a filing scheme rather than a mood, each a two-layer chip whose label word is mandatory), roster (a white field in a faint grid of squares whose argument is other people's marks — client logotypes in pill-labelled industry columns, an engine's wordmark inside the headline — where the proof is a name rather than a number), ora (a warm coal field with cream ink and no third hue — the accent is the inverted field — a serif carrying every human sentence over a monospace carrying every machine fact, a terminal surface cut below the page, and a six-step verdict ramp, for products whose output is a machine's verdict about the reader), tenor (warm paper with zero radius and zero shadow, one hairline weight, an orange that exists only on hover and on focus, a sans tracked negative against a mono tracked positive, display at a line-height below one in an eight-to-twelve-character measure, and product proof delivered as silent looping video, for products arguing that a new kind of thing must be managed like an existing organisation), paperclip (neutral coal with no functional colour at all — every control monochrome and elevation made of hairlines, with the whole chromatic budget spent on a curtain of gradient capsules and twelve gradient section badges that cannot be clicked — for products that ask a person to run something that runs itself: agent teams, autonomous back-office, schedulers and budget-governed compute), ledger (warm cream paper ruled by a hairline at 12% ink and no shadow on any card, radius 15 nested concentrically, an ink primary button and a terracotta accent that never fills a control — it labels, as a 10px monospace uppercase kicker — with a seal on every card stating how its number is known, for the console of a product that answers questions about data: AI analysts, BI surfaces, query workspaces), router (a near-white field with a trace of blue and white cards standing on it, hairline seams instead of shadows anywhere, body at 14px and weight 450, and a status triplet in which the colour you paint with is not the colour you write with, for product consoles and the landing pages that have to look like them), daylight (a cool near-white portal field with generous radii and one very large soft shadow spent on a single object per screen, for client portals), notation (a near-white page drawn entirely in hairlines with a light serif over a monospace, no bold anywhere and an ink primary, for developer products sold on restraint), almanac (oatmeal paper with 2px seams and no 1px anywhere, a display set below a line-height of one, and mono tags notched through drawn boxes, for pages that assert a category), vitrine (a white hairline field with a serif display, an ink primary and one framed record carrying the evidence, for the front door of a product sold on trust). Ships the sheleg-design skill, the architecture reference, the motion doctrine, the Figma and Claude Design bridges, AI-surface patterns, style packs with ready-made token CSS, and the /sheleg-design command, and awning (a white forecourt where the accent is black and no hue reaches the chrome at all, a pill whose radius is a declared component token, one variable grotesque at 420/550 with no 700, and a single three-layer shadow, for commerce and platform front doors), and proscenium (a white field carrying two cool acts and one deep indigo act at the middle, an electric violet filling a control that stays nearly square at 4px against cards at 16, one family at nine weights, and a framed product panel the fold cuts off, for product-led marketing front doors whose argument is a demonstration), and bulletin (warm cream paper cut by flat pastel bands, every card and control a 1px ink outline standing on a hard zero-blur ink offset it travels into when pressed, a display face at 800 inside controls and 700 in the headline, and no tracking at any size, for front doors whose argument is breadth), and nameplate (a cool near-white slab under a page that is square on 87% of its elements, where the one round shape is reserved for a white 1px-bordered pill carrying somebody else's publication name as type, one family with the body at weight 500, and two uppercase registers tracked 0.06em and 0.175em, for pages whose argument is that named third parties will vouch for you: press placement, trust marks, certification and review aggregation), and rimlight (a white field with a cool grey act separator and one near-black act, a grotesque for every sentence and a monospace for every piece of chrome, square on 84% of its elements and tracked negative at every size, whose only elevation is a sixteen-layer coloured light rig — six layers lit and ten held at alpha 0, thrown from below-left — for a studio's own front door and the pages that sell what it makes), and onionskin (a white technical sheet at 96.5% zero radius — the squarest page in the library — where two bases do all the work and everything quiet is one of them at an alpha: text dims through the ink, structure dims through a navy that is never a word, over a dot grid with dashed hairlines and three faces at an 11px working size, for developer and AI infrastructure whose front page is a working document), and deskmate, test-drive, surveyor (a warm beige working day lit from one source above the top edge, where a single four-stop ramp — peach, lilac, violet, deep navy — washes the field, fills a panel and fills one word of a heading, everything a hand touches is a pill at 56px and everything else a 32px slab, elevation is a field step with two shadows on a 10,211px page, and the set piece is a framed transcript whose quoted chat client keeps its own face, ink and status colours under a --quoted-* namespace, for products sold as a colleague rather than a tool: AI employees and chat-native agents).",
|
|
5
|
-
"version": "1.54.
|
|
5
|
+
"version": "1.54.1",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -3,7 +3,7 @@ name: sheleg-design
|
|
|
3
3
|
description: Use when deciding how something LOOKS or MOVES — cinematic landing pages and hero sections, particle/WebGL backgrounds, scroll-linked or scrubbed motion, layers that drift, dashboards, admin or internal tools, mobile screens, chat or agent interfaces, tokens, themes, palettes, typography and the Figma border. Triggers include "design a landing" / "дизайн лендинга", "build a landing page" / "сделай лендинг", "scroll animation" / "скролл-анимация", "dashboard style" / "стиль дашборда", "design tokens, style pack" / "дизайн-токены", "light/dark theme" / "светлая/тёмная тема", "figma variables" / "переменные фигмы, фигма в код", "mobile screen" / "мобильный экран", "palette, colors" / "палитра, цвета", "typography, font" / "типографика, шрифт", "how it looks, make it prettier" / "выглядит, красиво, красивее", "visual reference" / "визуальные референсы", "investor deck" / "презентация". Not for structure, copy or backend behavior.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: 1.54.
|
|
6
|
+
version: 1.54.1
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# SHELEG Design
|