sshlg-skills 1.76.4 → 1.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,3 +1,47 @@
1
+ ## v1.78.0 (2026-10-24): quiet core skills listed by name only
2
+
3
+ - **B-254:** `visibility` lists quiet core skills by name only on Claude Code. Measured
4
+ 2026-10-24 on Claude Code 2.1.299: `Skill listing over budget: 132 skills, 61725 chars > 30000
5
+ budget`; over budget the host keeps bundled skills whole, gives the rest their description
6
+ most-used first and lists the remainder by name. A personal skill in the core that was not
7
+ used within 14 days and is not named in `~/.claude/CLAUDE.md` now gets
8
+ `skillOverrides: "name-only"` (on this machine 22 skills, the launcher's estimate 46,402 to
9
+ 35,853 characters). `--full-days N|off`; ownership of each value is recorded
10
+ (`claudeNameOnly`), `--revert` removes only values still as written, and `update` re-applies
11
+ the tier only after an `--apply` that recorded `fullDays`. The listing estimate now counts
12
+ Claude's `- name: description` form, and the preview prints Claude Code's own last count
13
+ from its debug logs. `test/visibility_test.js` 22 to 29 checks,
14
+ `test/visibility_e2e_test.js` 11 to 15. Release impact card:
15
+ `docs/evidence/specs/2026-10-24-v1780-release-impact.md`.
16
+ - **Context audit, the same request:** B-255 (the listing still over budget: family and foreign
17
+ plugin descriptions) and B-256 (the 15,410-character routing block in every host file) are
18
+ open rows with their measurements; oversized project instruction files are tracked in the
19
+ HANDOFF entry.
20
+
21
+ ## v1.77.0 (2026-10-24): every release with users carries its impact card
22
+
23
+ - **Pins:** task-pipeline 1.102.0, the release impact card (operator, 2026-10-24): a release in a
24
+ project with users owes, before its tag, publish or deploy, a card naming who is affected and
25
+ how, the tracking that shows it going well with a watch window, the alert that fires when it
26
+ does not, and the rollback or hotfix with its decision trigger; stage 8 watches it
27
+ (`scripts/release_impact.py`, 47 cases); its own release carries the first card. Also B-155.
28
+ Member releases of what merged since their last tags (the family member gate and docs):
29
+ super-ux 0.66.1, sheleg-design 1.66.3, sheleg-dev 0.16.1, agent-sync 1.23.1, make-skill 0.33.1,
30
+ web3d-dev 0.2.3, xr-dev 0.4.3.
31
+
32
+ - **#267 closed:** `update` rolled telegram-dev back because one of its local scopes is a
33
+ subdirectory of a git repository (`sshlg-personal-os/apps/adops-bot`). Measured in a scratch
34
+ HOME on Claude Code 2.1.299: a local-scope update run in a repository's subdirectory moves the
35
+ repository root's record and leaves the subdirectory's unchanged, the B-251 worktree case
36
+ widened. The planner now resolves the address Claude uses (`claudeAddress()`: the repository
37
+ root, a worktree's main tree, or the directory itself outside a repository) and leaves a record
38
+ whose path differs from its address as recorded beside a recorded root, or blocks the member by
39
+ name without one. `test/claude_pinned_test.js` 37 to 40 cases.
40
+ - **B-253 closed:** the hygiene guard's `executablePart()` no longer drops text the shell would
41
+ still run: the `$(...)` and backtick substitutions in an unquoted-delimiter heredoc body fed to
42
+ a non-shell stay executable, and a `#` line inside a quote left open from an earlier line is
43
+ not a comment. `lib/guard.js` and `lib/repogate.js`, which reuse it, inherit the fix.
44
+
1
45
  ## v1.76.4 (2026-10-24): seo-aeo-audit pinned to 0.32.2
2
46
 
3
47
  - **seo-aeo-audit 0.32.2** (was 0.32.0), commit `08a57df`: `references/playbooks.md` grows. PB5
package/README.md CHANGED
@@ -46,17 +46,17 @@ scripts. No services, no telemetry, no API keys.
46
46
 
47
47
  | Skill | Version | What it does |
48
48
  |---|---|---|
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.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
- | **[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
- | **[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
- | **[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. |
49
+ | **[super-ux](https://github.com/ssheleg/super-ux)** | 0.66.1 | 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.102.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. |
51
+ | **[agent-sync](https://github.com/ssheleg/agent-sync)** | 1.23.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". |
52
+ | **[make-skill](https://github.com/ssheleg/make-skill)** | 0.33.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`. |
53
+ | **[sheleg-design](https://github.com/ssheleg/sheleg-design-skill)** | 1.66.3 | 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
54
  | **[seo-aeo-audit](https://github.com/ssheleg/seo-aeo-audit)** | 0.32.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. Before a site is built, `/seo-aeo-audit brief` writes the build-time brief that the audit later verifies. |
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. |
55
+ | **[sheleg-dev](https://github.com/ssheleg/sheleg-dev)** | 0.16.1 | 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.31.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.5.3 | 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, and a bot under load has its own reference: a poll that never waits on a handler, a queue per chat under one ceiling, payments outside it, guards measured from arrival, a bounded shutdown, with a discrete-event simulation whose nine invariants each go red without their rule. |
58
- | **[xr-dev](https://github.com/ssheleg/xr-dev)** | 0.4.2 | **`quest-lifecycle`** maps the product from platform choice through design, build, testing, Store, monetization, launch and operation. The existing owners cover native OpenXR, Kotlin Spatial/hybrid apps, measured rendering optimization, current-source/tool discovery, commercial and asset readiness, and WebXR/PWA. Every stage names evidence and a next action; Meta engine companions and official Godot XR documentation supply implementation detail. |
59
- | **[web3d-dev](https://github.com/ssheleg/web3d-dev)** | 0.2.2 | Realtime 3D on the web with three.js and React Three Fiber, split by the question. **`web3d-runtime`** — how the scene runs: WebGPURenderer and its WebGL2 fallback, TSL and compute, post-processing, device loss and profiling, led by the failures r186 keeps silent: `render()` before `init()` throws, `positionNode` collapses every instance to a point, `computeAsync` does not wait for the GPU, and about twenty drei components do not run on WebGPU. **`web3d-assets`** — the glTF pipeline from a source to the frame within a written budget: gltf-transform and gltfpack, KTX2 and meshopt, the loader that reads the result, sourcing and the four licence questions; it delegates orders to the asset service when the machine runs one and works by the same principles when not. **`web3d-animation`** — a two-sided animation protocol with a shared clip canon: rig, clips, blending, retargeting, root motion, crowds and vertex-animation textures. Every fact is pinned to three@0.186.1, and the gate checks each code block against that release's exports. |
58
+ | **[xr-dev](https://github.com/ssheleg/xr-dev)** | 0.4.3 | **`quest-lifecycle`** maps the product from platform choice through design, build, testing, Store, monetization, launch and operation. The existing owners cover native OpenXR, Kotlin Spatial/hybrid apps, measured rendering optimization, current-source/tool discovery, commercial and asset readiness, and WebXR/PWA. Every stage names evidence and a next action; Meta engine companions and official Godot XR documentation supply implementation detail. |
59
+ | **[web3d-dev](https://github.com/ssheleg/web3d-dev)** | 0.2.3 | Realtime 3D on the web with three.js and React Three Fiber, split by the question. **`web3d-runtime`** — how the scene runs: WebGPURenderer and its WebGL2 fallback, TSL and compute, post-processing, device loss and profiling, led by the failures r186 keeps silent: `render()` before `init()` throws, `positionNode` collapses every instance to a point, `computeAsync` does not wait for the GPU, and about twenty drei components do not run on WebGPU. **`web3d-assets`** — the glTF pipeline from a source to the frame within a written budget: gltf-transform and gltfpack, KTX2 and meshopt, the loader that reads the result, sourcing and the four licence questions; it delegates orders to the asset service when the machine runs one and works by the same principles when not. **`web3d-animation`** — a two-sided animation protocol with a shared clip canon: rig, clips, blending, retargeting, root motion, crowds and vertex-animation textures. Every fact is pinned to three@0.186.1, and the gate checks each code block against that release's exports. |
60
60
 
61
61
  They compose. `task-pipeline` hands user-facing work to `super-ux` and takes its
62
62
  leases from `agent-sync`; `make-skill` encodes the repo layout the others are
@@ -686,6 +686,17 @@ hides every other installed pack; an existing file is replaced only with `--repl
686
686
  so a plugin's skills stay listed (switch a foreign plugin off with `enabledPlugins`).
687
687
  The pack marks and the overrides below do not change them; `--keep <skill>` keeps a
688
688
  skill listed there.
689
+ - **Claude Code name-only tier** (B-254, since v1.78.0): a personal skill in the core that
690
+ was not used within 14 days and is not named in `~/.claude/CLAUDE.md` stays listed by name
691
+ without its description (`skillOverrides: "name-only"`). Claude Code 2.1.299 does the same
692
+ on its own once the listing is over budget (bundled skills whole, the others' descriptions
693
+ most-used first, the rest by name), so this picks the quiet ones by the operator's usage
694
+ instead of the host's order. `--full-days N` sets the window, `--full-days off` turns the
695
+ tier off. `update` re-applies it only after one `visibility --apply` that recorded
696
+ `fullDays`; an older record re-applies without it. The preview prints the launcher's
697
+ estimate of the listing and Claude Code's own last count from its debug logs (the one
698
+ `Skill listing over budget` line); the estimate leaves out bundled skills, plugin commands
699
+ and plugins loaded from other roots, so the logged count is the one to trust.
689
700
  - **Gemini, Pi, OpenCode and Hermes** hide the skills of marked packs, except the usage
690
701
  core. Strongest first: a family pack is never hidden; the usage core is never hidden
691
702
  (family skills, skills used in the last 60 days by Claude Code usage, skills
@@ -698,12 +709,13 @@ hides every other installed pack; an existing file is replaced only with `--repl
698
709
  npx sshlg-skills config set visibility.pack.anthropics/financial-services show # or hide, or default
699
710
  npx sshlg-skills visibility # preview: per-host counts, nothing written
700
711
  npx sshlg-skills visibility --apply # write each host's own switch, backups first; records consent
712
+ npx sshlg-skills visibility --apply --full-days off # Claude: keep every core description
701
713
  npx sshlg-skills visibility --revert # remove exactly what --apply wrote; withdraws consent
702
714
  ```
703
715
 
704
716
  | Host | The switch `visibility` writes | Source | A hidden skill can still |
705
717
  |---|---|---|---|
706
- | Claude Code | `skillOverrides: "user-invocable-only"` in `~/.claude/settings.json`; plugin skills are out of its reach | since v1.55.0; Claude Code settings reference: overrides do not apply to plugin skills | be run from the `/` menu by a person |
718
+ | Claude Code | `skillOverrides: "user-invocable-only"` (hidden) or `"name-only"` (quiet core) in `~/.claude/settings.json`; plugin skills are out of its reach | since v1.55.0; Claude Code settings reference: overrides do not apply to plugin skills | be run from the `/` menu by a person |
707
719
  | Codex | `enabled = false` entries in `~/.codex/config.toml` `[skills] config` | since v1.55.0 | be read from its SKILL.md path when asked |
708
720
  | Gemini CLI 0.63.0 | `skills.disabled` in `~/.gemini/settings.json`, the list `gemini skills disable <name> --scope user` writes; read back with `gemini skills list` (`[Disabled]`) | `packages/cli/src/utils/skillSettings.ts`; `SkillManager.getSkills()` drops disabled skills | come back with `gemini skills enable <name>` |
709
721
  | Pi 1.1.0 | `-<path>` exact exclusions in the `skills` array of `~/.pi/agent/settings.json`, one per folder holding the skill (`~/.agents/skills`, `~/.pi/agent/skills`); the file is created if absent and removed again by `--revert` | Pi's own docs, settings → Resources; `isEnabledByOverrides` in its `dist/core/package-manager.js` | be loaded for one session with `pi --skill <path>` |
@@ -314,8 +314,9 @@ Usage:
314
314
  # report header + footer, links looked up
315
315
  npx sshlg-skills toolkit [--for "<task>"] [--find "<concept>, …"] [--expand <provider>]
316
316
  # every skill this machine can reach
317
- npx sshlg-skills visibility [--apply | --revert] [--days 60] [--keep a,b]
317
+ npx sshlg-skills visibility [--apply | --revert] [--days 60] [--full-days 14|off] [--keep a,b]
318
318
  # Claude/Codex: hide all outside the core;
319
+ # Claude: quiet core skills name-only;
319
320
  # Gemini/Pi/OpenCode/Hermes: hide marked
320
321
  # packs; Cursor/Kimi: cannot hide
321
322
  npx sshlg-skills visibility marks [--init --show <owner/repo,…> [--replace] [--apply]]
@@ -773,6 +774,9 @@ function reapplyVisibility(f) {
773
774
  log(`\n== Skill visibility (re-applied: this machine ran \`visibility --apply\`; hosts: ${[...only].join(', ')}) ==`);
774
775
  return runVisibility({
775
776
  mode: 'apply', days: Number(rec.days) || undefined, keep: Array.isArray(rec.keep) ? rec.keep : [], only, reapply: true,
777
+ // A record from before the name-only tier carries no fullDays: re-apply keeps the old
778
+ // behaviour until the operator runs `visibility --apply` once (B-254, explicit consent).
779
+ fullDays: typeof rec.fullDays === 'number' ? rec.fullDays : null,
776
780
  }) === 0;
777
781
  }
778
782
 
@@ -2139,9 +2143,19 @@ function cmdVisibility(argv) {
2139
2143
  mode: flag('--revert') ? 'revert' : flag('--apply') ? 'apply' : 'preview',
2140
2144
  days: Number(value('--days')) || V.DEFAULT_DAYS,
2141
2145
  keep: (value('--keep') || '').split(',').map((s) => s.trim()).filter(Boolean),
2146
+ fullDays: fullDaysArg(value('--full-days'), V.DEFAULT_FULL_DAYS),
2142
2147
  });
2143
2148
  }
2144
2149
 
2150
+ /** `--full-days N` (a whole number of days), `--full-days off` (no name-only tier), or the default. */
2151
+ function fullDaysArg(raw, dflt) {
2152
+ if (raw === null) return dflt;
2153
+ if (raw === 'off') return null;
2154
+ const n = Number(raw);
2155
+ if (!Number.isInteger(n) || n < 0) { log(`visibility: --full-days takes a whole number of days or "off", got "${raw}"; using ${dflt}`); return dflt; }
2156
+ return n;
2157
+ }
2158
+
2145
2159
  /**
2146
2160
  * The work of `visibility`, callable from `update` (which re-applies it on a machine whose
2147
2161
  * record shows the operator ran `--apply`). `opts.only` limits the run to a set of host
@@ -2163,6 +2177,29 @@ function runVisibility(opts) {
2163
2177
  finally { lock.release(home, got.token); }
2164
2178
  }
2165
2179
 
2180
+ /**
2181
+ * Claude Code's own last listing count, read from its debug logs (newest first). Only the
2182
+ * one warning line is parsed; nothing else in a log is read into the output.
2183
+ */
2184
+ function lastListingMeasure(claudeRoot) {
2185
+ const dir = path.join(claudeRoot, 'debug');
2186
+ let files = [];
2187
+ try {
2188
+ files = fs.readdirSync(dir).filter((n) => n.endsWith('.txt'))
2189
+ .map((n) => ({ n, m: fs.statSync(path.join(dir, n)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, 40);
2190
+ } catch (e) { return null; }
2191
+ const re = /^(\S+) \[WARN\] Skill listing over budget: (\d+) skills, (\d+) chars > (\d+) budget/m;
2192
+ for (const f of files) {
2193
+ let text;
2194
+ try { text = fs.readFileSync(path.join(dir, f.n), 'utf8'); } catch (e) { continue; }
2195
+ const all = text.match(new RegExp(re.source, 'gm'));
2196
+ if (!all) continue;
2197
+ const m = re.exec(all[all.length - 1]);
2198
+ return { at: m[1], skills: Number(m[2]), chars: Number(m[3]), budget: Number(m[4]) };
2199
+ }
2200
+ return null;
2201
+ }
2202
+
2166
2203
  function runVisibilityUnlocked(opts) {
2167
2204
  const V = require(path.join(ROOT, 'lib', 'visibility.js'));
2168
2205
  const HV = require(path.join(ROOT, 'lib', 'hostvis.js'));
@@ -2179,6 +2216,8 @@ function runVisibilityUnlocked(opts) {
2179
2216
  const doRevert = opts.mode === 'revert';
2180
2217
  const days = opts.days || V.DEFAULT_DAYS;
2181
2218
  const keep = opts.keep || [];
2219
+ // null: no name-only tier (a re-apply of a record that predates it, or `--full-days off`).
2220
+ const fullDays = typeof opts.fullDays === 'number' ? opts.fullDays : null;
2182
2221
  const inScope = (id) => !opts.only || opts.only.has(id);
2183
2222
 
2184
2223
  const recordPath = path.join(home, '.sshlg-skills', 'visibility.json');
@@ -2226,11 +2265,24 @@ function runVisibilityUnlocked(opts) {
2226
2265
  try { settingsData = JSON.parse(settingsText || '{}'); } catch (e) { settingsData = {}; }
2227
2266
  const overrides = settingsData.skillOverrides || {};
2228
2267
  const mine = new Set(owned.claude.filter((n) => overrides[n] === V.HIDE));
2268
+ const ownedNameOnly = Array.isArray(owned.claudeNameOnly) ? owned.claudeNameOnly : [];
2269
+ const mineNameOnly = new Set(ownedNameOnly.filter((n) => overrides[n] === V.NAME_ONLY));
2229
2270
  const foreign = {};
2230
- for (const [k, v] of Object.entries(overrides)) if (!mine.has(k)) foreign[k] = v;
2231
- const plan = doRevert ? { hide: [], respected: [] } : V.claudePlan({ personal, core: coreSet, overrides: foreign, keep });
2232
- const claudeSet = plan.hide.filter((n) => !mine.has(n));
2233
- const claudeUnset = [...mine].filter((n) => !plan.hide.includes(n));
2271
+ for (const [k, v] of Object.entries(overrides)) if (!mine.has(k) && !mineNameOnly.has(k)) foreign[k] = v;
2272
+ const full = doRevert || fullDays === null ? null
2273
+ : V.fullSet({ personal, usage, now, fullDays, instructions });
2274
+ const plan = doRevert ? { hide: [], nameOnly: [], respected: [] }
2275
+ : V.claudePlan({ personal, core: coreSet, full, overrides: foreign, keep });
2276
+ // Values this run writes, and values it removes (only while they still hold what it wrote).
2277
+ const claudeSetMap = {};
2278
+ for (const n of plan.hide) if (overrides[n] !== V.HIDE) claudeSetMap[n] = V.HIDE;
2279
+ for (const n of plan.nameOnly) if (overrides[n] !== V.NAME_ONLY) claudeSetMap[n] = V.NAME_ONLY;
2280
+ const planned = new Set(plan.hide.concat(plan.nameOnly));
2281
+ const claudeUnsetMap = {};
2282
+ for (const n of mine) if (!planned.has(n)) claudeUnsetMap[n] = V.HIDE;
2283
+ for (const n of mineNameOnly) if (!planned.has(n)) claudeUnsetMap[n] = V.NAME_ONLY;
2284
+ const claudeSet = Object.keys(claudeSetMap);
2285
+ const claudeUnset = Object.keys(claudeUnsetMap);
2234
2286
  const stateOf = (s, ov) => {
2235
2287
  if (s.loaded === false) return 'hidden'; // installed, not loaded here (B-185): not in the listing
2236
2288
  if (s.namespace !== 'claude:plain') return 'on';
@@ -2239,7 +2291,7 @@ function runVisibilityUnlocked(opts) {
2239
2291
  return v === 'name-only' ? 'name-only' : 'on';
2240
2292
  };
2241
2293
  const after = Object.assign({}, overrides);
2242
- for (const n of claudeSet) after[n] = V.HIDE;
2294
+ for (const n of claudeSet) after[n] = claudeSetMap[n];
2243
2295
  for (const n of claudeUnset) delete after[n];
2244
2296
  const charsBefore = V.listingChars(skills.map((s) => ({ name: s.plugin && s.namespace === 'claude:plugin' ? `${s.plugin.split('@')[0]}:${s.id}` : s.id, description: s.description, state: stateOf(s, overrides) })));
2245
2297
  const charsAfter = V.listingChars(skills.map((s) => ({ name: s.plugin && s.namespace === 'claude:plugin' ? `${s.plugin.split('@')[0]}:${s.id}` : s.id, description: s.description, state: stateOf(s, after) })));
@@ -2336,11 +2388,21 @@ function runVisibilityUnlocked(opts) {
2336
2388
  log(` overrides (config.json): hidePacks ${(ov.hidePacks || []).length}, showPacks ${(ov.showPacks || []).length} — Gemini, Pi, OpenCode and Hermes only`);
2337
2389
  }
2338
2390
  if (inScope('claude')) {
2339
- log(` Claude: ${personal.length} personal skills; hide ${claudeSet.length} more, un-hide ${claudeUnset.length}; ` +
2391
+ const newHides = claudeSet.filter((n) => claudeSetMap[n] === V.HIDE).length;
2392
+ log(` Claude: ${personal.length} personal skills; hide ${newHides} more, name-only ${claudeSet.length - newHides} more, restore ${claudeUnset.length}; ` +
2340
2393
  `${Object.keys(foreign).length} operator-set override(s) left alone`);
2341
- log(` Claude listing ≈ ${charsBefore} → ${charsAfter} characters (names + descriptions, 1536 cap each).`);
2342
- log(' Budget: Claude Code logs it — `claude -p x --debug` then look for "Skill listing over budget"');
2343
- log(' (30000 characters measured on 2026-10-10). Over budget, descriptions drop least-used first.');
2394
+ log(fullDays === null
2395
+ ? ' name-only tier: off (`--full-days N` turns it on: core skills unused for N days keep their name, lose their description)'
2396
+ : ` name-only tier: core skills not used within ${fullDays} days and not named in the instructions are listed by name only (${plan.nameOnly.length})`);
2397
+ log(` Claude listing, launcher's estimate ≈ ${charsBefore} → ${charsAfter} characters`);
2398
+ log(' (personal and registered plugin skills in Claude\'s `- name: description` form; bundled skills,');
2399
+ log(' plugin commands and plugins loaded from other roots are not counted).');
2400
+ const measured = lastListingMeasure(claudeRoot);
2401
+ log(measured
2402
+ ? ` Claude Code's own count (debug log ${measured.at}): ${measured.skills} entries, ${measured.chars} characters > ${measured.budget} budget.`
2403
+ : ' Claude Code\'s own count: none logged yet. `claude -p x --debug`, then look for "Skill listing over budget".');
2404
+ log(' Over budget, Claude Code 2.1.299 keeps bundled skills whole, gives the others their description');
2405
+ log(' most-used first and lists the rest by name only.');
2344
2406
  }
2345
2407
  if (inScope('codex')) {
2346
2408
  log(` Codex: ${shared.length} shared skills; disable up to ${codexAdd.length} more (entries already present are left as they are), re-enable ${codexDrop.length}` +
@@ -2404,7 +2466,7 @@ function runVisibilityUnlocked(opts) {
2404
2466
  const degraded = [];
2405
2467
  let record = Object.assign({}, owned, {
2406
2468
  note: 'Written by `npx sshlg-skills visibility`; --revert removes these entries. Pending holds a write-ahead receipt; applied is consent for update on hosts only.',
2407
- days, keep, marksRevision: marksData && !markProblems.length ? marksData.revision : null,
2469
+ days, keep, fullDays, marksRevision: marksData && !markProblems.length ? marksData.revision : null,
2408
2470
  updatedAt: new Date().toISOString(), created: Object.assign({}, owned.created || {}),
2409
2471
  files: Object.assign({}, owned.files || {}, Object.fromEntries(Object.entries(files).filter(([id]) => inScope(id)))),
2410
2472
  });
@@ -2442,13 +2504,14 @@ function runVisibilityUnlocked(opts) {
2442
2504
  if (id === 'claude') {
2443
2505
  if (claudeSet.length && !('skillOverrides' in settingsData)) next.created.claude = ['skillOverrides'];
2444
2506
  if (doRevert) delete next.created.claude;
2507
+ next.claudeNameOnly = plan.nameOnly.slice().sort();
2445
2508
  }
2446
2509
  if (r.text === before) { journal.save(next); log(` ${id}: already as planned`); return; }
2447
2510
  transact(id, file, before, r.text, next, () => S.write(file, r.text, home));
2448
2511
  };
2449
2512
  const claudeCreated = createdOf('claude').includes('skillOverrides') || !Object.prototype.hasOwnProperty.call(owned, 'applied');
2450
2513
  writeSimple('claude', settingsPath, settingsText,
2451
- (t) => V.editClaudeSettings(t, { set: claudeSet, unset: claudeUnset, prune: claudeCreated }), () => plan.hide.slice().sort());
2514
+ (t) => V.editClaudeSettings(t, { set: claudeSetMap, unset: claudeUnsetMap, prune: claudeCreated }), () => plan.hide.slice().sort());
2452
2515
  writeSimple('codex', codexPath, codexText,
2453
2516
  (t) => V.editCodexConfig(t, { disable: codexAdd, enable: codexDrop }),
2454
2517
  (r) => [...new Set(owned.codex.filter((p) => codexWant.includes(p)).concat(r.added || []))].sort());
@@ -4,8 +4,8 @@
4
4
  {
5
5
  "name": "super-ux",
6
6
  "repo": "ssheleg/super-ux",
7
- "commit": "13195c6402705cb656961fb04ca6d1f8c1df3fb0",
8
- "version": "0.66.0",
7
+ "commit": "4965a0b5ff10bca27e7044d957f5cdb612841783",
8
+ "version": "0.66.1",
9
9
  "pluginInstall": "super-ux@super-ux",
10
10
  "pluginPath": "plugins/super-ux",
11
11
  "entry": {
@@ -13,7 +13,7 @@
13
13
  "displayName": "Super UX",
14
14
  "source": "./plugins/super-ux",
15
15
  "description": "Scenario-driven UI development: a versioned design chain in docs/ux/ — product vision -> personas, JTBD, journeys and stories -> user flows -> a screens+states UI map with Figma frames -> traced use-case scenarios -> evidence-backed audits -> concrete fix plans. Skills: vision, ux-foundation, ux-flows, ux-scenarios, ux-audit, brand-voice, copywriting. /ux is the single plain-language entry point and reaches every skill; a stdlib linter fails on doc drift; a tag-indexed best-practices catalog, PRN heuristics and component guidelines guide design; one style pack (via the sheleg-design companion) locks the visual identity.",
16
- "version": "0.66.0",
16
+ "version": "0.66.1",
17
17
  "author": {
18
18
  "name": "ssheleg",
19
19
  "url": "https://x.com/sshlg93"
@@ -40,7 +40,7 @@
40
40
  "files": [
41
41
  {
42
42
  "path": ".claude-plugin/plugin.json",
43
- "sha256": "42fd5c31e30c9df462bc7588731d2aa0e91de38d9e79bd039a165b163df345f8",
43
+ "sha256": "9a54d7d75b7d07030de41f0bfafff651b56cbf7063d0a2fcf4005f3b104d7635",
44
44
  "bytes": 1196
45
45
  },
46
46
  {
@@ -1073,8 +1073,8 @@
1073
1073
  {
1074
1074
  "name": "task-pipeline",
1075
1075
  "repo": "ssheleg/task-pipeline",
1076
- "commit": "c914a84d1240caef00c8ed4342b0ef3eddf4f5b0",
1077
- "version": "1.101.1",
1076
+ "commit": "34251bff4ab67bbaed8e290884327f03ad646ad8",
1077
+ "version": "1.102.0",
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.1",
1085
+ "version": "1.102.0",
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": "27aebdde4177506522664b4722111876ad30f2eeca938dfde28d25433ce7e625",
1108
+ "sha256": "0646241836573d8a111f38f4edb57d1d15621da1bfbaab7405ad14c1a9793ba4",
1109
1109
  "bytes": 1529
1110
1110
  },
1111
1111
  {
@@ -1305,13 +1305,13 @@
1305
1305
  },
1306
1306
  {
1307
1307
  "path": "skills/task-pipeline/pipeline.example.json",
1308
- "sha256": "253d7f3b83516933660b61e55b8756019caae182d759a2f1c5a21af9a0aba6d4",
1309
- "bytes": 25974
1308
+ "sha256": "e6caf3c47a5638d6bfdda19f16a58d3a8edc53a891c6363956d05e9febedaeb2",
1309
+ "bytes": 25999
1310
1310
  },
1311
1311
  {
1312
1312
  "path": "skills/task-pipeline/pipeline.schema.json",
1313
- "sha256": "4a123f1f501184a45de225e3568d60de0510b50d9b9e91e703b46d3e8550a930",
1314
- "bytes": 22920
1313
+ "sha256": "52739da82583aa96740359e6b3c3c6e9399d3f8c95df875e746fc460f1baf144",
1314
+ "bytes": 23552
1315
1315
  },
1316
1316
  {
1317
1317
  "path": "skills/task-pipeline/references/acceptance.md",
@@ -1325,8 +1325,8 @@
1325
1325
  },
1326
1326
  {
1327
1327
  "path": "skills/task-pipeline/references/artifacts.md",
1328
- "sha256": "49f82f9895b5e5df86471a1122d46adccdbccb3846f23485d815442e19af3044",
1329
- "bytes": 20165
1328
+ "sha256": "aa20a00752c9f5403212081cec24532da23f2aef5165827a448832b8c1bf84f9",
1329
+ "bytes": 20513
1330
1330
  },
1331
1331
  {
1332
1332
  "path": "skills/task-pipeline/references/audit.md",
@@ -1390,8 +1390,8 @@
1390
1390
  },
1391
1391
  {
1392
1392
  "path": "skills/task-pipeline/references/doctrine-map.md",
1393
- "sha256": "1928796d40bb9a9f4f2ec360063ad6d5101accbdb3755f62399beb90f5f9a880",
1394
- "bytes": 5350
1393
+ "sha256": "680452be2e1eadd42d7180ffeeaff2eb432b213e4dc4408f2d76bfc6de8e83fa",
1394
+ "bytes": 5543
1395
1395
  },
1396
1396
  {
1397
1397
  "path": "skills/task-pipeline/references/documentation.md",
@@ -1460,8 +1460,8 @@
1460
1460
  },
1461
1461
  {
1462
1462
  "path": "skills/task-pipeline/references/portability.md",
1463
- "sha256": "e9c039c741b743ed3ee0d93459773210fa79daeae9f55e2136aa5ceb1f113d48",
1464
- "bytes": 12060
1463
+ "sha256": "309fb98d58e9dc71ea3d3fd9f185371c70e745fbb42bc45614d015525a18691b",
1464
+ "bytes": 12313
1465
1465
  },
1466
1466
  {
1467
1467
  "path": "skills/task-pipeline/references/prioritisation.md",
@@ -1478,6 +1478,11 @@
1478
1478
  "sha256": "216f5d195c8b99aa7113d9fd19c6666b88b6b0cadd38eb93c840440fbabbb6eb",
1479
1479
  "bytes": 25540
1480
1480
  },
1481
+ {
1482
+ "path": "skills/task-pipeline/references/release-impact.md",
1483
+ "sha256": "182135808e6db37647cfb30dadede0deceecf4f6bd69dc9aa99589c9aefa2d1c",
1484
+ "bytes": 9909
1485
+ },
1481
1486
  {
1482
1487
  "path": "skills/task-pipeline/references/residue.md",
1483
1488
  "sha256": "1c63c29404ef1200c492e823bbf464f08c7dea71cda79a9dbb9dfbc8c4dad991",
@@ -1540,13 +1545,13 @@
1540
1545
  },
1541
1546
  {
1542
1547
  "path": "skills/task-pipeline/references/stage-07-lint-deploy.md",
1543
- "sha256": "2a1eeb370e346a679d05b2e1670f0cd4a2e8ebc485538f92e63ec3b185d6f138",
1544
- "bytes": 936
1548
+ "sha256": "6af757f8c22c4da3169600f3bb9bcf2f631411e8d676ad53b811fe154111bce3",
1549
+ "bytes": 1444
1545
1550
  },
1546
1551
  {
1547
1552
  "path": "skills/task-pipeline/references/stage-08-post-deploy.md",
1548
- "sha256": "b2d1c70fe9261d62985c1356b5650df3006f0e4e7dd8534753d824f43899bd2a",
1549
- "bytes": 2002
1553
+ "sha256": "bc10341cbc6b9356311ae62021a0182768930fc0221dcb142bf6d491262c79ab",
1554
+ "bytes": 2465
1550
1555
  },
1551
1556
  {
1552
1557
  "path": "skills/task-pipeline/references/stage-09-docs-wiki.md",
@@ -1560,8 +1565,8 @@
1560
1565
  },
1561
1566
  {
1562
1567
  "path": "skills/task-pipeline/references/stages.md",
1563
- "sha256": "d45637faf55c26e1a9e2d25e2fa7fca6ead1153d6f9cab2d536e6bad9723aed1",
1564
- "bytes": 37900
1568
+ "sha256": "cd2a737e30e96ef29a90c9d30790159a6eb88b223b524d46c46659d861498deb",
1569
+ "bytes": 38987
1565
1570
  },
1566
1571
  {
1567
1572
  "path": "skills/task-pipeline/references/tdd.md",
@@ -1605,7 +1610,7 @@
1605
1610
  },
1606
1611
  {
1607
1612
  "path": "skills/task-pipeline/scripts/graph.py",
1608
- "sha256": "a0d6c501ef4bf17b0f93b66e828ea662b925682bea7f9fbf8ca481f06df8925f",
1613
+ "sha256": "503afebfa1891badd0c5bf4dc7b41ee832021ddb1fdc5d0192d9cec507728a44",
1609
1614
  "bytes": 115059
1610
1615
  },
1611
1616
  {
@@ -1623,6 +1628,11 @@
1623
1628
  "sha256": "0c1c2a55b9907147c9f8f5dc9075f67b050df6d79581eef4dca4c89ec33e8728",
1624
1629
  "bytes": 17215
1625
1630
  },
1631
+ {
1632
+ "path": "skills/task-pipeline/scripts/release_impact.py",
1633
+ "sha256": "b9a6803e5ddd23372b737e428211c5b092c72e05209d1988356c4475c8778cee",
1634
+ "bytes": 11959
1635
+ },
1626
1636
  {
1627
1637
  "path": "skills/task-pipeline/scripts/resource_guard.py",
1628
1638
  "sha256": "6a66cb6b1e2826b3825e4f8c18a995eaa9934deda4b24a4d9c98b8c44e143abc",
@@ -1765,8 +1775,13 @@
1765
1775
  },
1766
1776
  {
1767
1777
  "path": "skills/task-pipeline/templates/README.md",
1768
- "sha256": "664ba4d50bd4ec6c7d6351189efb5004d162956219c44b54841d3374c9b26380",
1769
- "bytes": 5560
1778
+ "sha256": "cb2cdbd2d93d7bc8a06fc54d8b2d218b57d2911b7c7dc925320877c1e9733ee6",
1779
+ "bytes": 5811
1780
+ },
1781
+ {
1782
+ "path": "skills/task-pipeline/templates/release-impact.md",
1783
+ "sha256": "7d3d2b9e693b9cf42e47ffbbcafd7b5e4f033bfdfa381762175de7a38664c295",
1784
+ "bytes": 2141
1770
1785
  },
1771
1786
  {
1772
1787
  "path": "skills/task-pipeline/templates/retro-archive.md",
@@ -1785,7 +1800,7 @@
1785
1800
  },
1786
1801
  {
1787
1802
  "path": "skills/task-pipeline/templates/run.md",
1788
- "sha256": "126bfb4a4c18719eb41c485e830e1d40433f491b05a7e53a908214d930faedb0",
1803
+ "sha256": "bd89a1680e6f861d435df9caf0685385fa3f1d7ff7fbea93c153fde2c3be0b8e",
1789
1804
  "bytes": 13120
1790
1805
  },
1791
1806
  {
@@ -1803,8 +1818,8 @@
1803
1818
  {
1804
1819
  "name": "agent-sync",
1805
1820
  "repo": "ssheleg/agent-sync",
1806
- "commit": "5c169af9097f8192fe8786014fb08b3e8fe2204d",
1807
- "version": "1.23.0",
1821
+ "commit": "7c3f18aed38b4fa8d8c8d4d7da9df223141cb7ef",
1822
+ "version": "1.23.1",
1808
1823
  "pluginInstall": "agent-sync@agent-sync",
1809
1824
  "pluginPath": "plugins/agent-sync",
1810
1825
  "entry": {
@@ -1812,7 +1827,7 @@
1812
1827
  "displayName": "Agent Sync",
1813
1828
  "source": "./plugins/agent-sync",
1814
1829
  "description": "Coordination layer for multi-agent repositories. Gives task-pipeline runs leases with a TTL, race-free ID reservation, a cross-repo signal feed, an append-only run journal and a machine-generated read-only board. A lease is decided by a primitive that genuinely has compare-and-swap — an atomic file create on one machine, a pushed git ref across machines — never by the knowledge base, which loses concurrent writes; the store carries the record and the ID allocation, which is positional over the merged log. The knowledge backend is a pluggable adapter (Outline, filesystem) declaring its own capabilities and degrading out loud. Ships Claude Code hooks that deny edits to guarded registry files without a live lease.",
1815
- "version": "1.23.0",
1830
+ "version": "1.23.1",
1816
1831
  "author": {
1817
1832
  "name": "ssheleg",
1818
1833
  "url": "https://x.com/sshlg93"
@@ -1835,7 +1850,7 @@
1835
1850
  "files": [
1836
1851
  {
1837
1852
  "path": ".claude-plugin/plugin.json",
1838
- "sha256": "bca81db5728d6686d6664f3d248660e7155ad504a033eea65cbd4c43697b6291",
1853
+ "sha256": "69b086ad9fa4b2a71efee43fc01302fe40aa16e377c17586d058553ab7ba8a5c",
1839
1854
  "bytes": 695
1840
1855
  },
1841
1856
  {
@@ -1935,7 +1950,7 @@
1935
1950
  },
1936
1951
  {
1937
1952
  "path": "skills/agent-sync/scripts/agent_sync.py",
1938
- "sha256": "fc35d561ff73efbb31be792f2bfe46e51d72bcc8b8a04627f07aa0bf377b33d0",
1953
+ "sha256": "80a162732f4f8fe0cbca7df7355bbc757ed98e038d7e1ac9b2708de120b575d8",
1939
1954
  "bytes": 376420
1940
1955
  },
1941
1956
  {
@@ -1945,7 +1960,7 @@
1945
1960
  },
1946
1961
  {
1947
1962
  "path": "skills/agent-sync/SKILL.md",
1948
- "sha256": "6807c2cf0eb8e8ad675c8bf92d7eed550baeb8420442cdaf4002ab43a6b0c1e7",
1963
+ "sha256": "d49b5b0dad05af9a988d0cc31ef483be2d1006d01b21e519afc44691764dcd0d",
1949
1964
  "bytes": 19971
1950
1965
  }
1951
1966
  ]
@@ -1953,8 +1968,8 @@
1953
1968
  {
1954
1969
  "name": "make-skill",
1955
1970
  "repo": "ssheleg/make-skill",
1956
- "commit": "7745e2c646c0642af8aa0796522867ba115a0f42",
1957
- "version": "0.33.0",
1971
+ "commit": "c59b0761cb57c8a67bb35e18615ca6f77c08b170",
1972
+ "version": "0.33.1",
1958
1973
  "pluginInstall": "make-skill@make-skill",
1959
1974
  "pluginPath": "plugins/make-skill",
1960
1975
  "entry": {
@@ -1962,7 +1977,7 @@
1962
1977
  "displayName": "Make Skill",
1963
1978
  "source": "./plugins/make-skill",
1964
1979
  "description": "Encodes the Agent Skills open standard AND Anthropic's platform rules (front-matter limits, disclosure budgets, per-surface runtime limits, the Skills API, evaluation-driven authoring) plus the Claude Code plugin reference (manifest schemas, component layout, `claude plugin validate --strict`) and the proven ssheleg pipeline: marketplace repo layout, version sync, validator + CI, multi-channel distribution (Claude Code plugin, vercel skills CLI, npx, Cursor), npm gotchas, end-to-end first publish, the review checklist for third-party skills, and MCP / A2A rules for protocol-connected skills.",
1965
- "version": "0.33.0",
1980
+ "version": "0.33.1",
1966
1981
  "author": {
1967
1982
  "name": "ssheleg",
1968
1983
  "url": "https://x.com/sshlg93"
@@ -1990,7 +2005,7 @@
1990
2005
  "files": [
1991
2006
  {
1992
2007
  "path": ".claude-plugin/plugin.json",
1993
- "sha256": "0cab374d5d4bfc6d3a54a506170e3653fd6d2a7d48308ef4fbf815e25fa67f28",
2008
+ "sha256": "9e7c1b71a83cb84b5cc4d37c0b6d1b266caeba63c3167252295d88a1e42320dc",
1994
2009
  "bytes": 1093
1995
2010
  },
1996
2011
  {
@@ -2110,12 +2125,12 @@
2110
2125
  },
2111
2126
  {
2112
2127
  "path": "skills/make-skill/SKILL.md",
2113
- "sha256": "7fbbdfe703da183be326b04b8842fb3e71b45b16624c701333ec3cb1fce900d1",
2128
+ "sha256": "0e97e39e38c9bacdfc99c4a2744daada24a4820e40cdbae838fa86184e644ca5",
2114
2129
  "bytes": 19692
2115
2130
  },
2116
2131
  {
2117
2132
  "path": "skills/skill-search/SKILL.md",
2118
- "sha256": "79b79c7b65262400dc34e5f452668a1f7743d536301a05563d2ef2d67c0aba0b",
2133
+ "sha256": "2cb5cbe4a884dcc14c77ae697f5ff4de548f3aad67d036482c37af42659f0773",
2119
2134
  "bytes": 3490
2120
2135
  }
2121
2136
  ]
@@ -2123,8 +2138,8 @@
2123
2138
  {
2124
2139
  "name": "sheleg-design",
2125
2140
  "repo": "ssheleg/sheleg-design-skill",
2126
- "commit": "9d8dd8b36362d38a112d726c459c31a38c2b6673",
2127
- "version": "1.66.2",
2141
+ "commit": "f5743d2259da679a157e9d1c01b90e8e3e1d969a",
2142
+ "version": "1.66.3",
2128
2143
  "pluginInstall": "sheleg-design@sheleg-design-skill",
2129
2144
  "pluginPath": "plugins/sheleg-design",
2130
2145
  "entry": {
@@ -2132,7 +2147,7 @@
2132
2147
  "displayName": "SHELEG Design",
2133
2148
  "source": "./plugins/sheleg-design",
2134
2149
  "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-nine pluggable visual style packs, each with a ready-made token layer — instrument-console (near-black aerospace console; technical systems and infrastructure), editorial-luxury (cream and espresso; editorial, research, premium B2B), workbench (quiet light/dark UI; dashboards, admin, internal tools), briefing-room (dark 16:9 deck; investor and board presentations), atrium (cream daylight; consumer health and high-trust DTC), babylove (white with orange; SEO SaaS, long time-to-value, disconnected states), patchbay (black with mint-cyan; engines, buses, pipelines, OSS front doors), nameplate (cool slab with coral; press, certification and third-party trust), rimlight (white with blue light; studios, services and case studies), onionskin (white working sheet; developer and AI infrastructure), deskmate (warm beige with a dusk bleed; AI coworkers and chat-native agents), test-drive (warm paper with one coral; self-serve SaaS proven by the live product), surveyor (peach paper with teal and pink; visibility, monitoring and benchmark tools), chorus (warm paper under a crosshair grid, with a cut-corner bubble; AI-search visibility, brand monitoring and community marketing), outrank (white with violet; one brand across marketing and product), orchard (warm oat slabs; friendly biotech and wellness), field-notes (ruled green paper; auditable open-source developer tools), showroom (white gallery; product-led companies selling the app), blueprint (white technical stock; vector, storage and query infrastructure), prism (iridescent hard edge; command-first OSS infrastructure), maquette (near-black table; enterprise data infrastructure), cyclorama (looping pastel field; applied-AI consultancies), scoreboard (warm paper; growth, ads and accumulating metrics), datasheet (off-white specification; fraud, identity and device intelligence), manpage (cream manual; APIs, SDKs, CLIs and MCP servers), pigeonhole (filed white field; inbox, ticket and CRM triage), roster (faint square grid; platforms sold through who uses them), ora (warm coal; machine verdicts, audits and protocol traces), tenor (warm management paper; agent operations and autonomous back office), ledger (cream ruled console; analysts, BI and warehouse agents), paperclip (monochrome coal; orchestrators, schedulers and job runners), awning (white commerce forecourt; storefront, payroll and billing platforms), router (pale console with hairlines; dashboard, billing and inventory surfaces), daylight (bright portal with one shadow; client onboarding and service portals), notation (restrained technical hairlines; OSS, docs and developer workspaces), almanac (oatmeal editorial paper; manifestos and category-defining pages), vitrine (serif trust display; evaluated B2B, security and compliance), proscenium (white demo sequence; product tours and launch pages), bulletin (cheerful outlined bands; broad SMB and agency platforms). Ships the sheleg-design skill, the architecture reference, the motion doctrine, the Figma and Claude Design bridges, AI-surface patterns, the packs' token CSS, and the /sheleg-design command.",
2135
- "version": "1.66.2",
2150
+ "version": "1.66.3",
2136
2151
  "author": {
2137
2152
  "name": "ssheleg",
2138
2153
  "url": "https://x.com/sshlg93"
@@ -2159,7 +2174,7 @@
2159
2174
  "files": [
2160
2175
  {
2161
2176
  "path": ".claude-plugin/plugin.json",
2162
- "sha256": "c5ccd0f385217a5f5c69a80d8dc8ddc93b3ae9f36058c7617d13d96747a6a260",
2177
+ "sha256": "42d48b7b499f73a53b4660f3d97a6a5253ab8ebafdeb575bb61e313f6ea59df7",
2163
2178
  "bytes": 3896
2164
2179
  },
2165
2180
  {
@@ -2244,7 +2259,7 @@
2244
2259
  },
2245
2260
  {
2246
2261
  "path": "skills/sheleg-design/SKILL.md",
2247
- "sha256": "3e3c5afea5716b27238a7b13eb728be7adcefe41562542b8d0b9b88e480cc0d1",
2262
+ "sha256": "e1acc4d721e55a85c871a2172948e63405a393baa936ff2e7b8455565e5fa218",
2248
2263
  "bytes": 19980
2249
2264
  },
2250
2265
  {
@@ -2919,8 +2934,8 @@
2919
2934
  {
2920
2935
  "name": "sheleg-dev",
2921
2936
  "repo": "ssheleg/sheleg-dev",
2922
- "commit": "5842df5677ab330738ea5ef4c14add4f7dea089d",
2923
- "version": "0.16.0",
2937
+ "commit": "fa5a739960973aaacabfe0fb5db8b4f5e856f232",
2938
+ "version": "0.16.1",
2924
2939
  "pluginInstall": "sheleg-dev@sheleg-dev",
2925
2940
  "pluginPath": "plugins/sheleg-dev",
2926
2941
  "entry": {
@@ -2928,7 +2943,7 @@
2928
2943
  "displayName": "Sheleg Dev",
2929
2944
  "source": "./plugins/sheleg-dev",
2930
2945
  "description": "The integration layer a product needs once it has users: Stripe subscription billing reconciled into your own database, crypto payments that survive over-payment and duplicate webhooks, ad and conversion tracking under Consent Mode v2, Google sign-in with the account-linking guards, the wider Google auth surface, and Core Web Vitals work that moves the score, 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.",
2931
- "version": "0.16.0",
2946
+ "version": "0.16.1",
2932
2947
  "author": {
2933
2948
  "name": "ssheleg",
2934
2949
  "url": "https://x.com/sshlg93"
@@ -2957,7 +2972,7 @@
2957
2972
  "files": [
2958
2973
  {
2959
2974
  "path": ".claude-plugin/plugin.json",
2960
- "sha256": "4897cd65af1c37c75cd94c81324d2de8bb4973e0545f235a5c787ff7e0d83396",
2975
+ "sha256": "89e576714f389c51efccc25512df9ca65a5576e46691dc4ded0e5a14f5109250",
2961
2976
  "bytes": 1221
2962
2977
  },
2963
2978
  {
@@ -3635,15 +3650,15 @@
3635
3650
  {
3636
3651
  "name": "xr-dev",
3637
3652
  "repo": "ssheleg/xr-dev",
3638
- "commit": "98e26301a664232cd27c6ad9737bb74547dd4e1a",
3639
- "version": "0.4.2",
3653
+ "commit": "ba885bb48d2737902628c3a9e4d512379feb65c6",
3654
+ "version": "0.4.3",
3640
3655
  "pluginInstall": "xr-dev@xr-dev",
3641
3656
  "pluginPath": "plugins/xr-dev",
3642
3657
  "entry": {
3643
3658
  "name": "xr-dev",
3644
3659
  "displayName": "XR Dev",
3645
3660
  "description": "Seven skills for the Meta Quest product lifecycle: platform and engine discovery, immersive design, native OpenXR, Kotlin Spatial and hybrid apps, WebXR/PWA, rendering experiments, tool and source discovery, Store submission, monetization, launch assets and post-launch operation. Agents receive stage-specific next actions, evidence gates and fallbacks when tools or devices are absent. Engine specialists remain separate; live requirements are verified against current Meta documentation.",
3646
- "version": "0.4.2",
3661
+ "version": "0.4.3",
3647
3662
  "author": {
3648
3663
  "name": "ssheleg",
3649
3664
  "url": "https://x.com/sshlg93"
@@ -3681,7 +3696,7 @@
3681
3696
  "files": [
3682
3697
  {
3683
3698
  "path": ".claude-plugin/plugin.json",
3684
- "sha256": "766b9b27824b8f9c24ad690e40e2e6e6001ed8e5f731f9635a752b2ba66def53",
3699
+ "sha256": "5ddea375283df66b668a8880fa9f8a2dd0b8501449c7142125b7406ed655713b",
3685
3700
  "bytes": 1200
3686
3701
  },
3687
3702
  {
@@ -3701,7 +3716,7 @@
3701
3716
  },
3702
3717
  {
3703
3718
  "path": "skills/quest-lifecycle/SKILL.md",
3704
- "sha256": "52b2128d47e933094a22c63b9e17a0fb273c39cfaf571da8f6ef206ae2a3ca6d",
3719
+ "sha256": "4c5defbf25df5196bbae70fe26511d556845ffdc35d0b8e14f322aedc1d432f1",
3705
3720
  "bytes": 6283
3706
3721
  },
3707
3722
  {
@@ -3731,7 +3746,7 @@
3731
3746
  },
3732
3747
  {
3733
3748
  "path": "skills/quest-native/SKILL.md",
3734
- "sha256": "f83a678180a1aec766cb760283f024f53d5e34bd0795e8443a560bc85bab5da4",
3749
+ "sha256": "b059d2e0cdd2dd071cb9a1d86e1c0548559358365bf18646afea3cff92a9469e",
3735
3750
  "bytes": 9777
3736
3751
  },
3737
3752
  {
@@ -3751,7 +3766,7 @@
3751
3766
  },
3752
3767
  {
3753
3768
  "path": "skills/quest-perf/SKILL.md",
3754
- "sha256": "93cca47df4aa28d77a6f818bd5bd67f8ee406274b66a6d36404c1eb4b7907324",
3769
+ "sha256": "01d80cfcd2c026076d728e1d61cf198585d3a6a5a117e387ae47669273af7458",
3755
3770
  "bytes": 7155
3756
3771
  },
3757
3772
  {
@@ -3781,7 +3796,7 @@
3781
3796
  },
3782
3797
  {
3783
3798
  "path": "skills/quest-spatial/SKILL.md",
3784
- "sha256": "003e78099a8b438955f74d492cebf6530fdb581c791afe33cd0937f4cfa095f9",
3799
+ "sha256": "b4adbbda3e4e51caf6b91532c69dd0c910ea3b7524a26af61d49ebad0e71f824",
3785
3800
  "bytes": 8890
3786
3801
  },
3787
3802
  {
@@ -3806,7 +3821,7 @@
3806
3821
  },
3807
3822
  {
3808
3823
  "path": "skills/quest-store/SKILL.md",
3809
- "sha256": "dbece3ee9ee45f252360691333026a875f0bdb4abe022969c77476910b5ce3ed",
3824
+ "sha256": "bcc8e86d2eebdce7e3930e4c11caa0bc4d1b81b55335fc687378104c8cd0fc49",
3810
3825
  "bytes": 8416
3811
3826
  },
3812
3827
  {
@@ -3826,7 +3841,7 @@
3826
3841
  },
3827
3842
  {
3828
3843
  "path": "skills/quest-tooling/SKILL.md",
3829
- "sha256": "313027fb192461588c7b047d31777fa3014d01f091e59c9b0a7f54281726725f",
3844
+ "sha256": "5b6c343a5db725e3f630a8b5393c85139ed892afec54de113f86dae50a2def4d",
3830
3845
  "bytes": 8677
3831
3846
  },
3832
3847
  {
@@ -3841,7 +3856,7 @@
3841
3856
  },
3842
3857
  {
3843
3858
  "path": "skills/quest-webxr/SKILL.md",
3844
- "sha256": "370b86a7c9a47bcc7d472e9535cf2c5a9a0f289ae5c2700753c0dfa25ffa7461",
3859
+ "sha256": "3a42715f14f32009c4e50b3ccae8e6fe33c4d574fb18561b343bfd27e808457e",
3845
3860
  "bytes": 6526
3846
3861
  }
3847
3862
  ]
@@ -3849,15 +3864,15 @@
3849
3864
  {
3850
3865
  "name": "web3d-dev",
3851
3866
  "repo": "ssheleg/web3d-dev",
3852
- "commit": "7c04756d0124bb26b749535dc0ebb975741b19fb",
3853
- "version": "0.2.2",
3867
+ "commit": "c1f45420bfcbb1f03cd37e7fb95abdac1ce89f69",
3868
+ "version": "0.2.3",
3854
3869
  "pluginInstall": "web3d-dev@web3d-dev",
3855
3870
  "pluginPath": "plugins/web3d-dev",
3856
3871
  "entry": {
3857
3872
  "name": "web3d-dev",
3858
3873
  "displayName": "Web3D Dev",
3859
3874
  "description": "Three skills for realtime 3D on the web: the three.js WebGPU runtime with TSL, compute, post-processing and a WebGL2 fallback; the glTF asset pipeline from source to frame, with compression, budgets, sourcing and optional asset-service ordering; and a 3D animation protocol covering rigs, clip conventions, blending, GPU and instanced animation, and reduced motion. Every API fact is pinned to a verified three.js release.",
3860
- "version": "0.2.2",
3875
+ "version": "0.2.3",
3861
3876
  "author": {
3862
3877
  "name": "ssheleg",
3863
3878
  "url": "https://x.com/sshlg93"
@@ -3891,7 +3906,7 @@
3891
3906
  "files": [
3892
3907
  {
3893
3908
  "path": ".claude-plugin/plugin.json",
3894
- "sha256": "b908de45fd41fb40cc639e0b13fcc5274fb22ee3e3fa75651c9dab3828f5a1df",
3909
+ "sha256": "c1b85054996b3ce96b998e21c567a270a421494b4f20f9acb535f68fad94fe8d",
3895
3910
  "bytes": 1092
3896
3911
  },
3897
3912
  {
@@ -3911,7 +3926,7 @@
3911
3926
  },
3912
3927
  {
3913
3928
  "path": "skills/web3d-animation/SKILL.md",
3914
- "sha256": "8a95f66a049e7dc76bf798f7f28e67ff16cd85c2a3c8b03a49578669815e1549",
3929
+ "sha256": "c9e149c1c9b9f0f5c6fd74e2a101063059e74ca8a0c26ee9a6aa3b352c709a58",
3915
3930
  "bytes": 10234
3916
3931
  },
3917
3932
  {
@@ -3936,7 +3951,7 @@
3936
3951
  },
3937
3952
  {
3938
3953
  "path": "skills/web3d-assets/SKILL.md",
3939
- "sha256": "50abe858fe91e0203c42da1bbf5aaa897f697479b696c4fca58a30fd4f32f7db",
3954
+ "sha256": "9f811a6a00f50e1820d7153739dca5b7a54b3f0374025e00b078d389d0d0791d",
3940
3955
  "bytes": 8664
3941
3956
  },
3942
3957
  {
@@ -3956,7 +3971,7 @@
3956
3971
  },
3957
3972
  {
3958
3973
  "path": "skills/web3d-runtime/SKILL.md",
3959
- "sha256": "27103ee44ce4867be6fba80306d1daf696c9dcea9360eec89363d6100d373796",
3974
+ "sha256": "f3b54dc2c9540d96273832f49dbeb6a34a34a2b5ac5d0186e2417fd8fbd70c53",
3960
3975
  "bytes": 7721
3961
3976
  }
3962
3977
  ]
@@ -63,6 +63,17 @@ function worktreeMain(dir) {
63
63
  const gitdir=path.resolve(dir,m[1]),at=gitdir.lastIndexOf(path.sep+'.git'+path.sep+'worktrees'+path.sep);
64
64
  return at<0?null:physical(gitdir.slice(0,at));
65
65
  }
66
+ // The project Claude Code addresses a local scope by (measured on 2.1.299): the root of the
67
+ // git repository the directory sits in, a linked worktree's main working tree, and the
68
+ // directory itself outside any repository. A submodule checkout is its own root. (#267, B-251)
69
+ function claudeAddress(dir) {
70
+ for(let d=dir;;) {
71
+ let st=null;try{st=fs.lstatSync(path.join(d,'.git'));}catch(_){}
72
+ if(st && st.isDirectory()) return {address:d,worktree:false};
73
+ if(st && st.isFile()) {const main=worktreeMain(d);return main?{address:main,worktree:true}:{address:d,worktree:false};}
74
+ const up=path.dirname(d);if(up===d) return {address:dir,worktree:false};d=up;
75
+ }
76
+ }
66
77
  function prepare(members,inventory,opts) {
67
78
  const requested={profile:path.resolve(opts.profileRoot),home:path.resolve(opts.home)};
68
79
  const rows=Source.validate(inventory,members),profile=Bindings.profilePath(requested.profile),home=Bindings.profilePath(requested.home);
@@ -120,10 +131,11 @@ function prepare(members,inventory,opts) {
120
131
  // A linked git worktree: Claude runs a local-scope update from it against its main
121
132
  // repository's record (measured on 2.1.299, 2026-10-22), so the worktree's own
122
133
  // record is left as recorded beside a recorded main, and blocks without one.
123
- const main=real===r.projectPath?worktreeMain(real):null;
134
+ const at=real===r.projectPath?claudeAddress(real):null;
135
+ const main=at && at.address!==real?at.address:null;
124
136
  if(main) {
125
137
  if(locals.some(o=>o!==r && o.projectPath===main)) {aliases.push({projectPath:r.projectPath,real:main,record:r});continue;}
126
- unaddressable=r.projectPath+' is a git worktree of '+main+', which has no record';break;
138
+ unaddressable=r.projectPath+(at.worktree?' is a git worktree of ':' is inside the git repository ')+main+', which has no record';break;
127
139
  }
128
140
  if(real===r.projectPath && fs.statSync(real).isDirectory()) targets.push({scope:'local',projectPath:r.projectPath,record:r});
129
141
  // A path that resolves to ANOTHER record's project is that project under an
package/lib/hygiene.js CHANGED
@@ -73,23 +73,72 @@ function isFlag(token) {
73
73
  */
74
74
  const HEREDOC_SHELLS = new Set(['bash', 'sh', 'zsh', 'dash', 'ksh', 'eval', 'source', '.']);
75
75
 
76
+ /**
77
+ * B-253: the command substitutions in a piece of text, `$(...)` (not arithmetic `$((`) and
78
+ * backticks, outermost only. The shell runs these inside an unquoted-delimiter heredoc body
79
+ * even when the body itself is fed to a non-shell, so they are executable text.
80
+ */
81
+ function substitutions(text) {
82
+ const out = [];
83
+ const t = String(text || '');
84
+ for (let i = 0; i < t.length; i += 1) {
85
+ if (t[i] === '\\') { i += 1; continue; }
86
+ if (t[i] === '$' && t[i + 1] === '(' && t[i + 2] !== '(') {
87
+ let depth = 1, j = i + 2;
88
+ for (; j < t.length && depth; j += 1) { if (t[j] === '(') depth += 1; else if (t[j] === ')') depth -= 1; }
89
+ out.push(t.slice(i + 2, depth ? j : j - 1));
90
+ i = j - 1;
91
+ } else if (t[i] === '`') {
92
+ const j = t.indexOf('`', i + 1);
93
+ out.push(t.slice(i + 1, j < 0 ? t.length : j));
94
+ i = j < 0 ? t.length : j;
95
+ }
96
+ }
97
+ return out;
98
+ }
99
+
100
+ /** Whether a quote opened on this line is still open at its end, given the state at its start. */
101
+ function quoteAfter(line, open) {
102
+ let q = open;
103
+ for (let i = 0; i < line.length; i += 1) {
104
+ const c = line[i];
105
+ if (q === null) {
106
+ if (c === '\\') { i += 1; continue; }
107
+ if (c === '#' && (i === 0 || /\s/.test(line[i - 1]))) break; // the rest is a comment
108
+ if (c === '"' || c === "'") q = c;
109
+ } else if (q === '"') {
110
+ if (c === '\\') { i += 1; continue; }
111
+ if (c === '"') q = null;
112
+ } else if (c === "'") {
113
+ q = null;
114
+ }
115
+ }
116
+ return q;
117
+ }
118
+
76
119
  function executablePart(command) {
77
120
  const lines = String(command || '').split('\n');
78
121
  const out = [];
79
122
  let terminator = null;
80
123
  let dropping = false;
124
+ let expands = false;
125
+ let open = null; // a quote still open from an earlier line (B-253)
81
126
  for (const line of lines) {
82
127
  if (terminator !== null) {
83
128
  // The terminator may be indented when the heredoc used `<<-`.
84
129
  if (line.trim() === terminator) { terminator = null; dropping = false; continue; }
85
- if (dropping) continue;
130
+ // B-253: a non-shell's body is data, but an unquoted delimiter still runs its
131
+ // substitutions, so those (and only those) stay executable.
132
+ if (dropping) { if (expands) out.push(...substitutions(line)); continue; }
86
133
  out.push(line);
87
134
  continue;
88
135
  }
89
- if (/^\s*#/.test(line)) continue;
90
- const here = /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/.exec(line);
136
+ // A `#` line is a comment only outside a quote that an earlier line left open (B-253).
137
+ if (open === null && /^\s*#/.test(line)) continue;
138
+ const here = open === null ? /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1/.exec(line) : null;
91
139
  if (here) {
92
140
  terminator = here[2];
141
+ expands = here[1] === '';
93
142
  // Which command is being fed? The last simple-command word before the `<<`, taken
94
143
  // after the final pipe or `&&` so `foo | python3 - <<EOF` reads as python3.
95
144
  const before = line.slice(0, here.index);
@@ -100,6 +149,7 @@ function executablePart(command) {
100
149
  out.push(before);
101
150
  continue;
102
151
  }
152
+ open = quoteAfter(line, open);
103
153
  out.push(line);
104
154
  }
105
155
  return out.join('\n');
@@ -617,6 +667,6 @@ function hostSelfUpdate(command) {
617
667
 
618
668
  module.exports = {
619
669
  maskedGate, hostSelfUpdate,
620
- skillsCli, familyIds, bareFamilyInstall, launcherRunning, executablePart,
670
+ skillsCli, familyIds, bareFamilyInstall, launcherRunning, executablePart, substitutions,
621
671
  isObsidianSetup, parseConfig, reapply, bareName, REMEDY,
622
672
  };
@@ -39,6 +39,8 @@ function validate(r) {
39
39
  if (!r || typeof r !== 'object' || Array.isArray(r)) throw new Error('visibility record is not an object');
40
40
  for (const h of HOSTS) if (r[h] !== undefined && (!Array.isArray(r[h]) || r[h].some((x) => typeof x !== 'string')))
41
41
  throw new Error(`visibility record ${h} is not a list of strings`);
42
+ if (r.claudeNameOnly !== undefined && (!Array.isArray(r.claudeNameOnly) || r.claudeNameOnly.some((x) => typeof x !== 'string')))
43
+ throw new Error('visibility record claudeNameOnly is not a list of strings');
42
44
  if (r.files !== undefined && (!r.files || typeof r.files !== 'object' || Array.isArray(r.files)
43
45
  || Object.entries(r.files).some(([h, f]) => !HOSTS.includes(h) || typeof f !== 'string' || !path.isAbsolute(f))))
44
46
  throw new Error('visibility record files is not a host-to-absolute-path map');
package/lib/visibility.js CHANGED
@@ -23,8 +23,15 @@
23
23
  */
24
24
 
25
25
  const HIDE = 'user-invocable-only';
26
+ const NAME_ONLY = 'name-only';
26
27
  const DESC_CAP = 1536;
27
28
  const DEFAULT_DAYS = 60;
29
+ // B-254. Measured 2026-10-24: Claude Code 2.1.299 logged `Skill listing over budget:
30
+ // 132 skills, 61725 chars > 30000 budget`. Over budget it keeps bundled skills whole and
31
+ // gives the rest their description most-used first; the remainder are listed by name
32
+ // only. So a quiet core skill loses its description anyway. Within the core, only what
33
+ // was used within DEFAULT_FULL_DAYS or is named in the instructions keeps it.
34
+ const DEFAULT_FULL_DAYS = 14;
28
35
 
29
36
  /** Skill names the instruction text references deliberately: inside backticks. */
30
37
  function namedIn(text, names) {
@@ -53,16 +60,39 @@ function core({ personal, family, usage, now, days, instructions }) {
53
60
  return set;
54
61
  }
55
62
 
56
- function claudePlan({ personal, core: coreSet, overrides, keep }) {
63
+ /**
64
+ * The core members that keep their description: used within `fullDays`, or named in
65
+ * the instructions (an agent told to use a skill by name is already told when).
66
+ */
67
+ function fullSet({ personal, usage, now, fullDays, instructions }) {
68
+ const window = (fullDays == null ? DEFAULT_FULL_DAYS : fullDays) * 86400e3;
69
+ const set = new Set();
70
+ for (const n of personal || []) {
71
+ const u = (usage || {})[n];
72
+ if (u && typeof u.lastUsedAt === 'number' && now - u.lastUsedAt <= window) set.add(n);
73
+ }
74
+ for (const n of namedIn(instructions, personal)) set.add(n);
75
+ return set;
76
+ }
77
+
78
+ /**
79
+ * `hide`: outside the core. `nameOnly`: in the core but outside `full`, so listed by name
80
+ * without its description. Without `full` nothing goes name-only. A key the operator set
81
+ * is never planned over, in either list.
82
+ */
83
+ function claudePlan({ personal, core: coreSet, full, overrides, keep }) {
57
84
  const kept = new Set(keep || []);
58
85
  const hide = [];
86
+ const nameOnly = [];
59
87
  const respected = [];
60
88
  for (const n of personal || []) {
61
- if (coreSet.has(n) || kept.has(n)) continue;
89
+ if (kept.has(n)) continue;
90
+ const inCore = coreSet.has(n);
91
+ if (inCore && (!full || full.has(n))) continue;
62
92
  if (overrides && Object.prototype.hasOwnProperty.call(overrides, n)) { respected.push(n); continue; }
63
- hide.push(n);
93
+ (inCore ? nameOnly : hide).push(n);
64
94
  }
65
- return { hide: hide.sort(), respected: respected.sort() };
95
+ return { hide: hide.sort(), nameOnly: nameOnly.sort(), respected: respected.sort() };
66
96
  }
67
97
 
68
98
  /**
@@ -77,12 +107,19 @@ function editClaudeSettings(text, { set, unset, prune }) {
77
107
  if (JSON.stringify(data, null, 2) + '\n' !== text) {
78
108
  return { ok: false, reason: 'settings.json is not in the 2-space JSON format Claude Code writes; refusing to reformat it' };
79
109
  }
110
+ // `set` and `unset` map a name to its value; a bare list means the hidden value, the
111
+ // form callers used before the name-only tier. `unset` removes a key only while it
112
+ // still holds the value the launcher wrote.
113
+ const asMap = (x) => (Array.isArray(x) ? Object.fromEntries(x.map((n) => [n, HIDE])) : (x || {}));
114
+ const setMap = asMap(set);
115
+ const unsetMap = asMap(unset);
80
116
  const ov = Object.assign({}, data.skillOverrides || {});
81
117
  let changed = false;
82
- for (const n of set || []) if (ov[n] !== HIDE) { ov[n] = HIDE; changed = true; }
118
+ for (const [n, v] of Object.entries(setMap)) if (ov[n] !== v) { ov[n] = v; changed = true; }
83
119
  const kept = [];
84
- for (const n of unset || []) {
85
- if (ov[n] === HIDE) { delete ov[n]; changed = true; }
120
+ for (const [n, v] of Object.entries(unsetMap)) {
121
+ if (Object.prototype.hasOwnProperty.call(setMap, n)) continue;
122
+ if (ov[n] === v) { delete ov[n]; changed = true; }
86
123
  else if (n in ov) kept.push(n);
87
124
  }
88
125
  // Nothing to do leaves the file exactly as it was — including an empty map the
@@ -177,15 +214,21 @@ function editCodexConfig(text, { disable, enable }) {
177
214
  return { ok: true, text: lines.join('\n'), added };
178
215
  }
179
216
 
180
- /** Characters a listing spends: a listed name, plus its description while `on`. */
217
+ /**
218
+ * Characters a listing spends, in the form Claude Code 2.1.299 prints it: `- name: description`
219
+ * while `on` (description capped at 1536), `- name` when name-only, one newline between
220
+ * entries; hidden costs nothing.
221
+ */
181
222
  function listingChars(rows) {
182
223
  let n = 0;
224
+ let entries = 0;
183
225
  for (const r of rows || []) {
184
226
  if (r.state === 'hidden') continue;
185
- n += String(r.name).length;
186
- if (r.state === 'on') n += Math.min(DESC_CAP, String(r.description || '').length);
227
+ entries += 1;
228
+ n += 2 + String(r.name).length;
229
+ if (r.state === 'on') n += 2 + Math.min(DESC_CAP, String(r.description || '').length);
187
230
  }
188
- return n;
231
+ return entries ? n + entries - 1 : 0;
189
232
  }
190
233
 
191
234
  // ── Packs: the operator's marks (pack-marks.json) and per-machine overrides ──
@@ -453,7 +496,8 @@ function jsonAt(text, keys) {
453
496
  }
454
497
 
455
498
  module.exports = {
456
- core, claudePlan, editClaudeSettings, editCodexConfig, listingChars, namedIn, HIDE, DEFAULT_DAYS,
499
+ core, fullSet, claudePlan, editClaudeSettings, editCodexConfig, listingChars, namedIn,
500
+ HIDE, NAME_ONLY, DEFAULT_DAYS, DEFAULT_FULL_DAYS,
457
501
  MARKS_SCHEMA, marksProblems, marksIndex, marksFromLock, packHidden, hostHide, setPackOverride,
458
502
  editJsonList, editJsonMap, jsonAt,
459
503
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sshlg-skills",
3
- "version": "1.76.4",
3
+ "version": "1.78.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
@@ -56,13 +56,13 @@
56
56
  "pluginMarketplace": "ssheleg/super-ux",
57
57
  "pluginInstall": "super-ux@super-ux",
58
58
  "desc": "Scenario-driven UI development: a versioned design chain in docs/ux/ — the product vision, personas and jobs, user flows and the paid-acquisition funnel among them, 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 41-check copy linter. /ux and /brand entry points, two doc-drift linters and a contract doctor.",
59
- "version": "0.66.0",
59
+ "version": "0.66.1",
60
60
  "entry": "/ux",
61
61
  "role": "what the interface must do",
62
62
  "npm": "super-ux",
63
63
  "shape": "static",
64
64
  "shapeWhy": "The chain is fixed — foundation, flows, screens, scenarios — and every layer is a committed file. `/ux-audit` batches on the fly, and the batch list is printed before the run so what executed is recoverable.",
65
- "commit": "13195c6402705cb656961fb04ca6d1f8c1df3fb0"
65
+ "commit": "4965a0b5ff10bca27e7044d957f5cdb612841783"
66
66
  },
67
67
  {
68
68
  "name": "task-pipeline",
@@ -76,13 +76,13 @@
76
76
  "evidence-docs",
77
77
  "project-audit"
78
78
  ],
79
- "version": "1.101.1",
79
+ "version": "1.102.0",
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": "c914a84d1240caef00c8ed4342b0ef3eddf4f5b0"
85
+ "commit": "34251bff4ab67bbaed8e290884327f03ad646ad8"
86
86
  },
87
87
  {
88
88
  "name": "agent-sync",
@@ -94,13 +94,13 @@
94
94
  "skillNames": [
95
95
  "agent-sync"
96
96
  ],
97
- "version": "1.23.0",
97
+ "version": "1.23.1",
98
98
  "entry": "/agent-sync",
99
99
  "role": "who is holding this file right now",
100
100
  "npm": "@ssheleg/agent-sync",
101
101
  "shape": "static",
102
102
  "shapeWhy": "Leases, ids and the journal are a fixed protocol; what varies is who holds what, which is state rather than shape.",
103
- "commit": "5c169af9097f8192fe8786014fb08b3e8fe2204d"
103
+ "commit": "7c3f18aed38b4fa8d8c8d4d7da9df223141cb7ef"
104
104
  },
105
105
  {
106
106
  "name": "make-skill",
@@ -113,13 +113,13 @@
113
113
  "make-skill",
114
114
  "skill-search"
115
115
  ],
116
- "version": "0.33.0",
116
+ "version": "0.33.1",
117
117
  "entry": "/skill-audit",
118
118
  "role": "how the skill or plugin itself is built",
119
119
  "npm": "@ssheleg/make-skill",
120
120
  "shape": "static",
121
121
  "shapeWhy": "The standard is a checklist and the audit walks it in order; a skill that passes is auditable against the same list next time.",
122
- "commit": "7745e2c646c0642af8aa0796522867ba115a0f42"
122
+ "commit": "c59b0761cb57c8a67bb35e18615ca6f77c08b170"
123
123
  },
124
124
  {
125
125
  "name": "sheleg-design",
@@ -131,7 +131,7 @@
131
131
  "skillNames": [
132
132
  "sheleg-design"
133
133
  ],
134
- "version": "1.66.2",
134
+ "version": "1.66.3",
135
135
  "entry": "/sheleg-design",
136
136
  "role": "how it looks and moves",
137
137
  "npm": "sheleg-design-skill",
@@ -148,7 +148,7 @@
148
148
  "note": "the catalogue, rendered from each pack's own token layer — a data surface too large for this page, kept where it is built"
149
149
  }
150
150
  ],
151
- "commit": "9d8dd8b36362d38a112d726c459c31a38c2b6673"
151
+ "commit": "f5743d2259da679a157e9d1c01b90e8e3e1d969a"
152
152
  },
153
153
  {
154
154
  "name": "seo-aeo-audit",
@@ -184,13 +184,13 @@
184
184
  "google-auth",
185
185
  "frontend-performance"
186
186
  ],
187
- "version": "0.16.0",
187
+ "version": "0.16.1",
188
188
  "entry": null,
189
189
  "role": "integrations: money in, tracking, errors, sign-in, speed",
190
190
  "npm": "@ssheleg/sheleg-dev",
191
191
  "shape": "static",
192
192
  "shapeWhy": "Each integration is a fixed sequence of seams; nothing decides its own next step.",
193
- "commit": "5842df5677ab330738ea5ef4c14add4f7dea089d"
193
+ "commit": "fa5a739960973aaacabfe0fb5db8b4f5e856f232"
194
194
  },
195
195
  {
196
196
  "name": "agent-stack",
@@ -249,7 +249,7 @@
249
249
  "quest-store",
250
250
  "quest-webxr"
251
251
  ],
252
- "version": "0.4.2",
252
+ "version": "0.4.3",
253
253
  "entry": null,
254
254
  "role": "how a Quest product moves from platform choice to launch and operation",
255
255
  "npm": "@ssheleg/xr-dev",
@@ -262,7 +262,7 @@
262
262
  "note": "Stage map, engine paths and immersive design acceptance, with separate evidence for build, device, Store and operation."
263
263
  }
264
264
  ],
265
- "commit": "98e26301a664232cd27c6ad9737bb74547dd4e1a"
265
+ "commit": "ba885bb48d2737902628c3a9e4d512379feb65c6"
266
266
  },
267
267
  {
268
268
  "name": "web3d-dev",
@@ -276,13 +276,13 @@
276
276
  "web3d-assets",
277
277
  "web3d-animation"
278
278
  ],
279
- "version": "0.2.2",
279
+ "version": "0.2.3",
280
280
  "entry": null,
281
281
  "role": "how realtime 3D on the web runs, ships its assets and moves",
282
282
  "npm": "@ssheleg/web3d-dev",
283
283
  "shape": "static",
284
284
  "shapeWhy": "Three fixed questions with fixed seams — runtime, assets, motion — and one shared contract, the clip canon, duplicated into both skills that need it and checked identical.",
285
- "commit": "7c04756d0124bb26b749535dc0ebb975741b19fb"
285
+ "commit": "c1f45420bfcbb1f03cd37e7fb95abdac1ce89f69"
286
286
  }
287
287
  ],
288
288
  "agents": [