@helix3/helix-cli 0.1.13-helix3.76 → 0.1.13-helix3.78

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helix3/helix-cli",
3
- "version": "0.1.13-helix3.76",
3
+ "version": "0.1.13-helix3.78",
4
4
  "description": "helix — the HELIX creator CLI: scaffold, validate, and publish Instant Worlds",
5
5
  "main": "dist/lib.js",
6
6
  "types": "dist/lib.d.ts",
@@ -37,6 +37,7 @@ const has = (n) => argv.includes(`--${n}`);
37
37
  const SRC = arg('src', 'src');
38
38
  const DIST = arg('dist', 'dist');
39
39
  const MANIFEST = arg('manifest', 'public/helix.json');
40
+ const CONTROLS = arg('controls', 'public/helix.controls.json');
40
41
  const CONSOLE_LOG = arg('console');
41
42
  const PERF_JSON = arg('perf');
42
43
  const GENRE = arg('genre', 'none');
@@ -408,11 +409,11 @@ if (required === undefined) {
408
409
  );
409
410
  }
410
411
 
411
- // ── 6. mobile — supportsMobile is a claim about controls that must exist ────────────
412
- // humanoid-character carries a `touch` widget hint on every standard action, but its own source
413
- // marks the touch HUD "pre-HUD v1" — NOTHING renders those hints. A world that declares
414
- // supportsMobile and wires no virtual input ships a phone build where the player can look but
415
- // cannot move or jump, and the catalog repeats the claim.
412
+ // ── 6. mobile — supportsMobile is a claim backed by a durable controls contract ─────
413
+ // The contract file is copied into dist by ordinary Vite builds and the platform default exposes
414
+ // the same version marker on its generated DOM. That is a much stronger seam than guessing from a
415
+ // setVirtual* source regex, while still allowing an equivalent custom controller. Static validation
416
+ // cannot prove touch effects, so G6/G7 must still exercise the built world at a phone viewport.
416
417
  let manifest = null;
417
418
  if (existsSync(MANIFEST)) {
418
419
  try { manifest = JSON.parse(readFileSync(MANIFEST, 'utf8')); }
@@ -420,19 +421,37 @@ if (existsSync(MANIFEST)) {
420
421
  } else {
421
422
  warn('manifest.absent', `${MANIFEST} not found — the supportsMobile / touch-control gate measured NOTHING`);
422
423
  }
423
- const virtualInput = /\.setVirtualVec2\s*\(|\.setVirtualButton\s*\(/.test(allText);
424
+ let controls = null;
425
+ if (existsSync(CONTROLS)) {
426
+ try { controls = JSON.parse(readFileSync(CONTROLS, 'utf8')); }
427
+ catch (err) { fail('mobile.controls-unparseable', `${CONTROLS}: ${err.message}`); }
428
+ }
429
+ const requiredMobileCapabilities = ['move', 'look', 'zoom', 'jump'];
430
+ function validControlsContract(value) {
431
+ return value?.version === 1 &&
432
+ (value.provider === '@helix/humanoid-character' || value.provider === 'custom') &&
433
+ Array.isArray(value.capabilities) &&
434
+ requiredMobileCapabilities.every((capability) => value.capabilities.includes(capability));
435
+ }
424
436
  if (manifest) {
425
437
  if (manifest.supportsMobile === true) {
426
- if (!virtualInput) {
438
+ if (!validControlsContract(controls)) {
427
439
  fail(
428
440
  'mobile.no-touch-controls',
429
- `${MANIFEST} declares supportsMobile: true but the source never calls input.setVirtualVec2 / input.setVirtualButton. The platform renders NO touch HUD from the action \`touch\` hints (pre-HUD v1), so a phone player can look but cannot move or jump. Implement on-screen controls against the virtual-input API and verify them at a phone viewport, or set supportsMobile: false.`,
441
+ `${MANIFEST} declares supportsMobile: true but ${CONTROLS} does not declare the v1 move/look/zoom/jump contract. Mount createMobileControls(input, { surface }) or provide an equivalent custom controller, ship the contract file, and verify it at a phone viewport.`,
430
442
  );
431
443
  } else {
432
- info('mobile.touch-controls', 'supportsMobile: true and virtual input (setVirtualVec2/setVirtualButton) is wired — G6/G7 must still prove it drives the character at a phone viewport');
444
+ const builtContract = join(DIST, basename(CONTROLS));
445
+ if (!existsSync(builtContract)) {
446
+ fail('mobile.controls-not-shipped', `${CONTROLS} is valid but ${builtContract} is absent — the published bundle cannot prove which touch system it carries`);
447
+ } else if (controls.provider === '@helix/humanoid-character' && !/\bcreateMobileControls\s*\(/.test(allText)) {
448
+ fail('mobile.default-not-mounted', `${CONTROLS} claims the platform provider but source never mounts createMobileControls(input, { surface }). Use provider: "custom" only for a real equivalent implementation.`);
449
+ } else {
450
+ info('mobile.controls-contract', `supportsMobile: true · ${controls.provider} · ${controls.capabilities.join('/')} · contract shipped in ${builtContract}. G6/G7 must still prove touch effects at phone viewports.`);
451
+ }
433
452
  }
434
453
  } else {
435
- info('mobile.declared', `supportsMobile: ${manifest.supportsMobile ?? '(unset)'}${virtualInput ? ' — touch controls ARE wired; declare true once you have verified them on a phone viewport' : ''}`);
454
+ info('mobile.declared', `supportsMobile: ${manifest.supportsMobile ?? '(unset)'}${validControlsContract(controls) ? ' — a valid touch contract is present; declare true once phone QA passes' : ''}`);
436
455
  }
437
456
  }
438
457