@helix3/helix-cli 0.1.18-helix3.312 → 0.1.18-helix3.314
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/README.md +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +161 -0
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/visualQa/browser.d.ts +39 -0
- package/dist/visualQa/browser.js +328 -0
- package/dist/visualQa/browser.js.map +1 -0
- package/dist/visualQa/checklists.d.ts +4 -0
- package/dist/visualQa/checklists.js +59 -0
- package/dist/visualQa/checklists.js.map +1 -0
- package/dist/visualQa/command.d.ts +57 -0
- package/dist/visualQa/command.js +248 -0
- package/dist/visualQa/command.js.map +1 -0
- package/dist/visualQa/commonAsserts.d.ts +44 -0
- package/dist/visualQa/commonAsserts.js +186 -0
- package/dist/visualQa/commonAsserts.js.map +1 -0
- package/dist/visualQa/contactSheet.d.ts +14 -0
- package/dist/visualQa/contactSheet.js +67 -0
- package/dist/visualQa/contactSheet.js.map +1 -0
- package/dist/visualQa/critic.d.ts +13 -0
- package/dist/visualQa/critic.js +135 -0
- package/dist/visualQa/critic.js.map +1 -0
- package/dist/visualQa/harness.d.ts +35 -0
- package/dist/visualQa/harness.js +3 -0
- package/dist/visualQa/harness.js.map +1 -0
- package/dist/visualQa/hosted.d.ts +128 -0
- package/dist/visualQa/hosted.js +302 -0
- package/dist/visualQa/hosted.js.map +1 -0
- package/dist/visualQa/resolve.d.ts +41 -0
- package/dist/visualQa/resolve.js +97 -0
- package/dist/visualQa/resolve.js.map +1 -0
- package/dist/visualQa/types.d.ts +96 -0
- package/dist/visualQa/types.js +12 -0
- package/dist/visualQa/types.js.map +1 -0
- package/dist/visualQa/vehicle.d.ts +64 -0
- package/dist/visualQa/vehicle.js +808 -0
- package/dist/visualQa/vehicle.js.map +1 -0
- package/dist/visualQa/vehicleMath.d.ts +281 -0
- package/dist/visualQa/vehicleMath.js +592 -0
- package/dist/visualQa/vehicleMath.js.map +1 -0
- package/dist/visualQa/vehicleProbe.d.ts +3 -0
- package/dist/visualQa/vehicleProbe.js +289 -0
- package/dist/visualQa/vehicleProbe.js.map +1 -0
- package/dist/visualQa/viewer.d.ts +2 -0
- package/dist/visualQa/viewer.js +639 -0
- package/dist/visualQa/viewer.js.map +1 -0
- package/dist/visualQa/viewerGeometry.d.ts +114 -0
- package/dist/visualQa/viewerGeometry.js +473 -0
- package/dist/visualQa/viewerGeometry.js.map +1 -0
- package/dist/visualQa/viewerPage.d.ts +11 -0
- package/dist/visualQa/viewerPage.js +345 -0
- package/dist/visualQa/viewerPage.js.map +1 -0
- package/dist/visualQa/winChrome.d.ts +23 -0
- package/dist/visualQa/winChrome.js +221 -0
- package/dist/visualQa/winChrome.js.map +1 -0
- package/package.json +3 -2
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_abs.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_expression.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_jbeam.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_materials.cpython-312.pyc +0 -0
package/README.md
CHANGED
|
@@ -48,6 +48,7 @@ The token is stored in `~/.helix/credentials.json` (mode `600`). It's sent as
|
|
|
48
48
|
| `helix item list-slots [--json]` | Print the Character-Creator vocabulary a wearable declares: the cosmetic slot tags, and the genders. |
|
|
49
49
|
| `helix item publish <mesh.glb> --title <t> [--collectible-supply <n>] [initial distribution flags] [--dry-run\|--quote]` | Publish a Standard item by default, or one fixed-supply Collectible. The item definition is separate from acquisition routes. |
|
|
50
50
|
| `helix item distribution create\|list\|update\|disable …` | Manage Marketplace/World Claim or Buy routes without republishing the item or paying another publish fee. |
|
|
51
|
+
| `helix item visual-qa <item-id> [--submit] [--local-critic] [--storage-state <file>] [--host <id…>]` | Render the item's current package version headless in the real runtime (test-grounds world for vehicles, the customiser for add-ons and wearables on every declared host/base, the item viewer for props), measure it, and with `--submit` record the backend's verdict (numeric asserts + vision critic) against that exact version. **Marketplace/Vault listing, distributions and version moves on a public item require a pass.** See [docs/visual-qa.md](docs/visual-qa.md). |
|
|
51
52
|
| `helix device create <dir> --id <slug> --title <t> --model <mesh.glb> --template standing-desk\|clock\|television` | Scaffold a GLB-backed `helix.device/1` definition, including the interactive TV/media-player template. There is intentionally no website Device editor. |
|
|
52
53
|
| `helix device validate [dir] [--json]` | Validate the definition, GLB bytes and named-node bindings, typed state/controls, capabilities, and Home+World compatibility, including [declarative character hand reach](docs/device-hand-reach.md). |
|
|
53
54
|
| `helix device test [dir] [--mode single\|multiplayer\|both] [--json]` | Exercise every interaction, persistence remount, and deterministic one-/two-client authority convergence. |
|
package/dist/config.d.ts
CHANGED
|
@@ -15,6 +15,9 @@ export declare function resolveEnvironment(scope: string, override?: {
|
|
|
15
15
|
apiUrl: string;
|
|
16
16
|
webUrl: string;
|
|
17
17
|
};
|
|
18
|
+
/** The website that belongs to an API origin, when it is one of ours (visual QA renders on the site that serves the
|
|
19
|
+
* API the item lives on, not on this build's default site). */
|
|
20
|
+
export declare function webUrlForApi(apiUrl: string): string | null;
|
|
18
21
|
export declare const HELIX_SCOPE: string;
|
|
19
22
|
export declare const HELIX_ENV: HelixEnvName;
|
|
20
23
|
export declare const DEFAULT_API_URL: string;
|
package/dist/config.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DEFAULT_WEB_URL = exports.DEFAULT_API_URL = exports.HELIX_ENV = exports.HELIX_SCOPE = exports.CONFIG_DIR = void 0;
|
|
4
4
|
exports.resolveEnvironment = resolveEnvironment;
|
|
5
|
+
exports.webUrlForApi = webUrlForApi;
|
|
5
6
|
exports.apiUrlMatchesEnv = apiUrlMatchesEnv;
|
|
6
7
|
exports.credsEnvMismatchWarning = credsEnvMismatchWarning;
|
|
7
8
|
exports.saveCredentials = saveCredentials;
|
|
@@ -68,6 +69,16 @@ const RESOLVED = resolveEnvironment(ownScope(), {
|
|
|
68
69
|
apiUrl: process.env.HELIX_API_URL,
|
|
69
70
|
webUrl: process.env.HELIX_WEB_URL,
|
|
70
71
|
});
|
|
72
|
+
/** The website that belongs to an API origin, when it is one of ours (visual QA renders on the site that serves the
|
|
73
|
+
* API the item lives on, not on this build's default site). */
|
|
74
|
+
function webUrlForApi(apiUrl) {
|
|
75
|
+
const n = normalizeApiUrlForEnv(apiUrl);
|
|
76
|
+
for (const env of Object.values(ENVIRONMENTS))
|
|
77
|
+
if (normalizeApiUrlForEnv(env.apiUrl) === n)
|
|
78
|
+
return env.webUrl;
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const normalizeApiUrlForEnv = (url) => url.trim().replace(/\/+$/, '').toLowerCase();
|
|
71
82
|
exports.HELIX_SCOPE = RESOLVED.scope;
|
|
72
83
|
exports.HELIX_ENV = RESOLVED.env;
|
|
73
84
|
exports.DEFAULT_API_URL = RESOLVED.apiUrl;
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AAoDA,gDAsBC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1686,6 +1686,167 @@ item
|
|
|
1686
1686
|
// Distinct from `item distribution disable` below: a distribution is ONE
|
|
1687
1687
|
// acquisition route (you can have several); delist takes the whole item
|
|
1688
1688
|
// definition off browse/marketplace regardless of how many routes it has.
|
|
1689
|
+
// Visual QA: the publish/listing gate judges an item RENDERED, in the real runtime, not its numbers. This command is
|
|
1690
|
+
// the harness: it renders the item's current package version headless (test-grounds world for vehicles, the
|
|
1691
|
+
// customiser for add-ons and wearables, the item viewer for props), measures it, and with --submit hands it to the
|
|
1692
|
+
// backend, which runs the vision critic, records the verdict against that exact version and serves a contact sheet.
|
|
1693
|
+
item
|
|
1694
|
+
.command('visual-qa')
|
|
1695
|
+
.description('Render an item headless in the real HELIX runtime, measure it, and (with --submit) record the visual-QA verdict that Marketplace/Vault listing requires. --hosted asks the platform to render it on a GPU runner instead')
|
|
1696
|
+
.argument('[item-id]', 'universal item UUID (its CURRENT package version is rendered); omit with --hosted-worker')
|
|
1697
|
+
.option('--submit', 'submit frames + measurements to the backend, which judges and records the verdict (needs `helix login`)')
|
|
1698
|
+
.option('--hosted', 'queue a hosted render on the platform GPU runner and wait for the verdict (needs `helix login`; exit 0 pass, 1 fail, 2 error)')
|
|
1699
|
+
.option('--retry', 'with --hosted: re-queue after a failed/errored hosted run of this version')
|
|
1700
|
+
.option('--no-wait', 'with --hosted: queue the render and return without waiting')
|
|
1701
|
+
.option('--timeout <minutes>', 'with --hosted: how long to wait for the verdict', '30')
|
|
1702
|
+
.option('--status', 'read-only: show the hosted visual-QA state and recorded result for the item (no login needed)')
|
|
1703
|
+
.option('--hosted-worker', 'runner mode: claim hosted render jobs, render, submit (HELIX_VQA_BOT_EMAIL / HELIX_VQA_BOT_PASSWORD)')
|
|
1704
|
+
.option('--max-jobs <n>', 'with --hosted-worker: stop after n jobs')
|
|
1705
|
+
.option('--max-minutes <n>', 'with --hosted-worker: stop claiming new jobs after n minutes')
|
|
1706
|
+
.option('--idle-exit-minutes <n>', 'with --hosted-worker: keep polling an empty queue this long before exiting', '0')
|
|
1707
|
+
.option('--poll-seconds <n>', 'with --hosted-worker: queue polling interval', '10')
|
|
1708
|
+
.option('--render-timeout <seconds>', 'with --hosted-worker: hard limit per render', '900')
|
|
1709
|
+
.option('--worker <name>', 'with --hosted-worker: runner identity recorded on the job')
|
|
1710
|
+
.option('--local-critic', 'also run the vision critic locally (needs ANTHROPIC_API_KEY or OPENROUTER_API_KEY)')
|
|
1711
|
+
.option('--out <dir>', 'bundle directory (frames, bundle.json, contact-sheet.jpg)')
|
|
1712
|
+
.option('--storage-state <file>', 'Playwright storageState of a signed-in QA account (Try Now and the customiser need one); default $HELIX_VQA_STORAGE_STATE')
|
|
1713
|
+
.option('--host <id...>', 'only fit onto these host/base item ids (add-ons, wearables)')
|
|
1714
|
+
.option('--chrome <path>', 'Chrome/Chromium executable (default: system Chrome, headless)')
|
|
1715
|
+
.option('--api-url <url>', 'platform API base URL')
|
|
1716
|
+
.option('--web-url <url>', 'website base URL (default: the site that serves --api-url)')
|
|
1717
|
+
.option('--json', 'print the outcome as JSON')
|
|
1718
|
+
.action(async (id, opts) => {
|
|
1719
|
+
try {
|
|
1720
|
+
const creds = opts.submit || opts.hosted ? requireAuth() : (0, config_1.loadCredentials)();
|
|
1721
|
+
const apiBase = opts.apiUrl ?? creds?.apiUrl ?? config_1.DEFAULT_API_URL;
|
|
1722
|
+
const webBase = opts.webUrl ?? process.env.HELIX_WEB_URL ?? (0, config_1.webUrlForApi)(apiBase) ?? config_1.DEFAULT_WEB_URL;
|
|
1723
|
+
if (opts.hostedWorker) {
|
|
1724
|
+
const email = process.env.HELIX_VQA_BOT_EMAIL;
|
|
1725
|
+
const password = process.env.HELIX_VQA_BOT_PASSWORD;
|
|
1726
|
+
if (!email || !password)
|
|
1727
|
+
fail('✖ --hosted-worker needs HELIX_VQA_BOT_EMAIL and HELIX_VQA_BOT_PASSWORD in the environment');
|
|
1728
|
+
const { runHostedWorker } = await Promise.resolve().then(() => __importStar(require('./visualQa/hosted')));
|
|
1729
|
+
const workerApi = opts.apiUrl ?? process.env.HELIX_API_URL ?? config_1.DEFAULT_API_URL; // never a stored login: the runner is its own account
|
|
1730
|
+
const summary = await runHostedWorker({
|
|
1731
|
+
apiBase: workerApi,
|
|
1732
|
+
webBase: opts.webUrl ?? process.env.HELIX_WEB_URL ?? (0, config_1.webUrlForApi)(workerApi) ?? config_1.DEFAULT_WEB_URL,
|
|
1733
|
+
email,
|
|
1734
|
+
password,
|
|
1735
|
+
worker: opts.worker ?? process.env.HELIX_VQA_WORKER,
|
|
1736
|
+
maxJobs: opts.maxJobs ? Number(opts.maxJobs) : undefined,
|
|
1737
|
+
maxMinutes: opts.maxMinutes ? Number(opts.maxMinutes) : undefined,
|
|
1738
|
+
idleExitMinutes: Number(opts.idleExitMinutes ?? 0),
|
|
1739
|
+
pollSeconds: Number(opts.pollSeconds ?? 10),
|
|
1740
|
+
renderTimeoutSeconds: Number(opts.renderTimeout ?? 900),
|
|
1741
|
+
out: opts.out,
|
|
1742
|
+
chrome: opts.chrome,
|
|
1743
|
+
cliVersion: (0, lib_1.cliVersion)(),
|
|
1744
|
+
});
|
|
1745
|
+
if (opts.json)
|
|
1746
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
1747
|
+
else
|
|
1748
|
+
console.log(`hosted worker done (${summary.exit}): ${summary.jobs.length} job(s)${summary.jobs.map((j) => `\n ${j.jobId} ${j.outcome}${j.verdict ? ` ${j.verdict}` : ''}${j.error ? ` — ${j.error.slice(0, 120)}` : ''}`).join('')}`);
|
|
1749
|
+
return; // a failing item or a reported harness error is the queue's business; the runner itself succeeded
|
|
1750
|
+
}
|
|
1751
|
+
if (!id)
|
|
1752
|
+
fail('✖ visual-qa needs an <item-id> (omit it only with --hosted-worker)');
|
|
1753
|
+
if (opts.status || opts.hosted) {
|
|
1754
|
+
const hosted = await Promise.resolve().then(() => __importStar(require('./visualQa/hosted')));
|
|
1755
|
+
if (opts.status) {
|
|
1756
|
+
const st = await hosted.getItemVisualQaStatus(apiBase, id);
|
|
1757
|
+
const job = st.hostedJob;
|
|
1758
|
+
if (opts.json)
|
|
1759
|
+
console.log(JSON.stringify(st, null, 2));
|
|
1760
|
+
else {
|
|
1761
|
+
console.log(`hosted job: ${hosted.describeJob(job)}`);
|
|
1762
|
+
if (job?.contactSheetUrl)
|
|
1763
|
+
console.log(` contact sheet: ${job.contactSheetUrl}`);
|
|
1764
|
+
for (const r of job?.reasons ?? [])
|
|
1765
|
+
console.log(` - ${r}`);
|
|
1766
|
+
if (job?.error)
|
|
1767
|
+
console.log(` error: ${job.error}`);
|
|
1768
|
+
console.log(`current version: ${st.currentVersion ? (st.currentVersion.passed ? 'PASSED' : 'no passing run') : 'not pinned to a package version'}`);
|
|
1769
|
+
}
|
|
1770
|
+
process.exitCode = job && hosted.isTerminal(job.status) ? hosted.exitCodeForJob(job) : 0;
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
const token = creds?.token;
|
|
1774
|
+
const req = await hosted.requestHostedRun(apiBase, token, id, !!opts.retry);
|
|
1775
|
+
if (!opts.json) {
|
|
1776
|
+
if (req.alreadyPassed)
|
|
1777
|
+
console.log('✔ this version already has a passing visual-QA run');
|
|
1778
|
+
else if (req.exempt)
|
|
1779
|
+
console.log('✔ exempt: this item has nothing to render');
|
|
1780
|
+
else if (!req.job)
|
|
1781
|
+
console.log(`✖ nothing queued${req.skipped ? ` (${req.skipped})` : ''}${req.message ? `: ${req.message}` : ''}`);
|
|
1782
|
+
else
|
|
1783
|
+
console.log(`hosted render: ${hosted.describeJob(req.job)}`);
|
|
1784
|
+
}
|
|
1785
|
+
let job = req.job;
|
|
1786
|
+
let timedOut = false;
|
|
1787
|
+
if (job && !hosted.isTerminal(job.status) && opts.wait !== false) {
|
|
1788
|
+
const waited = await hosted.waitForHostedJob(apiBase, id, job.id, {
|
|
1789
|
+
timeoutMs: Number(opts.timeout ?? 30) * 60_000,
|
|
1790
|
+
onUpdate: (j) => { if (!opts.json)
|
|
1791
|
+
console.log(` ${hosted.describeJob(j)}`); },
|
|
1792
|
+
});
|
|
1793
|
+
job = waited.job;
|
|
1794
|
+
timedOut = waited.timedOut;
|
|
1795
|
+
}
|
|
1796
|
+
if (opts.json)
|
|
1797
|
+
console.log(JSON.stringify({ ...req, job, timedOut }, null, 2));
|
|
1798
|
+
else if (job && hosted.isTerminal(job.status)) {
|
|
1799
|
+
console.log(`${job.status === 'passed' ? '✔' : '✖'} visual QA ${job.status.toUpperCase()}`);
|
|
1800
|
+
for (const r of job.reasons)
|
|
1801
|
+
console.log(` - ${r}`);
|
|
1802
|
+
if (job.error)
|
|
1803
|
+
console.log(` error: ${job.error}`);
|
|
1804
|
+
if (job.contactSheetUrl)
|
|
1805
|
+
console.log(` contact sheet: ${job.contactSheetUrl}`);
|
|
1806
|
+
}
|
|
1807
|
+
else if (timedOut)
|
|
1808
|
+
console.log(`… still ${job?.status ?? 'queued'} after ${opts.timeout ?? 30} min; check later with: helix item visual-qa ${id} --status`);
|
|
1809
|
+
else if (job)
|
|
1810
|
+
console.log(` check later with: helix item visual-qa ${id} --status`);
|
|
1811
|
+
process.exitCode = req.alreadyPassed || req.exempt ? 0 : job && !hosted.isTerminal(job.status) && opts.wait === false ? 0 : hosted.exitCodeForJob(job, timedOut);
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
const { runVisualQa } = await Promise.resolve().then(() => __importStar(require('./visualQa/command')));
|
|
1815
|
+
const outcome = await runVisualQa(id, {
|
|
1816
|
+
apiBase,
|
|
1817
|
+
webBase,
|
|
1818
|
+
token: creds?.token ?? null,
|
|
1819
|
+
out: opts.out,
|
|
1820
|
+
storageState: opts.storageState ?? process.env.HELIX_VQA_STORAGE_STATE,
|
|
1821
|
+
hostIds: opts.host,
|
|
1822
|
+
chrome: opts.chrome,
|
|
1823
|
+
submit: opts.submit,
|
|
1824
|
+
localCritic: opts.localCritic,
|
|
1825
|
+
cliVersion: (0, lib_1.cliVersion)(),
|
|
1826
|
+
quiet: opts.json,
|
|
1827
|
+
});
|
|
1828
|
+
if (opts.json) {
|
|
1829
|
+
console.log(JSON.stringify({ verdict: outcome.verdict, reasons: outcome.reasons, bundleDir: outcome.bundleDir, contactSheet: outcome.contactSheet, server: outcome.server, critic: outcome.critic, timings: outcome.timings }, null, 2));
|
|
1830
|
+
}
|
|
1831
|
+
else {
|
|
1832
|
+
const mark = outcome.verdict === 'pass' ? '✔' : '✖';
|
|
1833
|
+
console.log(`${mark} visual QA ${outcome.verdict.toUpperCase()} — ${outcome.bundle.item.title} (${outcome.bundle.item.category}, package ${outcome.bundle.item.packageVersion ?? '?'})`);
|
|
1834
|
+
for (const r of outcome.reasons)
|
|
1835
|
+
console.log(` - ${r}`);
|
|
1836
|
+
if (outcome.contactSheet)
|
|
1837
|
+
console.log(` contact sheet: ${outcome.contactSheet}`);
|
|
1838
|
+
if (outcome.server?.contactSheetUrl)
|
|
1839
|
+
console.log(` recorded: ${outcome.server.contactSheetUrl}`);
|
|
1840
|
+
if (!opts.submit)
|
|
1841
|
+
console.log(' (local run only — add --submit to record the verdict the listing gate checks)');
|
|
1842
|
+
console.log(` ${(outcome.timings.totalMs / 1000).toFixed(1)} s (render ${(outcome.timings.renderMs / 1000).toFixed(1)} s)`);
|
|
1843
|
+
}
|
|
1844
|
+
process.exitCode = outcome.verdict === 'pass' ? 0 : outcome.verdict === 'fail' ? 1 : 2;
|
|
1845
|
+
}
|
|
1846
|
+
catch (error) {
|
|
1847
|
+
fail(error instanceof lib_1.ApiError ? error.render() : String(error?.message ?? error));
|
|
1848
|
+
}
|
|
1849
|
+
});
|
|
1689
1850
|
item
|
|
1690
1851
|
.command('delist')
|
|
1691
1852
|
.description('Unlist a published item you own — existing owners keep what they own, nobody new can acquire it. Not a delete (see `helix item publish` for why delete refuses an owned item), and not currently reversible.')
|