@ainyc/canonry 4.72.4 → 4.75.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.
Files changed (30) hide show
  1. package/README.md +1 -1
  2. package/assets/agent-workspace/skills/aero/references/orchestration.md +1 -1
  3. package/assets/agent-workspace/skills/canonry/SKILL.md +1 -1
  4. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +17 -0
  5. package/assets/assets/{BacklinksPage-CjfpwZEH.js → BacklinksPage-CwAplOLo.js} +1 -1
  6. package/assets/assets/{ChartPrimitives-Ckf2FrUy.js → ChartPrimitives-EGp5HFxn.js} +1 -1
  7. package/assets/assets/ProjectPage-C-zhkBKK.js +6 -0
  8. package/assets/assets/{RunRow-BuFyG0V_.js → RunRow-YFN2PwH-.js} +1 -1
  9. package/assets/assets/{RunsPage-D-pr000K.js → RunsPage-DlKS8zaS.js} +1 -1
  10. package/assets/assets/{SettingsPage-CiaapCYn.js → SettingsPage-Q0OZKjMD.js} +1 -1
  11. package/assets/assets/{TrafficPage-B40xytJD.js → TrafficPage-BbySUnhy.js} +1 -1
  12. package/assets/assets/{TrafficSourceDetailPage-7hHem-gM.js → TrafficSourceDetailPage-BGzuvTYp.js} +1 -1
  13. package/assets/assets/{extract-error-message-3GkDsu1h.js → extract-error-message-Czt2jFxA.js} +1 -1
  14. package/assets/assets/index-CFVX11lK.css +1 -0
  15. package/assets/assets/{index-BVdH2O9w.js → index-DYsYdWV8.js} +118 -118
  16. package/assets/assets/{server-traffic-CsgPsudZ.js → server-traffic-BzIFKqGS.js} +1 -1
  17. package/assets/assets/{trash-2-B8Ipf9rI.js → trash-2-DKCkbZUb.js} +1 -1
  18. package/assets/index.html +2 -2
  19. package/dist/{chunk-JXFNERK4.js → chunk-JNAKRK77.js} +1103 -998
  20. package/dist/{chunk-HOKVBMOD.js → chunk-JUWU2DV6.js} +402 -81
  21. package/dist/{chunk-SRBO33HB.js → chunk-QY5WZWU4.js} +403 -202
  22. package/dist/{chunk-ZUBBADMR.js → chunk-WFMEK34V.js} +162 -1
  23. package/dist/cli.js +237 -31
  24. package/dist/index.d.ts +10 -0
  25. package/dist/index.js +4 -4
  26. package/dist/{intelligence-service-CSW4R4I7.js → intelligence-service-L2A5MFB4.js} +2 -2
  27. package/dist/mcp.js +2 -2
  28. package/package.json +10 -10
  29. package/assets/assets/ProjectPage-DZeplYeC.js +0 -6
  30. package/assets/assets/index-B3nENtU0.css +0 -1
@@ -22,7 +22,7 @@ import {
22
22
  trafficConnectVercelRequestSchema,
23
23
  trafficConnectWordpressRequestSchema,
24
24
  trafficEventKindSchema
25
- } from "./chunk-JXFNERK4.js";
25
+ } from "./chunk-JNAKRK77.js";
26
26
 
27
27
  // src/config.ts
28
28
  import fs from "fs";
@@ -3345,6 +3345,58 @@ var postApiV1ProjectsByNameDiscoverSessionsByIdPromote = (options) => {
3345
3345
  }
3346
3346
  });
3347
3347
  };
