@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 +23 -8
- package/dist/cli.js +138 -7
- package/dist/cli.js.map +1 -1
- package/package.json +22 -19
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
|
|
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
|
|
170
|
+
### SEO/GEO
|
|
171
171
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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.
|
|
196
|
-
|
|
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,
|
|
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,
|
|
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({
|
|
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]
|
|
10577
|
-
const id = positionals[action.
|
|
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 (
|
|
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 = `
|
|
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
|
|
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.
|