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.
- package/.xray/features.json +1 -1
- package/AGENTS-consumer.md +1 -1
- package/dist/CHANGELOG.md +9 -0
- package/dist/cli/commands/opencode-install.js +1 -1
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/package.json +1 -1
- package/scripts/foundry/CHANGELOG.md +8 -2
- package/scripts/foundry/README.md +5 -5
- package/scripts/foundry/cli.mjs +1 -1
- package/scripts/foundry/mill-root.mjs +1 -1
- package/scripts/foundry/mint-suit.cjs +24 -24
- package/scripts/foundry/mint.mjs +2 -2
- package/scripts/foundry/package.json +1 -1
- package/scripts/foundry/plant/agents/inspect.yml +5 -0
- package/scripts/foundry/plant/agents/mill.yml +1 -1
- package/scripts/foundry/plant/skills/inspect/SKILL.md +31 -0
- package/scripts/foundry/plant/skills/mill/SKILL.md +5 -7
- package/scripts/node/consumer-install-smoke.mjs +7 -7
- package/scripts/node/install-bridges.cjs +1 -1
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/xray/features.json +1 -1
package/.xray/features.json
CHANGED
package/AGENTS-consumer.md
CHANGED
|
@@ -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
|
-
-
|
|
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', '
|
|
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');
|
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
**
|
|
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
|
|
package/scripts/foundry/cli.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
146
|
+
const skillDirs = listProjectSkillDirs(targetDir);
|
|
147
147
|
const agentsDest = path.join(targetDir, ".opencode", "agents");
|
|
148
|
-
for (const
|
|
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(
|
|
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", "
|
|
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
|
|
184
|
-
function
|
|
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
|
|
249
|
+
const skillDirs = listProjectSkillDirs(targetDir);
|
|
250
250
|
const agentsDest = path.join(targetDir, ".opencode", "agents");
|
|
251
251
|
|
|
252
|
-
for (const
|
|
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(
|
|
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
|
|
270
|
+
log("foundry-mint", "Overlaid consumer skills/agents", "info", {
|
|
271
271
|
skills: skills.length,
|
|
272
272
|
agents: agents.length,
|
|
273
|
-
|
|
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 {
|
|
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
|
|
302
|
+
const suit = overlayed
|
|
303
303
|
? "overlay"
|
|
304
304
|
: millPlanted
|
|
305
|
-
? "
|
|
305
|
+
? "fastened"
|
|
306
306
|
: costume
|
|
307
|
-
? "
|
|
308
|
-
: "
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
348
|
+
return { suit: "dogfood", skipped: true };
|
|
349
349
|
}
|
|
350
350
|
const params = loadFoundryParams(targetDir);
|
|
351
|
-
const millPlant =
|
|
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
|
-
|
|
385
|
+
fastenMillPlant,
|
|
386
386
|
resolveInside,
|
|
387
387
|
overlayJsonFacet,
|
|
388
388
|
overlayAgentsCard,
|
|
389
389
|
overlayConsumerTree,
|
|
390
390
|
listConsumerSkillNames,
|
|
391
391
|
listConsumerAgentFiles,
|
|
392
|
-
|
|
392
|
+
listProjectSkillDirs,
|
|
393
393
|
mintConsumerFromSsot,
|
|
394
394
|
mintConsumerSuit,
|
|
395
395
|
isDogfood,
|
package/scripts/foundry/mint.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Overlay their mill SSOT onto the
|
|
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
|
|
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`);
|
|
@@ -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:
|
|
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**
|
|
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
|
|
12
|
+
**Mill-fill:** their keys/files win. Mill plant names they did not overlay stay. JSON always merges.
|
|
13
13
|
|
|
14
|
-
**Factory:** Repertoire
|
|
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
|
|
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("
|
|
229
|
+
throw new Error("mill plant missing mill skill");
|
|
230
230
|
}
|
|
231
|
-
const
|
|
232
|
-
const
|
|
233
|
-
? fs.readdirSync(
|
|
234
|
-
fs.existsSync(path.join(
|
|
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 (
|
|
238
|
-
throw new Error(`costume dump
|
|
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", "
|
|
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
|
}
|