0xray 4.0.3 → 4.0.4

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.3",
3
+ "version": "4.0.4",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",
@@ -19,7 +19,7 @@ Before other work, Read `.xray/state/STATION.md`. Compaction and host change are
19
19
  `npm install 0xray` runs `install-bridges.cjs` and:
20
20
 
21
21
  - Copies this file → **`AGENTS.md`** in your project root
22
- - Mill plant (`mill` skill) onto hangers, then overlays **your** `src/skills` (same name wins). Does **not** dump 45/42 costume unless `foundry.json` `"costume": true`. Does **not** write root **`SKILLS.md`**
22
+ - Fastens mill plant (`mill` + `inspect`) then overlays **your** `src/skills` (same name wins). Inspect AI work is the mill discipline. Does **not** dump 45/42 costume unless `foundry.json` `"costume": true`. Does **not** write root **`SKILLS.md`**
23
23
  - Seeds **`.gitignore`** (from template, if absent)
24
24
  - Deploys **`.xray/`** (`codex.json`, `features.json`, `config.json`) then overlays **your** mill SSOT (`xray/codex.json`, `xray/features.json`, `src/skills`, `src/opencode/agents`; remap with `foundry.json`)
25
25
  - Writes **`.mcp.json`** with 7 MCPs servers (`npx -y 0xray mcp …`)
package/dist/CHANGELOG.md CHANGED
@@ -27,6 +27,15 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
27
27
  - Published mill `hooks` uses the 0xray garment installer (`node_modules/0xray/scripts/hooks`), not `node_modules/@0xray/hooks`. Mill tree 0.1.4 (not a 0xray bump).
28
28
  - Nested mill in the 0xray tarball (`scripts/foundry/`). Wear no longer needs a second `npm i @0xray/foundry` for mint-on-install. 4.0.2.
29
29
  - Empty garment: mill plant (`mill` skill) is the hanger. Not 45/42 costume unless `foundry.json` `"costume": true`. Mill 0.1.5.
30
+ - Mill plant fastens **inspect** (inspect AI work) plus `mill`. Not empty. Mill 0.1.6.
31
+
32
+ ---
33
+
34
+ ## [4.0.4] - 2026-09-04
35
+
36
+ Mill **fastens** an inspect suit: mill plant is `mill` + `inspect` (inspect AI work — diffs, traces, mill receipts, CI). Not empty. Not 45/42 costume unless `foundry.json` `"costume": true`. Factory Repertoire + PPE stay. Mill **0.1.6**. Not 5.0.0.
37
+
38
+ Naming: inventory `suit` (`fastened` / `overlay` / `costume`). Not garment. Not hanger. Costume is the 45/42 dump flag only.
30
39
 
31
40
  ---
32
41
 
@@ -111,7 +111,7 @@ async function installForOpencode(options = {}) {
111
111
  }
112
112
  else {
113
113
  fs.mkdirSync(opencodeDest, { recursive: true });
114
- frameworkLogger.log('opencode-integration', 'empty-garment-plugin', 'info', { destination: opencodeDest });
114
+ frameworkLogger.log('opencode-integration', 'mill-plant-plugin', 'info', { destination: opencodeDest });
115
115
  }
116
116
  const pluginSource = path.join(__dirname, '..', '..', '..', 'dist', 'plugin', 'xray-codex-injection.js');
117
117
  const pluginDest = path.join(opencodeDest, 'plugin', 'xray-codex-injection.js');
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.3",
3
+ "version": "4.0.4",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.3",
3
+ "version": "4.0.4",
4
4
  "description": "Multi-agent orchestration and Codex governance for OpenCode, Hermes, Grok Build, and OpenClaw",
5
5
  "readme": "README.md",
6
6
  "license": "MIT",
@@ -1,12 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.6] - 2026-09-04
4
+
5
+ Mill plant fastens an **inspect** suit: inspect AI work (diffs, traces, mill receipts, CI). Not empty. `mill` + `inspect` skills. Costume dump still opt-in.
6
+
7
+ Inventory field is `suit` (`fastened` / `overlay` / `costume` / `dogfood`). Not `garment`. `foundry.json` `"costume": true` is the 45/42 dump.
8
+
3
9
  ## [0.1.5] - 2026-09-04
4
10
 
