aeo-ready 1.3.1 → 1.3.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.3.2
4
+
5
+ - Fix broken `afdocs` fix command — was calling `npx afdocs <url>` instead of `npx afdocs check <url>`
6
+ - Fix shell injection in `promptFix` — switched `execSync` to `execFileSync`
7
+ - Add test suite (`node --test`)
8
+ - Add GitHub Actions CI
9
+
3
10
  ## 1.3.1
4
11
 
5
12
  - Add progress indicator during scan
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aeo-ready",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "AEO benchmark aggregator. One scan, every score. Collects agentic-seo, Cloudflare, and Fern in one report.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,7 +37,6 @@
37
37
  "bin/",
38
38
  "src/benchmark/",
39
39
  "src/history/",
40
- "src/utils/",
41
40
  "src/index.js",
42
41
  "src/scan.js",
43
42
  "skills/",
@@ -1,4 +1,4 @@
1
- import { execSync } from "child_process";
1
+ import { execFileSync } from "child_process";
2
2
  import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from "fs";
3
3
  import { tmpdir } from "os";
4
4
  import { join, dirname } from "path";
@@ -21,7 +21,8 @@ async function fetchText(url) {
21
21
  const res = await fetch(url, { redirect: "follow" });
22
22
  if (!res.ok) return null;
23
23
  return await res.text();
24
- } catch {
24
+ } catch (err) {
25
+ console.warn(`Warning: failed to fetch ${url}: ${err.message}`);
25
26
  return null;
26
27
  }
27
28
  }
@@ -102,7 +103,7 @@ export async function runBenchmark(target) {
102
103
  scanDir = target || ".";
103
104
  }
104
105
 
105
- const output = execSync(`npx agentic-seo ${scanDir} --json`, {
106
+ const output = execFileSync("npx", ["agentic-seo", scanDir, "--json"], {
106
107
  timeout: 60000,
107
108
  encoding: "utf8",
108
109
  stdio: ["pipe", "pipe", "pipe"],
@@ -135,7 +136,11 @@ export async function runBenchmark(target) {
135
136
  if (tempDir) {
136
137
  try {
137
138
  rmSync(tempDir, { recursive: true, force: true });
138
- } catch {}
139
+ } catch (cleanupErr) {
140
+ console.warn(
141
+ `Warning: failed to clean up temp dir ${tempDir}: ${cleanupErr.message}`,
142
+ );
143
+ }
139
144
  }
140
145
  }
141
146
  }
@@ -62,6 +62,9 @@ export async function runCloudflare(url) {
62
62
  available: true,
63
63
  };
64
64
  } catch (err) {
65
+ console.warn(
66
+ `Warning: Cloudflare benchmark failed for ${url}: ${err.message}`,
67
+ );
65
68
  return { available: false, reason: err.message?.slice(0, 100) };
66
69
  }
67
70
  }
@@ -46,6 +46,7 @@ export async function runFern(url) {
46
46
  available: true,
47
47
  };
48
48
  } catch (err) {
49
+ console.warn(`Warning: Fern benchmark failed for ${url}: ${err.message}`);
49
50
  return { available: false, reason: err.message?.slice(0, 100) };
50
51
  }
51
52
  }
package/src/scan.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import { createInterface } from "readline";
3
- import { execSync } from "child_process";
3
+ import { execFileSync } from "child_process";
4
4
  import { runAllBenchmarks, printBenchmarks } from "./benchmark/index.js";
5
5
  import { saveResult } from "./history/index.js";
6
6
 
@@ -100,7 +100,10 @@ function printNextSteps(result) {
100
100
  (c) => c.status === "fail" || c.status === "warn",
101
101
  ) || [];
102
102
  if (fernFails.length > 0) {
103
- steps.push([`npx afdocs ${result.url}`, `${fernFails.length} Fern issues`]);
103
+ steps.push([
104
+ `npx afdocs check ${result.url}`,
105
+ `${fernFails.length} Fern issues`,
106
+ ]);
104
107
  }
105
108
 
106
109
  steps.push([
@@ -138,7 +141,7 @@ async function promptFix(result, dir) {
138
141
 
139
142
  console.log(chalk.dim(` Running: npx agentic-seo init ${targetDir}\n`));
140
143
  try {
141
- execSync(`npx agentic-seo init ${targetDir}`, {
144
+ execFileSync("npx", ["agentic-seo", "init", targetDir], {
142
145
  stdio: "inherit",
143
146
  });
144
147
  } catch (err) {
@@ -150,9 +153,11 @@ async function promptFix(result, dir) {
150
153
  (c) => c.status === "fail" || c.status === "warn",
151
154
  ) || [];
152
155
  if (fernFails.length > 0) {
153
- console.log(chalk.dim(`\n Running: npx afdocs ${result.url}\n`));
156
+ console.log(chalk.dim(`\n Running: npx afdocs check ${result.url}\n`));
154
157
  try {
155
- execSync(`npx afdocs ${result.url}`, { stdio: "inherit" });
158
+ execFileSync("npx", ["afdocs", "check", result.url], {
159
+ stdio: "inherit",
160
+ });
156
161
  } catch (err) {
157
162
  console.log(chalk.red(`\n afdocs failed: ${err.message}\n`));
158
163
  }
@@ -1,42 +0,0 @@
1
- const DEFAULT_TIMEOUT = 10000;
2
- const USER_AGENT = "aeo-ready/1.3 (AEO benchmark aggregator)";
3
-
4
- export async function fetchUrl(url, opts = {}) {
5
- const controller = new AbortController();
6
- const timeout = setTimeout(
7
- () => controller.abort(),
8
- opts.timeout || DEFAULT_TIMEOUT,
9
- );
10
-
11
- try {
12
- const res = await fetch(url, {
13
- signal: controller.signal,
14
- headers: {
15
- "User-Agent": USER_AGENT,
16
- ...opts.headers,
17
- },
18
- redirect: "follow",
19
- });
20
- const text = await res.text();
21
- return {
22
- status: res.status,
23
- text,
24
- headers: Object.fromEntries(res.headers),
25
- };
26
- } catch (err) {
27
- if (err.name === "AbortError") {
28
- return { status: 0, text: "", headers: {}, error: "timeout" };
29
- }
30
- return { status: 0, text: "", headers: {}, error: err.message };
31
- } finally {
32
- clearTimeout(timeout);
33
- }
34
- }
35
-
36
- export function resolveUrl(base, path) {
37
- try {
38
- return new URL(path, base).href;
39
- } catch {
40
- return null;
41
- }
42
- }