@helix3/helix-cli 0.1.7-helix3.45 → 0.1.8-helix3.47
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/dist/browser/launch.d.ts +22 -0
- package/dist/browser/launch.js +46 -0
- package/dist/browser/launch.js.map +1 -0
- package/dist/gesture/worldRuntime.d.ts +2 -0
- package/dist/gesture/worldRuntime.js +5 -2
- package/dist/gesture/worldRuntime.js.map +1 -1
- package/dist/index.js +127 -0
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +19 -0
- package/dist/lib.js +36 -1
- package/dist/lib.js.map +1 -1
- package/dist/screenshot/captureScreenshots.d.ts +4 -16
- package/dist/screenshot/captureScreenshots.js +16 -43
- package/dist/screenshot/captureScreenshots.js.map +1 -1
- package/dist/screenshot/staticServe.d.ts +1 -1
- package/dist/screenshot/staticServe.js +34 -16
- package/dist/screenshot/staticServe.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/world/analyze.d.ts +40 -0
- package/dist/world/analyze.js +573 -0
- package/dist/world/analyze.js.map +1 -0
- package/dist/world/diff.d.ts +18 -0
- package/dist/world/diff.js +58 -0
- package/dist/world/diff.js.map +1 -0
- package/dist/world/focus.d.ts +11 -0
- package/dist/world/focus.js +99 -0
- package/dist/world/focus.js.map +1 -0
- package/dist/world/format.d.ts +6 -0
- package/dist/world/format.js +123 -0
- package/dist/world/format.js.map +1 -0
- package/dist/world/readWorldMetrics.d.ts +10 -0
- package/dist/world/readWorldMetrics.js +31 -0
- package/dist/world/readWorldMetrics.js.map +1 -0
- package/dist/world/snapshotTypes.d.ts +59 -0
- package/dist/world/snapshotTypes.js +8 -0
- package/dist/world/snapshotTypes.js.map +1 -0
- package/dist/world/snapshotWorld.d.ts +16 -0
- package/dist/world/snapshotWorld.js +120 -0
- package/dist/world/snapshotWorld.js.map +1 -0
- package/dist/world/zones.d.ts +23 -0
- package/dist/world/zones.js +134 -0
- package/dist/world/zones.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.diffWorldSnapshots = diffWorldSnapshots;
|
|
4
|
+
exports.formatWorldDiff = formatWorldDiff;
|
|
5
|
+
const analyze_1 = require("./analyze");
|
|
6
|
+
const MOVE_EPSILON_M = 0.01;
|
|
7
|
+
const r3 = (n) => Math.round(n * 1000) / 1000;
|
|
8
|
+
const findingKey = (f) => `${f.rule}|${f.path}`;
|
|
9
|
+
function diffWorldSnapshots(before, after) {
|
|
10
|
+
const beforeByPath = new Map(before.objects.map((o) => [o.path, o]));
|
|
11
|
+
const afterByPath = new Map(after.objects.map((o) => [o.path, o]));
|
|
12
|
+
const added = [...afterByPath.keys()].filter((p) => !beforeByPath.has(p));
|
|
13
|
+
const removed = [...beforeByPath.keys()].filter((p) => !afterByPath.has(p));
|
|
14
|
+
const moved = [];
|
|
15
|
+
for (const [path, a] of beforeByPath) {
|
|
16
|
+
const b = afterByPath.get(path);
|
|
17
|
+
if (!b)
|
|
18
|
+
continue;
|
|
19
|
+
const delta = { x: r3(b.position.x - a.position.x), y: r3(b.position.y - a.position.y), z: r3(b.position.z - a.position.z) };
|
|
20
|
+
const distance = Math.hypot(delta.x, delta.y, delta.z);
|
|
21
|
+
if (distance <= MOVE_EPSILON_M)
|
|
22
|
+
continue;
|
|
23
|
+
moved.push({ path, from: a.position, to: b.position, delta, distance: r3(distance) });
|
|
24
|
+
}
|
|
25
|
+
moved.sort((a, b) => b.distance - a.distance);
|
|
26
|
+
const beforeFindings = new Map((0, analyze_1.analyzeWorld)(before).findings.map((f) => [findingKey(f), f]));
|
|
27
|
+
const afterFindings = new Map((0, analyze_1.analyzeWorld)(after).findings.map((f) => [findingKey(f), f]));
|
|
28
|
+
const findingsAppeared = [...afterFindings.entries()].filter(([k]) => !beforeFindings.has(k)).map(([, f]) => f);
|
|
29
|
+
const findingsCleared = [...beforeFindings.entries()].filter(([k]) => !afterFindings.has(k)).map(([, f]) => f);
|
|
30
|
+
return { added, removed, moved, findingsAppeared, findingsCleared };
|
|
31
|
+
}
|
|
32
|
+
function formatWorldDiff(diff) {
|
|
33
|
+
const lines = [];
|
|
34
|
+
lines.push(`world diff — ${diff.added.length} added, ${diff.removed.length} removed, ${diff.moved.length} moved, ` +
|
|
35
|
+
`${diff.findingsAppeared.length} findings appeared, ${diff.findingsCleared.length} cleared`);
|
|
36
|
+
if (diff.added.length) {
|
|
37
|
+
lines.push('', 'added:');
|
|
38
|
+
lines.push(...diff.added.map((p) => ` + ${p}`));
|
|
39
|
+
}
|
|
40
|
+
if (diff.removed.length) {
|
|
41
|
+
lines.push('', 'removed:');
|
|
42
|
+
lines.push(...diff.removed.map((p) => ` - ${p}`));
|
|
43
|
+
}
|
|
44
|
+
if (diff.moved.length) {
|
|
45
|
+
lines.push('', 'moved:');
|
|
46
|
+
lines.push(...diff.moved.map((m) => ` ~ ${m.path}: Δ(${m.delta.x}, ${m.delta.y}, ${m.delta.z}) — ${m.distance} m`));
|
|
47
|
+
}
|
|
48
|
+
if (diff.findingsAppeared.length) {
|
|
49
|
+
lines.push('', 'findings appeared:');
|
|
50
|
+
lines.push(...diff.findingsAppeared.map((f) => ` ! [${f.severity}] ${f.rule} ${f.path} — ${f.detail}`));
|
|
51
|
+
}
|
|
52
|
+
if (diff.findingsCleared.length) {
|
|
53
|
+
lines.push('', 'findings cleared:');
|
|
54
|
+
lines.push(...diff.findingsCleared.map((f) => ` ✓ [${f.severity}] ${f.rule} ${f.path}`));
|
|
55
|
+
}
|
|
56
|
+
return lines.join('\n');
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/world/diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SnapshotObject, WorldSnapshot } from './snapshotTypes';
|
|
2
|
+
import { type AnalysisResult } from './analyze';
|
|
3
|
+
export interface FocusQuery {
|
|
4
|
+
/** Case-insensitive substring of the object path (for named/imported objects). */
|
|
5
|
+
path?: string | undefined;
|
|
6
|
+
/** World-space point — matches objects whose AABB is within `radius` of it (0 when inside). */
|
|
7
|
+
near?: [number, number, number] | undefined;
|
|
8
|
+
radius?: number | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare function resolveFocus(snapshot: WorldSnapshot, query: FocusQuery): SnapshotObject[];
|
|
11
|
+
export declare function formatWorldFocus(snapshot: WorldSnapshot, analysis: AnalysisResult, query: FocusQuery): string;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveFocus = resolveFocus;
|
|
4
|
+
exports.formatWorldFocus = formatWorldFocus;
|
|
5
|
+
const analyze_1 = require("./analyze");
|
|
6
|
+
const DEFAULT_NEAR_RADIUS_M = 2;
|
|
7
|
+
const r2 = (n) => Math.round(n * 100) / 100;
|
|
8
|
+
/** Distance from a point to an AABB — 0 when the point is inside. */
|
|
9
|
+
function pointToAabb(p, b) {
|
|
10
|
+
const dx = Math.max(b.min.x - p.x, 0, p.x - b.max.x);
|
|
11
|
+
const dy = Math.max(b.min.y - p.y, 0, p.y - b.max.y);
|
|
12
|
+
const dz = Math.max(b.min.z - p.z, 0, p.z - b.max.z);
|
|
13
|
+
return Math.hypot(dx, dy, dz);
|
|
14
|
+
}
|
|
15
|
+
function resolveFocus(snapshot, query) {
|
|
16
|
+
const candidates = snapshot.objects.filter((o) => o.aabb !== null);
|
|
17
|
+
if (query.path !== undefined) {
|
|
18
|
+
const needle = query.path.toLowerCase();
|
|
19
|
+
return candidates.filter((o) => o.path.toLowerCase().includes(needle));
|
|
20
|
+
}
|
|
21
|
+
if (query.near !== undefined) {
|
|
22
|
+
const p = { x: query.near[0], y: query.near[1], z: query.near[2] };
|
|
23
|
+
const radius = query.radius ?? DEFAULT_NEAR_RADIUS_M;
|
|
24
|
+
return candidates
|
|
25
|
+
.map((o) => ({ o, d: pointToAabb(p, o.aabb) }))
|
|
26
|
+
.filter(({ d }) => d <= radius)
|
|
27
|
+
.sort((a, b) => a.d - b.d)
|
|
28
|
+
.map(({ o }) => o);
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
// A finding involves a focused object when it is the subject OR its detail names the path as a
|
|
33
|
+
// whole token — plain substring would make Mesh#1 swallow Mesh#10.
|
|
34
|
+
function findingMentions(pathsSet, subject, detail) {
|
|
35
|
+
if (pathsSet.has(subject))
|
|
36
|
+
return true;
|
|
37
|
+
for (const path of pathsSet) {
|
|
38
|
+
const esc = path.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
39
|
+
if (new RegExp(`(?<!\\w)${esc}(?!\\w)`).test(detail))
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function formatWorldFocus(snapshot, analysis, query) {
|
|
45
|
+
const focused = resolveFocus(snapshot, query);
|
|
46
|
+
const lines = [];
|
|
47
|
+
const queryLabel = query.path !== undefined ? `path ~ "${query.path}"` : `near (${(query.near ?? []).join(', ')}) r=${query.radius ?? DEFAULT_NEAR_RADIUS_M}`;
|
|
48
|
+
if (focused.length === 0) {
|
|
49
|
+
lines.push(`focus ${queryLabel} — no objects matched.`);
|
|
50
|
+
// The agent's coordinate was off, or the object never made it into the scene — the three
|
|
51
|
+
// nearest objects answer both ("it landed over THERE" vs "it does not exist").
|
|
52
|
+
if (query.near !== undefined) {
|
|
53
|
+
const p = { x: query.near[0], y: query.near[1], z: query.near[2] };
|
|
54
|
+
const nearest = snapshot.objects
|
|
55
|
+
.filter((o) => o.aabb !== null)
|
|
56
|
+
.map((o) => ({ o, d: pointToAabb(p, o.aabb) }))
|
|
57
|
+
.sort((a, b) => a.d - b.d)
|
|
58
|
+
.slice(0, 3);
|
|
59
|
+
if (nearest.length) {
|
|
60
|
+
lines.push('nearest objects:');
|
|
61
|
+
for (const { o, d } of nearest)
|
|
62
|
+
lines.push(` ${o.path} — ${r2(d)} m away @ (${o.position.x}, ${o.position.y}, ${o.position.z})`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return lines.join('\n');
|
|
66
|
+
}
|
|
67
|
+
lines.push(`focus ${queryLabel} — ${focused.length} object${focused.length === 1 ? '' : 's'}:`);
|
|
68
|
+
const colliderBoxes = snapshot.colliders
|
|
69
|
+
.map((c, index) => ({ c, index, aabb: (0, analyze_1.colliderAabb)(c) }))
|
|
70
|
+
.filter((x) => x.aabb !== null);
|
|
71
|
+
for (const o of focused) {
|
|
72
|
+
const b = o.aabb;
|
|
73
|
+
const size = { x: r2(b.max.x - b.min.x), y: r2(b.max.y - b.min.y), z: r2(b.max.z - b.min.z) };
|
|
74
|
+
lines.push(` ${o.path} (${o.geometry ?? o.type}${o.color ? ` ${o.color}` : ''}${o.visible ? '' : ', INVISIBLE'})`);
|
|
75
|
+
lines.push(` position (${o.position.x}, ${o.position.y}, ${o.position.z}) · size ${size.x}×${size.y}×${size.z} · ${o.triangles} tris`);
|
|
76
|
+
lines.push(` aabb x[${r2(b.min.x)}..${r2(b.max.x)}] y[${r2(b.min.y)}..${r2(b.max.y)}] z[${r2(b.min.z)}..${r2(b.max.z)}]`);
|
|
77
|
+
// Touching colliders (gap ≤ 0.1 on every axis) — "does my object have collision" at a glance.
|
|
78
|
+
const touching = colliderBoxes.filter(({ aabb }) => {
|
|
79
|
+
const gx = Math.max(aabb.min.x - b.max.x, b.min.x - aabb.max.x, 0);
|
|
80
|
+
const gy = Math.max(aabb.min.y - b.max.y, b.min.y - aabb.max.y, 0);
|
|
81
|
+
const gz = Math.max(aabb.min.z - b.max.z, b.min.z - aabb.max.z, 0);
|
|
82
|
+
return gx <= 0.1 && gy <= 0.1 && gz <= 0.1;
|
|
83
|
+
});
|
|
84
|
+
lines.push(touching.length
|
|
85
|
+
? ` colliders touching: ${touching.map(({ c, index }) => `[${index}] ${c.shape}`).join(', ')}`
|
|
86
|
+
: ` colliders touching: none${snapshot.sources.colliders === 'ok' ? ' — walk-through unless intended' : ` (collider source: ${snapshot.sources.colliders})`}`);
|
|
87
|
+
}
|
|
88
|
+
const pathsSet = new Set(focused.map((o) => o.path));
|
|
89
|
+
const involved = analysis.findings.filter((f) => findingMentions(pathsSet, f.path, f.detail));
|
|
90
|
+
lines.push('');
|
|
91
|
+
lines.push(`findings involving the focused object${focused.length === 1 ? '' : 's'} (world total: ${analysis.findings.length}):`);
|
|
92
|
+
if (involved.length === 0)
|
|
93
|
+
lines.push(' (none)');
|
|
94
|
+
else
|
|
95
|
+
for (const f of involved)
|
|
96
|
+
lines.push(` [${f.severity}] ${f.rule} — ${f.detail}`);
|
|
97
|
+
return lines.join('\n');
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=focus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus.js","sourceRoot":"","sources":["../../src/world/focus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { WorldSnapshot } from './snapshotTypes';
|
|
2
|
+
import type { AnalysisResult } from './analyze';
|
|
3
|
+
import type { ZoneReport } from './zones';
|
|
4
|
+
export type ReportSection = 'anomalies' | 'roster' | 'colliders' | 'zones';
|
|
5
|
+
export declare const DEFAULT_REPORT: ReportSection[];
|
|
6
|
+
export declare function formatWorldInspection(snapshot: WorldSnapshot, analysis: AnalysisResult, report?: ReportSection[], zones?: ZoneReport[] | null): string;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_REPORT = void 0;
|
|
4
|
+
exports.formatWorldInspection = formatWorldInspection;
|
|
5
|
+
exports.DEFAULT_REPORT = ['anomalies'];
|
|
6
|
+
// A genuinely broken world can carry hundreds of findings of one kind; the render caps each rule
|
|
7
|
+
// at the worst N (the list is severity-sorted) with an explicit overflow line — same never-silent
|
|
8
|
+
// principle as the roster truncation. The json output always carries the full list.
|
|
9
|
+
const MAX_FINDINGS_PER_RULE = 10;
|
|
10
|
+
const r1 = (n) => Math.round(n * 10) / 10;
|
|
11
|
+
function formatFinding(f) {
|
|
12
|
+
const measured = f.measured
|
|
13
|
+
? ` {${Object.entries(f.measured)
|
|
14
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
15
|
+
.join(', ')}}`
|
|
16
|
+
: '';
|
|
17
|
+
return ` [${f.severity}] ${f.rule} ${f.path} — ${f.detail}${measured}\n method: ${f.method}; confidence: ${f.confidence}`;
|
|
18
|
+
}
|
|
19
|
+
function formatRoster(snapshot) {
|
|
20
|
+
const groups = new Map();
|
|
21
|
+
for (const obj of snapshot.objects) {
|
|
22
|
+
const s = obj.aabb
|
|
23
|
+
? `${r1(obj.aabb.max.x - obj.aabb.min.x)}×${r1(obj.aabb.max.y - obj.aabb.min.y)}×${r1(obj.aabb.max.z - obj.aabb.min.z)}`
|
|
24
|
+
: 'no-aabb';
|
|
25
|
+
const key = `${obj.type}|${obj.geometry ?? '-'}|${obj.triangles}|${s}|${obj.color ?? '-'}`;
|
|
26
|
+
const existing = groups.get(key);
|
|
27
|
+
if (existing) {
|
|
28
|
+
existing.count++;
|
|
29
|
+
if (obj.aabb) {
|
|
30
|
+
existing.min.x = Math.min(existing.min.x, obj.aabb.min.x);
|
|
31
|
+
existing.min.z = Math.min(existing.min.z, obj.aabb.min.z);
|
|
32
|
+
existing.max.x = Math.max(existing.max.x, obj.aabb.max.x);
|
|
33
|
+
existing.max.z = Math.max(existing.max.z, obj.aabb.max.z);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
groups.set(key, {
|
|
38
|
+
key,
|
|
39
|
+
label: `${obj.geometry ?? obj.type} tris=${obj.triangles} size=${s}${obj.color ? ` ${obj.color}` : ''}`,
|
|
40
|
+
count: 1,
|
|
41
|
+
min: { x: obj.aabb?.min.x ?? 0, z: obj.aabb?.min.z ?? 0 },
|
|
42
|
+
max: { x: obj.aabb?.max.x ?? 0, z: obj.aabb?.max.z ?? 0 },
|
|
43
|
+
firstPath: obj.path,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return [...groups.values()]
|
|
48
|
+
.sort((a, b) => b.count - a.count)
|
|
49
|
+
.map((g) => ` ${String(g.count).padStart(3)}× ${g.label} — e.g. ${g.firstPath}` +
|
|
50
|
+
(g.count > 1 ? ` (spread x[${r1(g.min.x)}..${r1(g.max.x)}] z[${r1(g.min.z)}..${r1(g.max.z)}])` : ''));
|
|
51
|
+
}
|
|
52
|
+
function formatColliders(snapshot) {
|
|
53
|
+
if (snapshot.sources.colliders !== 'ok')
|
|
54
|
+
return [` (skipped — sources.colliders: ${snapshot.sources.colliders})`];
|
|
55
|
+
if (snapshot.colliders.length === 0)
|
|
56
|
+
return [' (none)'];
|
|
57
|
+
// Ordinal labels — Rapier handles are opaque f64 bit-packs that print as denormals.
|
|
58
|
+
return snapshot.colliders.map((c, i) => {
|
|
59
|
+
const extent = c.halfExtents
|
|
60
|
+
? `he ${c.halfExtents.x}×${c.halfExtents.y}×${c.halfExtents.z}`
|
|
61
|
+
: typeof c.radius === 'number'
|
|
62
|
+
? `r ${c.radius}${typeof c.halfHeight === 'number' ? ` hh ${c.halfHeight}` : ''}`
|
|
63
|
+
: '';
|
|
64
|
+
return ` [${i}] ${c.shape} ${extent} @ (${c.position.x}, ${c.position.y}, ${c.position.z})`;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function formatWorldInspection(snapshot, analysis, report = exports.DEFAULT_REPORT, zones) {
|
|
68
|
+
const lines = [];
|
|
69
|
+
const spawn = snapshot.spawn ? `(${snapshot.spawn.x}, ${snapshot.spawn.y}, ${snapshot.spawn.z})` : '(not provided)';
|
|
70
|
+
lines.push(`world inspect — ${snapshot.objects.length} objects, ${snapshot.colliders.length} colliders (source: ${snapshot.sources.colliders}), spawn ${spawn}`);
|
|
71
|
+
for (const note of analysis.notes)
|
|
72
|
+
lines.push(`note: ${note}`);
|
|
73
|
+
if (report.includes('anomalies')) {
|
|
74
|
+
const counts = { error: 0, warn: 0, info: 0 };
|
|
75
|
+
for (const f of analysis.findings)
|
|
76
|
+
counts[f.severity]++;
|
|
77
|
+
lines.push('');
|
|
78
|
+
lines.push(`anomalies (${counts.error} error, ${counts.warn} warn, ${counts.info} info):`);
|
|
79
|
+
if (analysis.findings.length === 0)
|
|
80
|
+
lines.push(' (none — every placement check passed)');
|
|
81
|
+
else {
|
|
82
|
+
const shownPerRule = new Map();
|
|
83
|
+
const overflow = new Map();
|
|
84
|
+
for (const f of analysis.findings) {
|
|
85
|
+
const shown = shownPerRule.get(f.rule) ?? 0;
|
|
86
|
+
if (shown < MAX_FINDINGS_PER_RULE) {
|
|
87
|
+
shownPerRule.set(f.rule, shown + 1);
|
|
88
|
+
lines.push(formatFinding(f));
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
overflow.set(f.rule, (overflow.get(f.rule) ?? 0) + 1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const [rule, n] of overflow) {
|
|
95
|
+
lines.push(` … and ${n} more ${rule} finding${n === 1 ? '' : 's'} — the worst ${MAX_FINDINGS_PER_RULE} are shown (severity-sorted); the json output carries the full list`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (report.includes('roster')) {
|
|
100
|
+
lines.push('');
|
|
101
|
+
lines.push('roster (grouped):');
|
|
102
|
+
lines.push(...formatRoster(snapshot));
|
|
103
|
+
}
|
|
104
|
+
if (report.includes('colliders')) {
|
|
105
|
+
lines.push('');
|
|
106
|
+
lines.push('colliders:');
|
|
107
|
+
lines.push(...formatColliders(snapshot));
|
|
108
|
+
}
|
|
109
|
+
if (report.includes('zones')) {
|
|
110
|
+
lines.push('');
|
|
111
|
+
lines.push('zones (from multiplayer.json):');
|
|
112
|
+
if (!zones || zones.length === 0)
|
|
113
|
+
lines.push(' (none declared, or no multiplayer.json beside the bundle)');
|
|
114
|
+
else
|
|
115
|
+
for (const z of zones) {
|
|
116
|
+
lines.push(` ${z.id}: ${z.extent}`);
|
|
117
|
+
lines.push(` rest surfaces: ${z.restSurfaces.length ? z.restSurfaces.slice(0, 6).join(', ') : '(none — mid-air entry only)'}`);
|
|
118
|
+
lines.push(` touches: ${z.touches.length ? z.touches.slice(0, 6).join(', ') : '(no geometry)'}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return lines.join('\n');
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/world/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface WorldMetricsTable {
|
|
2
|
+
capsule: Record<string, number>;
|
|
3
|
+
traversal: Record<string, number>;
|
|
4
|
+
movement: Record<string, number>;
|
|
5
|
+
derived: Record<string, number>;
|
|
6
|
+
}
|
|
7
|
+
/** Null when the installed system predates WORLD_METRICS (< 0.2.13) — callers degrade with a message. */
|
|
8
|
+
export declare function readWorldMetrics(worldDir: string): Promise<WorldMetricsTable | null>;
|
|
9
|
+
export declare function renderWorldMetrics(metrics: WorldMetricsTable): string;
|
|
10
|
+
export declare const METRICS_UNSUPPORTED_MESSAGE: string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.METRICS_UNSUPPORTED_MESSAGE = void 0;
|
|
4
|
+
exports.readWorldMetrics = readWorldMetrics;
|
|
5
|
+
exports.renderWorldMetrics = renderWorldMetrics;
|
|
6
|
+
// Reads WORLD_METRICS from a world's OWN installed humanoid-character system (the readAxisTable
|
|
7
|
+
// pattern) — version-correct per world, so the table always matches the system the world actually
|
|
8
|
+
// runs. CLI-only: the engine tool reads the workspace package directly.
|
|
9
|
+
const node_url_1 = require("node:url");
|
|
10
|
+
const esm_1 = require("../character/esm");
|
|
11
|
+
const worldRuntime_1 = require("../gesture/worldRuntime");
|
|
12
|
+
/** Null when the installed system predates WORLD_METRICS (< 0.2.13) — callers degrade with a message. */
|
|
13
|
+
async function readWorldMetrics(worldDir) {
|
|
14
|
+
const entry = (0, worldRuntime_1.systemEntry)(worldDir);
|
|
15
|
+
const system = await (0, esm_1.importEsm)((0, node_url_1.pathToFileURL)(entry).href);
|
|
16
|
+
const metrics = system.WORLD_METRICS;
|
|
17
|
+
return metrics ?? null;
|
|
18
|
+
}
|
|
19
|
+
function renderWorldMetrics(metrics) {
|
|
20
|
+
const lines = ['world metrics — system DEFAULTS (worlds may override via config):'];
|
|
21
|
+
for (const [group, values] of Object.entries(metrics)) {
|
|
22
|
+
lines.push(` ${group}:`);
|
|
23
|
+
for (const [k, v] of Object.entries(values))
|
|
24
|
+
lines.push(` ${k}: ${v}`);
|
|
25
|
+
}
|
|
26
|
+
return lines.join('\n');
|
|
27
|
+
}
|
|
28
|
+
exports.METRICS_UNSUPPORTED_MESSAGE = 'the installed humanoid-character does not export WORLD_METRICS — it predates the table (added in 0.2.13).\n' +
|
|
29
|
+
' Any existing ^0.2 pin already allows it — rerun the install and rebuild:\n' +
|
|
30
|
+
' MCP: install_world_packages · CLI: helix install (via npx: `npx @hypersoniclabs/helix-cli install` — bare `helix` is an unrelated npm package).';
|
|
31
|
+
//# sourceMappingURL=readWorldMetrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readWorldMetrics.js","sourceRoot":"","sources":["../../src/world/readWorldMetrics.ts"],"names":[],"mappings":";;;AAeA,4CAKC;AAED,gDAOC;AA7BD,gGAAgG;AAChG,kGAAkG;AAClG,wEAAwE;AACxE,uCAAyC;AACzC,0CAA6C;AAC7C,0DAAsD;AAStD,yGAAyG;AAClG,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IACrD,MAAM,KAAK,GAAG,IAAA,0BAAW,EAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,IAAA,eAAS,EAAC,IAAA,wBAAa,EAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,aAA8C,CAAC;IACtE,OAAO,OAAO,IAAI,IAAI,CAAC;AACzB,CAAC;AAED,SAAgB,kBAAkB,CAAC,OAA0B;IAC3D,MAAM,KAAK,GAAa,CAAC,mEAAmE,CAAC,CAAC;IAC9F,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC;QAC1B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAEY,QAAA,2BAA2B,GACtC,6GAA6G;IAC7G,8EAA8E;IAC9E,mJAAmJ,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export interface Vec3 {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
z: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Quat {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
z: number;
|
|
10
|
+
w: number;
|
|
11
|
+
}
|
|
12
|
+
export interface ColliderInfo {
|
|
13
|
+
handle: number;
|
|
14
|
+
/** Lowercased Rapier shape name: 'cuboid', 'trimesh', 'ball', 'capsule', … */
|
|
15
|
+
shape: string;
|
|
16
|
+
halfExtents?: Vec3;
|
|
17
|
+
radius?: number;
|
|
18
|
+
halfHeight?: number;
|
|
19
|
+
position: Vec3;
|
|
20
|
+
rotation: Quat;
|
|
21
|
+
}
|
|
22
|
+
export interface SnapshotObject {
|
|
23
|
+
path: string;
|
|
24
|
+
type: string;
|
|
25
|
+
geometry: string | null;
|
|
26
|
+
position: Vec3;
|
|
27
|
+
rotation: Quat;
|
|
28
|
+
scale: Vec3;
|
|
29
|
+
aabb: {
|
|
30
|
+
min: Vec3;
|
|
31
|
+
max: Vec3;
|
|
32
|
+
} | null;
|
|
33
|
+
obb: {
|
|
34
|
+
center: Vec3;
|
|
35
|
+
half: Vec3;
|
|
36
|
+
} | null;
|
|
37
|
+
visible: boolean;
|
|
38
|
+
triangles: number;
|
|
39
|
+
color: string | null;
|
|
40
|
+
nonFinite?: true;
|
|
41
|
+
}
|
|
42
|
+
export type ColliderSource = 'ok' | 'unsupported' | 'absent';
|
|
43
|
+
export interface WorldSnapshot {
|
|
44
|
+
snapshotVersion: 1;
|
|
45
|
+
spawn: Vec3 | null;
|
|
46
|
+
objects: SnapshotObject[];
|
|
47
|
+
colliders: ColliderInfo[];
|
|
48
|
+
sources: {
|
|
49
|
+
scene: true;
|
|
50
|
+
colliders: ColliderSource;
|
|
51
|
+
};
|
|
52
|
+
truncated?: {
|
|
53
|
+
emitted: number;
|
|
54
|
+
total: number;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export interface SnapshotOptions {
|
|
58
|
+
maxObjects?: number;
|
|
59
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// The world-snapshot contract — the JSON a world's in-page inspect helper serializes.
|
|
3
|
+
// PORTED from helix-web-engine-new/systems/engine-core/src/inspect/WorldInspect.ts (the type
|
|
4
|
+
// declarations only) — the source of truth for the snapshot contract. SYNC OBLIGATION: change the
|
|
5
|
+
// shape there first (it is what worlds actually emit, versioned via snapshotVersion), then mirror
|
|
6
|
+
// here; do not diverge.
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
//# sourceMappingURL=snapshotTypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshotTypes.js","sourceRoot":"","sources":["../../src/world/snapshotTypes.ts"],"names":[],"mappings":";AAAA,sFAAsF;AACtF,6FAA6F;AAC7F,kGAAkG;AAClG,kGAAkG;AAClG,wBAAwB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type BrowserKey, type HelperTimeoutState } from '../browser/launch';
|
|
2
|
+
import type { WorldSnapshot } from './snapshotTypes';
|
|
3
|
+
export declare function composeInspectTimeoutDiagnosis(state: HelperTimeoutState, errors: string[]): string;
|
|
4
|
+
export type SnapshotWorldOptions = {
|
|
5
|
+
directory: string;
|
|
6
|
+
timeoutMs?: number | undefined;
|
|
7
|
+
/** Frames/assets settle time between helper-ready and the snapshot — determinism lever. */
|
|
8
|
+
settleMs?: number | undefined;
|
|
9
|
+
maxObjects?: number | undefined;
|
|
10
|
+
/** Diagnostic override: launch only this candidate, no fallback (default: try the whole chain). */
|
|
11
|
+
browser?: BrowserKey | undefined;
|
|
12
|
+
/** URL-prefix → dir fallbacks (e.g. a shared character-asset tree at /assets, /basis). */
|
|
13
|
+
fallbackMounts?: Record<string, string> | undefined;
|
|
14
|
+
onProgress?: ((message: string) => void) | undefined;
|
|
15
|
+
};
|
|
16
|
+
export declare function snapshotWorld(opts: SnapshotWorldOptions): Promise<WorldSnapshot>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.composeInspectTimeoutDiagnosis = composeInspectTimeoutDiagnosis;
|
|
37
|
+
exports.snapshotWorld = snapshotWorld;
|
|
38
|
+
// Headless snapshot transport for `helix world inspect`: serves the built bundle, drives the
|
|
39
|
+
// in-page inspect helper (window.__helixInspect) via Playwright, and returns the serialized
|
|
40
|
+
// WorldSnapshot. The helper ships in @helix/engine-core/inspect — this module only speaks its
|
|
41
|
+
// window protocol and never imports the engine.
|
|
42
|
+
// PORTED from helix-web-engine-new/tools/world-inspect/src/snapshotWorld.ts, rewired to the CLI's
|
|
43
|
+
// shared browser harness (full playwright with the bundled-Chromium candidate — the engine tool
|
|
44
|
+
// deliberately runs playwright-core with system channels only). The analysis mirror is strict;
|
|
45
|
+
// this transport divergence is expected and documented on both sides.
|
|
46
|
+
const node_fs_1 = require("node:fs");
|
|
47
|
+
const node_path_1 = require("node:path");
|
|
48
|
+
const launch_1 = require("../browser/launch");
|
|
49
|
+
const staticServe_1 = require("../screenshot/staticServe");
|
|
50
|
+
const MAX_DIAGNOSTIC_LINES = 6;
|
|
51
|
+
const DIAGNOSTIC_LINE_MAX_CHARS = 300;
|
|
52
|
+
const DEFAULT_SETTLE_MS = 750;
|
|
53
|
+
function composeInspectTimeoutDiagnosis(state, errors) {
|
|
54
|
+
return (0, launch_1.composeTimeoutDiagnosisWith)(state, errors, {
|
|
55
|
+
absent: 'This world does not integrate @helix/engine-core/inspect — add the "engine-core" system pin to helix.json ' +
|
|
56
|
+
"alongside humanoid-character, run helix install, wire world.ready({ scene, body, spawn }) at the end of " +
|
|
57
|
+
'boot (see the MCP world-inspect doc), and rebuild.',
|
|
58
|
+
present: 'The world loaded the inspect helper but its boot never completed — this looks like a load/boot failure, ' +
|
|
59
|
+
'not a missing integration. Check that the world runs standalone (missing character assets are the common cause).',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async function snapshotWorld(opts) {
|
|
63
|
+
const onProgress = opts.onProgress ?? (() => undefined);
|
|
64
|
+
const timeoutMs = opts.timeoutMs ?? 60000;
|
|
65
|
+
const settleMs = opts.settleMs ?? DEFAULT_SETTLE_MS;
|
|
66
|
+
if (!(0, node_fs_1.existsSync)((0, node_path_1.join)(opts.directory, 'index.html'))) {
|
|
67
|
+
throw new Error(`${opts.directory} is not a built world dir (no index.html) — point at the bundle build output (usually <world>/dist).`);
|
|
68
|
+
}
|
|
69
|
+
const playwright = await Promise.resolve().then(() => __importStar(require('playwright')));
|
|
70
|
+
const server = await (0, staticServe_1.startStaticServer)(opts.directory, opts.fallbackMounts ?? {});
|
|
71
|
+
let browser;
|
|
72
|
+
try {
|
|
73
|
+
const attempts = [];
|
|
74
|
+
for (const candidate of (0, launch_1.selectBrowserCandidates)(opts.browser)) {
|
|
75
|
+
try {
|
|
76
|
+
browser = await playwright.chromium.launch(candidate.launchOptions);
|
|
77
|
+
onProgress(`using ${candidate.label}`);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
attempts.push({ key: candidate.key, label: candidate.label, message: err instanceof Error ? err.message : String(err) });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!browser)
|
|
85
|
+
throw new Error((0, launch_1.composeLaunchFailure)(attempts));
|
|
86
|
+
const page = await browser.newPage({ viewport: { width: 1280, height: 720 }, deviceScaleFactor: 1 });
|
|
87
|
+
// Ring buffer of the last few load-time page errors — surfaced in the timeout diagnosis below.
|
|
88
|
+
const pageErrors = [];
|
|
89
|
+
const recordPageError = (line) => {
|
|
90
|
+
const truncated = line.length > DIAGNOSTIC_LINE_MAX_CHARS ? `${line.slice(0, DIAGNOSTIC_LINE_MAX_CHARS)}…` : line;
|
|
91
|
+
pageErrors.push(truncated);
|
|
92
|
+
if (pageErrors.length > MAX_DIAGNOSTIC_LINES)
|
|
93
|
+
pageErrors.shift();
|
|
94
|
+
};
|
|
95
|
+
page.on('pageerror', (err) => recordPageError(err.message));
|
|
96
|
+
page.on('console', (msg) => {
|
|
97
|
+
if (msg.type() === 'error')
|
|
98
|
+
recordPageError(msg.text());
|
|
99
|
+
});
|
|
100
|
+
await page.goto(`http://127.0.0.1:${server.port}/?helixInspect=1`);
|
|
101
|
+
try {
|
|
102
|
+
await page.waitForFunction('window.__helixInspect?.ready === true', undefined, { timeout: timeoutMs });
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
const helperState = await page.evaluate(() => typeof window.__helixInspect === 'undefined' ? 'absent' : 'present');
|
|
106
|
+
throw new Error(`Timed out after ${timeoutMs}ms waiting for the inspect helper (window.__helixInspect) to become ready. ` +
|
|
107
|
+
composeInspectTimeoutDiagnosis(helperState, pageErrors));
|
|
108
|
+
}
|
|
109
|
+
if (settleMs > 0)
|
|
110
|
+
await page.waitForTimeout(settleMs);
|
|
111
|
+
onProgress(`helper ready — snapshotting after ${settleMs}ms settle`);
|
|
112
|
+
const snapshot = await page.evaluate(({ maxObjects }) => window.__helixInspect.snapshot(maxObjects !== undefined ? { maxObjects } : undefined), { maxObjects: opts.maxObjects });
|
|
113
|
+
return snapshot;
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await browser?.close();
|
|
117
|
+
await server.close();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=snapshotWorld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshotWorld.js","sourceRoot":"","sources":["../../src/world/snapshotWorld.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { WorldSnapshot } from './snapshotTypes';
|
|
2
|
+
import { type Finding } from './analyze';
|
|
3
|
+
export interface ZoneConfig {
|
|
4
|
+
id: string;
|
|
5
|
+
shape: 'box' | 'sphere';
|
|
6
|
+
center: [number, number, number];
|
|
7
|
+
size?: [number, number, number];
|
|
8
|
+
radius?: number;
|
|
9
|
+
tracks?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ZoneReport {
|
|
12
|
+
id: string;
|
|
13
|
+
extent: string;
|
|
14
|
+
/** Paths of objects whose AABB intersects the zone volume. */
|
|
15
|
+
touches: string[];
|
|
16
|
+
/** Surfaces a standing player could rest on while inside the zone. */
|
|
17
|
+
restSurfaces: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface ZoneAnalysis {
|
|
20
|
+
findings: Finding[];
|
|
21
|
+
report: ZoneReport[];
|
|
22
|
+
}
|
|
23
|
+
export declare function analyzeZones(zones: ZoneConfig[], snapshot: WorldSnapshot): ZoneAnalysis;
|