5
- Empty garment: consumer hangers get mill plant (`plant/skills/mill`), not 45/42 costume. `foundry.json` `"costume": true` restores the dump. Plant overlay still mill-fill.
11
+ Mill plant (`plant/skills/mill`) fastened by default, not 45/42 costume. `foundry.json` `"costume": true` restores the dump. Plant overlay still mill-fill.
6
12
 
7
13
  ## [0.1.4] - 2026-09-04
8
14
 
9
- `npx @0xray/foundry hooks` on a published mill uses the worn garment
15
+ `npx @0xray/foundry hooks` on a published mill uses the worn 0xray installer
10
16
  `node_modules/0xray/scripts/hooks/install-hooks.cjs`. Dogfood still uses
11
17
  `scripts/hooks` next to `scripts/foundry`. Missing installer fails honestly
12
18
  (no spawn of `node_modules/@0xray/hooks/...`).
@@ -2,7 +2,7 @@
2
2
 
3
3
  The **mill**, not the worn exo. Reconcile, stamp JSON/CHANGELOG, verify docs, gate, publish, overlay their suit params.
4
4
 
5
- PPE (`evaluatePreToolGate`) stays worn. The mill plants **their** constitution, features, skills, and agents onto the hanger. It is not a fifth MCP. The suit is [`0xray`](https://www.npmjs.com/package/0xray).
5
+ PPE (`evaluatePreToolGate`) stays worn. The mill **fastens** their constitution, features, skills, and agents as the suit. It is not a fifth MCP. The suit is [`0xray`](https://www.npmjs.com/package/0xray).
6
6
 
7
7
  ## Install
8
8
 
@@ -35,11 +35,11 @@ npx @0xray/foundry hooks
35
35
 
36
36
  `docs-check` and `gate` run **full** 0xRay corpus only when the milled `package.json` name is `0xray` and `docs-site/` exists. Otherwise **light**: `package.json` + CHANGELOG.
37
37
 
38
- `hooks` installs git hooks via `scripts/hooks/install-hooks.cjs` (dogfood) or `node_modules/0xray/scripts/hooks/install-hooks.cjs` (published mill + worn garment). It does not look for `@0xray/hooks`.
38
+ `hooks` installs git hooks via `scripts/hooks/install-hooks.cjs` (dogfood) or `node_modules/0xray/scripts/hooks/install-hooks.cjs` (published mill + worn suit). It does not look for `@0xray/hooks`.
39
39
 
40
40
  ## Suit params (`mint`)
41
41
 
42
- After the garment is on the hanger, overlay their plant (defaults; remap in `foundry.json` or `.xray/foundry.json`):
42
+ After mill plant is fastened, overlay their plant (defaults; remap in `foundry.json` or `.xray/foundry.json`):
43
43
 
44
44
  | Facet | Default plant | Hanger |
45
45
  |---|---|---|
@@ -50,9 +50,9 @@ After the garment is on the hanger, overlay their plant (defaults; remap in `fou
50
50
  | Agents | `src/opencode/agents/*.yml` | `.opencode/agents/` (OpenCode hangar; other floors do not read mill YML agents) |
51
51
  | Agents card | `xray/AGENTS.md` | `AGENTS.md` if mill-managed |
52
52
 
53
- **Mill-fill is law:** their keys/files win; mill names they did not plant stay unless they overlay the same name. JSON facets always merge. Skill overlay is project hangers only. CLI re-wear calls mint **once** after mill copies.
53
+ **Mill-fill is law:** their keys/files win; mill names they did not plant stay unless they overlay the same name. JSON facets always merge. Skill overlay is project dirs only (`.opencode/skills`, project Grok plugin skills). CLI re-wear calls mint **once** after mill copies.
54
54
 
55
- **Empty garment (default):** mill plant (`plant/skills/mill`) is the hanger. Not 45 skills / 42 agents. `foundry.json` `"costume": true` copies that mill garment. Factory Repertoire still enable-when-resolves. PPE stays worn.
55
+ **Default mill plant:** `mill` + `inspect` (inspect AI work). Fastens a suit, not an empty one. Not 45/42 costume. `foundry.json` `"costume": true` copies that dump. Factory Repertoire still enable-when-resolves. PPE stays worn.
56
56
 
57
57
  ## Publish this mill
58
58
 
@@ -25,7 +25,7 @@ const HELP =
25
25
  "\n" +
26
26
  "Mill, not exo. FOUNDRY_ROOT overrides cwd (the repo being milled).\n" +
27
27
  "release bumps/commits/pushes/publishes the milled cwd — pass --dry-run or --i-mean-it (or FOUNDRY_RELEASE=1).\n" +
28
- "Mint overlays their plant onto project hangers (mill-fill). PPE stays worn.\n" +
28
+ "Mint fastens mill plant then overlays their plant (mill-fill JSON). PPE stays worn.\n" +
29
29
  "gate is build+test. docs-build is Docusaurus on the 0xray exo. ci reports GitHub Actions (no auto-push). hooks installs git pre/post hooks.\n";
30
30
 
31
31
  const cmd = process.argv[2];
@@ -24,7 +24,7 @@ export function resolveMillRoot() {
24
24
  /**
25
25
  * Git hook installer. Dogfood is `scripts/hooks` next to `scripts/foundry`.
26
26
  * Published mill lives in `node_modules/@0xray/foundry` — sibling `@0xray/hooks`
27
- * does not exist. Use the worn 0xray garment installer instead.
27
+ * does not exist. Use the worn 0xray installer instead.
28
28
  */
29
29
  export function resolveHookInstaller(rootDir = resolveMillRoot(), millPkg = millPackageDir()) {
30
30
  const candidates = [
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Mill overlay: their plant onto the hanger. Not PPE (evaluatePreToolGate).
2
+ * Mill overlay: fasten their plant as the suit. Not PPE (evaluatePreToolGate).
3
3
  *
4
4
  * Default SSOT (override with foundry.json or .xray/foundry.json):
5
5
  * xray/codex.json, xray/features.json, xray/config.json,
@@ -136,19 +136,19 @@ function listAgentFilesAt(agentsSrc) {
136
136
  }
137
137
 
138
138
  /** Mill mill-fill mill plant: mill mill mill mill-fill mill names they did not plant stay. */
139
- function millFillMillPlant(millPackageRoot, targetDir, log) {
139
+ function fastenMillPlant(millPackageRoot, targetDir, log) {
140
140
  const plant = millPlantDir(millPackageRoot);
141
141
  if (!plant) return { skills: [], agents: [] };
142
142
  const skillsSrc = path.join(plant, "skills");
143
143
  const agentsSrc = path.join(plant, "agents");
144
144
  const skills = listSkillNamesAt(skillsSrc);
145
145
  const agents = listAgentFilesAt(agentsSrc);
146
- const skillHangers = listSkillHangers(targetDir);
146
+ const skillDirs = listProjectSkillDirs(targetDir);
147
147
  const agentsDest = path.join(targetDir, ".opencode", "agents");
148
- for (const hanger of skillHangers) {
148
+ for (const dir of skillDirs) {
149
149
  for (const name of skills) {
150
150
  const src = path.join(skillsSrc, name, "SKILL.md");
151
- const destMd = path.join(hanger, name, "SKILL.md");
151
+ const destMd = path.join(dir, name, "SKILL.md");
152
152
  if (path.resolve(src) === path.resolve(destMd)) continue;
153
153
  if (fs.existsSync(destMd)) continue;
154
154
  fs.mkdirSync(path.dirname(destMd), { recursive: true });
@@ -164,7 +164,7 @@ function millFillMillPlant(millPackageRoot, targetDir, log) {
164
164
  fs.copyFileSync(src, dest);
165
165
  }
166
166
  if (log && (skills.length > 0 || agents.length > 0)) {
167
- log("foundry-mint", "Mill plant onto hangers", "info", {
167
+ log("foundry-mint", "Fastened mill plant", "info", {
168
168
  skills: skills.length,
169
169
  agents: agents.length,
170
170
  });
@@ -180,8 +180,8 @@ function isDirectory(p) {
180
180
  }
181
181
  }
182
182
 
183
- /** Project skill hangers only. */
184
- function listSkillHangers(targetDir) {
183
+ /** Project skill dirs only (.opencode/skills, project Grok plugin skills). */
184
+ function listProjectSkillDirs(targetDir) {
185
185
  const dests = [path.join(targetDir, ".opencode", "skills")];
186
186
  const projectGrok = path.join(targetDir, ".grok", "plugins", "0xray", "skills");
187
187
  if (isDirectory(projectGrok)) dests.push(projectGrok);
@@ -246,13 +246,13 @@ function overlayConsumerTree(targetDir, log, params) {
246
246
  const agents = listConsumerAgentFiles(targetDir, agentsRel);
247
247
  const skillsSrc = resolveInside(targetDir, skillsRel);
248
248
  const agentsSrc = resolveInside(targetDir, agentsRel);
249
- const skillHangers = listSkillHangers(targetDir);
249
+ const skillDirs = listProjectSkillDirs(targetDir);
250
250
  const agentsDest = path.join(targetDir, ".opencode", "agents");
251
251
 
252
- for (const hanger of skillHangers) {
252
+ for (const dir of skillDirs) {
253
253
  for (const name of skills) {
254
254
  const src = path.join(skillsSrc, name, "SKILL.md");
255
- const destMd = path.join(hanger, name, "SKILL.md");
255
+ const destMd = path.join(dir, name, "SKILL.md");
256
256
  if (path.resolve(src) === path.resolve(destMd)) continue;
257
257
  fs.mkdirSync(path.dirname(destMd), { recursive: true });
258
258
  fs.copyFileSync(src, destMd);
@@ -267,10 +267,10 @@ function overlayConsumerTree(targetDir, log, params) {
267
267
  }
268
268
 
269
269
  if (log && (skills.length > 0 || agents.length > 0)) {
270
- log("foundry-mint", "Overlaid consumer skills/agents onto hangers", "info", {
270
+ log("foundry-mint", "Overlaid consumer skills/agents", "info", {
271
271
  skills: skills.length,
272
272
  agents: agents.length,
273
- skillHangers: skillHangers.length,
273
+ skillDirs: skillDirs.length,
274
274
  });
275
275
  }
276
276
  return { skills, agents, params: resolved };
@@ -278,7 +278,7 @@ function overlayConsumerTree(targetDir, log, params) {
278
278
 
279
279
  function mintConsumerFromSsot(packageRoot, targetDir, log, tree) {
280
280
  if (isDogfood(packageRoot, targetDir)) {
281
- return { garment: "dogfood", skipped: true, consumer: readPackageIdentity(path.join(targetDir, "package.json")) };
281
+ return { suit: "dogfood", skipped: true, consumer: readPackageIdentity(path.join(targetDir, "package.json")) };
282
282
  }
283
283
  const mill = readPackageIdentity(path.join(packageRoot, "package.json"));
284
284
  const consumer = readPackageIdentity(path.join(targetDir, "package.json"));
@@ -299,17 +299,17 @@ function mintConsumerFromSsot(packageRoot, targetDir, log, tree) {
299
299
  (Array.isArray(tree?.millPlantSkills) && tree.millPlantSkills.length > 0) ||
300
300
  (Array.isArray(tree?.millPlantAgents) && tree.millPlantAgents.length > 0);
301
301
  const costume = wantsCostume(targetDir);
302
- const garment = overlayed
302
+ const suit = overlayed
303
303
  ? "overlay"
304
304
  : millPlanted
305
- ? "mill-fill"
305
+ ? "fastened"
306
306
  : costume
307
- ? "copied-onto-hanger"
308
- : "mill-fill";
307
+ ? "costume"
308
+ : "fastened";
309
309
  const inventory = {
310
310
  mill: { name: mill.name || "@0xray/foundry", version: mill.version },
311
311
  consumer: { name: consumer.name, version: consumer.version },
312
- garment,
312
+ suit,
313
313
  params: tree?.params || loadFoundryParams(targetDir),
314
314
  tree: { skills, agents },
315
315
  millPlant: {
@@ -337,7 +337,7 @@ function mintConsumerFromSsot(packageRoot, targetDir, log, tree) {
337
337
  log("foundry-mint", "Minted foundry-inventory from consumer mill SSOT", "info", {
338
338
  consumer: consumer.name,
339
339
  version: consumer.version,
340
- garment,
340
+ suit,
341
341
  });
342
342
  }
343
343
  return inventory;
@@ -345,10 +345,10 @@ function mintConsumerFromSsot(packageRoot, targetDir, log, tree) {
345
345
 
346
346
  function mintConsumerSuit(millPackageRoot, targetDir, log) {
347
347
  if (isDogfood(millPackageRoot, targetDir)) {
348
- return { garment: "dogfood", skipped: true };
348
+ return { suit: "dogfood", skipped: true };
349
349
  }
350
350
  const params = loadFoundryParams(targetDir);
351
- const millPlant = millFillMillPlant(millPackageRoot, targetDir, log);
351
+ const millPlant = fastenMillPlant(millPackageRoot, targetDir, log);
352
352
  const tree = overlayConsumerTree(targetDir, log, params);
353
353
  tree.millPlantSkills = millPlant.skills;
354
354
  tree.millPlantAgents = millPlant.agents;
@@ -382,14 +382,14 @@ module.exports = {
382
382
  loadFoundryExtra,
383
383
  wantsCostume,
384
384
  millPlantDir,
385
- millFillMillPlant,
385
+ fastenMillPlant,
386
386
  resolveInside,
387
387
  overlayJsonFacet,
388
388
  overlayAgentsCard,
389
389
  overlayConsumerTree,
390
390
  listConsumerSkillNames,
391
391
  listConsumerAgentFiles,
392
- listSkillHangers,
392
+ listProjectSkillDirs,
393
393
  mintConsumerFromSsot,
394
394
  mintConsumerSuit,
395
395
  isDogfood,
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Overlay their mill SSOT onto the hanger (cwd / FOUNDRY_ROOT).
3
+ * Overlay their mill SSOT onto the project (cwd / FOUNDRY_ROOT).
4
4
  * Not a fifth 0xray CLI. Not PPE.
5
5
  */
6
6
 
@@ -19,7 +19,7 @@ function main() {
19
19
  process.stdout.write(`${component} ${action} ${status}\n`);
20
20
  });
21
21
  if (inventory.skipped) {
22
- process.stderr.write("mint: skipped dogfood / 0xray exo plant (not a consumer hanger)\n");
22
+ process.stderr.write("mint: skipped dogfood / 0xray exo plant (not a consumer project)\n");
23
23
  process.exit(0);
24
24
  }
25
25
  process.stdout.write(`${JSON.stringify(inventory, null, 2)}\n`);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xray/foundry",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "0xRay mill: mint their suit params, stamp, gate, publish, CI report, git hooks. Not the worn exo.",
@@ -0,0 +1,5 @@
1
+ name: inspect
2
+ skill: inspect
3
+ description: "Inspect AI work: diffs, traces, mill receipts, CI. Fastened mill plant."
4
+ version: "0.1.6"
5
+ mode: subagent
@@ -1,5 +1,5 @@
1
1
  name: mill
2
2
  skill: mill
3
3
  description: "Mill mill-fill mill plant. Their plant is the suit. Factory Repertoire."
4
- version: "0.1.5"
4
+ version: "0.1.6"
5
5
  mode: subagent
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: inspect
3
+ description: Inspect AI work — diffs, tool traces, mill receipts, CI. Factory mill plant. Not 45/42 costume.
4
+ ---
5
+
6
+ # Inspect
7
+
8
+ This mill **fastens** a suit for **inspecting AI work**. Not an empty suit. Not a copy of 0xRay's 45/42 costume.
9
+
10
+ Use this when an agent (or a mill) just wrote, minted, or shipped something. Read the work. Do not trust the receipt until you have opened the files.
11
+
12
+ ## What to inspect
13
+
14
+ 1. **Diff.** What actually changed. Ignore the agent's summary if the diff disagrees.
15
+ 2. **Plant vs worn.** `src/skills`, `src/opencode/agents`, `xray/*.json` vs `.opencode/skills`, `.opencode/agents`, `.xray/`. Same name: plant should win. Costume dump (45 skills / 42 agents they did not plant) is a fail unless `foundry.json` has `"costume": true`.
16
+ 3. **Mill receipt.** `.xray/foundry-inventory.json` — mill name/version, `suit` (`fastened` / `overlay` / `costume`), `millPlant.skills` should include `mill` and `inspect`.
17
+ 4. **CI.** GitHub mill CI and mill-monitor report, not just a green check in chat.
18
+ 5. **Live PUT.** `npm view <pkg> version` and HTTP 200 on the `.tgz`. Metadata without a tarball is not shipped.
19
+ 6. **Machine hangar.** Isolated HOME last-mile must not clobber `~/.grok/plugins/0xray`.
20
+
21
+ ## How to work
22
+
23
+ - Open the files. Quote paths. Do not invent a pass.
24
+ - Constitution stays on (Codex 11 / 69 / destructive). Inspecting is not a license to add an 8th MCP.
25
+ - Factory Repertoire is the organ, not the inspection.
26
+ - Fasten their plant on top; do not dump our costume.
27
+
28
+ ```bash
29
+ npx @0xray/foundry mint
30
+ npx @0xray/foundry ci --report
31
+ ```
@@ -1,22 +1,20 @@
1
1
  ---
2
2
  name: mill
3
- description: Mill mill-fill mill plant. Their plant is the suit. Factory Repertoire. Not 45/42 costume.
3
+ description: Fasten their plant as the suit. Factory Repertoire. Inspect is the mill discipline. Not 45/42 costume.
4
4
  ---
5
5
 
6
6
  # Mill
7
7
 
8
- The mill **fastens** their plant onto the hanger. It does not copy the 0xRay 45-skill / 42-agent costume unless they opt in.
8
+ The mill **fastens** a suit. Default mill plant is **inspect** (inspecting AI work) plus this mill card. Not empty. Not 0xRay's 45-skill / 42-agent costume unless they opt in.
9
9
 
10
10
  **Plant (their SSOT):** `xray/codex.json`, `xray/features.json`, `xray/config.json`, `src/skills/<name>/SKILL.md`, `src/opencode/agents/*.yml`. Remap with `foundry.json`.
11
11
 
12
- **Mill-fill:** their keys/files win. Mill mill mill-fill mill names they did not plant stay. JSON always merges.
12
+ **Mill-fill:** their keys/files win. Mill plant names they did not overlay stay. JSON always merges.
13
13
 
14
- **Factory:** Repertoire organ enable-when-resolves. Seven generated MCP. Constitution (PPE) stays worn. Not a fifth MCP. Not 5.0.
14
+ **Factory:** Repertoire enable-when-resolves. Seven generated MCP. Constitution (PPE) stays worn. Not a fifth MCP. Not 5.0.
15
15
 
16
- **Costume:** `foundry.json` `"costume": true` copies the 45/42 mill garment. Default is empty garment + this mill mill-fill mill plant.
16
+ **Costume:** `foundry.json` `"costume": true` copies the 45/42 mill costume.
17
17
 
18
18
  ```bash
19
19
  npx @0xray/foundry mint
20
20
  ```
21
-
22
- Nested mill: `node node_modules/0xray/scripts/foundry/cli.js mint`.
@@ -226,16 +226,16 @@ function main() {
226
226
 
227
227
  const millSkillHanger = path.join(tmpRoot, ".opencode", "skills", "mill", "SKILL.md");
228
228
  if (!fs.existsSync(millSkillHanger)) {
229
- throw new Error("empty garment missing mill plant skill on hanger");
229
+ throw new Error("mill plant missing mill skill");
230
230
  }
231
- const hangerSkills = path.join(tmpRoot, ".opencode", "skills");
232
- const hangerNames = fs.existsSync(hangerSkills)
233
- ? fs.readdirSync(hangerSkills).filter((n) =>
234
- fs.existsSync(path.join(hangerSkills, n, "SKILL.md")),
231
+ const wornSkills = path.join(tmpRoot, ".opencode", "skills");
232
+ const wornNames = fs.existsSync(wornSkills)
233
+ ? fs.readdirSync(wornSkills).filter((n) =>
234
+ fs.existsSync(path.join(wornSkills, n, "SKILL.md")),
235
235
  )
236
236
  : [];
237
- if (hangerNames.length > 3) {
238
- throw new Error(`costume dump on empty garment: ${hangerNames.join(",")}`);
237
+ if (wornNames.length > 3) {
238
+ throw new Error(`costume dump: ${wornNames.join(",")}`);
239
239
  }
240
240
 
241
241
  const installedPkg = JSON.parse(fs.readFileSync(path.join(nmRoot, "package.json"), "utf-8"));
@@ -308,7 +308,7 @@ function installOpencodeBridge(targetDir, packageRoot, log) {
308
308
  const copied = syncCostumeSkills(path.join(opencodeDest, "skills"), packageRoot, targetDir);
309
309
  if (copied > 0) log("opencode-bridge", `skills synced (${copied})`, "info", { path: ".opencode/skills/" });
310
310
  } else {
311
- log("opencode-bridge", "empty garment — plugin only, mill mill-fill mill plant", "info");
311
+ log("opencode-bridge", "mill plant — plugin only, not costume dump", "info");
312
312
  fs.mkdirSync(opencodeDest, { recursive: true });
313
313
  copyOpencodePlugin(packageRoot, opencodeDest, log);
314
314
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.3",
3
+ "version": "4.0.4",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.3",
3
+ "version": "4.0.4",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",