@helix3/helix-cli 0.1.18-helix3.313 → 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/dist/index.js +109 -5
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/visualQa/browser.d.ts +5 -1
- package/dist/visualQa/browser.js +69 -15
- package/dist/visualQa/browser.js.map +1 -1
- package/dist/visualQa/command.d.ts +12 -0
- package/dist/visualQa/command.js +12 -3
- package/dist/visualQa/command.js.map +1 -1
- 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 +2 -1
- package/dist/visualQa/resolve.js +7 -6
- package/dist/visualQa/resolve.js.map +1 -1
- 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 +1 -1
- 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/dist/index.js
CHANGED
|
@@ -1692,9 +1692,21 @@ item
|
|
|
1692
1692
|
// backend, which runs the vision critic, records the verdict against that exact version and serves a contact sheet.
|
|
1693
1693
|
item
|
|
1694
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')
|
|
1696
|
-
.argument('
|
|
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
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')
|
|
1698
1710
|
.option('--local-critic', 'also run the vision critic locally (needs ANTHROPIC_API_KEY or OPENROUTER_API_KEY)')
|
|
1699
1711
|
.option('--out <dir>', 'bundle directory (frames, bundle.json, contact-sheet.jpg)')
|
|
1700
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')
|
|
@@ -1705,12 +1717,104 @@ item
|
|
|
1705
1717
|
.option('--json', 'print the outcome as JSON')
|
|
1706
1718
|
.action(async (id, opts) => {
|
|
1707
1719
|
try {
|
|
1708
|
-
const
|
|
1709
|
-
const creds = opts.submit ? requireAuth() : (0, config_1.loadCredentials)();
|
|
1720
|
+
const creds = opts.submit || opts.hosted ? requireAuth() : (0, config_1.loadCredentials)();
|
|
1710
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')));
|
|
1711
1815
|
const outcome = await runVisualQa(id, {
|
|
1712
1816
|
apiBase,
|
|
1713
|
-
webBase
|
|
1817
|
+
webBase,
|
|
1714
1818
|
token: creds?.token ?? null,
|
|
1715
1819
|
out: opts.out,
|
|
1716
1820
|
storageState: opts.storageState ?? process.env.HELIX_VQA_STORAGE_STATE,
|