@siteoshq/cli 1.11.0 → 1.13.0

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
@@ -1,7 +1,7 @@
1
1
  # SiteOS CLI
2
2
 
3
3
  `@siteoshq/cli` exposes one `siteos` binary for Auth, common Projects, Pulse, Cookie, Forms,
4
- Search, Trace, SEO and Integrations. This source prepares version 1.11.0; publishing is a separate release.
4
+ Search, Trace, SEO/GEO and Integrations. This source is version 1.13.0; source changes require a separate release to reach npm.
5
5
  Node.js 22 or newer is required.
6
6
 
7
7
  ## Install and authenticate
@@ -167,11 +167,17 @@ snippet is unavailable until runtime publication succeeds. Integrations connecti
167
167
  Organization; provider authorization opens the shared browser flow, and notification destinations
168
168
  are connected explicitly by each service.
169
169
 
170
- ### SEO (prepared for release)
170
+ ### SEO/GEO
171
171
 
172
- Check `siteos seo --help` before use; install a matching release only after it is published. An
173
- SEO-capable server returns SEO in its Project service catalog, which older strict CLI parsers may
174
- reject. Coordinate the CLI update before that server rollout, then publish the matching plugin.
172
+ The application calls this service **SEO/GEO**; its command and Project service key remain `seo`.
173
+ GEO means generative engine optimization, including technical AI-search accessibility and
174
+ AI mentions/citations. Check `siteos seo --help` against the installed CLI and server version.
175
+
176
+ Site Audit checks public HTML, canonical, robots.txt, sitemaps, snippets and basic structured data.
177
+ Its crawler-policy checks do not prove access from actual provider IPs. Performance adds
178
+ selected-page Lighthouse and response/rendered HTML comparisons. Brand lookup and Prompt checks
179
+ provide separate AI visibility evidence. No autonomous agent journey or target API/MCP audit is
180
+ performed by these commands, and no result guarantees AI inclusion or a universal AI rank.
175
181
 
176
182
  ```sh
177
183
  siteos project connect seo --json
@@ -192,13 +198,17 @@ observed URL. Read the returned audit ID until a terminal state; a queued respon
192
198
  `issue ignore` and `issue restore` require `--audit`, `--url`, `--rule`, `--reason` and the current
193
199
  `--revision` (0 before the first decision). They use a distinct issue-write scope. Read back the
194
200
  decision after success; a revision conflict requires refreshing it. Ignore never means resolved.
195
- All SEO commands resolve the selected common Project and explicit environment binding. Current
196
- The source CLI also supports SEO research and GSC Insights with a matching server release:
201
+ All SEO/GEO commands resolve the selected common Project and explicit environment binding.
202
+ Research and GSC Insights use these commands with a matching server release:
197
203
 
198
204
  ```sh
199
205
  siteos seo research summary --json
200
206
  siteos seo research history --kind keywords --json
201
207
  siteos seo research show <run-id> --json
208
+ siteos seo research serp show <run-id> --keyword "website analytics" --json
209
+ siteos seo research serp ensure <run-id> --keyword "website analytics" --json
210
+ siteos seo research serp wait <run-id> --keyword "website analytics" --json
211
+ siteos seo research serp export <run-id> --keyword "website analytics" --format json --output ./serp-report.json --json
202
212
  siteos seo research plan --input ./research-request.json --json
203
213
  siteos seo research run --input ./research-request.json --idempotency-key <retry-key> --json
204
214
  siteos seo research wait <run-id> --json
@@ -209,7 +219,12 @@ siteos seo gsc export --dataset queries --format csv --output ./gsc-queries.csv
209
219
  ```
210
220
 
211
221
  Run `siteos seo --help` for request JSON, limits, saved inputs, cancellation and GSC settings.
212
- Research supports keywords, rankings, competitors, backlinks, brand and AI visibility without GSC.
222
+ Research supports keywords, Domain Overview (`domain`), rankings, backlinks, brand and AI visibility without GSC.
223
+ Domain Overview collects domain totals, up to 100 ranking keywords, pages and competitors for a market.
224
+ `--kind domain` includes legacy `competitors` history; existing `competitors` inputs keep their original two-part plan.
225
+ New request example: `{"kind":"domain","target":"example.com","country":"US","language":"en"}`.
226
+ SERP `ensure` collects at most one saved snapshot per returned keyword and Keyword Research report. Repeat calls reuse the saved job, including failures. SERP show/wait/export only read; market and device come from the parent report.
227
+
213
228
  Reading/planning/saving spends no research credits. Launch uses Organization credits and the same
214
229
  server admission as the interface. Keep the retry key after an uncertain response; no paid retries
215
230
  are automatic. Wait exit 3 means pending; exit 4 failed/cancelled. Partial evidence remains readable.
package/dist/cli.js CHANGED
@@ -10516,17 +10516,24 @@ var RESEARCH_HELP = `
10516
10516
  siteos seo research wait <run-id> [--timeout <seconds>] [--environment <slug>] [--json]