3348
+ var getApiV1ProjectsByNameTechnicalAeo = (options) => {
3349
+ return (options.client ?? client).get({
3350
+ security: [
3351
+ {
3352
+ scheme: "bearer",
3353
+ type: "http"
3354
+ }
3355
+ ],
3356
+ url: "/api/v1/projects/{name}/technical-aeo",
3357
+ ...options
3358
+ });
3359
+ };
3360
+ var getApiV1ProjectsByNameTechnicalAeoPages = (options) => {
3361
+ return (options.client ?? client).get({
3362
+ security: [
3363
+ {
3364
+ scheme: "bearer",
3365
+ type: "http"
3366
+ }
3367
+ ],
3368
+ url: "/api/v1/projects/{name}/technical-aeo/pages",
3369
+ ...options
3370
+ });
3371
+ };
3372
+ var getApiV1ProjectsByNameTechnicalAeoTrend = (options) => {
3373
+ return (options.client ?? client).get({
3374
+ security: [
3375
+ {
3376
+ scheme: "bearer",
3377
+ type: "http"
3378
+ }
3379
+ ],
3380
+ url: "/api/v1/projects/{name}/technical-aeo/trend",
3381
+ ...options
3382
+ });
3383
+ };
3384
+ var postApiV1ProjectsByNameTechnicalAeoRuns = (options) => {
3385
+ return (options.client ?? client).post({
3386
+ security: [
3387
+ {
3388
+ scheme: "bearer",
3389
+ type: "http"
3390
+ }
3391
+ ],
3392
+ url: "/api/v1/projects/{name}/technical-aeo/runs",
3393
+ ...options,
3394
+ headers: {
3395
+ "Content-Type": "application/json",
3396
+ ...options.headers
3397
+ }
3398
+ });
3399
+ };
3348
3400
  var deleteApiV1ProjectsByNameAgentTranscript = (options) => {
3349
3401
  return (options.client ?? client).delete({
3350
3402
  security: [
@@ -4539,6 +4591,44 @@ var ApiClient = class {
4539
4591
  })
4540
4592
  );
4541
4593
  }
4594
+ // ── Technical AEO (site-audit) ──────────────────────────────────────────
4595
+ async getTechnicalAeoScore(project) {
4596
+ return this.invoke(
4597
+ () => getApiV1ProjectsByNameTechnicalAeo({ client: this.heyClient, path: { name: project } })
4598
+ );
4599
+ }
4600
+ async getTechnicalAeoPages(project, opts) {
4601
+ return this.invoke(
4602
+ () => getApiV1ProjectsByNameTechnicalAeoPages({
4603
+ client: this.heyClient,
4604
+ path: { name: project },
4605
+ query: {
4606
+ status: opts?.status,
4607
+ sort: opts?.sort,
4608
+ limit: opts?.limit !== void 0 ? String(opts.limit) : void 0,
4609
+ offset: opts?.offset !== void 0 ? String(opts.offset) : void 0
4610
+ }
4611
+ })
4612
+ );
4613
+ }
4614
+ async getTechnicalAeoTrend(project, opts) {
4615
+ return this.invoke(
4616
+ () => getApiV1ProjectsByNameTechnicalAeoTrend({
4617
+ client: this.heyClient,
4618
+ path: { name: project },
4619
+ query: { limit: opts?.limit !== void 0 ? String(opts.limit) : void 0 }
4620
+ })
4621
+ );
4622
+ }
4623
+ async triggerSiteAudit(project, body) {
4624
+ return this.invoke(
4625
+ () => postApiV1ProjectsByNameTechnicalAeoRuns({
4626
+ client: this.heyClient,
4627
+ path: { name: project },
4628
+ body: body ?? {}
4629
+ })
4630
+ );
4631
+ }
4542
4632
  // ── WordPress ──────────────────────────────────────────────────────────
4543
4633
  async wordpressConnect(project, body) {
4544
4634
  return this.invoke(
@@ -5190,6 +5280,25 @@ var discoveryPromoteInputSchema = z2.object({
5190
5280
  competitorTypes: z2.array(discoveryCompetitorTypeSchema).min(1).optional().describe("Which classified competitor types to merge. Omitted promotes direct-competitor only; pass an explicit list to also adopt editorial-media channels or to recover legacy unknown entries. Ignored when includeCompetitors is false.")
5191
5281
  }).optional()
5192
5282
  });
5283
+ var technicalAeoScoreInputSchema = z2.object({
5284
+ project: projectNameSchema
5285
+ });
5286
+ var technicalAeoPagesInputSchema = z2.object({
5287
+ project: projectNameSchema,
5288
+ status: z2.enum(["success", "error"]).optional().describe("Filter to successfully-audited or errored pages."),
5289
+ sort: z2.enum(["score-asc", "score-desc", "url"]).optional().describe("Sort order. Defaults to score-asc (worst pages first)."),
5290
+ limit: z2.number().int().positive().max(500).optional(),
5291
+ offset: z2.number().int().nonnegative().optional()
5292
+ });
5293
+ var technicalAeoTrendInputSchema = z2.object({
5294
+ project: projectNameSchema,
5295
+ limit: z2.number().int().positive().max(365).optional()
5296
+ });
5297
+ var technicalAeoRunInputSchema = z2.object({
5298
+ project: projectNameSchema,
5299
+ sitemapUrl: z2.string().url().optional().describe("Override the sitemap URL. Defaults to https://<canonicalDomain>/sitemap.xml."),
5300
+ limit: z2.number().int().positive().max(2e3).optional().describe("Cap pages audited (highest sitemap <priority> first).")
5301
+ });
5193
5302
  var AGENT_WEBHOOK_EVENTS = [
5194
5303
  notificationEventSchema.enum["run.completed"],
5195
5304
  notificationEventSchema.enum["insight.critical"],
@@ -6403,6 +6512,58 @@ var canonryMcpTools = [
6403
6512
  annotations: writeAnnotations({ idempotentHint: true }),
6404
6513
  openApiOperations: ["POST /api/v1/projects/{name}/discover/sessions/{id}/promote"],
6405
6514
  handler: (client2, input) => client2.promoteDiscovery(input.project, input.sessionId, input.request)
6515
+ }),
6516
+ defineTool({
6517
+ name: "canonry_technical_aeo_score",
6518
+ title: "Get Technical AEO score",
6519
+ description: "Get the Technical AEO scorecard for a project: the latest site-audit aggregate 0\u2013100 score, per-factor site-level averages (with pass/partial/fail distribution), cross-cutting issues, prioritized fixes, and the delta vs the previous audit. When `hasData` is false the project has never been audited \u2014 call canonry_technical_aeo_run first.",
6520
+ access: "read",
6521
+ tier: "monitoring",
6522
+ inputSchema: technicalAeoScoreInputSchema,
6523
+ annotations: readAnnotations(),
6524
+ openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo"],
6525
+ handler: (client2, input) => client2.getTechnicalAeoScore(input.project)
6526
+ }),
6527
+ defineTool({
6528
+ name: "canonry_technical_aeo_pages",
6529
+ title: "List Technical AEO pages",
6530
+ description: "List the per-page breakdown of the latest site-audit run (paginated). Filter status=error to surface unreachable pages, or sort score-asc (default) to surface the worst-scoring pages first. Use after canonry_technical_aeo_score to drill into which pages drag the site score down.",
6531
+ access: "read",
6532
+ tier: "monitoring",
6533
+ inputSchema: technicalAeoPagesInputSchema,
6534
+ annotations: readAnnotations(),
6535
+ openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/pages"],
6536
+ handler: (client2, input) => client2.getTechnicalAeoPages(input.project, {
6537
+ status: input.status,
6538
+ sort: input.sort,
6539
+ limit: input.limit,
6540
+ offset: input.offset
6541
+ })
6542
+ }),
6543
+ defineTool({
6544
+ name: "canonry_technical_aeo_trend",
6545
+ title: "Get Technical AEO trend",
6546
+ description: 'Get the aggregate Technical AEO score over time (oldest-first) across past site-audit runs. Use to answer "is our technical AEO improving?".',
6547
+ access: "read",
6548
+ tier: "monitoring",
6549
+ inputSchema: technicalAeoTrendInputSchema,
6550
+ annotations: readAnnotations(),
6551
+ openApiOperations: ["GET /api/v1/projects/{name}/technical-aeo/trend"],
6552
+ handler: (client2, input) => client2.getTechnicalAeoTrend(input.project, input.limit !== void 0 ? { limit: input.limit } : void 0)
6553
+ }),
6554
+ defineTool({
6555
+ name: "canonry_technical_aeo_run",
6556
+ title: "Run Technical AEO site audit",
6557
+ description: "Trigger a site-audit run: crawl the project sitemap and audit every reachable page across the aeo-audit ranking factors. Returns {runId, status}; the audit runs in the background (a large site can take minutes). Idempotent \u2014 if a site-audit is already in flight it returns that run. Poll canonry_run_get with the returned runId, then read canonry_technical_aeo_score.",
6558
+ access: "write",
6559
+ tier: "monitoring",
6560
+ inputSchema: technicalAeoRunInputSchema,
6561
+ annotations: writeAnnotations({ idempotentHint: false, openWorldHint: true }),
6562
+ openApiOperations: ["POST /api/v1/projects/{name}/technical-aeo/runs"],
6563
+ handler: (client2, input) => client2.triggerSiteAudit(input.project, {
6564
+ sitemapUrl: input.sitemapUrl,
6565
+ limit: input.limit
6566
+ })
6406
6567
  })
6407
6568
  ];
