@ssheleg/xr-dev 0.3.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/LICENSE +21 -0
  3. package/README.md +98 -0
  4. package/SECURITY.md +39 -0
  5. package/bin/xr-dev.js +186 -0
  6. package/package.json +56 -0
  7. package/plugins/xr-dev/.claude-plugin/plugin.json +37 -0
  8. package/plugins/xr-dev/skills/quest-lifecycle/SKILL.md +98 -0
  9. package/plugins/xr-dev/skills/quest-lifecycle/references/engine-paths.md +38 -0
  10. package/plugins/xr-dev/skills/quest-lifecycle/references/immersive-design.md +45 -0
  11. package/plugins/xr-dev/skills/quest-lifecycle/references/stage-map.md +60 -0
  12. package/plugins/xr-dev/skills/quest-native/SKILL.md +191 -0
  13. package/plugins/xr-dev/skills/quest-native/references/doc-map.md +90 -0
  14. package/plugins/xr-dev/skills/quest-native/references/frame-loop.md +92 -0
  15. package/plugins/xr-dev/skills/quest-native/references/manifest-and-gradle.md +111 -0
  16. package/plugins/xr-dev/skills/quest-native/references/mixed-reality.md +46 -0
  17. package/plugins/xr-dev/skills/quest-native/references/project-playbook.md +56 -0
  18. package/plugins/xr-dev/skills/quest-perf/SKILL.md +128 -0
  19. package/plugins/xr-dev/skills/quest-perf/references/capture-playbook.md +102 -0
  20. package/plugins/xr-dev/skills/quest-perf/references/mobile-rendering.md +56 -0
  21. package/plugins/xr-dev/skills/quest-perf/references/rendering-playbook.md +51 -0
  22. package/plugins/xr-dev/skills/quest-spatial/SKILL.md +170 -0
  23. package/plugins/xr-dev/skills/quest-spatial/references/budgets-and-traps.md +73 -0
  24. package/plugins/xr-dev/skills/quest-spatial/references/build-and-audit.md +36 -0
  25. package/plugins/xr-dev/skills/quest-spatial/references/docs-map.md +91 -0
  26. package/plugins/xr-dev/skills/quest-spatial/references/hybrid-activities.md +31 -0
  27. package/plugins/xr-dev/skills/quest-spatial/references/samples-map.md +60 -0
  28. package/plugins/xr-dev/skills/quest-store/SKILL.md +145 -0
  29. package/plugins/xr-dev/skills/quest-store/references/launch-and-growth.md +96 -0
  30. package/plugins/xr-dev/skills/quest-store/references/production-readiness.md +56 -0
  31. package/plugins/xr-dev/skills/quest-store/references/store-asset-production.md +48 -0
  32. package/plugins/xr-dev/skills/quest-store/references/vrc-checklist.md +193 -0
  33. package/plugins/xr-dev/skills/quest-tooling/SKILL.md +158 -0
  34. package/plugins/xr-dev/skills/quest-tooling/references/research-navigation.md +47 -0
  35. package/plugins/xr-dev/skills/quest-tooling/references/source-research.md +58 -0
  36. package/plugins/xr-dev/skills/quest-tooling/references/tool-matrix.md +54 -0
  37. package/plugins/xr-dev/skills/quest-webxr/SKILL.md +141 -0
  38. package/plugins/xr-dev/skills/quest-webxr/references/pwa-packaging.md +85 -0
  39. package/plugins/xr-dev/skills/quest-webxr/references/runtime-delivery.md +40 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,143 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the project uses
