Merge driver-check da254195 into release-0.3.22 (main: a 0.3.22 app item; the eGPU driver-install hold and warning)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
commit
bada1c96d0
10 changed files with 119 additions and 4 deletions
|
|
@ -244,9 +244,36 @@ pub fn authenticode_verdict(text: &str, signer: &str) -> Result<String, String>
|
|||
Ok(subject)
|
||||
}
|
||||
|
||||
/// The cards whose worker stops before a vendor's driver installer starts: that vendor's cards the app reads as
|
||||
/// external (the eGPU kind: a USB4 or Thunderbolt router in the device's parent chain). PC 2, 7 October 2026, 16:26Z:
|
||||
/// the Intel installer's display reset took the machine down while the app's own worker mined on the Arc in the Razer
|
||||
/// Core X V2; the machine needed a power cycle. The other cards keep mining through the install. Each item is
|
||||
/// (key, vendor, kind, enabled); a card already off has nothing to stop.
|
||||
pub fn install_hold_keys<'a>(cards: impl IntoIterator<Item = (&'a str, &'a str, &'a str, bool)>, vendor: &str) -> Vec<String> {
|
||||
cards.into_iter().filter(|(_, v, kind, enabled)| *v == vendor && *kind == "external" && *enabled).map(|(key, _, _, _)| key.to_string()).collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn an_install_on_an_egpu_card_stops_that_cards_worker_first_and_leaves_the_other_cards_mining() {
|
||||
// PC 2, 7 October 2026: the Arc B580 in the Razer Core X V2 was mining when the Intel installer's display
|
||||
// reset took the machine down. The rule: the vendor's external cards stop, nothing else does.
|
||||
let cards = [
|
||||
("nvidia:0:NVIDIA GeForce RTX 5090", "nvidia", "discrete", true),
|
||||
("nvidia:1:NVIDIA GeForce RTX 5060 Ti", "nvidia", "external", true),
|
||||
("intel:Intel(R) Arc(TM) B580 Graphics", "intel", "external", true),
|
||||
("intel::Intel UHD 770", "other", "integrated", false),
|
||||
];
|
||||
assert_eq!(install_hold_keys(cards, "intel"), vec!["intel:Intel(R) Arc(TM) B580 Graphics".to_string()], "the Arc in the enclosure stops; the NVIDIA cards and the iGPU keep mining");
|
||||
assert_eq!(install_hold_keys(cards, "nvidia"), vec!["nvidia:1:NVIDIA GeForce RTX 5060 Ti".to_string()], "the 5060 Ti in the enclosure stops; the 5090 inside the case keeps mining");
|
||||
assert!(install_hold_keys(cards, "amd").is_empty(), "no AMD card: nothing stops");
|
||||
// an external card already off has nothing to stop; a discrete card of the vendor is not held
|
||||
let off = [("intel:Intel(R) Arc(TM) B580 Graphics", "intel", "external", false), ("intel:Intel(R) Arc(TM) A770 Graphics", "intel", "discrete", true)];
|
||||
assert!(install_hold_keys(off, "intel").is_empty());
|
||||
}
|
||||
|
||||
|
||||
const TABLE: &str = r#"{"updated":"2026-10-07","vendors":{
|
||||
"nvidia":{"min_version":"570.00","version":"617.42","url":"https://us.download.nvidia.com/Windows/617.42/617.42-desktop-win10-win11-64bit-international-dch-whql.exe","size":990853168,"sha256":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","hash_source":"https://www.nvidia.com/en-us/drivers/details/","args":["-s","-noreboot"],"reboot_codes":[1],"signer":"NVIDIA","linux_package":"nvidia-driver-570","hive_package":"nvidia-driver-update 570"},
|
||||
|
|
|
|||
|
|
@ -700,6 +700,8 @@ pub struct Engine {
|
|||
/// driver-check: the manifest's table as last read from <app data>/drivers.json (None = none published)
|
||||
drivers_table: Option<crate::drivers::Table>,
|
||||
driver_busy: bool,
|
||||
/// the vendor's cards held off for a driver install, put back as they were when it ends
|
||||
driver_held: Vec<CardChoice>,
|
||||
/// the interface over the air (src/uiota.rs)
|
||||
uiota: crate::uiota::UiOta,
|
||||
jobs: crate::jobrun::Jobs,
|
||||
|
|
@ -869,6 +871,7 @@ impl Engine {
|
|||
upload_thread: None,
|
||||
drivers_table: ota.drivers_table(),
|
||||
driver_busy: false,
|
||||
driver_held: Vec::new(),
|
||||
ota,
|
||||
uiota,
|
||||
jobs,
|
||||
|
|
@ -1066,6 +1069,8 @@ impl Engine {
|
|||
self.shared.apply_prove_default();
|
||||
// driver-check: every card's driver against the manifest's table, at first run and every detection
|
||||
self.refresh_driver_offers();
|
||||
// a card the driver install took away is back: its worker returns
|
||||
self.driver_release_held(true);
|
||||
}
|
||||
Cmd::ApplyCards(choices) => self.apply_cards(choices),
|
||||
Cmd::ProveHold(on) => self.prove_hold(on),
|
||||
|
|
@ -1711,10 +1716,47 @@ impl Engine {
|
|||
d.finished_at = 0.0;
|
||||
}
|
||||
self.shared.event("info", &format!("driver install started: {} {} ({} MB) from the vendor's server{}", vendor.to_ascii_uppercase(), e.version, (e.size + 512 * 1024) / (1024 * 1024), if dry { ", dry run" } else { "" }));
|
||||
// PC 2, 7 October 2026, 16:26Z: the Intel installer's display reset took the machine down while the app's own
|
||||
// worker mined on the Arc in the Razer Core X V2 (a power cycle). The vendor's cards the app reads as external
|
||||
// (drivertable::install_hold_keys) stop before the installer starts; the other cards keep mining; each held card
|
||||
// comes back as it was when the installer ends, or when the card itself returns if the install took it away.
|
||||
let (off, restore): (Vec<CardChoice>, Vec<CardChoice>) = {
|
||||
let st = self.st();
|
||||
let keys = crate::drivertable::install_hold_keys(st.mining.cards.iter().map(|c| (c.key.as_str(), c.vendor.as_str(), c.kind.as_str(), c.enabled)), vendor);
|
||||
let live: Vec<crate::jobrun::LiveCard> = st.mining.cards.iter().map(|c| (c.key.clone(), c.enabled, c.identities, c.power_pct, c.present())).collect();
|
||||
crate::jobrun::cards_off_choices(&keys, &live)
|
||||
};
|
||||
if !off.is_empty() {
|
||||
self.shared.event("info", &format!("driver install: the worker on {} stops for the install (a card in an external enclosure; the display reset can take the machine for a minute); the other cards keep mining", off.iter().map(|c| c.key.as_str()).collect::<Vec<_>>().join(", ")));
|
||||
self.apply_cards(off);
|
||||
}
|
||||
self.driver_held = restore;
|
||||
let dir = self.shared.runtime.app_dir.join("drivers");
|
||||
crate::drivers::start_install(&self.shared, e, dir, dry);
|
||||
}
|
||||
|
||||
/// The cards held off for a driver install go back as they were: the ones present now, at once; a card the install
|
||||
/// took away (Windows re-enumerates an eGPU through the reset) waits for its return (`returned` = the call from a
|
||||
/// detection) and goes back then. A hold that nothing returns stays until the next install replaces it.
|
||||
fn driver_release_held(&mut self, returned: bool) {
|
||||
if self.driver_held.is_empty() || (returned && self.driver_busy) {
|
||||
return;
|
||||
}
|
||||
let held = std::mem::take(&mut self.driver_held);
|
||||
let (now, later): (Vec<CardChoice>, Vec<CardChoice>) = {
|
||||
let st = self.st();
|
||||
held.into_iter().partition(|ch| st.mining.cards.iter().any(|c| c.key == ch.key && c.present()))
|
||||
};
|
||||
if !now.is_empty() {
|
||||
self.shared.event("info", &format!("driver install: the worker on {} is back{}", now.iter().map(|c| c.key.as_str()).collect::<Vec<_>>().join(", "), if returned { " (the card returned)" } else { "" }));
|
||||
self.apply_cards(now);
|
||||
}
|
||||
if !later.is_empty() && !returned {
|
||||
self.shared.event("info", &format!("driver install: {} not listed after the install; its worker comes back when the card does", later.iter().map(|c| c.key.as_str()).collect::<Vec<_>>().join(", ")));
|
||||
}
|
||||
self.driver_held = later;
|
||||
}
|
||||
|
||||
fn driver_event(&mut self, ev: crate::drivers::Event) {
|
||||
match ev {
|
||||
crate::drivers::Event::Progress(p, text) => {
|
||||
|
|
@ -1725,6 +1767,7 @@ impl Engine {
|
|||
}
|
||||
crate::drivers::Event::Installed(r) => {
|
||||
self.driver_busy = false;
|
||||
self.driver_release_held(false);
|
||||
let (status, text, reboot, err) = match r {
|
||||
Ok((code, reboot, text)) => (if reboot { "reboot" } else if code == 0 { "done" } else { "error" }, text.clone(), reboot, if code == 0 || reboot { String::new() } else { text }),
|
||||
Err(e) => ("error", e.clone(), false, e),
|
||||
|
|
|
|||
|
|
@ -412,17 +412,22 @@ var View = (function () {
|
|||
function driverWords(cd, s) {
|
||||
var o = cd.driver_offer, d = (s && s.drivers) || {};
|
||||
if (!o) return { kind: 'none', text: '' };
|
||||
var mine = d.vendor && d.vendor === o.vendor;
|
||||
var mine = d.vendor && d.vendor === o.vendor, ext = cd.kind === 'external';
|
||||
// PC 2, 7 October 2026: a card in an external enclosure (the eGPU kind) has its worker stopped for the install, and the
|
||||
// installer's display reset can take the machine; the row says both before the click and while it runs
|
||||
var extRun = ext ? '. This card\u2019s worker is stopped until the installer ends; the display reset can take the machine for a minute.' : '';
|
||||
if (mine && (d.status === 'downloading' || d.status === 'verifying' || d.status === 'installing')) {
|
||||
var pct = d.status === 'downloading' ? Math.round((d.progress || 0) * 100) + '%' : '';
|
||||
return { kind: 'running', text: (d.status === 'downloading' ? 'Downloading the ' : d.status === 'verifying' ? 'Checking the ' : 'Installing the ') + vendorWord(o.vendor) + ' driver ' + d.version + (pct ? ' · ' + pct : ''), sub: d.message || '', progress: d.progress || 0, dry: !!d.dry_run };
|
||||
return { kind: 'running', text: (d.status === 'downloading' ? 'Downloading the ' : d.status === 'verifying' ? 'Checking the ' : 'Installing the ') + vendorWord(o.vendor) + ' driver ' + d.version + (pct ? ' · ' + pct : ''), sub: (d.message || '') + extRun, progress: d.progress || 0, dry: !!d.dry_run, external: ext };
|
||||
}
|
||||
if (mine && d.status === 'reboot') return { kind: 'reboot', text: vendorWord(o.vendor) + ' driver ' + d.version + ' installed. Restart Windows to finish.', button: 'restart', sub: 'Mining continues until you restart.' };
|
||||
if (mine && d.status === 'error') return { kind: 'error', text: 'The ' + vendorWord(o.vendor) + ' driver did not install: ' + (d.error || d.message || 'unknown error'), button: o.installable ? 'install' : '', sub: o.hash_source ? 'Checked against ' + o.hash_source : '' };
|
||||
if (o.status === 'fine') return { kind: 'fine', text: o.text };
|
||||
if (o.status === 'none') return { kind: 'note', text: o.text };
|
||||
if (!o.installable) return { kind: 'note', text: o.text };
|
||||
return { kind: 'offer', text: o.text, button: 'install', sub: 'Downloaded from ' + hostOf(o.url) + ', checked against the vendor\u2019s published hash and signature, then installed with one administrator prompt. Mining continues.' };
|
||||
var sub = 'Downloaded from ' + hostOf(o.url) + ', checked against the vendor\u2019s published hash and signature, then installed with one administrator prompt. ';
|
||||
sub += ext ? 'This card\u2019s worker stops for the install and comes back after it; the other cards keep mining. The display reset can take the machine for a minute and may need a restart: save your work first.' : 'Mining continues.';
|
||||
return { kind: 'offer', text: o.text, button: 'install', sub: sub, external: ext };
|
||||
}
|
||||
function vendorWord(v) { return v === 'nvidia' ? 'NVIDIA' : v === 'amd' ? 'AMD' : v === 'intel' ? 'Intel Arc' : v === 'apple' ? 'Apple' : v; }
|
||||
function hostOf(u) { var m = /^https?:\/\/([^\/]+)/.exec(u || ''); return m ? m[1] : 'the vendor'; }
|
||||
|
|
|
|||
|
|
@ -112,6 +112,27 @@ test('driver-check: the row\'s driver strip per state (offer, running, reboot, e
|
|||
assert.equal(V.vendorWord('amd'), 'AMD');
|
||||
});
|
||||
|
||||
test('driver-check: an install offer on an eGPU card warns that its worker stops and the display reset can take the machine (PC 2, 7 October 2026)', () => {
|
||||
const offer = { vendor: 'intel', status: 'old', installed: '32.0.101.6733', wanted: '32.0.101.9034', min_version: '32.0.101.9034', size: 932631144, url: 'https://downloadmirror.intel.com/929959/gfx_win_101.9034.exe', hash_source: 'https://www.intel.com/content/www/us/en/download/785597/', text: 'Install the Intel Arc driver 32.0.101.9034, 889 MB (the worker needs 32.0.101.9034 or newer; 32.0.101.6733 is installed)', installable: true };
|
||||
const idle = { drivers: { status: 'idle', vendor: '', version: '', progress: 0, message: '', error: '', reboot_required: false, dry_run: false } };
|
||||
const egpu = card({ key: 'intel:Intel(R) Arc(TM) B580 Graphics', name: 'Intel(R) Arc(TM) B580 Graphics', vendor: 'intel', kind: 'external', worker: 'OpenCL', enabled: true, state: 'mining', driver_offer: offer });
|
||||
let w = V.driverWords(egpu, idle);
|
||||
assert.equal(w.kind, 'offer');
|
||||
assert.equal(w.external, true);
|
||||
assert.ok(w.sub.includes('This card\u2019s worker stops for the install and comes back after it; the other cards keep mining.'), w.sub);
|
||||
assert.ok(w.sub.includes('The display reset can take the machine for a minute and may need a restart'), w.sub);
|
||||
// the same card inside the case: no stop, the plain sentence
|
||||
const inside = card({ ...egpu, kind: 'discrete' });
|
||||
w = V.driverWords(inside, idle);
|
||||
assert.equal(w.external, false);
|
||||
assert.ok(w.sub.endsWith('Mining continues.'), w.sub);
|
||||
assert.ok(!w.sub.includes('display reset'));
|
||||
// while it installs on the eGPU card, the running line says the worker is stopped
|
||||
w = V.driverWords(egpu, { drivers: { status: 'installing', vendor: 'intel', version: '32.0.101.9034', progress: 0.7, message: 'installing INTEL 32.0.101.9034: Windows asks for permission once', dry_run: false } });
|
||||
assert.equal(w.kind, 'running');
|
||||
assert.ok(w.sub.includes('This card\u2019s worker is stopped until the installer ends'), w.sub);
|
||||
});
|
||||
|
||||
test('a card behind a USB4 or Thunderbolt router is an eGPU on the Cards page (PC 2, 7 October 2026)', () => {
|
||||
const r = V.cardRow(card({ key: 'nvidia:1:NVIDIA GeForce RTX 5060 Ti', name: 'NVIDIA GeForce RTX 5060 Ti', vendor: 'nvidia', kind: 'external', enabled: true, state: 'mining', hash_now: 40, power_w: 120, temp_gpu: 55 }));
|
||||
assert.equal(r.kindWord, 'eGPU');
|
||||
|
|
|
|||
BIN
docs/plans/driver-check-shots/13-cards-egpu-offer-light.png
Normal file
BIN
docs/plans/driver-check-shots/13-cards-egpu-offer-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 375 KiB |
BIN
docs/plans/driver-check-shots/14-cards-egpu-offer-dark.png
Normal file
BIN
docs/plans/driver-check-shots/14-cards-egpu-offer-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 368 KiB |
BIN
docs/plans/driver-check-shots/15-cards-egpu-running-light.png
Normal file
BIN
docs/plans/driver-check-shots/15-cards-egpu-running-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 335 KiB |
BIN
docs/plans/driver-check-shots/16-cards-egpu-running-dark.png
Normal file
BIN
docs/plans/driver-check-shots/16-cards-egpu-running-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 331 KiB |
|
|
@ -41,6 +41,16 @@ Apple: none. The exit codes: Intel 14 and 1014 (the bootstrapper's wrap, measure
|
|||
|
||||
Sizes: the installers are 889 MB to 1.0 GB each; the download lands in `<app data>/drivers/` and stays (a second click reuses it when its sha256 still matches). Time: the download at a home line of 50 Mbit/s is 2.5 to 3 minutes; the install 1 to 4 minutes; the prompt is the only wait on the user.
|
||||
|
||||
## 3b. A card in an external enclosure (7 October 2026, after PC 2)
|
||||
|
||||
PC 2 at 16:26Z: the Intel installer started with the app's own worker mining on the Arc B580 in the Razer Core X V2. The installer's display reset took the machine down at 16:27:14Z (every log stops together; a power cycle). The rule, on this branch:
|
||||
|
||||
- A driver install on a card the app reads as `external` (the eGPU kind: a USB4 or Thunderbolt router in the device's parent chain, update-return-21b) stops that card's worker before the installer starts (`drivertable::install_hold_keys`, through the cards path with the restore choice kept, the `--cards-off` shape). The vendor's cards inside the case and every other vendor's card keep mining.
|
||||
- The row says so before the click ("This card's worker stops for the install and comes back after it; the other cards keep mining. The display reset can take the machine for a minute and may need a restart: save your work first.") and while it runs ("This card's worker is stopped until the installer ends; the display reset can take the machine for a minute.").
|
||||
- When the installer ends the held card goes back as it was (enabled, identities, cap). A card the install took away (Windows re-enumerates an eGPU through the reset) comes back when the card does: the detection that lists it again restores it (`driver_release_held(true)`). The app never restarts the machine.
|
||||
|
||||
Per tier: a solo miner with one eGPU loses that card's rate for the install (3 to 8 minutes on a home line, the download dominating) and nothing else; a rig with the card inside the case sees no change; macOS and Linux have no install step. Tests: the known-failed rule test first (an install on an eGPU card with the worker still running held nothing: `an_install_on_an_egpu_card_stops_that_cards_worker_first_and_leaves_the_other_cards_mining`, red on build-2 at 17:1xZ, then green), the view test for the two sentences. Captures 13 to 16: the eGPU offer (13, 14) and the install running with the card's worker off (15, 16), mock scenarios `drivers-egpu` and `drivers-egpu-running`.
|
||||
|
||||
## 4. Not done, and what follows
|
||||
|
||||
- The table's publish: `publish-manifest.sh --drivers packaging/ota/drivers.json` with the 0.3.21 manifest (the shipper's step); every row is measured.
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ function stateNow() {
|
|||
{ ...recState.mining.cards[0], key: 'intel:Intel(R) Arc(TM) B580 Graphics', name: 'Intel(R) Arc(TM) B580 Graphics', code: 'Intel(R) Arc(TM) B580 Graphics', platform: 'Intel(R) OpenCL Graphics (OpenCL 3.0 ), driver 32.0.101.9034', kind: 'discrete', vendor: 'intel', worker: 'OpenCL', detail: '160 compute units', vram_mb: 12208, device: '1', bus: '05:00.0', identities: 8, ids: ['c0ffee01', 'c0ffee02'], enabled: true, state: 'mining', hash_now: 15.2, hash_avg: 15.0, accepted: 3, rejected: 0, power_default_w: 0, power_pct: 0, power_applied: false, power_w: 0, temp_gpu: 0, temp_mem: 0, eff_mhw: 0, sweep_supported: false, sweep_state: 'unsupported', sweep_note: 'not available: Intel Arc exposes no power cap or reading through OpenCL (the driver\'s IGCL counters come next)', tune_line: '', tune_source: '', tune_control: false, driver: '32.0.101.9034' }];
|
||||
s.mining.hash_total = 142.9; s.display_name = 'pc-1';
|
||||
}
|
||||
if (scenario === 'drivers' || scenario === 'drivers-running' || scenario === 'drivers-reboot' || scenario === 'drivers-error' || scenario === 'drivers-mac') {
|
||||
if (scenario === 'drivers' || scenario === 'drivers-running' || scenario === 'drivers-reboot' || scenario === 'drivers-error' || scenario === 'drivers-mac' || scenario === 'drivers-egpu' || scenario === 'drivers-egpu-running') {
|
||||
// driver-check (7 October 2026): PC 1 after the Arc went in, with the manifest's table: the 5090 fine, the
|
||||
// 9070 XT's driver older than the worker needs, the Arc on Windows' inbox driver, the install's states
|
||||
var tbl = 'https://www.intel.com/content/www/us/en/download/785597/';
|
||||
|
|
@ -233,6 +233,15 @@ function stateNow() {
|
|||
if (scenario === 'drivers-running') s.drivers = { ...s.drivers, status: 'downloading', vendor: 'intel', version: '32.0.101.9034', progress: 0.43 + ((Date.now() / 1000) % 60) / 110, message: 'downloading 32.0.101.9034 (889 MB) from downloadmirror.intel.com', started_at: t - 40 };
|
||||
if (scenario === 'drivers-reboot') s.drivers = { ...s.drivers, status: 'reboot', vendor: 'intel', version: '32.0.101.9034', progress: 1, message: 'INTEL driver 32.0.101.9034 installed. Restart Windows to finish.', reboot_required: true, started_at: t - 300, finished_at: t - 20 };
|
||||
if (scenario === 'drivers-error') s.drivers = { ...s.drivers, status: 'error', vendor: 'amd', version: '26.9.2', progress: 1, message: 'download: sha256 mismatch: the file is not the one the table names (page https://www.amd.com/en/support/download/drivers.html)', error: 'download: sha256 mismatch: the file is not the one the table names (page https://www.amd.com/en/support/download/drivers.html)', started_at: t - 120, finished_at: t - 5 };
|
||||
if (scenario === 'drivers-egpu' || scenario === 'drivers-egpu-running') {
|
||||
// PC 2, 7 October 2026: the Arc B580 in the Razer Core X V2 (the eGPU kind), the 5060 Ti inside the case; the offer
|
||||
// on the eGPU row warns that its worker stops and the display reset can take the machine; running: the worker off
|
||||
var arcRow = s.mining.cards.find(c => c.vendor === 'intel');
|
||||
s.mining.cards = s.mining.cards.filter(c => c.vendor === 'intel' || c.vendor === 'nvidia').map(c => c.vendor === 'intel' ? { ...c, kind: 'external', enabled: true, state: 'mining', hash_now: 11.0, hash_avg: 10.98, power_w: 118, temp_gpu: 61, identities: 2, ids: ['7c2e', 'a91f'] } : { ...c, key: 'nvidia:0:NVIDIA GeForce RTX 5060 Ti', name: 'NVIDIA GeForce RTX 5060 Ti', detail: '4608 cores', vram_mb: 16384, hash_now: 40.2, hash_avg: 40.1, power_w: 152, power_default_w: 180, power_limit_w: 152 });
|
||||
s.display_name = 'pc-2'; s.mining.hash_total = 51.2;
|
||||
if (scenario === 'drivers-egpu-running') { s.mining.cards = s.mining.cards.map(c => c.vendor === 'intel' ? { ...c, enabled: false, state: 'off', hash_now: 0, power_w: 0 } : c); s.mining.hash_total = 40.2; s.drivers = { ...s.drivers, status: 'installing', vendor: 'intel', version: '32.0.101.9034', progress: 0.72, message: 'installing INTEL 32.0.101.9034: Windows asks for permission once', reboot_required: false, started_at: t - 95, finished_at: 0 }; }
|
||||
void arcRow;
|
||||
}
|
||||
if (scenario === 'drivers-mac') { s.mining.cards = [{ ...recState.mining.cards[0], driver_offer: { vendor: 'apple', status: 'none', installed: '', wanted: '', min_version: '', size: 0, url: '', hash_source: '', text: 'Apple silicon: no driver step, macOS carries it.', installable: false } }]; s.mining.hash_total = recState.mining.hash_total; s.display_name = recState.display_name; s.drivers.platform = 'macos'; }
|
||||
}
|
||||
if (scenario === 'euro') {
|
||||
|
|
|
|||
Loading…
Reference in a new issue