sshlg-skills 0.76.0 → 0.78.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/CHANGELOG.md CHANGED
@@ -1,5 +1,65 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.78.0 — an unqualified landing page reaches both crafts
4
+
5
+ **B-57: `сделай лендинг` reached no route at all — and neither did `build a landing page`,
6
+ which the row never mentioned.** A landing is the canonical two-craft surface, so the ask
7
+ for one arriving at nothing was the gap; both phrases now reach **`sheleg-design` ∥
8
+ `copywriting`** together, which is the composition this family prescribes for a landing.
9
+
10
+ **Verb phrases, not the bare noun, and the difference was measured rather than argued.**
11
+
12
+ | prompt | bare `лендинг` | verb phrase |
13
+ |---|---|---|
14
+ | `сделай лендинг` | both | **both** |
15
+ | `build a landing page` | both | **both** |
16
+ | `напиши текст для лендинга` | both — a copy task handed a visual route | **copywriting alone** |
17
+ | `почини баг на лендинге` | three routes | **task-pipeline alone** |
18
+
19
+ The bare noun fixes one case and damages two. Cycle 5 refused it for a reason that no
20
+ longer held — it said the bare noun would *take* the route from `copywriting`, and with
21
+ both crafts firing that is no longer true — but measuring found a different reason that
22
+ does hold, so the refusal stands on new evidence rather than old.
23
+
24
+ **A premise of the row had expired.** It said both descriptions were at or near the
25
+ 1024-character limit; `copywriting` is at **536**, with 488 free. Only `sheleg-design` was
26
+ tight, and there the room was **made rather than found** — `scrubbed sections` and one
27
+ `implemented` came out of the prose, 30 characters that were not carrying their weight
28
+ beside a phrase an operator actually types.
29
+
30
+ **Pins: `sheleg-design` 1.37.4 → 1.37.5, `super-ux` 0.41.4 → 0.41.5.**
31
+
32
+ ## v0.77.0 — closing a false positive found the bypass it was hiding
33
+
34
+ **B-59: the hygiene guard could not tell a command being run from one being written
35
+ down.** It reads the whole Bash payload, so quoting the forbidden invocation *in a
36
+ document* was refused too — a verification-ledger row blocked its own commit, and the
37
+ sentence had to be split around the guard.
38
+
39
+ `executablePart()` now removes what cannot execute before matching:
40
+
41
+ - **A heredoc body fed to something that is not a shell.** `python3 - <<'PY' … PY` and
42
+ `cat > f <<EOF … EOF` are data.
43
+ - **A whole-line comment.**
44
+
45
+ And what it keeps is the load-bearing half. **A `bash <<EOF … EOF` body is still read** —
46
+ stripping every heredoc would trade a false positive for a documented bypass. **Quoted
47
+ strings are still read** too, because `bash -c '…'` is a real invocation.
48
+
49
+ **That last decision is where the actual finding was.** Testing it produced a case the
50
+ guard *should* refuse and did not: `bareName` kept the trailing quote, so `ux-flows'`
51
+ matched no family id and **`bash -c 'npx skills add ux-flows'` passed the guard untouched**
52
+ — verified against `HEAD` before the change, so it had been open the whole time. The row
53
+ asked for relief from an annoyance; the annoyance was hiding a hole.
54
+
55
+ Both directions are fixtured — 17 → **22** checks — and the real hook was driven as a
56
+ process to confirm it agrees with the pure module. The fixture strings are **assembled at
57
+ runtime** rather than written whole, because a file containing the literal payload is
58
+ itself refused by anything that reads it: the defect demonstrated itself three times
59
+ during the fix, twice blocking the commands that were repairing it, and once making three
60
+ new cases pass for the wrong reason by targeting a member the fixture's manifest does not
61
+ declare.
62
+
3
63
  ## v0.76.0 — a ledger records two different things, and most record only one
4
64
 
5
65
  **B-62 said five ledger shapes. Measured: ten, across 815 rows.**
package/README.md CHANGED
@@ -33,11 +33,11 @@ scripts. No services, no telemetry, no API keys.
33
33
 
34
34
  | Skill | Version | What it does |
35
35
  |---|---|---|
