idlewatch 0.1.4 → 0.1.5

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 CHANGED
@@ -17,7 +17,7 @@ npx idlewatch quickstart
17
17
  npx idlewatch --dry-run
18
18
  ```
19
19
 
20
- `quickstart` is the happy path: create an API key on idlewatch.com/api, run the wizard, pick a device name + metrics, and IdleWatch saves local config before sending a first sample. By default, quickstart will try to install Rust/Cargo automatically if needed so it can launch the ratatui onboarding flow. Use `idlewatch quickstart --no-tui` to skip the TUI and stay on the plain text setup path without installing Cargo.
20
+ `quickstart` is the happy path: create an API key on idlewatch.com/api, run the wizard, pick a device name + metrics, and IdleWatch saves local config before sending a first sample. It prefers a bundled TUI binary when available, otherwise falls back to a local Cargo build only on developer machines that already have Cargo installed. Use `idlewatch quickstart --no-tui` to skip the TUI and stay on the plain text setup path.
21
21
 
22
22
  ## CLI options
23
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "idlewatch",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Host telemetry collector for IdleWatch",
5
5
  "type": "module",
6
6
  "files": [
@@ -9,6 +9,7 @@
9
9
  "scripts",
10
10
  "skill",
11
11
  "tui/src",
12
+ "tui/bin",
12
13
  "tui/Cargo.toml",
13
14
  "tui/Cargo.lock",
14
15
  "README.md",
package/src/enrollment.js CHANGED
@@ -99,43 +99,47 @@ function cargoAvailable() {
99
99
  return cargoProbe.status === 0
100
100
  }
101
101
 
102
- function installRustToolchain() {
103
- if (cargoAvailable()) return { ok: true, installed: false }
104
- if (process.env.IDLEWATCH_DISABLE_RUST_INSTALL === '1') return { ok: false, reason: 'install-disabled' }
105
- if (!process.stdin.isTTY || !process.stdout.isTTY) return { ok: false, reason: 'non-tty' }
106
- if (!['darwin', 'linux'].includes(process.platform)) return { ok: false, reason: `unsupported-platform:${process.platform}` }
107
-
108
- console.log('IdleWatch TUI needs Rust/Cargo. Installing rustup + Cargo now...')
109
- const install = spawnSync('sh', ['-c', 'curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y'], {
102
+ function bundledTuiBinaryPath() {
103
+ const platform = process.platform
104
+ const arch = process.arch
105
+ const ext = platform === 'win32' ? '.exe' : ''
106
+ return path.join(PACKAGE_ROOT, 'tui', 'bin', `${platform}-${arch}`, `idlewatch-setup${ext}`)
107
+ }
108
+
109
+ function tryBundledRustTui({ configDir, outputEnvFile }) {
110
+ const binPath = bundledTuiBinaryPath()
111
+ if (!fs.existsSync(binPath)) return { ok: false, reason: 'bundled-binary-missing', binPath }
112
+
113
+ try {
114
+ fs.chmodSync(binPath, 0o755)
115
+ } catch {
116
+ // best effort
117
+ }
118
+
119
+ const run = spawnSync(binPath, [], {
110
120
  stdio: 'inherit',
111
121
  env: {
112
122
  ...process.env,
113
- CARGO_HOME: process.env.CARGO_HOME || path.join(os.homedir(), '.cargo'),
114
- RUSTUP_HOME: process.env.RUSTUP_HOME || path.join(os.homedir(), '.rustup')
123
+ IDLEWATCH_ENROLL_CONFIG_DIR: configDir,
124
+ IDLEWATCH_ENROLL_OUTPUT_ENV_FILE: outputEnvFile
115
125
  }
116
126
  })
117
127
 
118
- if (install.status !== 0) return { ok: false, reason: `rustup-install-failed:${install.status ?? 'unknown'}` }
119
-
120
- const cargoBinDir = path.join(process.env.CARGO_HOME || path.join(os.homedir(), '.cargo'), 'bin')
121
- if (!process.env.PATH?.split(path.delimiter).includes(cargoBinDir)) {
122
- process.env.PATH = `${cargoBinDir}${path.delimiter}${process.env.PATH || ''}`
123
- }
124
-
125
- return cargoAvailable() ? { ok: true, installed: true } : { ok: false, reason: 'cargo-still-missing' }
128
+ if (run.status === 0) return { ok: true, binPath }
129
+ return { ok: false, reason: `bundled-binary-failed:${run.status ?? 'unknown'}`, binPath }
126
130
  }
127
131
 
128
- function tryRustTui({ configDir, outputEnvFile, autoInstallRust = true }) {
132
+ function tryRustTui({ configDir, outputEnvFile }) {
129
133
  const disabled = process.env.IDLEWATCH_DISABLE_RUST_TUI === '1'
130
134
  if (disabled) return { ok: false, reason: 'disabled' }
131
135
 
136
+ const bundled = tryBundledRustTui({ configDir, outputEnvFile })
137
+ if (bundled.ok) return bundled
138
+
132
139
  if (!cargoAvailable()) {
133
- if (autoInstallRust) {
134
- const installResult = installRustToolchain()
135
- if (!installResult.ok) return { ok: false, reason: installResult.reason || 'cargo-missing' }
136
- } else {
137
- return { ok: false, reason: 'cargo-missing' }
138
- }
140
+ return bundled.reason === 'bundled-binary-missing'
141
+ ? { ok: false, reason: 'bundled-binary-missing-and-cargo-missing', binPath: bundled.binPath }
142
+ : { ok: false, reason: 'cargo-missing' }
139
143
  }
140
144
 
141
145
  const manifestPath = path.join(PACKAGE_ROOT, 'tui', 'Cargo.toml')
@@ -179,7 +183,7 @@ export async function runEnrollmentWizard(options = {}) {
179
183
  )
180
184
 
181
185
  if (!nonInteractive && !noTui) {
182
- const tuiResult = tryRustTui({ configDir, outputEnvFile, autoInstallRust: true })
186
+ const tuiResult = tryRustTui({ configDir, outputEnvFile })
183
187
  if (tuiResult.ok) {
184
188
  return {
185
189
  mode: 'tui',
@@ -188,7 +192,9 @@ export async function runEnrollmentWizard(options = {}) {
188
192
  }
189
193
  }
190
194
 
191
- if (!['disabled', 'cargo-missing'].includes(tuiResult.reason || '')) {
195
+ if (tuiResult.reason === 'bundled-binary-missing-and-cargo-missing') {
196
+ console.warn('IdleWatch TUI is not bundled for this platform and Cargo is not installed. Falling back to text setup. Use --no-tui to skip this check.')
197
+ } else if (!['disabled', 'cargo-missing', 'bundled-binary-missing'].includes(tuiResult.reason || '')) {
192
198
  console.warn(`IdleWatch TUI unavailable (${tuiResult.reason || 'unknown'}). Falling back to text setup.`)
193
199
  }
194
200
  }