6408
6569
  var CANONRY_MCP_TOOL_COUNT = canonryMcpTools.length;
package/dist/cli.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  setTelemetrySource,
28
28
  showFirstRunNotice,
29
29
  trackEvent
30
- } from "./chunk-SRBO33HB.js";
30
+ } from "./chunk-QY5WZWU4.js";
31
31
  import {
32
32
  CliError,
33
33
  EXIT_SYSTEM_ERROR,
@@ -44,7 +44,7 @@ import {
44
44
  saveConfig,
45
45
  saveConfigPatch,
46
46
  usageError
47
- } from "./chunk-ZUBBADMR.js";
47
+ } from "./chunk-WFMEK34V.js";
48
48
  import {
49
49
  apiKeys,
50
50
  createClient,
@@ -52,7 +52,7 @@ import {
52
52
  projects,
53
53
  queries,
54
54
  renderReportHtml
55
- } from "./chunk-HOKVBMOD.js";
55
+ } from "./chunk-JUWU2DV6.js";
56
56
  import {
57
57
  CcReleaseSyncStatuses,
58
58
  CheckScopes,
@@ -63,6 +63,7 @@ import {
63
63
  discoveryBucketSchema,
64
64
  discoveryCompetitorTypeSchema,
65
65
  effectiveDomains,
66
+ factorStatusFromScore,
66
67
  formatGbpMetricLabel,
67
68
  formatIsoDate,
68
69
  formatRunErrorOneLine,
@@ -71,7 +72,7 @@ import {
71
72
  providerQuotaPolicySchema,
72
73
  resolveProviderInput,
73
74
  winnabilityClassSchema
74
- } from "./chunk-JXFNERK4.js";
75
+ } from "./chunk-JNAKRK77.js";
75
76
 
76
77
  // src/cli.ts
77
78
  import { pathToFileURL } from "url";
@@ -8510,7 +8511,7 @@ function renderCover(pdf, report) {
8510
8511
  hour: "numeric",
8511
8512
  minute: "2-digit"
8512
8513
  }));