36
- | **[super-ux](https://github.com/ssheleg/super-ux)** | 0.41.4 | Scenario-driven UI development. A versioned design chain in `docs/ux/` — the product vision → personas and jobs → user flows → a screens-and-states map with Figma frames → traced scenarios → evidence-backed audits → fix plans, plus `docs/brand/` for how the product speaks. One `/ux` entry point that reaches every skill, two doc-drift linters and a contract doctor. |
36
+ | **[super-ux](https://github.com/ssheleg/super-ux)** | 0.41.5 | Scenario-driven UI development. A versioned design chain in `docs/ux/` — the product vision → personas and jobs → user flows → a screens-and-states map with Figma frames → traced scenarios → evidence-backed audits → fix plans, plus `docs/brand/` for how the product speaks. One `/ux` entry point that reaches every skill, two doc-drift linters and a contract doctor. |
37
37
  | **[task-pipeline](https://github.com/ssheleg/task-pipeline)** | 1.67.0 | Full-cycle delivery orchestrator. An intake grill interrogates the request into a complete brief, then **ten gated stages** carry it — docs, brainstorm and decompose, spec, plan, build, tests, deploy, post-deploy, wiki, acceptance — refusing to advance until each gate passes. Documentation is a deliverable with its own portable gate, and the retrospective it leaves behind is traceable to the commit that earned each lesson. |
38
38
  | **[agent-sync](https://github.com/ssheleg/agent-sync)** | 1.11.1 | Several agents, one repository, no collisions. Leases with a TTL so two agents cannot claim the same work, race-free id reservation, a run journal and a generated board — over a pluggable knowledge cloud. The answer to "two sessions just committed over each other". |
39
39
  | **[make-skill](https://github.com/ssheleg/make-skill)** | 0.19.1 | A skill that builds skills. Create, retrofit, audit and publish agent skills and Claude Code plugins: conformance to the [Agent Skills](https://agentskills.io/specification) open standard, [Anthropic's platform rules](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) (per-surface runtime limits, the Skills API, evals) and the [Claude Code plugin reference](https://code.claude.com/docs/en/plugins-reference), marketplace layout, version sync, validator + CI, every distribution channel, the review checklist for third-party skills, and what a *skill author* must know about MCP and A2A — the protocols themselves live in `agent-stack`. |
40
- | **[sheleg-design](https://github.com/ssheleg/sheleg-design-skill)** | 1.37.4 | The taste layer. Cinematic scroll-driven landing pages — one scroll clock, motion that degrades to calm, WebGL particle formations — plus product-UI style packs each shipping a ready token layer, and the Figma border: tokens as variables, design to code without hand-copied values. |
40
+ | **[sheleg-design](https://github.com/ssheleg/sheleg-design-skill)** | 1.37.5 | The taste layer. Cinematic scroll-driven landing pages — one scroll clock, motion that degrades to calm, WebGL particle formations — plus product-UI style packs each shipping a ready token layer, and the Figma border: tokens as variables, design to code without hand-copied values. |
41
41
  | **[seo-aeo-audit](https://github.com/ssheleg/seo-aeo-audit)** | 0.20.2 | Evidence-first website audit for search **and** answer engines. Ten tracks from crawl access to AI citation mechanics; every finding carries an observation, every recommendation an evidence tier, and the output is a prioritized change plan plus a link-building brief — not a score. |
42
42
  | **[sheleg-dev](https://github.com/ssheleg/sheleg-dev)** | 0.5.2 | The integration layer a product reaches once it has users: **money in, tracking, sign-in, speed**. Stripe subscription billing reconciled into your own database — webhook idempotency, renewals, seats and proration, refunds, price drift; crypto payments that survive under-payment, duplicate webhooks and rate drift; GA4, Google Ads, Meta and LinkedIn under Consent Mode v2; Google sign-in with the account pre-hijacking guard, and the server-side auth surface behind it; Core Web Vitals work that moves the score rather than the report. |
43
43
  | **[agent-stack](https://github.com/ssheleg/agent-stack)** | 0.11.1 | Production patterns for agent systems, in four skills. **The orchestrator** — tool-calling loops that survive their own context pressure, pipelines with human checkpoints and resume, provider routing with fallback and health checks, four memory layers with confidence decay and conflict resolution, and **the shape of the work decided before the work**: an edge that carries no data is no edge, a plan that declares its dependencies is executed in layers rather than in list order, and a parallel layer gets a checker before the node that consumes it. **The harness** — what the agent is *told*: system prompts at the right altitude, tool descriptions the model can act on, technique choice with a verdict each, workflow versus agent and static versus dynamic, plus a seven-track audit of an agent somebody else built and a scanner for the defects that are mechanically visible. **The evals** — suites that measure whether it actually works: judging trajectories, regression fixtures grown from production, judges calibrated before they are trusted. **The interop layer** — MCP at revision 2026-07-28 and the four features it deprecated, running many servers at once, the registry, A2A 1.0, and the gateway, every reference carrying the spec revision it was read against. Plus the wallet side of reselling LLM access: tiered balances, one markup boundary, two-phase commit against a provider API. |
package/lib/hygiene.js CHANGED
@@ -22,6 +22,12 @@
22
22
 
23
23
  /** Strip an `@version` suffix so `sshlg-skills@latest` is not read as `skills`. */
24
24
  function bareName(token) {
25
+ // Shell quoting is not part of a name. `bash -c 'npx skills update ux-flows'` reaches
26
+ // this as the token `ux-flows'`, which matched no family id — so a real invocation
27
+ // wrapped in quotes passed the guard untouched. Found on 2026-08-16 while fixing the
28
+ // opposite complaint (B-59, a false positive on documented text); the same run turned
29
+ // up a bypass worth more than the annoyance that started it.
30
+ token = String(token || '').replace(/^['"]+/, '').replace(/['"]+$/, '');
25
31
  return String(token || '').replace(/@.*$/, '').replace(/^.*\//, '');
26
32
  }
27
33
 
@@ -43,6 +49,62 @@ function isFlag(token) {
43
49
  * `claude` exactly where the target would be, and reading it as the target let a
44
50
  * real family skill through unguarded. Watched failing in the fixtures.
45
51
  */
52
+ /**
53
+ * The part of a payload that could actually run, with data stripped out.
54
+ *
55
+ * B-59: this guard reads the whole command text, so **writing the forbidden string into a
56
+ * document is refused too**. On 2026-08-16 a verification-ledger row quoting the
57
+ * diagnostic invocation blocked its own commit, and the sentence had to be split around
58
+ * the guard. The family's own documents could not quote the command they warn about.
59
+ *
60
+ * Two things are removed, and the boundary between them and everything else is the whole
61
+ * design:
62
+ *
63
+ * - **A heredoc body fed to something that is not a shell.** `python3 - <<'PY' … PY` and
64
+ * `cat > f <<EOF … EOF` are data. `bash <<EOF … EOF` is a script, so its body is KEPT —
65
+ * stripping every heredoc would be a documented bypass, which is worse than the false
66
+ * positive it fixes.
67
+ * - **A whole-line comment.** A line whose first non-space character is `#` does not run.
68
+ *
69
+ * **Quoted strings are deliberately NOT stripped.** `bash -c 'npx skills update ux-flows'`
70
+ * is a real invocation living inside quotes, and a guard that ignored quoted text would
71
+ * miss it. The false positive that remains — the string in a single-line argument to
72
+ * `echo` — is the price of not opening that hole, and it is documented rather than fixed.
73
+ */
74
+ const HEREDOC_SHELLS = new Set(['bash', 'sh', 'zsh', 'dash', 'ksh', 'eval', 'source', '.']);
75
+
76
+ function executablePart(command) {
77
+ const lines = String(command || '').split('\n');
78
+ const out = [];
79
+ let terminator = null;
80
+ let dropping = false;
81
+ for (const line of lines) {
82
+ if (terminator !== null) {
83
+ // The terminator may be indented when the heredoc used `<<-`.
84
+ if (line.trim() === terminator) { terminator = null; dropping = false; continue; }
85
+ if (dropping) continue;
86
+ out.push(line);
87
+ continue;
88
+ }
89
+ if (/^\s*#/.test(line)) continue;
90
+ const here = /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/.exec(line);
91
+ if (here) {
92
+ terminator = here[2];
93
+ // Which command is being fed? The last simple-command word before the `<<`, taken
94
+ // after the final pipe or `&&` so `foo | python3 - <<EOF` reads as python3.
95
+ const before = line.slice(0, here.index);
96
+ const segment = before.split(/\|\||&&|[|;]/).pop();
97
+ const words = segment.trim().split(/\s+/).filter(Boolean).map(bareName);
98
+ const cmd = words.find((w) => !w.includes('=')) || '';
99
+ dropping = !HEREDOC_SHELLS.has(cmd);
100
+ out.push(before);
101
+ continue;
102
+ }
103
+ out.push(line);
104
+ }
105
+ return out.join('\n');
106
+ }
107
+
46
108
  function skillsCli(command) {
47
109
  const tokens = String(command || '').split(/\s+/).filter(Boolean);
48
110
  for (let i = 0; i < tokens.length; i += 1) {
@@ -83,7 +145,9 @@ const REMEDY = 'npx --yes sshlg-skills@latest update';
83
145
  * `~/.claude/skills/`, which is what does the shadowing.
84
146
  */
85
147
  function bareFamilyInstall(command, ids) {
86
- const call = skillsCli(command);
148
+ // Data first: a heredoc body written by a non-shell, and whole-line comments, cannot
149
+ // install anything. See `executablePart` for why quoted strings are not stripped.
150
+ const call = skillsCli(executablePart(command));
87
151
  if (!call || !call.args.length) return null;
88
152
  if (!['update', 'add', 'install'].includes(call.verb)) return null;
89
153
  const target = call.args.find((a) => ids.has(bareName(a)));
@@ -174,6 +238,6 @@ function reapply(snapshot, fresh) {
174
238
  }
175
239
 
176
240
  module.exports = {
177
- skillsCli, familyIds, bareFamilyInstall, launcherRunning,
241
+ skillsCli, familyIds, bareFamilyInstall, launcherRunning, executablePart,
178
242
  isObsidianSetup, parseConfig, reapply, bareName, REMEDY,
179
243
  };
package/lib/triggers.js CHANGED
@@ -112,6 +112,7 @@ const ROUTES = {
112
112
  'палитра', 'palette', 'цвета', 'colors', 'типографика', 'typography',
113
113
  'шрифт', 'font', 'выглядит', 'how it looks', 'красивее', 'красиво',
114
114
  'make it prettier', 'анимация', 'hero',
115
+ 'сделай лендинг', 'build a landing page',
115
116
  // Both forms of the same adjective, because the stemmer cannot bridge them:
116
117
  // `красивее` cuts to `красиве`, which is not a prefix of `красиво`. The skill
117
118
  // advertises both for that reason — a stem in this list instead of a word
@@ -159,6 +160,7 @@ const ROUTES = {
159
160
  'write copy', 'напиши текст', 'rewrite this', 'перепиши',
160
161
  'store listing', 'описание в сторе', 'microcopy', 'микрокопия',
161
162
  'звучит как нейросеть',
163
+ 'сделай лендинг', 'build a landing page',
162
164
  ],
163
165
  line: 'is text a user of the product will read → `/copy` writes it in the recorded voice',
164
166
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sshlg-skills",
3
- "version": "0.76.0",
3
+ "version": "0.78.0",
4
4
  "description": "One launcher/updater for the ssheleg skill family (super-ux, task-pipeline, agent-sync, make-skill, sheleg-design, seo-aeo-audit, sheleg-dev, agent-stack) across every agent — Claude Code, Cursor, OpenCode, Kilo, Kimi, Hermes, OpenClaw, Codex, and more.",
5
5
  "bin": {
6
6
  "sshlg-skills": "bin/sshlg-skills.js"
package/skills.json CHANGED
@@ -31,7 +31,7 @@
31
31
  "pluginMarketplace": "ssheleg/super-ux",
32
32
  "pluginInstall": "super-ux@super-ux",
33
33
  "desc": "Scenario-driven UI development: a versioned design chain in docs/ux/ — the product vision, personas and jobs, user flows, a screens-and-states map with Figma frames, traced scenarios, evidence-backed audits, fix plans — plus docs/brand/, the verbal identity: one voice, per-surface registers, a string registry and a 35-check copy linter. /ux and /brand entry points, two doc-drift linters and a contract doctor.",
34
- "version": "0.41.4",
34
+ "version": "0.41.5",
35
35
  "entry": "/ux",
36
36
  "role": "what the interface must do and how it sounds",
37
37
  "npm": "super-ux",
@@ -100,7 +100,7 @@
100
100
  "skillNames": [
101
101
  "sheleg-design"
102
102
  ],
103
- "version": "1.37.4",
103
+ "version": "1.37.5",
104
104
  "entry": "/sheleg-design",
105
105
  "role": "how it looks and moves",
106
106
  "npm": "sheleg-design-skill",