geo-new 0.1.0 → 0.1.1

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/cli.js CHANGED
@@ -7311,7 +7311,7 @@ var ApiError = class extends Error {
7311
7311
  };
7312
7312
 
7313
7313
  // packages/geo-new/src/client.ts
7314
- var VERSION = true ? "0.1.0" : "0.0.0-dev";
7314
+ var VERSION = true ? "0.1.1" : "0.0.0-dev";
7315
7315
  var DEFAULT_ORIGIN = "https://geo.new";
7316
7316
  var isLoopback = (url2) => url2.hostname === "localhost" || url2.hostname === "127.0.0.1" || url2.hostname === "[::1]" || url2.hostname === "::1";
7317
7317
  var sleep = (ms, signal) => new Promise((resolve, reject) => {
@@ -7510,7 +7510,7 @@ var GeoNewClient = class {
7510
7510
  snapshot = await this.snapshot(id, { signal: options.signal });
7511
7511
  }
7512
7512
  }
7513
- /** The keyless session token, when the client holds one; the CLI prints it on request, never by default. */
7513
+ /** The last audit this machine started, so a bare `geo-new report` has something to read. */
7514
7514
  get lastAuditId() {
7515
7515
  return this.credentials.load().last_audit_id;
7516
7516
  }
@@ -37127,6 +37127,11 @@ var CreateAuditSchema = external_exports.object({ url: external_exports.string()
37127
37127
  var IssueKeySchema = external_exports.object({
37128
37128
  label: external_exports.string().regex(/^[\x20-\x7e]{1,40}$/).optional()
37129
37129
  }).strict();
37130
+ var AdminPlanSchema = external_exports.object({
37131
+ plan: external_exports.enum(["free", "builder"]),
37132
+ days: external_exports.number().int().min(1).max(365).optional(),
37133
+ reason: external_exports.string().min(1).max(200).optional()
37134
+ }).strict();
37130
37135
  var ClaimSessionSchema = external_exports.object({ key: external_exports.string().min(1).max(128) }).strict();
37131
37136
 
37132
37137
  // src/mcp/summary.ts
@@ -37157,6 +37162,22 @@ function summarize(snapshot, actionLimit = 8) {
37157
37162
  ai: snapshot.ai.status
37158
37163
  };
37159
37164
  }
37165
+ function summarizeComparison(comparison, current = null, changedLimit = 40) {
37166
+ const c = comparison ?? {};
37167
+ const moved = (c.checks ?? []).filter((row) => row.change !== "unchanged"), before = c.baseline?.scores?.catalog?.value ?? null, after = current?.scores.catalog?.value ?? null;
37168
+ return {
37169
+ baseline_id: c.baseline_id ?? null,
37170
+ current_id: c.current_id ?? null,
37171
+ state: c.state ?? "unknown",
37172
+ reason: c.reason ?? null,
37173
+ score_delta: c.score_delta ?? null,
37174
+ score: { before, after, delta: before === null || after === null ? null : after - before },
37175
+ changed: moved.slice(0, changedLimit),
37176
+ changed_omitted: Math.max(0, moved.length - changedLimit),
37177
+ unchanged: (c.checks ?? []).length - moved.length,
37178
+ resolved_actions: c.resolved_actions ?? []
37179
+ };
37180
+ }
37160
37181
 
37161
37182
  // src/mcp/server.ts
37162
37183
  var MAX_WAIT_SECONDS = 45;
@@ -37334,7 +37355,7 @@ function createMcpServer(api, options) {
37334
37355
  "compare_reports",
37335
37356
  {
37336
37357
  title: "Compare two reports",
37337
- description: "Score, category and row deltas between a report and an earlier one of the same URL that you also own.",
37358
+ description: "Score, category and row deltas between a report and an earlier one of the same URL that you also own. The result is the rows that moved and a count of the rest, not the baseline report; read either side with get_report.",
37338
37359
  inputSchema: {
37339
37360
  audit_id: external_exports.string().regex(/^aud_[a-f0-9]{32}$/),
37340
37361
  baseline_id: external_exports.string().regex(/^aud_[a-f0-9]{32}$/)
@@ -37342,7 +37363,11 @@ function createMcpServer(api, options) {
37342
37363
  },
37343
37364
  async ({ audit_id, baseline_id }) => {
37344
37365
  try {
37345
- return text(await api.compare(audit_id, baseline_id));
37366
+ const [comparison, current] = await Promise.all([
37367
+ api.compare(audit_id, baseline_id),
37368
+ api.snapshot(audit_id)
37369
+ ]);
37370
+ return text(summarizeComparison(comparison, current));
37346
37371
  } catch (error61) {
37347
37372
  return failed(error61, { tool: "compare_reports", args: { audit_id, baseline_id } });
37348
37373
  }
@@ -37549,19 +37574,32 @@ var FLAGS = {
37549
37574
  help: false,
37550
37575
  version: false
37551
37576
  };
37552
- var COMMANDS = ["audit", "report", "fix", "share", "compare", "usage", "key", "login", "logout", "mcp"];
37577
+ var COMMANDS = [
37578
+ "audit",
37579
+ "report",
37580
+ "fix",
37581
+ "share",
37582
+ "compare",
37583
+ "usage",
37584
+ "key",
37585
+ "login",
37586
+ "logout",
37587
+ "mcp"
37588
+ ];
37553
37589
  var HELP = `geo-new ${VERSION} \u2014 audit one page for GEO, SEO and agent readiness
37554
37590
 
37555
37591
  npx -y geo-new audit <url> [--fresh] [--json] [--out file] [--wait s] [--wait-for-ai] [--share] [--open]
37556
37592
  [--min-score N] [--allow-unscored]
37557
37593
  geo-new report [audit_id] [--json] [--out file] geo-new fix [audit_id]
37558
- geo-new share [audit_id] [--revoke] geo-new usage [--json]
37559
- geo-new compare <before> <after> [--min-score N] [--allow-drop] [--allow-missing-baseline] [--json]
37594
+ geo-new share [audit_id] [--revoke] [--open] geo-new usage [--json]
37595
+ geo-new compare <before> <after> [--json] [--out file] [--min-score N] [--allow-drop]
37596
+ [--allow-missing-baseline]
37560
37597
  geo-new key create [--label name] | list | revoke <prefix> | set <key>
37561
37598
  geo-new login <key> geo-new logout geo-new mcp geo-new --version
37562
37599
 
37563
37600
  Keyless by default: the first call mints a session and keeps it in your config directory.
37564
37601
  A key (geo-new key create) is the durable identity with a larger allowance; GEO_NEW_API_KEY also works.
37602
+ --out writes JSON, the snapshot compare reads, and leaves stdout empty; the report itself is Markdown.
37565
37603
  Exit codes: 0 done \xB7 1 audit failed \xB7 2 usage \xB7 3 rate limited \xB7 4 auth or ownership \xB7 5 network or server
37566
37604
  6 below --min-score \xB7 7 score dropped \xB7 8 still running when --wait expired \xB7 130 interrupted
37567
37605
  Docs: https://geo.new/docs/api`;
@@ -37606,7 +37644,8 @@ function parseArgs(argv) {
37606
37644
  var integer2 = (value, name, fallback) => {
37607
37645
  if (value === void 0) return fallback;
37608
37646
  const n = Number(value);
37609
- if (!Number.isInteger(n) || n < 0) throw new Exit(EXIT.usage, `--${name} needs a whole number`);
37647
+ if (!Number.isInteger(n) || n < 0)
37648
+ throw new Exit(EXIT.usage, `--${name} needs a whole number of 0 or more`);
37610
37649
  return n;
37611
37650
  };
37612
37651
  function errorLine(error61) {
@@ -37673,7 +37712,7 @@ async function main(argv, deps = {}) {
37673
37712
  if (flags.help || !command) {
37674
37713
  stdout.write(`${HELP}
37675
37714
  `);
37676
- return command ? EXIT.ok : EXIT.usage;
37715
+ return flags.help ? EXIT.ok : EXIT.usage;
37677
37716
  }
37678
37717
  if (!COMMANDS.includes(command)) {
37679
37718
  const hint = nearest(command, COMMANDS);
@@ -37695,9 +37734,10 @@ async function main(argv, deps = {}) {
37695
37734
  } else if (flags.json) stdout.write(JSON.stringify(snapshot, null, 2) + "\n");
37696
37735
  else stdout.write((await client.markdown(snapshot.audit_id)).text);
37697
37736
  };
37737
+ let floor = null;
37698
37738
  const minimum = async (snapshot) => {
37699
- if (flags["min-score"] === void 0) return EXIT.ok;
37700
- const min = integer2(flags["min-score"], "min-score", 0);
37739
+ if (floor === null) return EXIT.ok;
37740
+ const min = floor;
37701
37741
  const value = scoreOf(snapshot);
37702
37742
  if (value === null) {
37703
37743
  if (flags["allow-unscored"]) return EXIT.ok;
@@ -37713,6 +37753,7 @@ async function main(argv, deps = {}) {
37713
37753
  return EXIT.ok;
37714
37754
  };
37715
37755
  try {
37756
+ if (flags["min-score"] !== void 0) floor = integer2(flags["min-score"], "min-score", 0);
37716
37757
  switch (command) {
37717
37758
  case "audit": {
37718
37759
  const url2 = positional[0];
@@ -37725,7 +37766,8 @@ async function main(argv, deps = {}) {
37725
37766
  deps.onAudit?.(envelope.audit_id);
37726
37767
  output2.debug(`admitted ${envelope.audit_id} \xB7 cached ${envelope.cached}`);
37727
37768
  if (waitSeconds === 0) {
37728
- stdout.write(JSON.stringify(envelope) + "\n");
37769
+ const { session: _session, ...admission } = envelope;
37770
+ stdout.write(JSON.stringify(admission) + "\n");
37729
37771
  return EXIT.ok;
37730
37772
  }
37731
37773
  const started = Date.now();
@@ -37754,7 +37796,7 @@ async function main(argv, deps = {}) {
37754
37796
  output2.note(line);
37755
37797
  if (shareUrl && flags.open) openBrowser(shareUrl);
37756
37798
  if (snapshot.status === "failed") return EXIT.failed;
37757
- return minimum(snapshot);
37799
+ return await minimum(snapshot);
37758
37800
  }
37759
37801
  case "report": {
37760
37802
  const snapshot = await client.snapshot(lastId(positional[0]));
@@ -37797,16 +37839,18 @@ async function main(argv, deps = {}) {
37797
37839
  const load = async (v) => isFile(v) ? readSnapshotFile(v) : client.snapshot(v);
37798
37840
  const [baseline, current] = await Promise.all([load(before), load(after)]);
37799
37841
  const comparison = isFile(before) || isFile(after) ? compareReports(current, baseline) : await client.compare(after, before);
37842
+ const from = scoreOf(baseline), to = scoreOf(current);
37843
+ const moved = from !== null && to !== null && to !== from ? ` (${to > from ? "+" : ""}${to - from})` : "";
37844
+ const scoreLine = `score ${from ?? "unmeasured"} \u2192 ${to ?? "unmeasured"}${moved}`;
37800
37845
  if (flags.out) writeFileSync2(String(flags.out), JSON.stringify(comparison, null, 2) + "\n", "utf8");
37801
37846
  else if (flags.json) stdout.write(JSON.stringify(comparison, null, 2) + "\n");
37802
- else stdout.write(comparisonLines(comparison).join("\n") + "\n");
37803
- const from = scoreOf(baseline), to = scoreOf(current);
37804
- output2.note(`score ${from ?? "unmeasured"} \u2192 ${to ?? "unmeasured"}`);
37847
+ else stdout.write([scoreLine, ...comparisonLines(comparison)].join("\n") + "\n");
37848
+ if (flags.out || flags.json) output2.note(scoreLine);
37805
37849
  if (from !== null && to !== null && to < from && !flags["allow-drop"]) {
37806
37850
  output2.line(`score dropped by ${from - to}`);
37807
37851
  return EXIT.dropped;
37808
37852
  }
37809
- return minimum(current);
37853
+ return await minimum(current);
37810
37854
  }
37811
37855
  case "usage": {
37812
37856
  const usage = await client.usage();
@@ -37909,7 +37953,7 @@ interrupted${current ? ` \xB7 the audit continues \xB7 geo-new report ${current}
37909
37953
  (error61) => {
37910
37954
  process.stderr.write(`geo-new: ${error61 instanceof Error ? error61.message : String(error61)}
37911
37955
  `);
37912
- process.exit(EXIT.network);
37956
+ process.exit(error61 instanceof Exit ? error61.code : EXIT.network);
37913
37957
  }
37914
37958
  );
37915
37959
  }
package/dist/client.d.ts CHANGED
@@ -90,7 +90,7 @@ export declare class GeoNewClient implements Api {
90
90
  }>;
91
91
  /** Polls until the report is measured (`writing` or terminal), terminal (`ai`), or the timeout. */
92
92
  waitFor(id: string, options?: WaitOptions): Promise<WaitResult>;
93
- /** The keyless session token, when the client holds one; the CLI prints it on request, never by default. */
93
+ /** The last audit this machine started, so a bare `geo-new report` has something to read. */
94
94
  get lastAuditId(): string | undefined;
95
95
  remember(patch: Partial<{
96
96
  key: string;
package/dist/index.js CHANGED
@@ -107,7 +107,7 @@ var ApiError = class extends Error {
107
107
  };
108
108
 
109
109
  // packages/geo-new/src/client.ts
110
- var VERSION = true ? "0.1.0" : "0.0.0-dev";
110
+ var VERSION = true ? "0.1.1" : "0.0.0-dev";
111
111
  var DEFAULT_ORIGIN = "https://geo.new";
112
112
  var isLoopback = (url) => url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]" || url.hostname === "::1";
113
113
  var sleep = (ms, signal) => new Promise((resolve, reject) => {
@@ -306,7 +306,7 @@ var GeoNewClient = class {
306
306
  snapshot = await this.snapshot(id, { signal: options.signal });
307
307
  }
308
308
  }
309
- /** The keyless session token, when the client holds one; the CLI prints it on request, never by default. */
309
+ /** The last audit this machine started, so a bare `geo-new report` has something to read. */
310
310
  get lastAuditId() {
311
311
  return this.credentials.load().last_audit_id;
312
312
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geo-new",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Audit one page for GEO, SEO and agent readiness from a terminal, a coding agent (MCP) or a script. Keyless by default; a key is optional.",
5
5
  "license": "MIT",
6
6
  "type": "module",