* fix: avoid cmd.exe spawn on Windows by using os.hostname() before execSync fallback
On Windows, execSync() wraps the command in cmd.exe /d /s /c,
spawning a new cmd.exe process. getMachineIdRaw() called
execSync("hostname") as Strategy 4 before trying os.hostname()
as Strategy 5 -- meaning every dashboard API call spawned an
unnecessary cmd.exe process.
This commit:
- Moves os.hostname() to Strategy 4 (no child process, native binding)
- Keeps execSync("hostname") as Strategy 5 fallback
- Adds module-level caching so getMachineIdRaw() only runs once per
process lifetime since the machine ID never changes at runtime
- Caches all strategy results at the first successful return
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* fix: avoid cmd.exe spawn on Windows by using os.hostname() before execSync fallback
Prioritize os.hostname() (sync, no subprocess) over execSync hostname fallback. Cache the result so subsequent calls never spawn. Export resetMachineIdCache() for test isolation.
Tests: 10 tests covering cache behavior, strategy fallback order, and consistent machine ID hashing. The 2 tests that mock os.hostname() now also stub fs.readFileSync for /etc/machine-id to throw, so Strategy 3 (Linux machine-id file) does not preempt Strategy 4 on real Linux runners.
---------
Co-authored-by: tientien17 <tientien17@users.noreply.github.com>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>