10517
10517
  siteos seo research cancel <run-id> [--environment <slug>] [--json]
10518
10518
  siteos seo research export <run-id> --format <json|csv> --output <new-file> [--environment <slug>] [--json]
10519
+ siteos seo research serp show <run-id> --keyword <word> [--environment <slug>] [--json]
10520
+ siteos seo research serp ensure <run-id> --keyword <word> [--environment <slug>] [--json]
10521
+ siteos seo research serp wait <run-id> --keyword <word> [--timeout <seconds>] [--environment <slug>] [--json]
10522
+ siteos seo research serp export <run-id> --keyword <word> --format <json|csv> --output <new-file> [--environment <slug>] [--json]
10519
10523
  siteos seo research saved list --kind <kind> [--environment <slug>] [--json]
10520
10524
  siteos seo research saved save --input <request.json> --name <name> [--id <saved-id>] [--environment <slug>] [--json]
10521
10525
  siteos seo research saved remove <saved-id> [--environment <slug>] [--json]
10522
10526
 
10523
- Research kinds: keywords, rankings, competitors, backlinks, brand, ai-visibility.
10527
+ Research kinds: keywords, domain, rankings, backlinks, brand, ai-visibility.
10528
+ Domain Overview: {"kind":"domain","target":"example.com","country":"US","language":"en"}.
10529
+ Domain collects summary, ranking keywords, top pages and competitors. The legacy competitors kind retains its two-part plan; domain history includes those reports.
10524
10530
  Request JSON: {"kind":"keywords","target":"example.com","keywords":["website analytics"],"country":"US","language":"en"}.
10525
10531
  Rankings accepts up to 10 keywords and 5 competitors. AI visibility requires brand, prompt and platforms.
10526
10532
  Markets: US, GB, ES, DE, FR, CA, AU. Languages: en, es, de, fr, pt, it, nl, ru.
10527
10533
  Platforms: chat_gpt, claude, gemini, perplexity. Brand lookup uses brandPlatform chat_gpt|google and brandMatch domain|brand.
10528
10534
  Plan validates the request and shows planned parts and available research credits without enqueueing work.
10529
10535
  Run consumes Organization research credits through the same worker as the interface. Preserve the retry key after an uncertain response.
10536
+ SERP ensure collects one saved organic snapshot for a keyword returned by the selected completed Keyword Research report. It uses research credits once; repeating the same report/word returns the saved job, including failures. Show/wait/export only read and never spend. New reports can collect fresh snapshots.
10530
10537
  History returns the latest 30 checks per kind; show/export can address older retained run IDs. Saved checks are limited to 100 per resource.
10531
10538
  Wait defaults to 120 seconds (maximum 900); exit 3 means still pending, exit 4 means failed or cancelled. Partial evidence stays accessible.
10532
10539
  Exports preserve scope, dates and partial state. CSV stores one dataset row as JSON per row, including failed parts; it never converts missing metrics to zero.
@@ -10539,7 +10546,10 @@ var kinds = [
10539
10546
  "brand",
10540
10547
  "ai-visibility"
10541
10548
  ];
