shortcutxl 0.2.6 → 0.2.8

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.
@@ -14,6 +14,35 @@ import { resetShellConfig } from '../utils/shell.js';
14
14
  import { EXCEL_HTTP_URL } from './constants.js';
15
15
  import { fetchExcelConfig } from './excel-config.js';
16
16
  import { getStableXllDir } from './sync-xll.js';
17
+ // ── PATH refresh ────────────────────────────────────────────────────────
18
+ /**
19
+ * Re-read the Windows PATH from the registry and merge it into process.env.PATH.
20
+ * After winget installs a program (Git, Python, etc.) the system/user PATH is
21
+ * updated, but the running Node process still has the old value. This reads the
22
+ * current registry entries and splices in any new directories.
23
+ */
24
+ function refreshPath() {
25
+ try {
26
+ const user = spawnSync('reg', ['query', 'HKCU\\Environment', '/v', 'Path'], { encoding: 'utf-8', timeout: 5_000 });
27
+ const system = spawnSync('reg', ['query', 'HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment', '/v', 'Path'], { encoding: 'utf-8', timeout: 5_000 });
28
+ const extract = (out) => (out.match(/REG_(?:EXPAND_)?SZ\s+(.+)/i)?.[1] ?? '')
29
+ .split(';')
30
+ .map((p) => p.trim())
31
+ .filter(Boolean);
32
+ const fresh = new Set([...extract(system.stdout ?? ''), ...extract(user.stdout ?? '')]);
33
+ const current = (process.env.PATH ?? '').split(';').filter(Boolean);
34
+ const currentSet = new Set(current.map((p) => p.toLowerCase()));
35
+ for (const dir of fresh) {
36
+ if (!currentSet.has(dir.toLowerCase())) {
37
+ current.push(dir);
38
+ }
39
+ }
40
+ process.env.PATH = current.join(';');
41
+ }
42
+ catch {
43
+ // Best-effort — if registry read fails, continue with stale PATH
44
+ }
45
+ }
17
46
  /** Accumulated log entries, exposed to callers via runPreflight(). */
18
47
  const preflightLog = [];
19
48
  let currentStep = 'setup';
@@ -135,7 +164,9 @@ function runWithProgress(cmd, options) {
135
164
  // ── Step implementations ─────────────────────────────────────────────────
136
165
  async function ensureGitBash() {
137
166
  header('Git');
138
- const bashCheck = run('bash --version');
167
+ // Use git's bundled bash directly — plain `bash` can hang on Windows
168
+ // when WSL is installed but not configured.
169
+ const bashCheck = run('git --version', { timeout: 5_000 });
139
170
  if (bashCheck.ok) {
140
171
  ok('Installed.');
141
172
  return;
@@ -158,12 +189,13 @@ async function ensureGitBash() {
158
189
  }
159
190
  }
160
191
  log('Installing Git (you may see a permissions prompt — click Yes)...');
161
- const result = await runWithProgress('winget install --id Git.Git -e -h --accept-source-agreements --accept-package-agreements', { timeout: 120_000, label: 'Installing Git' });
192
+ const result = await runWithProgress('winget install --id Git.Git -e -h --accept-source-agreements --accept-package-agreements', { timeout: 300_000, label: 'Installing Git' });
162
193
  if (!result.ok && !result.stdout.includes('already installed')) {
163
194
  warn('Install failed — the setup agent will help.');
164
195
  return;
165
196
  }
166
- // Reset shell cache so it re-detects bash
197
+ // Refresh PATH so the newly installed git is visible to this process
198
+ refreshPath();
167
199
  resetShellConfig();
168
200
  const gitCheck = run('git --version');
169
201
  if (!gitCheck.ok) {
@@ -196,12 +228,13 @@ async function ensurePython() {
196
228
  return;
197
229
  }
198
230
  log('Installing Python 3.12...');
199
- const result = await runWithProgress('winget install --id Python.Python.3.12 -e -h --accept-source-agreements --accept-package-agreements', { timeout: 120_000, label: 'Installing Python 3.12' });
231
+ const result = await runWithProgress('winget install --id Python.Python.3.12 -e -h --accept-source-agreements --accept-package-agreements', { timeout: 600_000, label: 'Installing Python 3.12' });
200
232
  if (!result.ok && !result.stdout.includes('already installed')) {
201
233
  warn('Install failed — the setup agent will help.');
202
234
  return;
203
235
  }
204
236
  freshInstall = true;
237
+ refreshPath();
205
238
  detected = detectPython312();
206
239
  if (!detected) {
207
240
  warn('Installed but not detected yet — try restarting your terminal.');
@@ -231,7 +264,7 @@ async function ensurePython() {
231
264
  }
232
265
  // Install pywin32 + openpyxl + playwright + httpx
233
266
  log('Installing required packages...');
234
- const pipResult = await runWithProgress(`${pythonCmd} -m pip install pywin32 openpyxl playwright httpx`, { timeout: 120_000, label: 'Installing packages' });
267
+ const pipResult = await runWithProgress(`${pythonCmd} -m pip install pywin32 openpyxl playwright httpx`, { timeout: 300_000, label: 'Installing packages' });
235
268
  if (pipResult.ok) {
236
269
  ok('Packages installed.');
237
270
  }
@@ -253,7 +286,7 @@ async function ensurePython() {
253
286
  if (installChrome) {
254
287
  log('Installing Chrome for PDF conversion...');
255
288
  const pwResult = await runWithProgress(`${pythonCmd} -m playwright install chrome`, {
256
- timeout: 120_000,
289
+ timeout: 300_000,
257
290
  label: 'Installing Chrome'
258
291
  });
259
292
  if (pwResult.ok) {
@@ -140,6 +140,7 @@ End-to-end verification: agent → HTTP → XLL → Python → COM → Excel.
140
140
 
141
141
  Run via excel_exec:
142
142
  \`\`\`python
143
+ from shortcut_xl import xl_app
143
144
  print(f"Excel {xl_app().Version}")
144
145
  \`\`\`
145
146
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shortcutxl",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/",