sshlg-skills 1.75.0 → 1.76.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,3 +1,30 @@
1
+ ## v1.76.0 (2026-10-23): M3 waves 2 and 3, the operator's decisions and one member gate
2
+
3
+ - **Pin:** task-pipeline 1.101.1 (B-153: the release gate's python3-failure fallback reads
4
+ command shapes, not words).
5
+
6
+ - **B-180 closed:** the routing block's star line is opt-in, off by default
7
+ (`npx sshlg-skills config set rules.star on`). An installed block that carries it is the
8
+ pack's own text and is refreshed. Shown in `config list`.
9
+ - **B-248 closed:** the public site no longer announces the private asset agent: the Harness
10
+ section, its table row, the llms line, the harness README paragraph and the brand rows are gone;
11
+ SCN-004 retired.
12
+ - **B-249 closed:** `scripts/host-compat/mcp_schema_bridge.py`, an opt-in stdio MCP wrapper that
13
+ rewrites boolean JSON Schemas (`true` to `{}`) in `tools/list` output schemas for clients that
14
+ reject them, with its test.
15
+ - **B-108, B-109:** `member-gate/family_gate.py`, the canonical member gate (the board parses;
16
+ `release.yml` keeps the tag-ancestry check), copied byte for byte into each member's
17
+ `test/family_gate.py` and run in its gate with `--self-test`; `test/member_gate_copies_test.py`
18
+ compares the pinned copies with the canonical file.
19
+
20
+ ## v1.75.1 (2026-10-23): seo-aeo-audit pinned to 0.31.0
21
+
22
+ - **seo-aeo-audit 0.31.0** (was 0.30.0), commit `1cbb361`: the property instrument registry, the
23
+ checkup by occasion with an indexing push run as an experiment, UI-only steps and how an agent
24
+ takes one, paid indexers and index checkers with provider sheets and the push ledger.
25
+ `skills.json` and `claude-plugin-pins.json` regenerated by `scripts/sync-member-pins.js --write`
26
+ and `scripts/sync-claude-pins.js --write` from the staged gitlink; README table updated.
27
+
1
28
  ## v1.75.0 (2026-10-23): milestone M3 wave 1, two guards that let defects through
2
29
 
3
30
  - **B-223 closed:** on 2026-10-17 a review agent's backticked `pi update` inside a double-quoted
package/README.md CHANGED
@@ -47,11 +47,11 @@ scripts. No services, no telemetry, no API keys.
47
47
  | Skill | Version | What it does |
48
48
  |---|---|---|
