0xray 4.0.9 → 4.0.11
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/.grok-plugin/plugin.json +20 -0
- package/.xray/features.json +1 -1
- package/AGENTS-consumer.md +1 -0
- package/AGENTS.md +10 -6
- package/README.md +15 -8
- package/SKILLS.md +3 -3
- package/dist/AGENTS.md +10 -6
- package/dist/CHANGELOG.md +26 -0
- package/dist/README.md +15 -8
- package/dist/SKILLS.md +3 -3
- package/dist/governance/llm-governance-provider.js +20 -4
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/memory-routing/provider-loader.js +4 -0
- package/llms.txt +59 -0
- package/package.json +5 -3
- package/scripts/foundry/CHANGELOG.md +4 -0
- package/scripts/foundry/README.md +2 -0
- package/scripts/foundry/inspect.mjs +3 -0
- package/scripts/foundry/mint-suit.cjs +60 -2
- package/scripts/foundry/plant/skills/inspect/SKILL.md +1 -1
- package/scripts/foundry/validate-release-docs.mjs +69 -2
- package/scripts/foundry/version-manager.mjs +4 -0
- package/scripts/node/bridge-mcp-wiring.cjs +23 -0
- package/scripts/node/consumer-install-smoke.mjs +82 -14
- package/scripts/node/install-bridges.cjs +4 -0
- package/scripts/node/pack-tmp-suit-proof.mjs +242 -0
- package/scripts/node/wear-vendored-repertoire.cjs +120 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/xray/features.json +1 -1
|
@@ -21,6 +21,9 @@ const DEFAULT_PARAMS = {
|
|
|
21
21
|
agentsCard: "xray/AGENTS.md",
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
/** Factory shop plant. First-class with mill plant. Not 45/42 costume. */
|
|
25
|
+
const FACTORY_SHOP_SKILLS = ["shop-extract", "shop-witness", "shop-pin"];
|
|
26
|
+
|
|
24
27
|
function deepMerge(src, dest) {
|
|
25
28
|
if (typeof src !== "object" || src === null) return dest !== undefined ? dest : src;
|
|
26
29
|
if (Array.isArray(src)) return Array.isArray(dest) ? dest : src;
|
|
@@ -298,13 +301,59 @@ function wornAgentFiles(targetDir) {
|
|
|
298
301
|
return listAgentFilesAt(path.join(targetDir, ".opencode", "agents"));
|
|
299
302
|
}
|
|
300
303
|
|
|
304
|
+
function normalizeNameList(value) {
|
|
305
|
+
if (!Array.isArray(value)) return [];
|
|
306
|
+
const names = [];
|
|
307
|
+
for (const item of value) {
|
|
308
|
+
if (typeof item !== "string") continue;
|
|
309
|
+
const name = item.trim();
|
|
310
|
+
if (name) names.push(name);
|
|
311
|
+
}
|
|
312
|
+
return names;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function shopPlantFromDir(targetDir, rel) {
|
|
316
|
+
const resolved = resolveInside(targetDir, rel);
|
|
317
|
+
if (!resolved || !isDirectory(resolved)) return [];
|
|
318
|
+
const nested = path.join(resolved, "skills");
|
|
319
|
+
return listSkillNamesAt(isDirectory(nested) ? nested : resolved);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function declaredShopPlant(targetDir) {
|
|
323
|
+
const raw = loadFoundryExtra(targetDir).shopPlant;
|
|
324
|
+
const names = [];
|
|
325
|
+
if (Array.isArray(raw)) {
|
|
326
|
+
names.push(...normalizeNameList(raw));
|
|
327
|
+
} else if (typeof raw === "string" && raw.trim()) {
|
|
328
|
+
names.push(...shopPlantFromDir(targetDir, raw.trim()));
|
|
329
|
+
} else if (raw && typeof raw === "object") {
|
|
330
|
+
names.push(...normalizeNameList(raw.skills));
|
|
331
|
+
if (typeof raw.dir === "string" && raw.dir.trim()) {
|
|
332
|
+
names.push(...shopPlantFromDir(targetDir, raw.dir.trim()));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return names;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Factory shop names plus foundry.json shopPlant. Not costume. */
|
|
339
|
+
function loadShopPlant(targetDir) {
|
|
340
|
+
return [...new Set([...FACTORY_SHOP_SKILLS, ...declaredShopPlant(targetDir)])];
|
|
341
|
+
}
|
|
342
|
+
|
|
301
343
|
function previousTreeAllowlist(targetDir) {
|
|
302
344
|
const file = path.join(targetDir, ".xray", "foundry-inventory.json");
|
|
303
345
|
if (!fs.existsSync(file)) return { skills: [], agents: [] };
|
|
304
346
|
try {
|
|
305
347
|
const inventory = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
348
|
+
const shopFromInv = inventory?.shopPlant;
|
|
349
|
+
const shopSkills = Array.isArray(shopFromInv)
|
|
350
|
+
? normalizeNameList(shopFromInv)
|
|
351
|
+
: normalizeNameList(shopFromInv?.skills);
|
|
306
352
|
return {
|
|
307
|
-
skills:
|
|
353
|
+
skills: [
|
|
354
|
+
...(Array.isArray(inventory?.tree?.skills) ? inventory.tree.skills : []),
|
|
355
|
+
...shopSkills,
|
|
356
|
+
],
|
|
308
357
|
agents: Array.isArray(inventory?.tree?.agents) ? inventory.tree.agents : [],
|
|
309
358
|
};
|
|
310
359
|
} catch {
|
|
@@ -312,13 +361,15 @@ function previousTreeAllowlist(targetDir) {
|
|
|
312
361
|
}
|
|
313
362
|
}
|
|
314
363
|
|
|
315
|
-
/** Extra worn names that are neither mill plant, their plant, nor a prior overlay. */
|
|
364
|
+
/** Extra worn names that are neither mill plant, their plant, shop plant, nor a prior overlay. */
|
|
316
365
|
function costumeDumpExtras(targetDir, millPlant, tree) {
|
|
317
366
|
const prior = previousTreeAllowlist(targetDir);
|
|
367
|
+
const shopPlant = loadShopPlant(targetDir);
|
|
318
368
|
const allowedSkills = new Set([
|
|
319
369
|
...(Array.isArray(millPlant?.skills) ? millPlant.skills : []),
|
|
320
370
|
...(Array.isArray(tree?.skills) ? tree.skills : []),
|
|
321
371
|
...prior.skills,
|
|
372
|
+
...shopPlant,
|
|
322
373
|
]);
|
|
323
374
|
const allowedAgents = new Set([
|
|
324
375
|
...(Array.isArray(millPlant?.agents) ? millPlant.agents : []),
|
|
@@ -427,6 +478,9 @@ function mintConsumerFromSsot(packageRoot, targetDir, log, tree) {
|
|
|
427
478
|
skills: Array.isArray(tree?.millPlantSkills) ? tree.millPlantSkills : [],
|
|
428
479
|
agents: Array.isArray(tree?.millPlantAgents) ? tree.millPlantAgents : [],
|
|
429
480
|
},
|
|
481
|
+
shopPlant: {
|
|
482
|
+
skills: Array.isArray(tree?.shopPlantSkills) ? tree.shopPlantSkills : loadShopPlant(targetDir),
|
|
483
|
+
},
|
|
430
484
|
costume,
|
|
431
485
|
facets: {
|
|
432
486
|
constitution,
|
|
@@ -465,6 +519,7 @@ function mintConsumerSuit(millPackageRoot, targetDir, log) {
|
|
|
465
519
|
const tree = overlayConsumerTree(targetDir, log, params);
|
|
466
520
|
tree.millPlantSkills = millPlant.skills;
|
|
467
521
|
tree.millPlantAgents = millPlant.agents;
|
|
522
|
+
tree.shopPlantSkills = loadShopPlant(targetDir);
|
|
468
523
|
tree.codex = overlayJsonFacet(
|
|
469
524
|
resolveInside(targetDir, params.codex),
|
|
470
525
|
path.join(targetDir, ".xray", "codex.json"),
|
|
@@ -491,9 +546,12 @@ function mintConsumerSuit(millPackageRoot, targetDir, log) {
|
|
|
491
546
|
|
|
492
547
|
module.exports = {
|
|
493
548
|
DEFAULT_PARAMS,
|
|
549
|
+
FACTORY_SHOP_SKILLS,
|
|
494
550
|
deepMerge,
|
|
495
551
|
loadFoundryParams,
|
|
496
552
|
loadFoundryExtra,
|
|
553
|
+
loadShopPlant,
|
|
554
|
+
declaredShopPlant,
|
|
497
555
|
wantsCostume,
|
|
498
556
|
millPlantDir,
|
|
499
557
|
listSkillNamesAt,
|
|
@@ -12,7 +12,7 @@ Mill **does** these checks (`npx @0xray/foundry inspect`). Mint fails on a costu
|
|
|
12
12
|
## What mill inspects
|
|
13
13
|
|
|
14
14
|
1. **Diff.** `git status` / `git diff --stat` of the milled cwd. Ignore the agent's summary if the diff disagrees.
|
|
15
|
-
2. **Plant vs worn.** `src/skills`, `src/opencode/agents` vs `.opencode/skills`, `.opencode/agents`. Same name: plant wins. Costume dump (worn names they did not plant and
|
|
15
|
+
2. **Plant vs worn.** `src/skills`, `src/opencode/agents` vs `.opencode/skills`, `.opencode/agents`. Same name: plant wins. Shop plant (`shop-extract`, `shop-witness`, `shop-pin`, plus `foundry.json` `shopPlant`) is first-class with mill plant. Costume dump (worn names they did not plant, mill did not fasten, and shop plant did not name) fails mint unless `foundry.json` has `"costume": true`.
|
|
16
16
|
3. **Mill receipt.** `.xray/foundry-inventory.json` — mill name/version, `suit` (`fastened` / `overlay` / `costume`), `millPlant.skills` must include `mill` and `inspect`.
|
|
17
17
|
4. **CI.** GitHub mill CI report (`.opencode/logs/ci-cd-monitor-report.json`), not a green check in chat. No token is a skip, not a pass invented.
|
|
18
18
|
5. **Live PUT.** HTTP 200 on the npm `.tgz`. Metadata without a tarball is not shipped.
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* validate-release-docs.mjs — Blocking guard for release doc freshness.
|
|
4
4
|
*
|
|
5
|
-
* Ensures README, AGENTS, SKILLS, CHANGELOG, Docusaurus headers, and
|
|
6
|
-
* guides match package.json version and
|
|
5
|
+
* Ensures README, AGENTS, SKILLS, llms.txt, CHANGELOG, Docusaurus headers, and
|
|
6
|
+
* required guides match package.json version and mill law before tag/publish.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* npx @0xray/foundry docs-check
|
|
@@ -42,6 +42,24 @@ const REQUIRED_GUIDES = [
|
|
|
42
42
|
'docs-site/docs/agents/README.md',
|
|
43
43
|
];
|
|
44
44
|
|
|
45
|
+
function millLawLagErrors(content) {
|
|
46
|
+
const errors = [];
|
|
47
|
+
if (/Syncs \*\*45 framework skills\*\*/.test(content) || /syncs all 45 skills/i.test(content)) {
|
|
48
|
+
errors.push('lags mill law: default plant is mill+inspect, not 45-skill sync');
|
|
49
|
+
}
|
|
50
|
+
if (/SKILLS\.md \+ 45 skills → platform skill directories/.test(content)) {
|
|
51
|
+
errors.push('lags mill law: postinstall must not sync 45 skills as default plant');
|
|
52
|
+
}
|
|
53
|
+
return errors;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function millPlantMentionErrors(content) {
|
|
57
|
+
if (!content.includes('mill') || !content.includes('inspect')) {
|
|
58
|
+
return ['missing mill+inspect plant'];
|
|
59
|
+
}
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
|
|
45
63
|
const ROOT_DOC_CHECKS = [
|
|
46
64
|
{
|
|
47
65
|
rel: 'README.md',
|
|
@@ -62,6 +80,14 @@ const ROOT_DOC_CHECKS = [
|
|
|
62
80
|
if (!content.includes('install-bridges') && !content.includes('installAllBridges')) {
|
|
63
81
|
errors.push('missing install-bridges / installAllBridges reference');
|
|
64
82
|
}
|
|
83
|
+
if (!content.includes('llms.txt')) {
|
|
84
|
+
errors.push('missing llms.txt agent-map reference');
|
|
85
|
+
}
|
|
86
|
+
if (!content.includes('shopPlant') && !content.includes('shop-extract')) {
|
|
87
|
+
errors.push('missing shop plant / shopPlant');
|
|
88
|
+
}
|
|
89
|
+
errors.push(...millPlantMentionErrors(content));
|
|
90
|
+
errors.push(...millLawLagErrors(content));
|
|
65
91
|
return errors;
|
|
66
92
|
},
|
|
67
93
|
},
|
|
@@ -81,6 +107,11 @@ const ROOT_DOC_CHECKS = [
|
|
|
81
107
|
if (!content.includes('SKILLS.md')) {
|
|
82
108
|
errors.push('missing SKILLS.md link');
|
|
83
109
|
}
|
|
110
|
+
if (!content.includes('llms.txt')) {
|
|
111
|
+
errors.push('missing llms.txt agent-map reference');
|
|
112
|
+
}
|
|
113
|
+
errors.push(...millPlantMentionErrors(content));
|
|
114
|
+
errors.push(...millLawLagErrors(content));
|
|
84
115
|
return errors;
|
|
85
116
|
},
|
|
86
117
|
},
|
|
@@ -100,6 +131,11 @@ const ROOT_DOC_CHECKS = [
|
|
|
100
131
|
if (!content.includes('AsideContext')) {
|
|
101
132
|
errors.push('missing AsideContext section');
|
|
102
133
|
}
|
|
134
|
+
if (!content.includes('shopPlant') && !content.includes('shop-extract')) {
|
|
135
|
+
errors.push('missing shop plant / shopPlant');
|
|
136
|
+
}
|
|
137
|
+
errors.push(...millPlantMentionErrors(content));
|
|
138
|
+
errors.push(...millLawLagErrors(content));
|
|
103
139
|
return errors;
|
|
104
140
|
},
|
|
105
141
|
},
|
|
@@ -113,6 +149,37 @@ const ROOT_DOC_CHECKS = [
|
|
|
113
149
|
if (!content.includes(`**${counts.skills} skills**`)) {
|
|
114
150
|
errors.push(`skill count stale (expected **${counts.skills} skills**)`);
|
|
115
151
|
}
|
|
152
|
+
errors.push(...millPlantMentionErrors(content));
|
|
153
|
+
errors.push(...millLawLagErrors(content));
|
|
154
|
+
return errors;
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
rel: 'llms.txt',
|
|
159
|
+
validate: (content) => {
|
|
160
|
+
const errors = [];
|
|
161
|
+
if (kernelLineHasPatchStamp(content)) {
|
|
162
|
+
errors.push('kernel header must be era (major.minor), not a patch stamp');
|
|
163
|
+
}
|
|
164
|
+
if (!content.includes('mill') || !content.includes('inspect')) {
|
|
165
|
+
errors.push('missing mill+inspect plant');
|
|
166
|
+
}
|
|
167
|
+
if (!content.includes('shopPlant') && !content.includes('shop-extract')) {
|
|
168
|
+
errors.push('missing hangar / shopPlant coexistence');
|
|
169
|
+
}
|
|
170
|
+
if (!content.includes('69')) {
|
|
171
|
+
errors.push('missing Codex 69');
|
|
172
|
+
}
|
|
173
|
+
if (!content.includes('xray-governance') || !content.includes('xray-orchestrator')) {
|
|
174
|
+
errors.push('missing 7 MCP agent map');
|
|
175
|
+
}
|
|
176
|
+
if (!content.toLowerCase().includes('costume')) {
|
|
177
|
+
errors.push('missing no-costume-dump law');
|
|
178
|
+
}
|
|
179
|
+
if (/^## Complete catalog/m.test(content) || content.includes('`api-design` · `architect-tools`')) {
|
|
180
|
+
errors.push('llms.txt must not costume-dump the 45-skill catalog');
|
|
181
|
+
}
|
|
182
|
+
errors.push(...millLawLagErrors(content));
|
|
116
183
|
return errors;
|
|
117
184
|
},
|
|
118
185
|
},
|
|
@@ -348,6 +348,7 @@ export function getReleaseArtifactPaths(baseDir = resolveMillRoot()) {
|
|
|
348
348
|
'AGENTS.md',
|
|
349
349
|
'AGENTS-consumer.md',
|
|
350
350
|
'SKILLS.md',
|
|
351
|
+
'llms.txt',
|
|
351
352
|
'.grok-plugin/plugin.json',
|
|
352
353
|
'docs/README.md',
|
|
353
354
|
'docs-site/docs/index.md',
|
|
@@ -366,6 +367,9 @@ export function getReleaseArtifactPaths(baseDir = resolveMillRoot()) {
|
|
|
366
367
|
'docs-site/docs/architecture/GROK_GUIDE.md',
|
|
367
368
|
'docs-site/sidebars.ts',
|
|
368
369
|
'xray/features.json',
|
|
370
|
+
'.xray/features.json',
|
|
371
|
+
'docs/PIPELINE-FACET-SNAPSHOT.json',
|
|
372
|
+
'src/integrations/openclaw/plugin/xray-pre-tool/package.json',
|
|
369
373
|
];
|
|
370
374
|
return candidates.filter((rel) => fs.existsSync(path.join(baseDir, rel)));
|
|
371
375
|
}
|
|
@@ -39,6 +39,17 @@ function resolveRepertoireMcp(targetDir) {
|
|
|
39
39
|
const candidates = [
|
|
40
40
|
path.join(targetDir, "node_modules", "@0xray", "repertoire", "dist", "mcp", "server.js"),
|
|
41
41
|
path.join(targetDir, "vendor", "@0xray", "repertoire", "dist", "mcp", "server.js"),
|
|
42
|
+
path.join(
|
|
43
|
+
targetDir,
|
|
44
|
+
"node_modules",
|
|
45
|
+
"0xray",
|
|
46
|
+
"vendor",
|
|
47
|
+
"@0xray",
|
|
48
|
+
"repertoire",
|
|
49
|
+
"dist",
|
|
50
|
+
"mcp",
|
|
51
|
+
"server.js",
|
|
52
|
+
),
|
|
42
53
|
isRepertoirePackageRoot(selfRoot) ? path.join(selfRoot, "dist", "mcp", "server.js") : null,
|
|
43
54
|
isRepertoirePackageRoot(siblingRoot) ? path.join(siblingRoot, "dist", "mcp", "server.js") : null,
|
|
44
55
|
];
|
|
@@ -66,8 +77,20 @@ function resolveRepertoireProvider(targetDir) {
|
|
|
66
77
|
"provider",
|
|
67
78
|
"memory-routing-provider.js",
|
|
68
79
|
);
|
|
80
|
+
const packedVendorProvider = path.join(
|
|
81
|
+
targetDir,
|
|
82
|
+
"node_modules",
|
|
83
|
+
"0xray",
|
|
84
|
+
"vendor",
|
|
85
|
+
"@0xray",
|
|
86
|
+
"repertoire",
|
|
87
|
+
"dist",
|
|
88
|
+
"provider",
|
|
89
|
+
"memory-routing-provider.js",
|
|
90
|
+
);
|
|
69
91
|
if (fs.existsSync(nmProvider)) return nmProvider;
|
|
70
92
|
if (fs.existsSync(vendorProvider)) return vendorProvider;
|
|
93
|
+
if (fs.existsSync(packedVendorProvider)) return packedVendorProvider;
|
|
71
94
|
if (isRepertoirePackageRoot(siblingRoot) && fs.existsSync(siblingProvider)) return siblingProvider;
|
|
72
95
|
return null;
|
|
73
96
|
}
|
|
@@ -15,6 +15,7 @@ import os from "os";
|
|
|
15
15
|
import path from "path";
|
|
16
16
|
import { fileURLToPath } from "url";
|
|
17
17
|
import { createRequire } from "module";
|
|
18
|
+
import { proveSuitAfterInstall } from "./pack-tmp-suit-proof.mjs";
|
|
18
19
|
|
|
19
20
|
const require = createRequire(import.meta.url);
|
|
20
21
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -39,6 +40,64 @@ function run(cmd, cwd, { inherit = false } = {}) {
|
|
|
39
40
|
return inherit ? "" : String(result).trim();
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
function assertPackedPackageHasNoFileDeps(tarballPath) {
|
|
44
|
+
const packedJson = run(`tar -xOf ${JSON.stringify(tarballPath)} package/package.json`);
|
|
45
|
+
const packed = JSON.parse(packedJson);
|
|
46
|
+
const buckets = ["dependencies", "optionalDependencies", "peerDependencies"];
|
|
47
|
+
for (const bucket of buckets) {
|
|
48
|
+
const entries = packed[bucket] || {};
|
|
49
|
+
for (const [name, spec] of Object.entries(entries)) {
|
|
50
|
+
if (String(spec).startsWith("file:")) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`packed package.json must not ship file: ${bucket} ${name}=${spec} (consumers resolve file: from their root)`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (!String(packedJson).includes("vendor/@0xray/repertoire/")) {
|
|
58
|
+
const listing = run(`tar -tzf ${JSON.stringify(tarballPath)}`);
|
|
59
|
+
if (!listing.includes("package/vendor/@0xray/repertoire/package.json")) {
|
|
60
|
+
throw new Error("packed tarball missing vendor/@0xray/repertoire/package.json");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
console.log(" ✅ packed package.json has no file: deps; vendor organ is in the tarball");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function assertOrganRequire(tmpRoot) {
|
|
67
|
+
const consumerRequire = createRequire(path.join(tmpRoot, "package.json"));
|
|
68
|
+
let organPkg;
|
|
69
|
+
try {
|
|
70
|
+
organPkg = consumerRequire("@0xray/repertoire/package.json");
|
|
71
|
+
} catch (err) {
|
|
72
|
+
throw new Error(`require('@0xray/repertoire') failed: ${err.message}`);
|
|
73
|
+
}
|
|
74
|
+
if (organPkg.name !== "@0xray/repertoire") {
|
|
75
|
+
throw new Error(`required organ name ${organPkg.name}`);
|
|
76
|
+
}
|
|
77
|
+
if (organPkg.version !== "0.2.0") {
|
|
78
|
+
throw new Error(`required organ version ${organPkg.version}`);
|
|
79
|
+
}
|
|
80
|
+
if (fs.existsSync(path.join(tmpRoot, "vendor"))) {
|
|
81
|
+
throw new Error("consumer install must not create or require a consumer-root vendor/ tree");
|
|
82
|
+
}
|
|
83
|
+
console.log(" ✅ require('@0xray/repertoire') from consumer cwd (no consumer vendor/)");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function writeBareConsumerManifest(tmpRoot) {
|
|
87
|
+
fs.writeFileSync(
|
|
88
|
+
path.join(tmpRoot, "package.json"),
|
|
89
|
+
`${JSON.stringify(
|
|
90
|
+
{
|
|
91
|
+
name: "xray-consumer-test",
|
|
92
|
+
version: "0.0.1",
|
|
93
|
+
private: true,
|
|
94
|
+
},
|
|
95
|
+
null,
|
|
96
|
+
2,
|
|
97
|
+
)}\n`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
42
101
|
function assertFreshInstallDefaults(tmpRoot, version) {
|
|
43
102
|
const consumerFeaturesPath = path.join(tmpRoot, ".xray", "features.json");
|
|
44
103
|
if (!fs.existsSync(consumerFeaturesPath)) {
|
|
@@ -188,25 +247,30 @@ function main() {
|
|
|
188
247
|
throw new Error(`Tarball not found: ${tarballPath}`);
|
|
189
248
|
}
|
|
190
249
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
version: "1.0.0",
|
|
195
|
-
dependencies: {
|
|
196
|
-
"0xray": `file:${tarballPath}`,
|
|
197
|
-
},
|
|
198
|
-
};
|
|
199
|
-
fs.writeFileSync(
|
|
200
|
-
path.join(tmpRoot, "package.json"),
|
|
201
|
-
JSON.stringify(consumerPkg, null, 2) + "\n",
|
|
202
|
-
);
|
|
250
|
+
assertPackedPackageHasNoFileDeps(tarballPath);
|
|
251
|
+
|
|
252
|
+
writeBareConsumerManifest(tmpRoot);
|
|
203
253
|
|
|
204
|
-
console.log("📥 npm install (
|
|
205
|
-
run(
|
|
254
|
+
console.log("📥 npm install tarball into bare consumer (exact ENOENT repro)...");
|
|
255
|
+
run(`npm install ${JSON.stringify(tarballPath)}`, tmpRoot, { inherit: true });
|
|
256
|
+
|
|
257
|
+
const installLinksRoot = fs.mkdtempSync(path.join(os.tmpdir(), "0xray-smoke-links-"));
|
|
258
|
+
writeBareConsumerManifest(installLinksRoot);
|
|
259
|
+
console.log("📥 npm install tarball --install-links (file: ENOENT path)...");
|
|
260
|
+
run(`npm install ${JSON.stringify(tarballPath)} --install-links`, installLinksRoot, {
|
|
261
|
+
inherit: true,
|
|
262
|
+
});
|
|
263
|
+
assertOrganRequire(installLinksRoot);
|
|
264
|
+
try {
|
|
265
|
+
fs.rmSync(installLinksRoot, { recursive: true, force: true });
|
|
266
|
+
} catch {
|
|
267
|
+
/* best-effort */
|
|
268
|
+
}
|
|
206
269
|
|
|
207
270
|
const nmRoot = path.join(tmpRoot, "node_modules", "0xray");
|
|
208
271
|
const requiredFiles = [
|
|
209
272
|
"scripts/node/install-bridges.cjs",
|
|
273
|
+
"scripts/node/wear-vendored-repertoire.cjs",
|
|
210
274
|
"scripts/node/postinstall.cjs",
|
|
211
275
|
"scripts/foundry/mint-suit.cjs",
|
|
212
276
|
"scripts/foundry/hooks.mjs",
|
|
@@ -274,6 +338,7 @@ function main() {
|
|
|
274
338
|
console.log(` ✅ .mcp.json has ${XRAY_MCP_NAMES.length} npx MCP servers`);
|
|
275
339
|
|
|
276
340
|
assertFreshInstallDefaults(tmpRoot, version);
|
|
341
|
+
assertOrganRequire(tmpRoot);
|
|
277
342
|
|
|
278
343
|
const schemaInPackage = path.join(nmRoot, "xray", "features.schema.json");
|
|
279
344
|
if (!fs.existsSync(schemaInPackage)) {
|
|
@@ -283,6 +348,9 @@ function main() {
|
|
|
283
348
|
|
|
284
349
|
runUpgradeMergeSmoke(tmpRoot, nmRoot, version);
|
|
285
350
|
|
|
351
|
+
console.log("\n📋 Pack → tmp mill fasten + hangar shop plant (not costume)...");
|
|
352
|
+
proveSuitAfterInstall(tmpRoot, path.join(nmRoot, "scripts", "foundry"));
|
|
353
|
+
|
|
286
354
|
console.log("\n✅ Consumer install smoke passed\n");
|
|
287
355
|
} catch (err) {
|
|
288
356
|
console.error(`\n❌ Consumer smoke failed: ${err.message}\n`);
|
|
@@ -9,6 +9,7 @@ const path = require("path");
|
|
|
9
9
|
const os = require("os");
|
|
10
10
|
const { execSync } = require("child_process");
|
|
11
11
|
const { wantsCostume, isIsolatedHome, machineHome } = require("../foundry/mint-suit.cjs");
|
|
12
|
+
const { wearVendoredRepertoire } = require("./wear-vendored-repertoire.cjs");
|
|
12
13
|
const {
|
|
13
14
|
wireHermesBridge,
|
|
14
15
|
wireOpencodeBridge,
|
|
@@ -742,6 +743,8 @@ function installAllBridges(opts) {
|
|
|
742
743
|
/* noop */
|
|
743
744
|
});
|
|
744
745
|
|
|
746
|
+
wearVendoredRepertoire(packageRoot, targetDir, log);
|
|
747
|
+
|
|
745
748
|
if (!isConsumerInstall(packageRoot, targetDir)) {
|
|
746
749
|
log("install-bridges", "framework dogfood wear", "info");
|
|
747
750
|
installFrameworkDogfoodWear(packageRoot, log);
|
|
@@ -779,4 +782,5 @@ module.exports = {
|
|
|
779
782
|
isEphemeralInstallRoot,
|
|
780
783
|
isIsolatedHome,
|
|
781
784
|
installFrameworkDogfoodWear,
|
|
785
|
+
wearVendoredRepertoire,
|
|
782
786
|
};
|