8513
- pdf.keyValue("AEO Audit", `${report.audit.overallScore}/100 (${report.audit.overallGrade})`);
8514
+ pdf.keyValue("AEO Audit", `${report.audit.overallScore}/100`);
8514
8515
  pdf.keyValue("Visibility Gap (Citations + Mentions)", report.summary.visibilityGap);
8515
8516
  pdf.paragraph(report.profile.summary, { size: 11, color: INK, lineHeight: 16 });
8516
8517
  pdf.rule();
@@ -8532,7 +8533,7 @@ function renderAudit(pdf, report) {
8532
8533
  const factorRows = [...report.audit.factors].sort((a, b) => a.score - b.score || a.name.localeCompare(b.name)).slice(0, 5).map((factor) => [
8533
8534
  factor.name,
8534
8535
  formatAuditFactorScore(factor),
8535
- factor.status
8536
+ factorStatusFromScore(factor.score)
8536
8537
  ]);
8537
8538
  if (factorRows.length > 0) {
8538
8539
  pdf.table(["Weakest factor", "Score / Weight", "Status"], factorRows, [270, 120, 126]);
@@ -8664,7 +8665,7 @@ function formatSnapshotMarkdown(report) {
8664
8665
  lines.push("");
8665
8666
  lines.push(`**Domain:** ${report.domain}`);
8666
8667
  lines.push(`**Generated:** ${new Date(report.generatedAt).toLocaleString("en-US", { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "2-digit" })}`);
8667
- lines.push(`**AEO Audit Score:** ${report.audit.overallScore}/100 (${report.audit.overallGrade})`);
8668
+ lines.push(`**AEO Audit Score:** ${report.audit.overallScore}/100`);
8668
8669
  lines.push("");
8669
8670
  lines.push("## Visibility Gap (Citations + Mentions)");
8670
8671
  lines.push("");
@@ -8725,7 +8726,7 @@ function formatSnapshotMarkdown(report) {
8725
8726
  lines.push("|--------|-------|--------|--------|");
8726
8727
  const sorted = [...report.audit.factors].sort((a, b) => a.score - b.score);
8727
8728
  for (const factor of sorted) {
8728
- lines.push(`| ${factor.name} | ${factor.score} | ${factor.weight} | ${factor.status} |`);
8729
+ lines.push(`| ${factor.name} | ${factor.score} | ${factor.weight} | ${factorStatusFromScore(factor.score)} |`);
8729
8730
  }
8730
8731
  lines.push("");
8731
8732
  }
@@ -8736,7 +8737,7 @@ function formatSnapshotMarkdown(report) {
8736
8737
  function formatSnapshotText(report) {
8737
8738
  const lines = [];
8738
8739
  lines.push(`Snapshot: ${report.companyName} (${report.domain})`);
8739
- lines.push(`AEO audit: ${report.audit.overallScore}/100 (${report.audit.overallGrade})`);
8740
+ lines.push(`AEO audit: ${report.audit.overallScore}/100`);
8740
8741
  lines.push(report.summary.visibilityGap);
8741
8742
  lines.push("");
8742
8743
  if (report.summary.topCompetitors.length > 0) {
@@ -10375,7 +10376,7 @@ async function serveCommand(format = "text") {
10375
10376
  process.stderr.write(`warning: ai-referral-paths backfill skipped: ${msg}
10376
10377
  `);
10377
10378
  }
10378
- const app = await createServer({ config, db });
10379
+ const app = await createServer({ config, db, host });
10379
10380
  let shuttingDown = false;
10380
10381
  const shutdown = (signal) => {
10381
10382
  if (shuttingDown) return;
@@ -10698,11 +10699,215 @@ var SYSTEM_CLI_COMMANDS = [
10698
10699
  }
10699
10700
  ];
10700
10701
 
10702
+ // src/commands/technical-aeo.ts
10703
+ function getClient24() {
10704
+ return createApiClient();
10705
+ }
10706
+ async function technicalAeoScore(project, opts) {
10707
+ const client = getClient24();
10708
+ const score = await client.getTechnicalAeoScore(project);
10709
+ if (isMachineFormat(opts.format)) {
10710
+ console.log(JSON.stringify(score, null, 2));
10711
+ return;
10712
+ }
10713
+ if (!score.hasData) {
10714
+ console.log(
10715
+ `No technical audit yet for "${project}". Run \`canonry technical-aeo run ${project}\` to generate one.`
10716
+ );
10717
+ return;
10718
+ }
10719
+ const lines = [];
10720
+ const delta = score.deltaScore == null ? "" : ` (${score.deltaScore >= 0 ? "+" : ""}${score.deltaScore} vs prev)`;
10721
+ lines.push(`Technical AEO: ${score.aggregateScore}/100${delta}`);
10722
+ lines.push(
10723
+ `Audited ${score.pagesAudited} page(s) \xB7 ${score.pagesSkipped} skipped \xB7 ${score.pagesErrored} errored \xB7 sitemap ${score.sitemapUrl}`
10724
+ );
10725
+ lines.push(`As of ${score.auditedAt}`);
10726
+ if (score.factors.length > 0) {
10727
+ lines.push("");
10728
+ lines.push(`${"Factor".padEnd(32)}${"Wt".padStart(4)}${"Avg".padStart(6)}${"Status".padStart(9)} Pass/Part/Fail`);
10729
+ for (const f of score.factors) {
10730
+ lines.push(
10731
+ `${f.name.slice(0, 31).padEnd(32)}${String(f.weight).padStart(4)}${String(f.avgScore).padStart(6)}${f.status.padStart(9)} ${f.pagesPassing}/${f.pagesPartial}/${f.pagesFailing}`
10732
+ );
10733
+ }
10734
+ }
10735
+ if (score.prioritizedFixes.length > 0) {
10736
+ lines.push("");
10737
+ lines.push("Prioritized fixes:");
10738
+ score.prioritizedFixes.forEach((fix, i) => lines.push(` ${i + 1}. ${fix}`));
10739
+ }
10740
+ console.log(lines.join("\n"));
10741
+ }
10742
+ async function technicalAeoPages(project, opts) {
10743
+ const client = getClient24();
10744
+ const status = opts.status === "success" || opts.status === "error" ? opts.status : void 0;
10745
+ const res = await client.getTechnicalAeoPages(project, { status, sort: opts.sort, limit: opts.limit });
10746
+ if (opts.format === "jsonl") {
10747
+ emitJsonl(res.pages.map((p) => ({ project, runId: res.runId, ...p })));
10748
+ return;
10749
+ }
10750
+ if (opts.format === "json") {
10751
+ console.log(JSON.stringify(res, null, 2));
10752
+ return;
10753
+ }
10754
+ if (res.pages.length === 0) {
10755
+ console.log(`No audited pages for "${project}". Run \`canonry technical-aeo run ${project}\` first.`);
10756
+ return;
10757
+ }
10758
+ const lines = [];
10759
+ lines.push(`${res.pages.length} of ${res.total} page(s) from run ${res.runId}:
10760
+ `);
10761
+ lines.push(`${"Score".padStart(5)} ${"Status".padEnd(7)} URL`);
10762
+ for (const p of res.pages) {
10763
+ const tail = p.status === "error" ? ` ${p.error ?? "error"}` : "";
10764
+ lines.push(`${String(p.overallScore).padStart(5)} ${p.status.padEnd(7)} ${p.url}${tail}`);
10765
+ }
10766
+ console.log(lines.join("\n"));
10767
+ }
10768
+ async function technicalAeoTrend(project, opts) {
10769
+ const client = getClient24();
10770
+ const res = await client.getTechnicalAeoTrend(project, { limit: opts.limit });
10771
+ if (opts.format === "jsonl") {
10772
+ emitJsonl(res.points.map((p) => ({ project, ...p })));
10773
+ return;
10774
+ }
10775
+ if (opts.format === "json") {
10776
+ console.log(JSON.stringify(res, null, 2));
10777
+ return;
10778
+ }
10779
+ if (res.points.length === 0) {
10780
+ console.log(`No audits yet for "${project}". Run \`canonry technical-aeo run ${project}\` first.`);
10781
+ return;
10782
+ }
10783
+ const lines = [];
10784
+ lines.push(`${"Date".padEnd(26)} ${"Score".padStart(5)} Pages`);
10785
+ for (const p of res.points) {
10786
+ lines.push(`${p.auditedAt.padEnd(26)} ${String(p.aggregateScore).padStart(5)} ${p.pagesAudited}`);
10787
+ }
10788
+ console.log(lines.join("\n"));
10789
+ }
10790
+ async function technicalAeoRun(project, opts) {
10791
+ const client = getClient24();
10792
+ const { runId, status } = await client.triggerSiteAudit(project, {
10793
+ sitemapUrl: opts.sitemapUrl,
10794
+ limit: opts.limit
10795
+ });
10796
+ if (!opts.wait) {
10797
+ if (isMachineFormat(opts.format)) {
10798
+ console.log(JSON.stringify({ runId, status }, null, 2));
10799
+ return;
10800
+ }
10801
+ console.log(
10802
+ `Site audit started (run ${runId}, status ${status}). Use \`canonry runs get ${runId}\` to check status, or pass --wait.`
10803
+ );
10804
+ return;
10805
+ }
10806
+ const terminal = /* @__PURE__ */ new Set(["completed", "partial", "failed", "cancelled"]);
10807
+ const start = Date.now();
10808
+ const timeoutMs = 15 * 60 * 1e3;
10809
+ if (!isMachineFormat(opts.format)) process.stderr.write("Auditing");
10810
+ let final = status;
10811
+ while (!terminal.has(final) && Date.now() - start < timeoutMs) {
10812
+ await new Promise((r) => setTimeout(r, 2e3));
10813
+ const run = await client.getRun(runId);
10814
+ if (!isMachineFormat(opts.format)) process.stderr.write(".");
10815
+ final = run.status;
10816
+ }
10817
+ if (!isMachineFormat(opts.format)) process.stderr.write("\n");
10818
+ if (isMachineFormat(opts.format)) {
10819
+ console.log(JSON.stringify({ runId, status: final }, null, 2));
10820
+ return;
10821
+ }
10822
+ console.log(`Site audit ${final} (run ${runId}).`);
10823
+ }
10824
+
10825
+ // src/cli-commands/technical-aeo.ts
10826
+ var TECHNICAL_AEO_CLI_COMMANDS = [
10827
+ {
10828
+ path: ["technical-aeo", "score"],
10829
+ usage: "canonry technical-aeo score <project> [--format json]",
10830
+ run: async (input) => {
10831
+ const project = requireProject(
10832
+ input,
10833
+ "technical-aeo.score",
10834
+ "canonry technical-aeo score <project> [--format json]"
10835
+ );
10836
+ await technicalAeoScore(project, { format: input.format });
10837
+ }
10838
+ },
10839
+ {
10840
+ path: ["technical-aeo", "pages"],
10841
+ usage: "canonry technical-aeo pages <project> [--status success|error] [--sort score-asc|score-desc|url] [--limit <n>] [--format json|jsonl]",
10842
+ options: {
10843
+ status: stringOption(),
10844
+ sort: stringOption(),
10845
+ limit: stringOption()
10846
+ },
10847
+ run: async (input) => {
10848
+ const usage = "canonry technical-aeo pages <project> [--status success|error] [--sort score-asc|score-desc|url] [--limit <n>] [--format json|jsonl]";
10849
+ const project = requireProject(input, "technical-aeo.pages", usage);
10850
+ await technicalAeoPages(project, {
10851
+ status: getString(input.values, "status"),
10852
+ sort: getString(input.values, "sort"),
10853
+ limit: parseIntegerOption(input, "limit", {
10854
+ command: "technical-aeo.pages",
10855
+ usage,
10856
+ message: "--limit must be an integer"
10857
+ }),
10858
+ format: input.format
10859
+ });
10860
+ }
10861
+ },
10862
+ {
10863
+ path: ["technical-aeo", "trend"],
10864
+ usage: "canonry technical-aeo trend <project> [--limit <n>] [--format json|jsonl]",
10865
+ options: {
10866
+ limit: stringOption()
10867
+ },
10868
+ run: async (input) => {
10869
+ const usage = "canonry technical-aeo trend <project> [--limit <n>] [--format json|jsonl]";
10870
+ const project = requireProject(input, "technical-aeo.trend", usage);
10871
+ await technicalAeoTrend(project, {
10872
+ limit: parseIntegerOption(input, "limit", {
10873
+ command: "technical-aeo.trend",
10874
+ usage,
10875
+ message: "--limit must be an integer"
10876
+ }),
10877
+ format: input.format
10878
+ });
10879
+ }
10880
+ },
10881
+ {
10882
+ path: ["technical-aeo", "run"],
10883
+ usage: "canonry technical-aeo run <project> [--sitemap-url <url>] [--limit <n>] [--wait] [--format json]",
10884
+ options: {
10885
+ "sitemap-url": stringOption(),
10886
+ limit: stringOption(),
10887
+ wait: { type: "boolean", default: false }
10888
+ },
10889
+ run: async (input) => {
10890
+ const usage = "canonry technical-aeo run <project> [--sitemap-url <url>] [--limit <n>] [--wait] [--format json]";
10891
+ const project = requireProject(input, "technical-aeo.run", usage);
10892
+ await technicalAeoRun(project, {
10893
+ sitemapUrl: getString(input.values, "sitemap-url"),
10894
+ limit: parseIntegerOption(input, "limit", {
10895
+ command: "technical-aeo.run",
10896
+ usage,
10897
+ message: "--limit must be an integer"
10898
+ }),
10899
+ wait: getBoolean(input.values, "wait"),
10900
+ format: input.format
10901
+ });
10902
+ }
10903
+ }
10904
+ ];
10905
+
10701
10906
  // src/cli-commands/wordpress.ts
10702
10907
  import fs11 from "fs";
10703
10908
 
10704
10909
  // src/commands/wordpress.ts
10705
- function getClient24() {
10910
+ function getClient25() {
10706
10911
  return createApiClient();
10707
10912
  }
10708
10913
  async function loadYamlModule() {
@@ -10852,7 +11057,7 @@ async function wordpressConnect(project, opts) {
10852
11057
  details: { project }
10853
11058
  });
10854
11059
  }
10855
- const client = getClient24();
11060
+ const client = getClient25();
10856
11061
  const result = await client.wordpressConnect(project, {
10857
11062
  url: opts.url,
10858
11063
  stagingUrl: opts.stagingUrl,
@@ -10869,7 +11074,7 @@ async function wordpressConnect(project, opts) {
10869
11074
  printWordpressStatus(project, result);
10870
11075
  }
10871
11076
  async function wordpressDisconnect(project, format) {
10872
- const client = getClient24();
11077
+ const client = getClient25();
10873
11078
  await client.wordpressDisconnect(project);
10874
11079
  if (isMachineFormat(format)) {
10875
11080
  printJson2({ project, disconnected: true });
@@ -10878,7 +11083,7 @@ async function wordpressDisconnect(project, format) {
10878
11083
  console.log(`WordPress disconnected from project "${project}".`);
10879
11084
  }
10880
11085
  async function wordpressStatus(project, format) {
10881
- const client = getClient24();
11086
+ const client = getClient25();
10882
11087
  const result = await client.wordpressStatus(project);
10883
11088
  if (isMachineFormat(format)) {
10884
11089
  printJson2(result);
@@ -10887,7 +11092,7 @@ async function wordpressStatus(project, format) {
10887
11092
  printWordpressStatus(project, result);
10888
11093
  }
10889
11094
  async function wordpressPages(project, opts) {
10890
- const client = getClient24();
11095
+ const client = getClient25();
10891
11096
  const result = await client.wordpressPages(project, opts.env);
10892
11097
  if (isMachineFormat(opts.format)) {
10893
11098
  printJson2(result);
@@ -10896,7 +11101,7 @@ async function wordpressPages(project, opts) {
10896
11101
  printPages(project, result.env, result.pages);
10897
11102
  }
10898
11103
  async function wordpressPage(project, slug, opts) {
10899
- const client = getClient24();
11104
+ const client = getClient25();
10900
11105
  const result = await client.wordpressPage(project, slug, opts.env);
10901
11106
  if (isMachineFormat(opts.format)) {
10902
11107
  printJson2(result);
@@ -10905,7 +11110,7 @@ async function wordpressPage(project, slug, opts) {
10905
11110
  printPageDetail(result);
10906
11111
  }
10907
11112
  async function wordpressCreatePage(project, body) {
10908
- const client = getClient24();
11113
+ const client = getClient25();
10909
11114
  const result = await client.wordpressCreatePage(project, body);
10910
11115
  if (isMachineFormat(body.format)) {
10911
11116
  printJson2(result);
@@ -10916,7 +11121,7 @@ async function wordpressCreatePage(project, body) {
10916
11121
  printPageDetail(result);
10917
11122
  }
10918
11123
  async function wordpressUpdatePage(project, body) {
10919
- const client = getClient24();
11124
+ const client = getClient25();
10920
11125
  const result = await client.wordpressUpdatePage(project, body);
10921
11126
  if (isMachineFormat(body.format)) {
10922
11127
  printJson2(result);
@@ -10927,7 +11132,7 @@ async function wordpressUpdatePage(project, body) {
10927
11132
  printPageDetail(result);
10928
11133
  }
10929
11134
  async function wordpressSetMeta(project, body) {
10930
- const client = getClient24();
11135
+ const client = getClient25();
10931
11136
  const result = await client.wordpressSetMeta(project, body);
10932
11137
  if (isMachineFormat(body.format)) {
10933
11138
  printJson2(result);
@@ -10977,7 +11182,7 @@ async function wordpressBulkSetMeta(project, opts) {
10977
11182
  details: { path: filePath }
10978
11183
  });
10979
11184
  }
10980
- const client = getClient24();
11185
+ const client = getClient25();
10981
11186
  const result = await client.wordpressBulkSetMeta(project, { entries, env: opts.env });
10982
11187
  if (isMachineFormat(opts.format)) {
10983
11188
  printJson2(result);
@@ -11020,7 +11225,7 @@ async function wordpressBulkSetMeta(project, opts) {
11020
11225
  Total: ${applied.length} applied, ${skipped.length} skipped, ${manual.length} manual`);
11021
11226
  }
11022
11227
  async function wordpressSchema(project, slug, opts) {
11023
- const client = getClient24();
11228
+ const client = getClient25();
11024
11229
  const result = await client.wordpressSchema(project, slug, opts.env);
11025
11230
  if (isMachineFormat(opts.format)) {
11026
11231
  printJson2(result);
@@ -11031,7 +11236,7 @@ async function wordpressSchema(project, slug, opts) {
11031
11236
  printSchemaBlocks(result.blocks);
11032
11237
  }
11033
11238
  async function wordpressSetSchema(project, body) {
11034
- const client = getClient24();
11239
+ const client = getClient25();
11035
11240
  const result = await client.wordpressSetSchema(project, body);
11036
11241
  if (isMachineFormat(body.format)) {
11037
11242
  printJson2(result);
@@ -11079,7 +11284,7 @@ async function wordpressSchemaDeploy(project, opts) {
11079
11284
  details: { path: filePath }
11080
11285
  });
11081
11286
  }
11082
- const client = getClient24();
11287
+ const client = getClient25();
11083
11288
  const result = await client.wordpressSchemaDeploy(project, { profile: parsed, env: opts.env });
11084
11289
  if (isMachineFormat(opts.format)) {
11085
11290
  printJson2(result);
@@ -11118,7 +11323,7 @@ async function wordpressSchemaDeploy(project, opts) {
11118
11323
  Total: ${deployed} deployed, ${stripped} stripped, ${skipped} skipped, ${failed} failed`);
11119
11324
  }
11120
11325
  async function wordpressSchemaStatus(project, opts) {
11121
- const client = getClient24();
11326
+ const client = getClient25();
11122
11327
  const result = await client.wordpressSchemaStatus(project, opts.env);
11123
11328
  if (isMachineFormat(opts.format)) {
11124
11329
  printJson2(result);
@@ -11177,7 +11382,7 @@ async function wordpressOnboard(project, opts) {
11177
11382
  });
11178
11383
  }
11179
11384
  }
11180
- const client = getClient24();
11385
+ const client = getClient25();
11181
11386
  const result = await client.wordpressOnboard(project, {
11182
11387
  url: opts.url,
11183
11388
  username: opts.user,
@@ -11202,7 +11407,7 @@ async function wordpressOnboard(project, opts) {
11202
11407
  }
11203
11408
  }
11204
11409
  async function wordpressLlmsTxt(project, opts) {
11205
- const client = getClient24();
11410
+ const client = getClient25();
11206
11411
  const result = await client.wordpressLlmsTxt(project, opts.env);
11207
11412
  if (isMachineFormat(opts.format)) {
11208
11413
  printJson2(result);
@@ -11213,7 +11418,7 @@ async function wordpressLlmsTxt(project, opts) {
11213
11418
  console.log(result.content ?? "(not found)");
11214
11419
  }
11215
11420
  async function wordpressSetLlmsTxt(project, body) {
11216
- const client = getClient24();
11421
+ const client = getClient25();
11217
11422
  const result = await client.wordpressSetLlmsTxt(project, body);
11218
11423
  if (isMachineFormat(body.format)) {
11219
11424
  printJson2(result);
@@ -11222,7 +11427,7 @@ async function wordpressSetLlmsTxt(project, body) {
11222
11427
  printManualAssist(`llms.txt update for "${project}"`, result);
11223
11428
  }
11224
11429
  async function wordpressAudit(project, opts) {
11225
- const client = getClient24();
11430
+ const client = getClient25();
11226
11431
  const result = await client.wordpressAudit(project, opts.env);
11227
11432
  if (isMachineFormat(opts.format)) {
11228
11433
  printJson2(result);
@@ -11236,7 +11441,7 @@ async function wordpressAudit(project, opts) {
11236
11441
  printAuditIssues(result.issues);
11237
11442
  }
11238
11443
  async function wordpressDiff(project, slug, format) {
11239
- const client = getClient24();
11444
+ const client = getClient25();
11240
11445
  const result = await client.wordpressDiff(project, slug);
11241
11446
  if (isMachineFormat(format)) {
11242
11447
  printJson2(result);
@@ -11245,7 +11450,7 @@ async function wordpressDiff(project, slug, format) {
11245
11450
  printDiff(result);
11246
11451
  }
11247
11452
  async function wordpressStagingStatus(project, format) {
11248
- const client = getClient24();
11453
+ const client = getClient25();
11249
11454
  const result = await client.wordpressStagingStatus(project);
11250
11455
  if (isMachineFormat(format)) {
11251
11456
  printJson2(result);
@@ -11259,7 +11464,7 @@ async function wordpressStagingStatus(project, format) {
11259
11464
  console.log(` Admin URL: ${result.adminUrl}`);
11260
11465
  }
11261
11466
  async function wordpressStagingPush(project, format) {
11262
- const client = getClient24();
11467
+ const client = getClient25();
11263
11468
  const result = await client.wordpressStagingPush(project);
11264
11469
  if (isMachineFormat(format)) {
11265
11470
  printJson2(result);
@@ -12284,6 +12489,7 @@ var REGISTERED_CLI_COMMANDS = [
12284
12489
  ...CONTENT_CLI_COMMANDS,
12285
12490
  ...AGENT_CLI_COMMANDS,
12286
12491
  ...DISCOVER_CLI_COMMANDS,
12492
+ ...TECHNICAL_AEO_CLI_COMMANDS,
12287
12493
  ...DOCTOR_CLI_COMMANDS,
12288
12494
  ...GET_CLI_COMMANDS,
12289
12495
  ...MCP_CLI_COMMANDS