5
+ [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## 0.3.0 — 2026-09-21
8
+
9
+ - Add quest-lifecycle: a portable product-stage map with proactive next actions, engine selection, immersive-design acceptance and evidence gates.
10
+ - Extend all six existing owners with platform/research/rendering coverage, cooperative hybrid activities, source-conflict handling, commercial readiness, capture and Store asset production, and post-launch analytics.
11
+ - Correct stale descriptions, hard Spatial limits, CPU/GPU timing claims, release manifest guidance and duplicate MCP setup defaults. Keep current SDK/device/Dashboard checks explicit.
12
+ - Add lifecycle evaluation cases and record isolated baseline/candidate planning probes separately from routing, build and headset verification.
13
+
14
+
15
+ ## [0.2.1] — 2026-09-20
16
+
17
+ ### Changed
18
+
19
+ - `quest-spatial`'s description trimmed to 882 characters. It shipped at 955 and
20
+ moved the family's reserve ratchet — the 60 characters below the 970 cap exist
21
+ for the "NOT for" clause the next neighbouring skill will force, and this pack
22
+ now sits beside Meta's `hz-spatial-sdk`, which is exactly such a neighbour.
23
+ - The card the umbrella generates for this member, regenerated from the new
24
+ manifest.
25
+
26
+ ## [0.2.0] — 2026-09-20
27
+
28
+ ### Added
29
+
30
+ - **`quest-spatial`** — the Kotlin lane. Meta Spatial SDK is how an Android team
31
+ reaches Horizon OS, and the pack had no answer for it: which lane it is right
32
+ for, the toolchain it demands (Horizon OS v69+, AGP 8.11.1 under the Gradle
33
+ 9.4.1 wrapper, Kotlin 2.1.0, JDK 17, Spatial Editor for all but two samples),
34
+ and the budgets that decide a design rather than tune it — 2,000 entity
35
+ operations per tick, 500 physics objects, ~1,000 scene-graph entities, and a
36
+ panel table whose sharpest rows are three video panels and two activity-based
37
+ ones.
38
+ - Its three references: `samples-map.md` (15 official samples mapped to the
39
+ question each answers, plus the `hzdb` MCP server a clone brings with it),
40
+ `docs-map.md` (197 pages, by prefix and by topic), `budgets-and-traps.md`
41
+ (the tables, and the five issues Meta lists against itself — including debug
42
+ builds being slow enough to invalidate a measurement, and `finish()` on an
43
+ immersive activity crashing inside `libMetaSpatialSDK.so`).
44
+
45
+ ### Changed
46
+
47
+ - The pack now routes six lanes, not five; Meta's `hz-spatial-sdk` still owns
48
+ the implementation of a Spatial SDK app, and `quest-spatial` says when to be
49
+ there at all and where to read.
50
+
51
+ ## [0.1.5] — 2026-09-20
52
+
53
+ ### Fixed
54
+
55
+ - `test/social_preview.py`, the last CI step this repository inherited a job for
56
+ and never inherited the script for. Every step of both jobs has now been run
57
+ locally against this tree before the push, which is how the previous two
58
+ failures should have been caught.
59
+
60
+ ## [0.1.4] — 2026-09-20
61
+
62
+ ### Fixed
63
+
64
+ - CI was red on the first push and the repository did not know it: the online
65
+ schema check imports `SCHEMA_FOR` from the validator, which exported only an
66
+ internal `SCHEMAS` map, and the audit job ran a `test/evals_validate.py` that
67
+ had never been copied in. Both closed — the pinned addresses now live in one
68
+ map that both halves read, and the eval data validates with its own planted
69
+ defect.
70
+
71
+ ### Added
72
+
73
+ - `test/evals/README.md` and `RESULTS.md`. Results says, in as many words, that
74
+ no model run has happened yet: an unrun eval reported as a pass is worse than
75
+ no eval.
76
+ - The trigger split now carries **both classes in each half** — a train split of
77
+ positives only cannot show over-firing, which is the failure mode that matters
78
+ beside Meta's 29 neighbouring skills.
79
+
80
+ ## [0.1.3] — 2026-09-20
81
+
82
+ ### Added
83
+
84
+ - `docs/assets/social-preview.png` — the card the family umbrella generates for
85
+ this member from `skills.json`, byte-compared in its suite so the pixels and
86
+ the manifest cannot drift apart.
87
+
88
+ ## [0.1.2] — 2026-09-20
89
+
90
+ ### Added
91
+
92
+ - `docs/AGENT_SYNC.md`, generated from the live coordination config, and a
93
+ repository `CLAUDE.md` that links it and states the invariants each gate
94
+ checks. A guarded-file list no agent instruction points at is a list nobody
95
+ reads.
96
+
97
+ ## [0.1.1] — 2026-09-20
98
+
99
+ ### Changed
100
+
101
+ - `quest-tooling`'s description trimmed back inside the 60-character reserve the
102
+ family keeps below the 970 cap — the room a near-miss neighbour's "NOT for"
103
+ clause will need.
104
+ - README says where its verification commands run: a clone, not the published
105
+ package, which ships the skills without `test/`.
106
+
107
+ ### Added
108
+
109
+ - `.claude/agent-sync.json`, so a second agent in this repository claims the
110
+ guarded files instead of overwriting them.
111
+
112
+ ## [0.1.0] — 2026-09-20
113
+
114
+ First release. Five skills, seven references.
115
+
116
+ ### Added
117
+
118
+ - `quest-native` — the native OpenXR lane: development versus release manifest,
119
+ SDK levels including the 1 March 2026 target-34 rule, the Khronos loader and
120
+ its two initialisation extensions, the frame loop and the focus rules review
121
+ enforces, capability checks over device models.
122
+ - `quest-perf` — per-refresh-rate frame budgets, the `GPU%` reading that falls
123
+ exactly when an app is GPU-bound and the 50% threshold behind it, the four
124
+ recovery levers in order, and a capture playbook for Perfetto, simpleperf,
125
+ RenderDoc and OVR Metrics through `metavr`.
126
+ - `quest-tooling` — the metavr CLI surface, its MCP server and how one server
127
+ ends up registered twice, `metavr init`'s all-agents default measured at 4129
128
+ files inside a repository, the managed tool matrix, and the hygiene rules.
129
+ - `quest-store` — the four release channels and what review actually checks,
130
+ the VRC list generated from Meta's page (80 requirements, 14 groups), the
131
+ release manifest delta, uploading with `metavr store dist`.
132
+ - `quest-webxr` — requesting an immersive session on load, IWSDK versus three.js
133
+ versus A-Frame, Bubblewrap packaging with the Digital Asset Links step, and
134
+ the performance honesty a browser build needs.
135
+
136
+ [0.2.1]: https://github.com/ssheleg/xr-dev/releases/tag/v0.2.1
137
+ [0.2.0]: https://github.com/ssheleg/xr-dev/releases/tag/v0.2.0
138
+ [0.1.5]: https://github.com/ssheleg/xr-dev/releases/tag/v0.1.5
139
+ [0.1.4]: https://github.com/ssheleg/xr-dev/releases/tag/v0.1.4
140
+ [0.1.3]: https://github.com/ssheleg/xr-dev/releases/tag/v0.1.3
141
+ [0.1.2]: https://github.com/ssheleg/xr-dev/releases/tag/v0.1.2
142
+ [0.1.1]: https://github.com/ssheleg/xr-dev/releases/tag/v0.1.1
143
+ [0.1.0]: https://github.com/ssheleg/xr-dev/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ssheleg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # xr-dev — Meta Quest product lifecycle, seven skills
2
+
3
+ Agent skills for taking Quest games and apps from platform choice to release and
4
+ operation. Each stage names its owner, evidence and next action, so the agent can
5
+ surface account, design, performance and launch work before it becomes a blocker.
6
+
7
+ Part of the [ssheleg harness](https://skills.sshlg.me/harness/). This pack works
8
+ independently and composes with the family delivery, UX and design skills.
9
+
10
+ ## The seven skills
11
+
12
+ | Skill | Answers |
13
+ |---|---|
14
+ | [quest-lifecycle](plugins/xr-dev/skills/quest-lifecycle/SKILL.md) | What stage is this product at, what is missing, and what should happen next? |
15
+ | [quest-native](plugins/xr-dev/skills/quest-native/SKILL.md) | How is the C/C++ OpenXR project built and audited, including MR capability and lifecycle boundaries? |
16
+ | [quest-spatial](plugins/xr-dev/skills/quest-spatial/SKILL.md) | How do Kotlin Spatial SDK, ECS, panels and hybrid activities fit this app? |
17
+ | [quest-perf](plugins/xr-dev/skills/quest-perf/SKILL.md) | What limits frames, memory or sustained performance, and which rendering experiment tests it? |
18
+ | [quest-tooling](plugins/xr-dev/skills/quest-tooling/SKILL.md) | Which tools and sources are available, current and appropriate for this host? |
19
+ | [quest-store](plugins/xr-dev/skills/quest-store/SKILL.md) | What remains for testing, submission, monetization, Store assets, launch and operation? |
20
+ | [quest-webxr](plugins/xr-dev/skills/quest-webxr/SKILL.md) | How does the browser/PWA experience handle sessions, optional features and delivery? |
21
+
22
+ References live inside their owning skill and load on demand. The skill bodies
23
+ link every shipped reference with a use condition. For the complete change and
24
+ verification record, see [lifecycle release evidence](docs/evidence/verification/2026-09-21-lifecycle/README.md).
25
+
26
+ ## Start with the product stage
27
+
28
+ For a new or inherited product, invoke `/quest-lifecycle` from a skills directory
29
+ or `/xr-dev:quest-lifecycle` from the plugin. It inspects the actual engine and app
30
+ category, preserves existing project records, and proposes the earliest unresolved
31
+ step. For a single bug, capture or upload, use that specialist directly.
32
+
33
+ The workflow covers platform selection, immersive UX, a device-tested vertical
34
+ slice, content/performance budgets, commercial prerequisites, real gameplay
35
+ capture, Store review and post-launch checks. It distinguishes 2D, immersive,
36
+ hybrid, WebXR, packaged PWA and PC VR requirements.
37
+
38
+ [Meta's own companion skills](https://github.com/meta-quest/agentic-tools) supply
39
+ engine and tool workflows when installed. The lifecycle engine map also points
40
+ to Godot's official XR/export/vendor-plugin documentation. This pack supplies
41
+ fallback procedures; it does not install an engine, promise every device feature,
42
+ or treat a generated image as gameplay evidence.
43
+
44
+ ## Install
45
+
46
+ Claude Code plugin:
47
+
48
+ ```text
49
+ /plugin marketplace add ssheleg/xr-dev
50
+ /plugin install xr-dev@xr-dev
51
+ ```
52
+
53
+ Portable Agent Skills:
54
+
55
+ ```bash
56
+ npx skills add ssheleg/xr-dev
57
+ ```
58
+
59
+ The standalone npm installer also works when the same Claude plugin is absent:
60
+
61
+ ```bash
62
+ npx @ssheleg/xr-dev --help
63
+ ```
64
+
65
+ Use one channel per agent. For a composing family installation, update through
66
+ `npx sshlg-skills update`. Restart the agent after updates so skills reload.
67
+
68
+ ## Tools and source freshness
69
+
70
+ Inspect existing CLI/MCP/plugin registration before setup. `quest-tooling` maps
71
+ Meta VR CLI, device/debug/profiling tools and Markdown documentation indexes,
72
+ with the operator's gateway policy taking precedence over generic setup examples.
73
+ No MCP uses CLI; no CLI uses official docs; absent engine/device/account access
74
+ leaves dependent checks explicitly unverified. An HTTP 200 may be an unavailable
75
+ page, and a source example is not a universal SDK or Store requirement.
76
+
77
+ ## Verifying a change
78
+
79
+ <!-- commands-run-in: a clone -->
80
+ The repository carries tests; the npm payload carries the skills and references.
81
+
82
+ ```bash
83
+ npm test
84
+ npm run test:negatives
85
+ node test/installer_test.js
86
+ python3 test/evals_validate.py
87
+ claude plugin validate . --strict
88
+ claude plugin validate plugins/xr-dev --strict
89
+ ```
90
+
91
+ [Test evaluation documentation](test/evals/README.md) separates scenario definitions,
92
+ isolated model planning probes, runtime routing and device/product evidence.
93
+
94
+ ## License
95
+
96
+ MIT for this pack. Primary documentation is linked and dated; third-party tools,
97
+ assets and models retain their own licenses. Recheck volatile requirements before
98
+ implementation and submission.
package/SECURITY.md ADDED
@@ -0,0 +1,39 @@
1
+ # Security
2
+
3
+ ## Reporting
4
+
5
+ Report anything sensitive privately to **security@sshlg.me**, not in a public
6
+ issue. Include the file, what happens, and what you expected.
7
+
8
+ ## What executes when you install this
9
+
10
+ | Path | Runs when | What it touches |
11
+ |---|---|---|
12
+ | `bin/xr-dev.js` | `npx @ssheleg/xr-dev` | copies the skill directories into `~/.claude/skills/<name>`; refuses (exit 3) when the plugin is already installed; writes nothing else |
13
+ | `install.sh` | run by hand | the same copy, in POSIX shell |
14
+ | `test/*.py`, `test/*.js` | only in CI or by hand | read the repository; `check_schemas.py` makes outbound HTTPS requests to schemastore.org |
15
+
16
+ The skills themselves ship **no hooks, no MCP server and no background
17
+ process**. Nothing here runs at session start.
18
+
19
+ ## What the skills tell an agent to run
20
+
21
+ The bodies name `metavr`, `adb`, `keytool`, `bubblewrap`, `npm` and `git`
22
+ commands. Two classes deserve attention before an agent runs them unattended:
23
+
24
+ - **Device-mutating**: `metavr app install|uninstall`, `metavr files rm`,
25
+ `metavr device configure-testing`, `metavr shell`. They act on a connected
26
+ headset.
27
+ - **Outward-facing**: `metavr store dist upload` and `copy-build` put a build in
28
+ front of testers or the Store. Uploads default to a **draft**; `--publish` is
29
+ the flag that makes it visible. Treat both as actions needing a human's say-so.
30
+
31
+ No skill asks an agent to bypass a consent prompt, and no skill fetches its own
32
+ instructions from a URL at runtime.
33
+
34
+ ## Credentials
35
+
36
+ Nothing in this repository stores or reads a credential. `metavr auth login`
37
+ keeps its token in the OS keychain; `METAVR_TOKEN` exists for CI. Signing
38
+ keystores belong outside the repository, and every skill that mentions one says
39
+ so.
package/bin/xr-dev.js ADDED
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * xr-dev installer CLI.
4
+ *
5
+ * Installs every xr-dev skill into ~/.claude/skills/<name>
6
+ * (same layout as install.sh). Idempotent: an existing install is skipped unless
7
+ * --force. Zero dependencies.
8
+ *
9
+ * For other agents (Cursor, Codex, 70+) use: npx skills add ssheleg/xr-dev
10
+ */
11
+ 'use strict';
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const os = require('os');
16
+
17
+ const ROOT = path.resolve(__dirname, '..');
18
+ const REPO = 'ssheleg/xr-dev';
19
+ const PLUGIN = 'xr-dev';
20
+
21
+ // Exit codes are the contract: 0 installed or skipped, 1 corrupted package,
22
+ // 2 usage error, 3 refused — the plugin channel owns this agent (--force overrides).
23
+ const EXIT_PLUGIN_PRESENT = 3;
24
+
25
+ /**
26
+ * The plugin spec (`<name>@<marketplace>`) installed for `name` in this home,
27
+ * or null.
28
+ *
29
+ * `installed_plugins.json` is the record of what is actually installed. The
30
+ * `plugins/marketplaces/<name>` directory — the only signal older family
31
+ * installers read — under-reports: a marketplace added from a local `directory`
32
+ * source has no dir there at all, and plugin names differ from marketplace
33
+ * names, so a check keyed on it stays green while the shadow lands. Absence
34
+ * and corruption both read as "no plugin": the fresh HOME is the common case,
35
+ * and an installer that crashes on a parse error refuses the machines that
36
+ * need it most.
37
+ */
38
+ function installedPluginSpec(home, name) {
39
+ try {
40
+ const raw = fs.readFileSync(
41
+ path.join(home, '.claude', 'plugins', 'installed_plugins.json'), 'utf8');
42
+ const parsed = JSON.parse(raw);
43
+ const plugins =
44
+ parsed && typeof parsed === 'object' &&
45
+ parsed.plugins && typeof parsed.plugins === 'object'
46
+ ? parsed.plugins
47
+ : parsed;
48
+ if (!plugins || typeof plugins !== 'object') return null;
49
+ for (const spec of Object.keys(plugins)) {
50
+ if (spec === name) return `${name}@${name}`;
51
+ if (spec.startsWith(name + '@')) return spec;
52
+ }
53
+ } catch {
54
+ // missing or corrupt = no plugin — fail open on absence, never crash
55
+ }
56
+ return null;
57
+ }
58
+
59
+ function usage() {
60
+ console.log(`xr-dev installer
61
+
62
+ Usage:
63
+ npx @ssheleg/xr-dev [--force] install all xr-dev skills
64
+ into ~/.claude (skip existing unless --force)
65
+ npx @ssheleg/xr-dev --help
66
+
67
+ Exit codes:
68
+ 0 installed or skipped 2 usage error
69
+ 1 corrupted package 3 refused: the xr-dev PLUGIN is installed in
70
+ this home — plain copies would shadow it (pass
71
+ --force to write them anyway)
72
+
73
+ Other install paths:
74
+ Claude Code plugin: /plugin marketplace add ${REPO}
75
+ /plugin install xr-dev@xr-dev
76
+ Any agent (70+): npx skills add ${REPO}`);
77
+ }
78
+
79
+ function copyDir(src, dest) {
80
+ fs.mkdirSync(dest, { recursive: true });
81
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
82
+ const s = path.join(src, entry.name);
83
+ const d = path.join(dest, entry.name);
84
+ if (entry.isDirectory()) copyDir(s, d);
85
+ else fs.copyFileSync(s, d);
86
+ }
87
+ }
88
+
89
+ function installOne(label, src, dest, isDir, force) {
90
+ if (fs.existsSync(dest) && !force) {
91
+ console.log(`skip: ${label} already installed at ${dest} (rerun with --force to overwrite)`);
92
+ return;
93
+ }
94
+ fs.rmSync(dest, { recursive: true, force: true });
95
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
96
+ if (isDir) copyDir(src, dest);
97
+ else fs.copyFileSync(src, dest);
98
+ console.log(`Installed ${label} -> ${dest}`);
99
+ }
100
+
101
+ function main(argv) {
102
+ const args = argv.slice(2);
103
+ if (args.includes('--help') || args.includes('-h')) {
104
+ usage();
105
+ return 0;
106
+ }
107
+ const force = args.includes('--force');
108
+ const unknown = args.filter((a) => a !== '--force');
109
+ if (unknown.length) {
110
+ console.error(`unknown argument(s): ${unknown.join(' ')}`);
111
+ usage();
112
+ return 2;
113
+ }
114
+
115
+ const skillsRoot = path.join(ROOT, 'plugins/xr-dev/skills');
116
+ if (!fs.existsSync(skillsRoot)) {
117
+ console.error(`error: skill sources missing at ${skillsRoot} — corrupted package?`);
118
+ return 1;
119
+ }
120
+
121
+ const names = fs
122
+ .readdirSync(skillsRoot, { withFileTypes: true })
123
+ .filter((e) => e.isDirectory())
124
+ .map((e) => e.name)
125
+ .sort();
126
+ if (!names.length) {
127
+ console.error(`error: no skills found under ${skillsRoot} — corrupted package?`);
128
+ return 1;
129
+ }
130
+
131
+ const home = os.homedir();
132
+
133
+ // One channel per agent. A plain ~/.claude/skills/<name> beside an installed
134
+ // plugin is two listings of the same skill, and the stale copy wins — the
135
+ // exact shadow the family canon forbids. Refuse rather than create it, and
136
+ // refuse LOUDLY: reproduced live 2026-08-29 ON THIS PACKAGE — a bare
137
+ // `npx @ssheleg/xr-dev` shipped all three skills as plain copies into
138
+ // the operator's ~/.claude/skills/ while the xr-dev plugin was
139
+ // enabled, because until v0.1.9 nothing here looked. A refusal that exits 0
140
+ // reads as success to every script above it, so this one exits 3.
141
+ const spec = installedPluginSpec(home, PLUGIN);
142
+ const marketplace = path.join(home, '.claude', 'plugins', 'marketplaces', PLUGIN);
143
+ const viaMarketplaceDir = !spec && fs.existsSync(marketplace);
144
+ if ((spec || viaMarketplaceDir) && !force) {
145
+ const found = spec
146
+ ? `installed as the Claude Code plugin ${spec}\n` +
147
+ ' (declared in ~/.claude/plugins/installed_plugins.json)'
148
+ : `registered as a Claude Code marketplace\n (${marketplace})`;
149
+ console.error(
150
+ `refused: xr-dev is already ${found}.\n` +
151
+ " Plain copies in ~/.claude/skills/ would shadow the plugin's skills\n" +
152
+ ' and serve this frozen version forever. Update the plugin channel\n' +
153
+ ' instead:\n' +
154
+ ' claude plugin marketplace update xr-dev\n' +
155
+ ` claude plugin update ${spec || 'xr-dev@xr-dev'}\n` +
156
+ ' Family launcher (updates every member, prunes shadow copies):\n' +
157
+ ' npx --yes sshlg-skills@latest update\n' +
158
+ ' Pass --force to write the plain copies anyway — a deliberate choice\n' +
159
+ ' to run two channels, where the stale one wins.'
160
+ );
161
+ return EXIT_PLUGIN_PRESENT;
162
+ }
163
+
164
+ for (const name of names) {
165
+ installOne(
166
+ `${name} skill`,
167
+ path.join(skillsRoot, name),
168
+ path.join(home, '.claude', 'skills', name),
169
+ true,
170
+ force
171
+ );
172
+ }
173
+
174
+ // The last line says how the next version arrives — "Installed" is not a
175
+ // complete sentence. Auto-update is off on purpose: this member composes
176
+ // with its family, and per-marketplace autoUpdate moves each member on its
177
+ // own clock, into combinations nobody tested together.
178
+ console.log(
179
+ '\nUpdates: rerun `npx @ssheleg/xr-dev@latest --force`, or refresh the\n' +
180
+ 'whole family with `npx --yes sshlg-skills@latest update` (every channel,\n' +
181
+ 'and it prunes plain copies that would shadow a plugin).'
182
+ );
183
+ return 0;
184
+ }
185
+
186
+ process.exit(main(process.argv));
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@ssheleg/xr-dev",
3
+ "version": "0.3.0",
4
+ "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.",
5
+ "bin": {
6
+ "xr-dev": "bin/xr-dev.js"
7
+ },
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "files": [
12
+ "bin",
13
+ "plugins",
14
+ "README.md",
15
+ "LICENSE",
16
+ "CHANGELOG.md",
17
+ "SECURITY.md"
18
+ ],
19
+ "repository": "github:ssheleg/xr-dev",
20
+ "homepage": "https://skills.sshlg.me/skills/xr-dev/",
21
+ "license": "MIT",
22
+ "author": {
23
+ "name": "ssheleg",
24
+ "url": "https://x.com/sshlg93"
25
+ },
26
+ "engines": {
27
+ "node": ">=16"
28
+ },
29
+ "keywords": [
30
+ "agent-skills",
31
+ "android-ndk",
32
+ "ar",
33
+ "bubblewrap",
34
+ "claude-code",
35
+ "cursor",
36
+ "horizon-os",
37
+ "kotlin",
38
+ "meta-quest",
39
+ "metavr",
40
+ "mruk",
41
+ "openxr",
42
+ "perfetto",
43
+ "pwa",
44
+ "quest",
45
+ "renderdoc",
46
+ "spatial-sdk",
47
+ "vr",
48
+ "vulkan",
49
+ "webxr",
50
+ "xr"
51
+ ],
52
+ "scripts": {
53
+ "test": "python3 test/validate.py",
54
+ "test:negatives": "python3 test/validate.py --self-test"
55
+ }
56
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
+ "name": "xr-dev",
4
+ "displayName": "XR Dev",
5
+ "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.",
6
+ "version": "0.3.0",
7
+ "author": {
8
+ "name": "ssheleg",
9
+ "url": "https://x.com/sshlg93"
10
+ },
11
+ "homepage": "https://skills.sshlg.me/skills/xr-dev/",
12
+ "repository": "https://github.com/ssheleg/xr-dev",
13
+ "license": "MIT",
14
+ "keywords": [
15
+ "agent-skills",
16
+ "android-ndk",
17
+ "ar",
18
+ "bubblewrap",
19
+ "claude-code",
20
+ "cursor",
21
+ "horizon-os",
22
+ "kotlin",
23
+ "meta-quest",
24
+ "metavr",
25
+ "mruk",
26
+ "openxr",
27
+ "perfetto",
28
+ "pwa",
29
+ "quest",
30
+ "renderdoc",
31
+ "spatial-sdk",
32
+ "vr",
33
+ "vulkan",
34
+ "webxr",
35
+ "xr"
36
+ ]
37
+ }