49
49
  | **[super-ux](https://github.com/ssheleg/super-ux)** | 0.66.0 | 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. |
50
- | **[task-pipeline](https://github.com/ssheleg/task-pipeline)** | 1.101.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. Ships `project-audit`: a cold-start audit of a whole project — discovery, probes whose unmet needs read `blind` rather than clean, production evidence including one artefact served under two channels, and an HTML report beside a JSON sidecar that says what moved. |
50
+ | **[task-pipeline](https://github.com/ssheleg/task-pipeline)** | 1.101.1 | 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. Ships `project-audit`: a cold-start audit of a whole project — discovery, probes whose unmet needs read `blind` rather than clean, production evidence including one artefact served under two channels, and an HTML report beside a JSON sidecar that says what moved. |
51
51
  | **[agent-sync](https://github.com/ssheleg/agent-sync)** | 1.23.0 | 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". |
52
52
  | **[make-skill](https://github.com/ssheleg/make-skill)** | 0.33.0 | 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`. |
53
53
  | **[sheleg-design](https://github.com/ssheleg/sheleg-design-skill)** | 1.66.2 | 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. |
54
- | **[seo-aeo-audit](https://github.com/ssheleg/seo-aeo-audit)** | 0.30.0 | 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. Before a site is built, `/seo-aeo-audit brief` writes the build-time brief that the audit later verifies. |
54
+ | **[seo-aeo-audit](https://github.com/ssheleg/seo-aeo-audit)** | 0.31.0 | 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. Before a site is built, `/seo-aeo-audit brief` writes the build-time brief that the audit later verifies. |
55
55
  | **[sheleg-dev](https://github.com/ssheleg/sheleg-dev)** | 0.16.0 | 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, and the coupon offered at the cancel step, where a `duration=once` discount leaves `subscription.discounts` the moment its invoice finalizes and the offer can be taken every cycle; 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; and Sentry error tracking wired so it does not forward your own credentials to a third party and so a stack trace names the commit that caused it. |
56
56
  | **[agent-stack](https://github.com/ssheleg/agent-stack)** | 0.30.2 | 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, memory architecture — form, function and dynamics, the four-stage retrieval pipeline, and what a layer table alone cannot say, 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. |
57
57
  | **[telegram-dev](https://github.com/ssheleg/telegram-dev)** | 0.4.0 | Telegram, split by the API each surface actually speaks. **`telegram-bots`** — the official HTTP Bot API: `update_id` as the only idempotency key an update carries, the `allowed_updates` default that subscribes you to everything *except* `chat_member` and the two reaction types while answering `ok: true`, the webhook secret header that is the real check, rate limits as a design constraint (1/sec per chat, 20/min per group, ~30/sec bulk), and Telegram Stars with a **ten-second** pre-checkout window and a grant that belongs to `successful_payment`. **`telegram-userbots`** — MTProto and Telethon: the session file as a credential equal to the password, `FloodWaitError` as the API telling you exactly how long to wait, pinning across minor releases that move session and entity-cache behaviour, and the account-ban risk a bot token does not carry — the skill opens with whether a user account is needed at all. **`telegram-miniapps`** — the web layer, whose entire security model is one signed query string: verifying `initData` server-side, the `auth_date` window, the Ed25519 path for a third party, and the SDK package whose name moved while the organisation's own page still fronts the old one. Both the verifier and the delivery invariants ship as runnable fixtures with their mutants. |
@@ -600,6 +600,20 @@ still refuses as a whole and writes nothing.
600
600
  The rule describes continuation and durable handoff. It creates no watcher or job,
601
601
  and sign-ins, consent, payment and action-specific authority keep their own gates.
602
602
 
603
+ ### The star line is opt-in
604
+
605
+ The routing block's request for a star on this repository is off by default
606
+ (operator, 2026-10-22). Turn it on, then let the next refresh write it:
607
+
608
+ ```bash
609
+ npx sshlg-skills config set rules.star on
610
+ npx sshlg-skills update
611
+ ```
612
+
613
+ `rules.star off` (or absence) removes it on the next refresh. A block written by an
614
+ older release, star included, is the pack's own text and is refreshed, not kept as a
615
+ hand edit.
616
+
603
617
  ### Inspect an interrupted wait-rule change
604
618
 
605
619
  A backup referenced by an unfinished wait-rule operation stays protected from
@@ -1526,6 +1526,8 @@ function cmdRouters(f) {
1526
1526
  // With --member the caller speaks only for itself and must not render a
1527
1527
  // roster of the whole family from a manifest it happens to ship.
1528
1528
  members: f.member ? [] : SKILLS,
1529
+ // B-180: the star line rides only when the operator turned it on.
1530
+ star: require('../lib/config.js').starEnabled(require('../lib/config.js').readConfig(home)),
1529
1531
  remove, preserve, sources, dryRun: f.dryRun, log,
1530
1532
  });
1531
1533
 
@@ -1735,6 +1737,7 @@ function cmdConfig(argv) {
1735
1737
  log(` routers.${name.padEnd(16)} ${configLib.isEnabled(config, name) ? 'on' : 'off'}`);
1736
1738
  }
1737
1739
  log(` update.auto${' '.repeat(11)} ${configLib.autoUpdateEnabled(config) ? 'on' : 'off'}`);
1740
+ log(` rules.star${' '.repeat(12)} ${configLib.starEnabled(config) ? 'on' : 'off'}`);
1738
1741
  try { log(` rules.wait ${require('../lib/wait-rule-policy.js').read(home).enabled ? 'on' : 'off'}`); }
1739
1742
  catch (e) { log(` rules.wait unknown — ${e.message}`); return 2; }
1740
1743
  const declared = configLib.externalGet(config);
@@ -1752,6 +1755,7 @@ function cmdConfig(argv) {
1752
1755
  for (const p of packs.showPacks) log(` visibility.pack.${p} show`);
1753
1756
  log('\nПоменять: npx sshlg-skills config set routers.<имя> on|off');
1754
1757
  log(' npx sshlg-skills config set update.auto on|off');
1758
+ log(' npx sshlg-skills config set rules.star on|off');
1755
1759
  log(' npx sshlg-skills config set rules.wait on|off');
1756
1760
  log(' npx sshlg-skills config set routes.external.<имя>.triggers "слово, фраза, …"');
1757
1761
  log(' npx sshlg-skills config set routes.external.<имя>.skill <skill-id>');
@@ -1778,6 +1782,19 @@ function cmdConfig(argv) {
1778
1782
  } catch (e) { log(`rules.wait: refused: ${e.message}`); return 2; }
1779
1783
  }
1780
1784
 
1785
+ if (key === 'rules.star') {
1786
+ if (configLib.STATES.indexOf(value) === -1) {
1787
+ log(`config set: состояние должно быть on или off — получено "${value === undefined ? '' : value}"`);
1788
+ return 2;
1789
+ }
1790
+ const was = configLib.starEnabled(configLib.readConfig(home)) ? 'on' : 'off';
1791
+ if (was === value) { log(`rules.star: ${value} (без изменений)`); return 0; }
1792
+ configLib.setStar(home, value);
1793
+ log(`rules.star: ${was} → ${value}`);
1794
+ log('Блок маршрутизации получит или потеряет строку со звездой при следующем npx sshlg-skills update.');
1795
+ return 0;
1796
+ }
1797
+
1781
1798
  if (key === 'update.auto') {
1782
1799
  if (configLib.STATES.indexOf(value) === -1) {
1783
1800
  log(`config set: состояние должно быть on или off — получено "${value === undefined ? '' : value}"`);
@@ -1814,7 +1831,7 @@ function cmdConfig(argv) {
1814
1831
  }
1815
1832
 
1816
1833
  if (!key || key.indexOf('routers.') !== 0) {
1817
- log('config set: ключ должен начинаться с "routers.", "routes.external." или "visibility.pack.", или быть "update.auto"');
1834
+ log('config set: ключ должен начинаться с "routers.", "routes.external." или "visibility.pack.", или быть "update.auto" или "rules.star"');
1818
1835
  return 2;
1819
1836
  }
1820
1837
 
@@ -1073,8 +1073,8 @@
1073
1073
  {
1074
1074
  "name": "task-pipeline",
1075
1075
  "repo": "ssheleg/task-pipeline",
1076
- "commit": "8c0a06404faf381b029f1080e1d9324d3b8d5fb1",
1077
- "version": "1.101.0",
1076
+ "commit": "c914a84d1240caef00c8ed4342b0ef3eddf4f5b0",
1077
+ "version": "1.101.1",
1078
1078
  "pluginInstall": "task-pipeline@task-pipeline",
1079
1079
  "pluginPath": "plugins/task-pipeline",
1080
1080
  "entry": {
@@ -1082,7 +1082,7 @@
1082
1082
  "displayName": "Task Pipeline",
1083
1083
  "source": "./plugins/task-pipeline",
1084
1084
  "description": "Runs a substantial task through a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine is built into the skill — no companion plugin required — with typed auto/judgment/manual gates, a frozen requirement spine that closes with evidence, a work board and a verification ledger that outlive a run, an exposure line naming what shipped unconfirmed, a progress rail computed from the project's own config, a proportional short path for small changes, a loop guard whose ceilings stop and record a blocker, and stage-3 tracks for what a product does, how it sounds and how it looks. Two modes need no task: `checkup` (what is unverified) and `setup` (audit existing docs); a third, `waves`, takes the whole board and closes it in waves that each finish in one pass. Retro insights can publish upstream as issues, opt-in and redacted.",
1085
- "version": "1.101.0",
1085
+ "version": "1.101.1",
1086
1086
  "author": {
1087
1087
  "name": "ssheleg",
1088
1088
  "url": "https://x.com/sshlg93"
@@ -1105,7 +1105,7 @@
1105
1105
  "files": [
1106
1106
  {
1107
1107
  "path": ".claude-plugin/plugin.json",
1108
- "sha256": "85d2c7a14a0c6042d6b8575ef71e48476bac7bc4220a3a995a58bb841bceb046",
1108
+ "sha256": "27aebdde4177506522664b4722111876ad30f2eeca938dfde28d25433ce7e625",
1109
1109
  "bytes": 1529
1110
1110
  },
1111
1111
  {
@@ -1170,8 +1170,8 @@
1170
1170
  },
1171
1171
  {
1172
1172
  "path": "hooks/release-gate.sh",
1173
- "sha256": "29b30f85220398c5a17dbaaba1cb7977ab36e0c2f86855abd08040dcf5ed4350",
1174
- "bytes": 14083
1173
+ "sha256": "57d19a885632678014fca7c9374469ee711487798f0089158aed6676c9fa39b9",
1174
+ "bytes": 14452
1175
1175
  },
1176
1176
  {
1177
1177
  "path": "hooks/run-lifecycle.sh",
@@ -2682,8 +2682,8 @@
2682
2682
  {
2683
2683
  "name": "seo-aeo-audit",
2684
2684
  "repo": "ssheleg/seo-aeo-audit",
2685
- "commit": "3b2b13d693111784420fe13e3952a533967ed670",
2686
- "version": "0.30.0",
2685
+ "commit": "1cbb3610b484dfc700086c8470377944c0e405da",
2686
+ "version": "0.31.0",
2687
2687
  "pluginInstall": "seo-aeo-audit@seo-aeo-audit",
2688
2688
  "pluginPath": "plugins/seo-aeo-audit",
2689
2689
  "entry": {
@@ -2691,7 +2691,7 @@
2691
2691
  "displayName": "SEO + AEO Audit",
2692
2692
  "source": "./plugins/seo-aeo-audit",
2693
2693
  "description": "Audits a website across ten evidence-based tracks (access & indexation, canonicalization, architecture & link equity, intent, content value, extractability/AEO, entity consensus, experience signals, risk, measurement) and outputs a findings report plus a prioritized change plan with verification steps. Includes a stdlib-only page auditor with answer-engine read-budget analysis.",
2694
- "version": "0.30.0",
2694
+ "version": "0.31.0",
2695
2695
  "author": {
2696
2696
  "name": "ssheleg",
2697
2697
  "url": "https://x.com/sshlg93"
@@ -2716,7 +2716,7 @@
2716
2716
  "files": [
2717
2717
  {
2718
2718
  "path": ".claude-plugin/plugin.json",
2719
- "sha256": "b409b02222d63afeb1026ae21aef1fa70b4e72f30d72167b9e9c0cf402ee07a3",
2719
+ "sha256": "45c983161bfb449a821f3fe0f4d600f137e843abb3bb41a00973a94c9ca4906e",
2720
2720
  "bytes": 766
2721
2721
  },
2722
2722
  {
@@ -2751,8 +2751,8 @@
2751
2751
  },
2752
2752
  {
2753
2753
  "path": "skills/seo-aeo-audit/references/benchmarks.md",
2754
- "sha256": "c9edddf4e6fd9d712d1596add60942c4cc9149c4688fae80b6b030e94f50dc3e",
2755
- "bytes": 31793
2754
+ "sha256": "9df13c51fa45f24610bf3312b1f0d698fe9ee4bcb1448f64d5fe3edf1f945dc1",
2755
+ "bytes": 32172
2756
2756
  },
2757
2757
  {
2758
2758
  "path": "skills/seo-aeo-audit/references/build-time.md",
@@ -2856,52 +2856,52 @@
2856
2856
  },
2857
2857
  {
2858
2858
  "path": "skills/seo-aeo-audit/references/tooling.md",
2859
- "sha256": "dff178e16dd2bff376f803ad007a430ae0604165dec6e97ab6ba0e257b3e644c",
2860
- "bytes": 21102
2859
+ "sha256": "692d232dcdc6a52f4c8d40785b2a320387df48f4630ffd3b246345f1caaa4677",
2860
+ "bytes": 41865
2861
2861
  },
2862
2862
  {
2863
2863
  "path": "skills/seo-aeo-audit/scripts/agent_surface.py",
2864
- "sha256": "b6acd544d16ee74bf747823435f9e3319608eb7ab25ca7edba1ba5ede7a443c9",
2864
+ "sha256": "bc5d2d01a482d84a0630ec842ca418698f1c32912f89f6a7cb556d16666fb1ef",
2865
2865
  "bytes": 97372
2866
2866
  },
2867
2867
  {
2868
2868
  "path": "skills/seo-aeo-audit/scripts/ai_panel.py",
2869
- "sha256": "0b86fefc620e01f353920421c4262cd76301baa121a7a36d04a3651adcfaee51",
2869
+ "sha256": "2c7231e84d8528c04e2b6431d3585e9c44c9a28b8ddc7d663f6000500830d7c2",
2870
2870
  "bytes": 25268
2871
2871
  },
2872
2872
  {
2873
2873
  "path": "skills/seo-aeo-audit/scripts/bwt_pull.py",
2874
- "sha256": "ebd4161a9722ccb94a856682a21126e0507b1c47765705c246cc0b619118252b",
2874
+ "sha256": "b8dece8c1755ab0f0a2e71080a87ebd90f241ce60ba7e5b9affac612d0b8c562",
2875
2875
  "bytes": 25409
2876
2876
  },
2877
2877
  {
2878
2878
  "path": "skills/seo-aeo-audit/scripts/gsc_pull.py",
2879
- "sha256": "a1dff8c0934f11a026deda46d08ce18a000595016c135a304184b1414d05824b",
2879
+ "sha256": "bcf4c84b57cee199fe72950bd7f05e0a02132d9bd6fcc00feed1af5e6f49dabe",
2880
2880
  "bytes": 61132
2881
2881
  },
2882
2882
  {
2883
2883
  "path": "skills/seo-aeo-audit/scripts/page_audit.py",
2884
- "sha256": "e044c3bd0d9ce495ea6cab2259127bc17539fde3b803d841b88481083d66f1c6",
2884
+ "sha256": "492ae9dac4f32158db50def808f7f9b0952d188dafdb47984df01c02b2c5e965",
2885
2885
  "bytes": 80703
2886
2886
  },
2887
2887
  {
2888
2888
  "path": "skills/seo-aeo-audit/scripts/preflight.py",
2889
- "sha256": "97fed4a1cc80d34cba51217b91562b19de9af200238708028393f5bfa808aae2",
2889
+ "sha256": "5497598d14dfcfada90e41ec2684e32d56b786e6314c16c1d84c65ea6d5d5047",
2890
2890
  "bytes": 65317
2891
2891
  },
2892
2892
  {
2893
2893
  "path": "skills/seo-aeo-audit/scripts/psi_pull.py",
2894
- "sha256": "1a7e87d23964a524f7612c6847bba420d2171d51424600d9f7bbd667e89e01ea",
2894
+ "sha256": "38fde119ac40aeec72c0f8dca88f31ac730382f2b9272a3d10993ea83848f848",
2895
2895
  "bytes": 28522
2896
2896
  },
2897
2897
  {
2898
2898
  "path": "skills/seo-aeo-audit/scripts/sitemap_audit.py",
2899
- "sha256": "7d36f2cad978b308a455ed0f577b5053cccb7084acc85ae8088b5acd4043518d",
2899
+ "sha256": "c17da63f913fe256879b02dd3da978b36f45959818f153efec256878e51eeeba",
2900
2900
  "bytes": 44650
2901
2901
  },
2902
2902
  {
2903
2903
  "path": "skills/seo-aeo-audit/scripts/url_inspection.py",
2904
- "sha256": "8095a2adf754defd4da3f0a226d58e4d8e017943d4637ca225b7179d38af7ff7",
2904
+ "sha256": "31e10819459f89246ce55d3fc5b678c20e2177c5faedb3bdbbdd22bfbf9243ee",
2905
2905
  "bytes": 34553
2906
2906
  },
2907
2907
  {
package/lib/apply.js CHANGED
@@ -217,6 +217,7 @@ function applyOne(file, routers, opts) {
217
217
  preserve: opts.preserve || [],
218
218
  // B-202: the hub's record of what it last wrote here; hand edits are kept.
219
219
  rendered: opts.rendered ? (opts.rendered[file] || {}) : undefined,
220
+ star: opts.star === true,
220
221
  });
221
222
  const next = result.text;
222
223
  const removed = result.removed || {};
@@ -363,6 +364,7 @@ function applyCursor(opts) {
363
364
  remove: opts.remove || [],
364
365
  preserve: opts.preserve || [],
365
366
  rendered: opts.rendered ? (opts.rendered[file] || {}) : undefined,
367
+ star: opts.star === true,
366
368
  // Kept lines are named in the rule file's own numbering, frontmatter included.
367
369
  lineOffset: existing === null ? 0 : existing.slice(0, existing.length - body.length).split('\n').length - 1,
368
370
  });
package/lib/config.js CHANGED
@@ -99,6 +99,24 @@ function setAutoUpdate(home, state) {
99
99
  });
100
100
  }
101
101
 
102
+ /**
103
+ * The routing block's star line (B-180, operator 2026-10-22): opt-in, off by default.
104
+ * Only `on` is stored; `off` deletes the key so the file keeps only deviations.
105
+ */
106
+ function starEnabled(config) {
107
+ const r = (config && config.rules) || {};
108
+ return r.star === 'on';
109
+ }
110
+ function setStar(home, state) {
111
+ if (!STATES.includes(state)) {
112
+ throw new Error(`state must be one of on, off — got "${state}"`);
113
+ }
114
+ return editSub(home, 'rules', (rules) => {
115
+ if (state === 'on') rules.star = 'on';
116
+ else delete rules.star;
117
+ }, true);
118
+ }
119
+
102
120
  /**
103
121
  * Sections the operator wrote themselves, keyed by router name.
104
122
  *
@@ -227,4 +245,5 @@ module.exports = {
227
245
  authoredGet, authoredSet, authoredClear,
228
246
  stashGet, stashSet, stashClear, STATES,
229
247
  autoUpdateEnabled, setAutoUpdate,
248
+ starEnabled, setStar,
230
249
  };
package/lib/routers.js CHANGED
@@ -212,10 +212,14 @@ function renderMapSection(members) {
212
212
  * present is a fact about one machine and cannot ship in a block written for every operator,
213
213
  * so it is read at the moment it is needed. Same split, same reason, as `conflicts`.
214
214
  */
215
- function renderProtocolSection() {
215
+ function renderProtocolSection(opts) {
216
+ // B-180 (operator, 2026-10-22): the star line is opt-in, off by default
217
+ // (`npx sshlg-skills config set rules.star on`). It rides after the reports line.
218
+ const lines = PROTOCOL_LINES.slice();
219
+ if (opts && opts.star === true) lines.splice(lines.indexOf(STAR_AFTER) + 1, 0, ...STAR_LINES);
216
220
  return [
217
221
  PROTOCOL_BEGIN,
218
- ...PROTOCOL_LINES,
222
+ ...lines,
219
223
  PROTOCOL_END,
220
224
  ].join('\n');
221
225
  }
@@ -302,10 +306,8 @@ const PROTOCOL_LINES = [
302
306
  "**At completion, print every skill actually used** and what it did; disclose a foreign",
303
307
  "skill on a router's ground or a wrongly chosen route. Forwardable reports take their",
304
308
  "header and footer from `npx sshlg-skills signature --used \"<skill>=<what it did>,…\"`.",
305
- "**A star, once per session, only if a family skill actually did work:** one line naming",
306
- "`github.com/ssheleg/sshlg-skills`; skip when the used-skills list above is empty or inside",
307
- "the family's own repositories. Routes declared in `.claude/routers.json` are checked with",
308
- "`npx sshlg-skills materialised` (FALSE: the named file lost the doctrine).",
309
+ "Routes declared in `.claude/routers.json` are checked with `npx sshlg-skills materialised`",
310
+ "(FALSE: the named file lost the doctrine).",
309
311
  "",
310
312
  "**In Claude Code, any refusal phrase drops that prompt's notes and quiets",
311
313
  "permission-prompt escalation for every route for the rest of the session.**",
@@ -325,6 +327,26 @@ const PROTOCOL_LINES = [
325
327
  "above, this has no boundary and no refusal phrase.",
326
328
  ];
327
329
 
330
+ /** The opt-in star line (B-180), inserted after this protocol line when `rules.star` is on. */
331
+ const STAR_AFTER = "header and footer from `npx sshlg-skills signature --used \"<skill>=<what it did>,…\"`.";
332
+ const STAR_LINES = [
333
+ "**A star, once per session, only if a family skill actually did work:** one line naming",
334
+ "`github.com/ssheleg/sshlg-skills`; skip when the used-skills list above is empty or inside",
335
+ "the family's own repositories.",
336
+ ];
337
+
338
+ /**
339
+ * The protocol as 1.70.1 to 1.75.0 wrote it, with the star line always on, kept only as
340
+ * KNOWN lines for the hand-edit guard (B-202): 1.76.0 made the star opt-in (B-180), and on
341
+ * a machine with no rendered record the old packaged lines must read as the pack's own.
342
+ */
343
+ const PROTOCOL_1_75 = [
344
+ "**A star, once per session, only if a family skill actually did work:** one line naming",
345
+ "`github.com/ssheleg/sshlg-skills`; skip when the used-skills list above is empty or inside",
346
+ "the family's own repositories. Routes declared in `.claude/routers.json` are checked with",
347
+ "`npx sshlg-skills materialised` (FALSE: the named file lost the doctrine).",
348
+ ].join('\n');
349
+
328
350
  /**
329
351
  * Refresh a sentinel-delimited region in place, or report that it is absent.
330
352
  * The table and the map are the same shape of problem and were one copy each
@@ -553,7 +575,7 @@ function upsert(text, routers, opts) {
553
575
  // written before this region existed carries no sentinels, so a refresh finds nothing and
554
576
  // an upgrade that only refreshed would leave every existing machine on the old block.
555
577
  // It sits AFTER the map — what you have, then how to open a task with it.
556
- if (!refreshRegion(segments, PROTOCOL_BEGIN, PROTOCOL_END, renderProtocolSection(), regionGuard('PROTOCOL', `${PREVIOUS_PROTOCOL}\n${PROTOCOL_1_69}`))) {
578
+ if (!refreshRegion(segments, PROTOCOL_BEGIN, PROTOCOL_END, renderProtocolSection(opts), regionGuard('PROTOCOL', `${PREVIOUS_PROTOCOL}\n${PROTOCOL_1_69}\n${PROTOCOL_1_75}\n${STAR_LINES.join('\n')}`))) {
557
579
  const mapAt = segments.findIndex(
558
580
  (s) => s.type === 'chrome' && s.raw.includes(MAP_END)
559
581
  );
@@ -568,7 +590,7 @@ function upsert(text, routers, opts) {
568
590
  segments.splice(
569
591
  at,
570
592
  1,
571
- { type: 'chrome', raw: chrome.raw.slice(0, cut) + '\n\n' + renderProtocolSection() },
593
+ { type: 'chrome', raw: chrome.raw.slice(0, cut) + '\n\n' + renderProtocolSection(opts) },
572
594
  { type: 'chrome', raw: chrome.raw.slice(cut) }
573
595
  );
574
596
  }
@@ -697,5 +719,5 @@ module.exports = {
697
719
  HEADING, LEGACY_HEADINGS, parse, render, segment, upsert, sectionRaw, renderTable, renderMapSection, diff, removeBlock, renderedOf,
698
720
  STATE, BEGIN, END, OPTOUT, OPTOUT_RE, SECTION_RE, ROUTER_ROWS,
699
721
  // For fixtures only: the 1.69.0 protocol's lines, as the hand-edit guard knows them.
700
- PROTOCOL_1_69, MAP_1_69,
722
+ PROTOCOL_1_69, PROTOCOL_1_75, MAP_1_69, STAR_LINES,
701
723
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sshlg-skills",
3
- "version": "1.75.0",
3
+ "version": "1.76.0",
4
4
  "skillsCli": "skills@1.7.2",
5
5
  "description": "The ssheleg harness skill layer: routing, delivery gates, specialist skills and durable handoffs for coding agents.",
6
6
  "bin": {
package/skills.json CHANGED
@@ -76,13 +76,13 @@
76
76
  "evidence-docs",
77
77
  "project-audit"
78
78
  ],
79
- "version": "1.101.0",
79
+ "version": "1.101.1",
80
80
  "entry": "/task-pipeline",
81
81
  "role": "how a change reaches the repository",
82
82
  "npm": "task-pipeline-skill",
83
83
  "shape": "static",
84
84
  "shapeWhy": "The stage list is decided before the run and stays decided, because stage 10 has to account for what ran. THREE places discover structure, and they do not land the same way: the module map and the carry-over ledger are committed artifacts, and since v1.69.0 the work graph is a third — `.task-pipeline/graph.json`, mutated mid-run by `graph.py add` and deliberately NOT committed. Every mutation records why it happened, which is what keeps a run from explaining its completion by a plan that existed only at the end; that the graph itself does not survive the run is an open row rather than a settled decision.",
85
- "commit": "8c0a06404faf381b029f1080e1d9324d3b8d5fb1"
85
+ "commit": "c914a84d1240caef00c8ed4342b0ef3eddf4f5b0"
86
86
  },
87
87
  {
88
88
  "name": "agent-sync",
@@ -160,13 +160,13 @@
160
160
  "skillNames": [
161
161
  "seo-aeo-audit"
162
162
  ],
163
- "version": "0.30.0",
163
+ "version": "0.31.0",
164
164
  "entry": "/seo-aeo-audit",
165
165
  "role": "whether a machine will find it",
166
166
  "npm": "@ssheleg/seo-aeo-audit",
167
167
  "shape": "static, with a bounded discovery",
168
168
  "shapeWhy": "The ten tracks are fixed; **which** are in scope is decided per site at step 0 and written into the report, so the executed set is recoverable. An eleventh pass (Discover) is added by a stated condition, never by taste.",
169
- "commit": "3b2b13d693111784420fe13e3952a533967ed670"
169
+ "commit": "1cbb3610b484dfc700086c8470377944c0e405da"
170
170
  },
171
171
  {
172
172
  "name": "sheleg-dev",