clawfire 0.4.2 → 0.4.4

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/dev.js CHANGED
@@ -1457,38 +1457,89 @@ async function checkCli(projectDir) {
1457
1457
  return result;
1458
1458
  }
1459
1459
  async function fetchFirebaseSdkConfig(projectDir) {
1460
- const output = await execWithTimeout(
1461
- "firebase",
1462
- ["apps:sdkconfig", "web", "--json"],
1463
- projectDir,
1464
- 15e3
1465
- );
1466
- const data = JSON.parse(output);
1467
- if (data?.result?.sdkConfig) {
1468
- return data.result.sdkConfig;
1469
- }
1470
- if (data?.result?.fileContents) {
1471
- const contents = data.result.fileContents;
1472
- const config = {};
1473
- const extract = (key) => {
1474
- const match = contents.match(new RegExp(`"${key}"\\s*:\\s*"([^"]+)"`));
1475
- return match ? match[1] : void 0;
1476
- };
1477
- config.apiKey = extract("apiKey");
1478
- config.authDomain = extract("authDomain");
1479
- config.projectId = extract("projectId");
1480
- config.storageBucket = extract("storageBucket");
1481
- config.messagingSenderId = extract("messagingSenderId");
1482
- config.appId = extract("appId");
1483
- return config;
1460
+ try {
1461
+ const output = await execWithTimeout(
1462
+ "firebase",
1463
+ ["apps:sdkconfig", "web", "--json"],
1464
+ projectDir,
1465
+ 15e3
1466
+ );
1467
+ const config = parseSdkConfigOutput(output);
1468
+ if (config) return config;
1469
+ } catch {
1470
+ }
1471
+ let webApps = [];
1472
+ try {
1473
+ const appsOutput = await execWithTimeout(
1474
+ "firebase",
1475
+ ["apps:list", "--json"],
1476
+ projectDir,
1477
+ 15e3
1478
+ );
1479
+ const appsData = JSON.parse(appsOutput);
1480
+ const allApps = appsData?.result || [];
1481
+ webApps = allApps.filter((a) => a.platform === "WEB").map((a) => ({
1482
+ appId: String(a.appId || ""),
1483
+ displayName: String(a.displayName || "")
1484
+ })).filter((a) => a.appId);
1485
+ } catch {
1486
+ throw new Error(
1487
+ "Failed to fetch Firebase SDK config. Make sure you are logged in and have an active project selected."
1488
+ );
1489
+ }
1490
+ if (webApps.length === 0) {
1491
+ throw new Error(
1492
+ "No web app registered in this Firebase project. Go to Firebase Console > Project Settings > General > Your apps > Add app (Web) to create one, then click Auto-fill again."
1493
+ );
1494
+ }
1495
+ const appId = webApps[0].appId;
1496
+ try {
1497
+ const output = await execWithTimeout(
1498
+ "firebase",
1499
+ ["apps:sdkconfig", "web", appId, "--json"],
1500
+ projectDir,
1501
+ 15e3
1502
+ );
1503
+ const config = parseSdkConfigOutput(output);
1504
+ if (config) return config;
1505
+ } catch (err) {
1506
+ const msg = err instanceof Error ? err.message : "Unknown error";
1507
+ throw new Error(`Failed to fetch config for web app ${appId}: ${msg}`);
1484
1508
  }
1485
1509
  throw new Error("Could not parse Firebase SDK config from CLI output");
1486
1510
  }
1511
+ function parseSdkConfigOutput(output) {
1512
+ try {
1513
+ const data = JSON.parse(output);
1514
+ if (data?.result?.sdkConfig) {
1515
+ return data.result.sdkConfig;
1516
+ }
1517
+ if (data?.result?.fileContents) {
1518
+ const contents = data.result.fileContents;
1519
+ const config = {};
1520
+ const extract = (key) => {
1521
+ const match = contents.match(new RegExp(`"${key}"\\s*:\\s*"([^"]+)"`));
1522
+ return match ? match[1] : void 0;
1523
+ };
1524
+ config.apiKey = extract("apiKey");
1525
+ config.authDomain = extract("authDomain");
1526
+ config.projectId = extract("projectId");
1527
+ config.storageBucket = extract("storageBucket");
1528
+ config.messagingSenderId = extract("messagingSenderId");
1529
+ config.appId = extract("appId");
1530
+ if (config.apiKey || config.projectId) return config;
1531
+ }
1532
+ } catch {
1533
+ }
1534
+ return null;
1535
+ }
1487
1536
  function execWithTimeout(command, args, cwd, timeoutMs) {
1488
1537
  return new Promise((resolve7, reject) => {
1489
- const proc = execFile(command, args, { cwd, timeout: timeoutMs }, (err, stdout) => {
1538
+ const proc = execFile(command, args, { cwd, timeout: timeoutMs }, (err, stdout, stderr) => {
1490
1539
  if (err) {
1491
- reject(err);
1540
+ const detail = stderr?.trim() || stdout?.trim() || "";
1541
+ const enriched = new Error(`${err.message}${detail ? "\n" + detail : ""}`);
1542
+ reject(enriched);
1492
1543
  } else {
1493
1544
  resolve7(stdout);
1494
1545
  }
@@ -1787,6 +1838,9 @@ function generateDashboardHtml(options) {
1787
1838
  document.getElementById('step-' + i).style.display = 'none';
1788
1839
  }
1789
1840
  document.getElementById('setup-done').style.display = 'none';
1841
+ // Reset login UI state from previous interactions
1842
+ document.getElementById('login-waiting').style.display = 'none';
1843
+ document.getElementById('login-result').style.display = 'none';
1790
1844
 
1791
1845
  if (status.nextStep === 'done') {
1792
1846
  // All done!
@@ -1950,7 +2004,12 @@ function generateDashboardHtml(options) {
1950
2004
  var result = document.getElementById('login-result');
1951
2005
  result.textContent = 'Login successful! Logged in as ' + status.auth.user;
1952
2006
  result.style.cssText = 'display:block;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;background:#0a1a0a;border:1px solid #22c55e;color:#22c55e;';
1953
- setTimeout(refreshSetupStatus, 1500);
2007
+ // Wait for token to fully settle, then refresh wizard + force-load projects
2008
+ setTimeout(function() {
2009
+ refreshSetupStatus();
2010
+ // Extra delay for project list \u2014 Firebase CLI needs time after fresh login
2011
+ setTimeout(function() { loadProjectList(''); }, 2500);
2012
+ }, 2000);
1954
2013
  }
1955
2014
  })
1956
2015
  .catch(function() {});
@@ -1958,7 +2017,8 @@ function generateDashboardHtml(options) {
1958
2017
  }
1959
2018
 
1960
2019
  // \u2500\u2500\u2500 Step 3: Project Selection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1961
- function loadProjectList(currentProjectId) {
2020
+ function loadProjectList(currentProjectId, retryCount) {
2021
+ retryCount = retryCount || 0;
1962
2022
  var select = document.getElementById('project-select');
1963
2023
  select.innerHTML = '<option value="">Loading projects...</option>';
1964
2024
  select.disabled = true;
@@ -1968,10 +2028,21 @@ function generateDashboardHtml(options) {
1968
2028
  .then(function(data) {
1969
2029
  select.innerHTML = '';
1970
2030
  if (data.error) {
2031
+ // Auto-retry up to 2 times on error (token might not be ready yet after fresh login)
2032
+ if (retryCount < 2) {
2033
+ select.innerHTML = '<option value="">Loading projects... (retry)</option>';
2034
+ setTimeout(function() { loadProjectList(currentProjectId, retryCount + 1); }, 3000);
2035
+ return;
2036
+ }
1971
2037
  select.innerHTML = '<option value="">Error: ' + escHtml(data.error) + '</option>';
1972
2038
  return;
1973
2039
  }
1974
2040
  if (!data.projects || data.projects.length === 0) {
2041
+ if (retryCount < 2) {
2042
+ select.innerHTML = '<option value="">Loading projects... (retry)</option>';
2043
+ setTimeout(function() { loadProjectList(currentProjectId, retryCount + 1); }, 3000);
2044
+ return;
2045
+ }
1975
2046
  select.innerHTML = '<option value="">No projects found</option>';
1976
2047
  return;
1977
2048
  }
@@ -1987,6 +2058,11 @@ function generateDashboardHtml(options) {
1987
2058
  select.disabled = false;
1988
2059
  })
1989
2060
  .catch(function(err) {
2061
+ if (retryCount < 2) {
2062
+ select.innerHTML = '<option value="">Loading projects... (retry)</option>';
2063
+ setTimeout(function() { loadProjectList(currentProjectId, retryCount + 1); }, 3000);
2064
+ return;
2065
+ }
1990
2066
  select.innerHTML = '<option value="">Failed to load</option>';
1991
2067
  });
1992
2068
  }
@@ -2212,7 +2288,12 @@ function generateDashboardHtml(options) {
2212
2288
  if (wizStatus) wizStatus.style.display = 'none';
2213
2289
 
2214
2290
  fetch(API + '/__dev/firebase-sdk-config')
2215
- .then(function(r) { return r.json(); })
2291
+ .then(function(r) {
2292
+ if (!r.ok) {
2293
+ return r.json().catch(function() { return { error: 'Server error (' + r.status + ')' }; });
2294
+ }
2295
+ return r.json();
2296
+ })
2216
2297
  .then(function(data) {
2217
2298
  if (data.error) {
2218
2299
  showAutoFillResult(false, data.error);
@@ -2528,13 +2609,16 @@ var FirebaseSetup = class {
2528
2609
  `cd "${this.projectDir}"`,
2529
2610
  cmd,
2530
2611
  'echo ""',
2531
- 'echo "Login complete! You can close this window."',
2532
- 'read -p "Press Enter to close..."'
2612
+ 'echo "Login complete! Closing in 3 seconds..."',
2613
+ "sleep 3",
2614
+ // Spawn osascript in background to close this specific terminal window, then exit
2615
+ `(sleep 1 && osascript -e 'tell application "Terminal" to close (every window whose name contains "clawfire-firebase-login")' 2>/dev/null) &`,
2616
+ "exit 0"
2533
2617
  ].join("\n"), { mode: 493 });
2534
2618
  const child = spawn("open", [scriptPath], { detached: true, stdio: "ignore" });
2535
2619
  child.unref();
2536
2620
  } else if (os === "win32") {
2537
- const child = spawn("cmd", ["/c", "start", "cmd", "/k", cmd], {
2621
+ const child = spawn("cmd", ["/c", "start", "cmd", "/c", `${cmd} && timeout /t 3 >nul`], {
2538
2622
  cwd: this.projectDir,
2539
2623
  detached: true,
2540
2624
  stdio: "ignore"
@@ -2547,8 +2631,9 @@ var FirebaseSetup = class {
2547
2631
  `cd "${this.projectDir}"`,
2548
2632
  cmd,
2549
2633
  'echo ""',
2550
- 'echo "Login complete! You can close this window."',
2551
- 'read -p "Press Enter to close..."'
2634
+ 'echo "Login complete! Closing in 3 seconds..."',
2635
+ "sleep 3",
2636
+ "exit 0"
2552
2637
  ].join("\n"), { mode: 493 });
2553
2638
  const terminals = [
2554
2639
  { cmd: "x-terminal-emulator", args: ["-e", scriptPath] },