10542
- var requestSchema = z19.object({ kind: z19.enum(kinds), target: z19.string().min(1).max(253) }).passthrough();
10549
+ var requestSchema = z19.object({
10550
+ kind: z19.enum(["domain", ...kinds]).transform((kind) => kind === "domain" ? "competitors" : kind),
10551
+ target: z19.string().min(1).max(253)
10552
+ }).passthrough();
10543
10553
  var runStates = z19.enum([
10544
10554
  "queued",
10545
10555
  "running",
@@ -10564,6 +10574,7 @@ async function runSeoResearchCommand(options) {
10564
10574
  json: { type: "boolean" },
10565
10575
  environment: { type: "string" },
10566
10576
  kind: { type: "string" },
10577
+ keyword: { type: "string" },
10567
10578
  input: { type: "string" },
10568
10579
  name: { type: "string" },
10569
10580
  id: { type: "string" },
@@ -10573,9 +10584,13 @@ async function runSeoResearchCommand(options) {
10573
10584
  output: { type: "string" }
10574
10585
  }
10575
10586
  });
10576
- const action = positionals[0] === "saved" ? positionals.slice(0, 2).join(" ") : positionals[0] ?? "";
10577
- const id = positionals[action.startsWith("saved ") ? 2 : 1];
10587
+ const action = ["saved", "serp"].includes(positionals[0] ?? "") ? positionals.slice(0, 2).join(" ") : positionals[0] ?? "";
10588
+ const id = positionals[action.includes(" ") ? 2 : 1];
10578
10589
  const operations = {
10590
+ "serp show": { args: 3, flags: ["keyword"] },
10591
+ "serp ensure": { args: 3, flags: ["keyword"] },
10592
+ "serp wait": { args: 3, flags: ["keyword", "timeout"] },
10593
+ "serp export": { args: 3, flags: ["keyword", "format", "output"] },
10579
10594
  summary: { args: 1, flags: [] },
10580
10595
  status: { args: 1, flags: ["kind"] },
10581
10596
  history: { args: 1, flags: ["kind"] },
@@ -10596,6 +10611,11 @@ async function runSeoResearchCommand(options) {
10596
10611
  throw new Error(
10597
10612
  "Invalid research operation or flags. Run siteos seo --help."
10598
10613
  );
10614
+ if (action.startsWith("serp ") && (!values.keyword?.trim() || values.keyword.length > 200))
10615
+ throw new Error(
10616
+ "Provide --keyword with 1 to 200 characters from the selected keyword report."
10617
+ );
10618
+ if (values.kind === "domain") values.kind = "competitors";
10599
10619
  if (operation.flags.includes("kind") && !kinds.includes(values.kind))
10600
10620
  throw new Error("Choose a documented --kind.");
10601
10621
  if (operation.flags.includes("input") && !values.input)
@@ -10607,7 +10627,7 @@ async function runSeoResearchCommand(options) {
10607
10627
  const timeout = Number(values.timeout ?? 120);
10608
10628
  if (!Number.isInteger(timeout) || timeout < 1 || timeout > 900)
10609
10629
  throw new Error("Use a wait timeout between 1 and 900 seconds.");
10610
- if (action === "export" && (!values.output || !["json", "csv"].includes(values.format ?? "")))
10630
+ if (["export", "serp export"].includes(action) && (!values.output || !["json", "csv"].includes(values.format ?? "")))
10611
10631
  throw new Error(
10612
10632
  "Export requires --format json|csv and --output for a new file."
10613
10633
  );
@@ -10659,6 +10679,109 @@ async function runSeoResearchCommand(options) {
10659
10679
  );
10660
10680
  const query = `?kind=${encodeURIComponent(values.kind ?? "rankings")}`;
10661
10681
  let record;
10682
+ if (action.startsWith("serp ")) {
10683
+ const snapshotSchema = z19.object({
10684
+ id: z19.string(),
10685
+ organizationId: z19.literal(client.organizationId),
10686
+ resourceId: z19.literal(client.resourceId),
10687
+ sourceRunId: z19.literal(id),
10688
+ request: requestSchema,
10689
+ keywordKey: z19.literal(
10690
+ values.keyword.normalize("NFKC").trim().toLowerCase().replace(/\s+/gu, " ")
10691
+ ),
10692
+ state: z19.enum([
10693
+ "queued",
10694
+ "running",
10695
+ "completed",
10696
+ "failed",
10697
+ "cancelled"
10698
+ ]),
10699
+ dataset: z19.object({
10700
+ type: z19.literal("serp"),
10701
+ keyword: z19.string(),
10702
+ country: z19.string(),
10703
+ language: z19.string(),
10704
+ device: z19.enum(["desktop", "mobile"]),
10705
+ observedAt: z19.string(),
10706
+ rows: z19.array(
10707
+ z19.object({
10708
+ position: z19.number(),
10709
+ title: z19.string(),
10710
+ url: z19.string(),
10711
+ domain: z19.string(),
10712
+ description: z19.string()
10713
+ })
10714
+ )
10715
+ }).nullable()
10716
+ }).passthrough();
10717
+ const suffix = `/runs/${encodeURIComponent(id)}/serp`;
10718
+ const read = () => get(`${suffix}?keyword=${encodeURIComponent(values.keyword)}`);
10719
+ record = action === "serp ensure" ? await get(suffix, "run", { keyword: values.keyword }) : await read();
10720
+ const deadline = Date.now() + timeout * 1e3;
10721
+ let snapshot = record.serp == null ? null : snapshotSchema.parse(record.serp);
10722
+ if (action === "serp ensure" && !snapshot)
10723
+ throw new Error(
10724
+ "The server did not return the admitted SERP snapshot."
10725
+ );
10726
+ while (action === "serp wait" && snapshot && ["queued", "running"].includes(snapshot.state)) {
10727
+ if (Date.now() >= deadline)
10728
+ return {
10729
+ exitCode: 3,
10730
+ stdout: JSON.stringify({ ...record, timedOut: true }, null, 2)
10731
+ };
10732
+ await setTimeout2(Math.min(2e3, Math.max(0, deadline - Date.now())));
10733
+ record = await read();
10734
+ snapshot = record.serp == null ? null : snapshotSchema.parse(record.serp);
10735
+ }
10736
+ if (action === "serp export") {
10737
+ if (!snapshot)
10738
+ throw new Error("No saved SERP exists for this report and keyword.");
10739
+ const data = snapshot.dataset;
10740
+ const content = values.format === "json" ? JSON.stringify(record, null, 2) : [
10741
+ [
10742
+ "report_id",
10743
+ "keyword",
10744
+ "country",
10745
+ "language",
10746
+ "device",
10747
+ "state",
10748
+ "observed_at",
10749
+ "error",
10750
+ "position",
10751
+ "title",
10752
+ "url",
10753
+ "description"
10754
+ ],
10755
+ ...(data?.rows.length ? data.rows : [null]).map((row) => [
10756
+ id,
10757
+ values.keyword,
10758
+ data?.country,
10759
+ data?.language,
10760
+ data?.device,
10761
+ snapshot.state,
10762
+ data?.observedAt,
10763
+ snapshot.error,
10764
+ row?.position,
10765
+ row?.title,
10766
+ row?.url,
10767
+ row?.description
10768
+ ])
10769
+ ].map((row) => row.map(csvCell).join(",")).join("\r\n");
10770
+ const output = await writeSeoReport(options, values.output, content);
10771
+ record = {
10772
+ contractVersion: 1,
10773
+ runId: id,
10774
+ keyword: values.keyword,
10775
+ state: snapshot.state,
10776
+ format: values.format,
10777
+ output
10778
+ };
10779
+ }
10780
+ return {
10781
+ exitCode: action === "serp wait" && (!snapshot || ["failed", "cancelled"].includes(snapshot.state)) ? 4 : 0,
10782
+ stdout: JSON.stringify(record, null, 2)
10783
+ };
10784
+ }
10662
10785
  if (action === "plan" || action === "run" || action === "saved save") {
10663
10786
  const plan = await get("/plan", "read", input);
10664
10787
  resourceSchema.parse(plan.resource);
@@ -11273,7 +11396,15 @@ async function runSeoPerformanceCommand(options) {
11273
11396
  }
11274
11397
 
11275
11398
  // src/services/seo-command.ts
11276
- var SEO_HELP = `Audit SEO and work with search and AI research in the selected Project environment.
11399
+ var SEO_HELP = `SEO/GEO: audit your website and research search-engine and AI visibility in the selected Project environment.
11400
+
11401
+ Site Audit checks public HTML, canonical, robots.txt, sitemap and technical GEO signals.
11402
+ Performance measures selected pages with Lighthouse and compares response/rendered HTML.
11403
+ Research covers keywords, rankings, competitors, backlinks, Brand lookup and Prompt checks.
11404
+ GSC Insights reads your connected property's Google Search Console data; other research needs no GSC.
11405
+ Technical GEO checks crawler policies, content, snippets and structured-data syntax/shape.
11406
+ These checks do not measure autonomous agent journeys or guarantee AI inclusion or citations.
11407
+ The service is named SEO/GEO in the application; its command remains siteos seo.
11277
11408
 
11278
11409
  Usage:
11279
11410
  siteos seo status [--environment <slug>] [--json]
@@ -11820,7 +11951,7 @@ Commands:
11820
11951
  cookie Configure, publish, and inspect the Project\u2019s cookie banner.
11821
11952
  trace Configure analytics observation and inspect evidence.
11822
11953
  analytics Configure website Analytics, events and realtime reports.
11823
- seo Audit HTML, inspect changes and verify fixes.
11954
+ seo SEO/GEO audits, keyword research and AI visibility reports.
11824
11955
  integrations Manage Organization connections and destinations.
11825
11956
  pulse Manage monitoring checks, tests, and deployments.
11826
11957
  search Run SiteOS search operations for a project environment.