@ainyc/canonry 3.3.9 → 3.4.5

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.
@@ -1,3 +1,17 @@
1
+ import {
2
+ AGENT_MEMORY_KEY_MAX_LENGTH,
3
+ AGENT_MEMORY_VALUE_MAX_BYTES,
4
+ competitorBatchRequestSchema,
5
+ keywordBatchRequestSchema,
6
+ keywordGenerateRequestSchema,
7
+ notificationCreateRequestSchema,
8
+ notificationEventSchema,
9
+ projectConfigSchema,
10
+ projectUpsertRequestSchema,
11
+ runTriggerRequestSchema,
12
+ scheduleUpsertRequestSchema
13
+ } from "./chunk-D4YFX3X4.js";
14
+
1
15
  // src/config.ts
2
16
  import fs from "fs";
3
17
  import path from "path";
@@ -238,1843 +252,6 @@ function printCliError(err, format) {
238
252
  console.error("An unexpected error occurred");
239
253
  }
240
254
 
241
- // ../contracts/src/errors.ts
242
- var AppError = class extends Error {
243
- code;
244
- statusCode;
245
- details;
246
- constructor(code, message, statusCode, details) {
247
- super(message);
248
- this.name = "AppError";
249
- this.code = code;
250
- this.statusCode = statusCode;
251
- this.details = details;
252
- }
253
- toJSON() {
254
- return {
255
- error: {
256
- code: this.code,
257
- message: this.message,
258
- ...this.details ? { details: this.details } : {}
259
- }
260
- };
261
- }
262
- };
263
- function notFound(entity, id) {
264
- return new AppError("NOT_FOUND", `${entity} '${id}' not found`, 404);
265
- }
266
- function validationError(message, details) {
267
- return new AppError("VALIDATION_ERROR", message, 400, details);
268
- }
269
- function authRequired() {
270
- return new AppError("AUTH_REQUIRED", "Authentication required", 401);
271
- }
272
- function authInvalid() {
273
- return new AppError("AUTH_INVALID", "Invalid API key", 401);
274
- }
275
- function providerError(message, details) {
276
- return new AppError("PROVIDER_ERROR", message, 502, details);
277
- }
278
- function runInProgress(projectName) {
279
- return new AppError("RUN_IN_PROGRESS", `A run is already in progress for '${projectName}'`, 409);
280
- }
281
- function runNotCancellable(runId, status) {
282
- return new AppError("RUN_NOT_CANCELLABLE", `Run '${runId}' is already in terminal state '${status}' and cannot be cancelled`, 409);
283
- }
284
- function unsupportedKind(kind) {
285
- return new AppError("UNSUPPORTED_KIND", `Kind '${kind}' is not supported in this version`, 400);
286
- }
287
- function notImplemented(message) {
288
- return new AppError("NOT_IMPLEMENTED", message, 501);
289
- }
290
- function deliveryFailed(message) {
291
- return new AppError("DELIVERY_FAILED", message, 502);
292
- }
293
- function agentBusy(projectName) {
294
- return new AppError(
295
- "AGENT_BUSY",
296
- `Aero is already running a turn for '${projectName}'. Retry after the current turn settles.`,
297
- 409
298
- );
299
- }
300
- function missingDependency(message, details) {
301
- return new AppError("MISSING_DEPENDENCY", message, 422, details);
302
- }
303
- function internalError(message, details) {
304
- return new AppError("INTERNAL_ERROR", message, 500, details);
305
- }
306
-
307
- // ../contracts/src/run.ts
308
- import { z as z2 } from "zod";
309
-
310
- // ../contracts/src/provider.ts
311
- import { z } from "zod";
312
- var providerQuotaPolicySchema = z.object({
313
- maxConcurrency: z.number().int().positive(),
314
- maxRequestsPerMinute: z.number().int().positive(),
315
- maxRequestsPerDay: z.number().int().positive()
316
- });
317
- var ProviderNames = {
318
- gemini: "gemini",
319
- openai: "openai",
320
- claude: "claude",
321
- perplexity: "perplexity",
322
- local: "local",
323
- cdpChatgpt: "cdp:chatgpt"
324
- };
325
- var providerNameSchema = z.string().min(1);
326
- var apiProviderNameSchema = z.string().min(1);
327
- function isBrowserProvider(name) {
328
- return name.startsWith("cdp:");
329
- }
330
- var CDP_TARGETS = ["cdp:chatgpt"];
331
- function resolveProviderInput(input) {
332
- const lower = input.trim().toLowerCase();
333
- if (lower === "cdp") {
334
- return [...CDP_TARGETS];
335
- }
336
- return lower ? [lower] : [];
337
- }
338
- var locationContextSchema = z.object({
339
- label: z.string().min(1),
340
- city: z.string().min(1),
341
- region: z.string().min(1),
342
- country: z.string().length(2),
343
- timezone: z.string().optional()
344
- });
345
-
346
- // ../contracts/src/run.ts
347
- var runStatusSchema = z2.enum(["queued", "running", "completed", "partial", "failed", "cancelled"]);
348
- var RunStatuses = runStatusSchema.enum;
349
- var runKindSchema = z2.enum([
350
- "answer-visibility",
351
- "site-audit",
352
- "gsc-sync",
353
- "inspect-sitemap",
354
- "ga-sync",
355
- "bing-inspect",
356
- "bing-inspect-sitemap",
357
- "backlink-extract"
358
- ]);
359
- var RunKinds = runKindSchema.enum;
360
- var runTriggerSchema = z2.enum(["manual", "scheduled", "config-apply"]);
361
- var RunTriggers = runTriggerSchema.enum;
362
- var citationStateSchema = z2.enum(["cited", "not-cited"]);
363
- var CitationStates = citationStateSchema.enum;
364
- var visibilityStateSchema = z2.enum(["visible", "not-visible"]);
365
- var VisibilityStates = visibilityStateSchema.enum;
366
- var computedTransitionSchema = z2.enum(["new", "cited", "lost", "emerging", "not-cited"]);
367
- var ComputedTransitions = computedTransitionSchema.enum;
368
- var runTriggerRequestSchema = z2.object({
369
- kind: z2.literal(RunKinds["answer-visibility"]).optional(),
370
- trigger: z2.literal(RunTriggers.manual).optional(),
371
- providers: z2.array(providerNameSchema).optional(),
372
- location: z2.string().min(1).optional(),
373
- allLocations: z2.boolean().optional(),
374
- noLocation: z2.boolean().optional()
375
- }).refine(
376
- (data) => Number(Boolean(data.location)) + Number(Boolean(data.allLocations)) + Number(Boolean(data.noLocation)) <= 1,
377
- { message: 'Only one of "location", "allLocations", or "noLocation" may be provided' }
378
- );
379
- var runProviderErrorSchema = z2.object({
380
- /** Human-readable error message (best-effort extracted from `raw.error.message` / `raw.message`, otherwise the raw text with any `[provider-X]` prefix stripped). */
381
- message: z2.string(),
382
- /** Original provider response payload, if the underlying error body parsed as JSON. Use this for structured fields like HTTP status, error code, etc. */
383
- raw: z2.unknown().optional()
384
- });
385
- var runErrorSchema = z2.object({
386
- /** Top-level message for runs that failed without a per-provider error (e.g. user cancellation, internal scheduling failures). */
387
- message: z2.string().optional(),
388
- /** Per-provider errors for visibility-sweep runs that had at least one provider fail. */
389
- providers: z2.record(z2.string(), runProviderErrorSchema).optional()
390
- });
391
- var runDtoSchema = z2.object({
392
- id: z2.string(),
393
- projectId: z2.string(),
394
- kind: runKindSchema,
395
- status: runStatusSchema,
396
- trigger: runTriggerSchema.default("manual"),
397
- location: z2.string().nullable().optional(),
398
- startedAt: z2.string().nullable().optional(),
399
- finishedAt: z2.string().nullable().optional(),
400
- error: runErrorSchema.nullable().optional(),
401
- createdAt: z2.string()
402
- });
403
- var PROVIDER_PREFIX = /^\[provider-[a-zA-Z0-9_-]+\]\s+/;
404
- function parseProviderErrorMessage(msg) {
405
- const stripped = msg.replace(PROVIDER_PREFIX, "");
406
- try {
407
- const raw = JSON.parse(stripped);
408
- if (raw && typeof raw === "object") {
409
- const inner = raw;
410
- const fromErrorMessage = typeof inner.error?.message === "string" ? inner.error.message : void 0;
411
- const fromMessage = typeof inner.message === "string" ? inner.message : void 0;
412
- return { message: fromErrorMessage ?? fromMessage ?? stripped, raw };
413
- }
414
- } catch {
415
- }
416
- return { message: stripped };
417
- }
418
- function parseRunError(raw) {
419
- if (!raw) return null;
420
- let parsed;
421
- try {
422
- parsed = JSON.parse(raw);
423
- } catch {
424
- return { message: raw };
425
- }
426
- if (!parsed || typeof parsed !== "object") {
427
- return { message: raw };
428
- }
429
- const obj = parsed;
430
- const hasProviders = obj.providers && typeof obj.providers === "object";
431
- const hasMessage = typeof obj.message === "string";
432
- if (hasProviders || hasMessage) {
433
- return parsed;
434
- }
435
- const providers = {};
436
- for (const [name, val] of Object.entries(obj)) {
437
- providers[name] = parseProviderErrorMessage(typeof val === "string" ? val : JSON.stringify(val));
438
- }
439
- return { providers };
440
- }
441
- function buildRunErrorFromMessages(messages) {
442
- const providers = {};
443
- for (const [name, msg] of messages) {
444
- providers[name] = parseProviderErrorMessage(msg);
445
- }
446
- return { providers };
447
- }
448
- function serializeRunError(err) {
449
- return JSON.stringify(err);
450
- }
451
- function formatRunErrorOneLine(err) {
452
- if (err.providers) {
453
- const entries = Object.entries(err.providers);
454
- if (entries.length === 1) {
455
- const [provider, detail] = entries[0];
456
- return `${provider}: ${detail.message}`;
457
- }
458
- if (entries.length > 1) {
459
- return entries.map(([p, d]) => `${p}: ${d.message}`).join(" \u2022 ");
460
- }
461
- }
462
- return err.message ?? "Run failed.";
463
- }
464
- var groundingSourceSchema = z2.object({
465
- uri: z2.string(),
466
- title: z2.string()
467
- });
468
- var querySnapshotDtoSchema = z2.object({
469
- id: z2.string(),
470
- runId: z2.string(),
471
- keywordId: z2.string(),
472
- keyword: z2.string().optional(),
473
- provider: providerNameSchema,
474
- citationState: citationStateSchema,
475
- answerMentioned: z2.boolean().optional(),
476
- visibilityState: visibilityStateSchema.optional(),
477
- transition: computedTransitionSchema.optional(),
478
- answerText: z2.string().nullable().optional(),
479
- citedDomains: z2.array(z2.string()).default([]),
480
- competitorOverlap: z2.array(z2.string()).default([]),
481
- recommendedCompetitors: z2.array(z2.string()).default([]),
482
- matchedTerms: z2.array(z2.string()).default([]),
483
- groundingSources: z2.array(groundingSourceSchema).default([]),
484
- searchQueries: z2.array(z2.string()).default([]),
485
- model: z2.string().nullable().optional(),
486
- location: z2.string().nullable().optional(),
487
- createdAt: z2.string()
488
- });
489
- var snapshotListResponseSchema = z2.object({
490
- snapshots: z2.array(querySnapshotDtoSchema),
491
- total: z2.number().int().nonnegative()
492
- });
493
- var snapshotDiffRowSchema = z2.object({
494
- keywordId: z2.string().nullable(),
495
- keyword: z2.string().nullable(),
496
- run1State: citationStateSchema.nullable(),
497
- run2State: citationStateSchema.nullable(),
498
- run1AnswerMentioned: z2.boolean().nullable(),
499
- run2AnswerMentioned: z2.boolean().nullable(),
500
- run1VisibilityState: visibilityStateSchema.nullable(),
501
- run2VisibilityState: visibilityStateSchema.nullable(),
502
- changed: z2.boolean(),
503
- visibilityChanged: z2.boolean()
504
- });
505
- var snapshotDiffResponseSchema = z2.object({
506
- run1: z2.string(),
507
- run2: z2.string(),
508
- diff: z2.array(snapshotDiffRowSchema)
509
- });
510
- var runDetailDtoSchema = runDtoSchema.extend({
511
- snapshots: z2.array(querySnapshotDtoSchema).optional()
512
- });
513
- var latestProjectRunDtoSchema = z2.object({
514
- totalRuns: z2.number().int().nonnegative(),
515
- run: runDetailDtoSchema.nullable()
516
- });
517
- var auditLogEntrySchema = z2.object({
518
- id: z2.string(),
519
- projectId: z2.string().nullable().optional(),
520
- actor: z2.string(),
521
- action: z2.string(),
522
- entityType: z2.string(),
523
- entityId: z2.string().nullable().optional(),
524
- diff: z2.unknown().optional(),
525
- createdAt: z2.string()
526
- });
527
-
528
- // ../contracts/src/config-schema.ts
529
- import { z as z5 } from "zod";
530
-
531
- // ../contracts/src/notification.ts
532
- import { z as z3 } from "zod";
533
- var notificationEventSchema = z3.enum([
534
- "citation.lost",
535
- "citation.gained",
536
- "run.completed",
537
- "run.failed",
538
- "insight.critical",
539
- "insight.high"
540
- ]);
541
- var notificationDtoSchema = z3.object({
542
- id: z3.string(),
543
- projectId: z3.string(),
544
- channel: z3.literal("webhook"),
545
- url: z3.string().url(),
546
- urlDisplay: z3.string(),
547
- urlHost: z3.string(),
548
- events: z3.array(notificationEventSchema),
549
- enabled: z3.boolean().default(true),
550
- /** Opaque tag identifying the creator (e.g. `"agent"` for Aero webhooks). */
551
- source: z3.string().optional(),
552
- webhookSecret: z3.string().optional(),
553
- createdAt: z3.string(),
554
- updatedAt: z3.string()
555
- });
556
- var notificationCreateRequestSchema = z3.object({
557
- channel: z3.literal("webhook"),
558
- url: z3.string().url(),
559
- events: z3.array(notificationEventSchema).min(1),
560
- source: z3.string().optional()
561
- });
562
-
563
- // ../contracts/src/project.ts
564
- import { z as z4 } from "zod";
565
- var configSourceSchema = z4.enum(["cli", "api", "config-file"]);
566
- function findDuplicateLocationLabels(locations) {
567
- const seen = /* @__PURE__ */ new Set();
568
- const duplicates = /* @__PURE__ */ new Set();
569
- for (const location of locations) {
570
- if (seen.has(location.label)) {
571
- duplicates.add(location.label);
572
- continue;
573
- }
574
- seen.add(location.label);
575
- }
576
- return [...duplicates];
577
- }
578
- function hasLocationLabel(locations, label) {
579
- if (!label) return true;
580
- return locations.some((location) => location.label === label);
581
- }
582
- var projectUpsertRequestSchema = z4.object({
583
- displayName: z4.string().min(1),
584
- canonicalDomain: z4.string().min(1),
585
- ownedDomains: z4.array(z4.string().min(1)).optional(),
586
- country: z4.string().length(2),
587
- language: z4.string().min(2),
588
- tags: z4.array(z4.string()).optional(),
589
- labels: z4.record(z4.string(), z4.string()).optional(),
590
- providers: z4.array(providerNameSchema).optional(),
591
- locations: z4.array(locationContextSchema).optional(),
592
- defaultLocation: z4.string().nullable().optional(),
593
- autoExtractBacklinks: z4.boolean().optional(),
594
- configSource: configSourceSchema.optional()
595
- });
596
- var projectDtoSchema = z4.object({
597
- id: z4.string(),
598
- name: z4.string(),
599
- displayName: z4.string().optional(),
600
- canonicalDomain: z4.string(),
601
- ownedDomains: z4.array(z4.string()).default([]),
602
- country: z4.string().length(2),
603
- language: z4.string().min(2),
604
- tags: z4.array(z4.string()).default([]),
605
- labels: z4.record(z4.string(), z4.string()).default({}),
606
- locations: z4.array(locationContextSchema).default([]),
607
- defaultLocation: z4.string().nullable().optional(),
608
- autoExtractBacklinks: z4.boolean().default(false),
609
- configSource: configSourceSchema.default("cli"),
610
- configRevision: z4.number().int().positive().default(1),
611
- createdAt: z4.string().optional(),
612
- updatedAt: z4.string().optional()
613
- });
614
- var keywordDtoSchema = z4.object({
615
- id: z4.string(),
616
- keyword: z4.string(),
617
- createdAt: z4.string()
618
- });
619
- var keywordBatchRequestSchema = z4.object({
620
- keywords: z4.array(z4.string().trim().min(1)).min(1)
621
- });
622
- var keywordGenerateRequestSchema = z4.object({
623
- provider: providerNameSchema,
624
- count: z4.number().int().min(1).max(20).optional()
625
- });
626
- var competitorDtoSchema = z4.object({
627
- id: z4.string(),
628
- domain: z4.string(),
629
- createdAt: z4.string()
630
- });
631
- var competitorBatchRequestSchema = z4.object({
632
- competitors: z4.array(z4.string().trim().min(1)).min(1)
633
- });
634
- function normalizeProjectDomain(input) {
635
- let domain = input.trim().toLowerCase();
636
- try {
637
- if (domain.includes("://")) {
638
- domain = new URL(domain).hostname.toLowerCase();
639
- }
640
- } catch {
641
- }
642
- return domain.replace(/^www\./, "");
643
- }
644
- var MULTI_LABEL_PUBLIC_SUFFIXES = /* @__PURE__ */ new Set([
645
- "ac.uk",
646
- "co.id",
647
- "co.il",
648
- "co.in",
649
- "co.jp",
650
- "co.kr",
651
- "co.nz",
652
- "co.th",
653
- "co.uk",
654
- "co.za",
655
- "com.au",
656
- "com.br",
657
- "com.cn",
658
- "com.mx",
659
- "com.ph",
660
- "com.sg",
661
- "com.tr",
662
- "edu.au",
663
- "edu.sg",
664
- "gov.au",
665
- "gov.uk",
666
- "me.uk",
667
- "ne.jp",
668
- "net.au",
669
- "net.br",
670
- "net.cn",
671
- "net.in",
672
- "net.tr",
673
- "or.jp",
674
- "or.kr",
675
- "org.au",
676
- "org.br",
677
- "org.in",
678
- "org.nz",
679
- "org.tr",
680
- "org.uk",
681
- "org.za"
682
- ]);
683
- function registrableDomain(input) {
684
- const normalized = normalizeProjectDomain(input);
685
- if (!normalized) return "";
686
- const hostname = normalized.split("/")[0]?.split(":")[0] ?? "";
687
- if (!hostname) return "";
688
- const labels = hostname.split(".").filter(Boolean);
689
- if (labels.length < 2) return "";
690
- if (labels.length === 2) return labels.join(".");
691
- const lastTwo = labels.slice(-2).join(".");
692
- if (MULTI_LABEL_PUBLIC_SUFFIXES.has(lastTwo)) {
693
- return labels.length >= 3 ? labels.slice(-3).join(".") : "";
694
- }
695
- return labels.slice(-2).join(".");
696
- }
697
- function brandLabelFromDomain(input) {
698
- const reg = registrableDomain(input);
699
- if (!reg) return "";
700
- return reg.split(".")[0] ?? "";
701
- }
702
- function effectiveDomains(project) {
703
- const all = [project.canonicalDomain, ...project.ownedDomains ?? []];
704
- const seen = /* @__PURE__ */ new Set();
705
- const result = [];
706
- for (const d of all) {
707
- const trimmed = d.trim();
708
- if (!trimmed) continue;
709
- const norm = normalizeProjectDomain(trimmed);
710
- if (seen.has(norm)) continue;
711
- seen.add(norm);
712
- result.push(trimmed);
713
- }
714
- return result;
715
- }
716
-
717
- // ../contracts/src/config-schema.ts
718
- var configMetadataSchema = z5.object({
719
- name: z5.string().min(1).max(63).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, {
720
- message: "Name must be a lowercase slug (letters, numbers, hyphens)"
721
- }),
722
- labels: z5.record(z5.string(), z5.string()).optional().default({})
723
- });
724
- var configScheduleSchema = z5.object({
725
- preset: z5.string().optional(),
726
- cron: z5.string().optional(),
727
- timezone: z5.string().optional().default("UTC"),
728
- providers: z5.array(providerNameSchema).optional().default([])
729
- }).refine(
730
- (data) => data.preset && !data.cron || !data.preset && data.cron,
731
- { message: 'Exactly one of "preset" or "cron" must be provided' }
732
- ).optional();
733
- var configNotificationSchema = z5.object({
734
- channel: z5.literal("webhook"),
735
- url: z5.string().url(),
736
- events: z5.array(notificationEventSchema).min(1)
737
- });
738
- var configGoogleSchema = z5.object({
739
- gsc: z5.object({
740
- propertyUrl: z5.string()
741
- }).optional(),
742
- syncSchedule: z5.object({
743
- preset: z5.string().optional(),
744
- cron: z5.string().optional()
745
- }).optional()
746
- }).optional();
747
- var configSpecSchema = z5.object({
748
- displayName: z5.string().min(1),
749
- canonicalDomain: z5.string().min(1),
750
- ownedDomains: z5.array(z5.string().min(1)).optional().default([]),
751
- country: z5.string().length(2),
752
- language: z5.string().min(2),
753
- keywords: z5.array(z5.string().min(1)).optional().default([]),
754
- competitors: z5.array(z5.string().min(1)).optional().default([]),
755
- providers: z5.array(providerNameSchema).optional().default([]),
756
- locations: z5.array(locationContextSchema).optional().default([]),
757
- defaultLocation: z5.string().optional(),
758
- schedule: configScheduleSchema,
759
- notifications: z5.array(configNotificationSchema).optional().default([]),
760
- google: configGoogleSchema,
761
- autoExtractBacklinks: z5.boolean().optional().default(false)
762
- }).superRefine((spec, ctx) => {
763
- const duplicateLabels = findDuplicateLocationLabels(spec.locations);
764
- if (duplicateLabels.length > 0) {
765
- ctx.addIssue({
766
- code: "custom",
767
- message: `Duplicate location labels are not allowed: ${duplicateLabels.join(", ")}`,
768
- path: ["locations"]
769
- });
770
- }
771
- if (!hasLocationLabel(spec.locations, spec.defaultLocation)) {
772
- ctx.addIssue({
773
- code: "custom",
774
- message: `defaultLocation "${spec.defaultLocation}" must match a configured location label`,
775
- path: ["defaultLocation"]
776
- });
777
- }
778
- });
779
- var projectConfigSchema = z5.object({
780
- apiVersion: z5.literal("canonry/v1"),
781
- kind: z5.literal("Project"),
782
- metadata: configMetadataSchema,
783
- spec: configSpecSchema
784
- });
785
-
786
- // ../contracts/src/google.ts
787
- import { z as z6 } from "zod";
788
- var googleConnectionTypeSchema = z6.enum(["gsc", "ga4"]);
789
- var googleConnectionDtoSchema = z6.object({
790
- id: z6.string(),
791
- domain: z6.string(),
792
- connectionType: googleConnectionTypeSchema,
793
- propertyId: z6.string().nullable().optional(),
794
- sitemapUrl: z6.string().nullable().optional(),
795
- scopes: z6.array(z6.string()).default([]),
796
- createdAt: z6.string(),
797
- updatedAt: z6.string()
798
- });
799
- var gscSearchDataDtoSchema = z6.object({
800
- date: z6.string(),
801
- query: z6.string(),
802
- page: z6.string(),
803
- country: z6.string().nullable().optional(),
804
- device: z6.string().nullable().optional(),
805
- clicks: z6.number(),
806
- impressions: z6.number(),
807
- ctr: z6.number(),
808
- position: z6.number()
809
- });
810
- var gscUrlInspectionDtoSchema = z6.object({
811
- id: z6.string(),
812
- url: z6.string(),
813
- indexingState: z6.string().nullable().optional(),
814
- verdict: z6.string().nullable().optional(),
815
- coverageState: z6.string().nullable().optional(),
816
- pageFetchState: z6.string().nullable().optional(),
817
- robotsTxtState: z6.string().nullable().optional(),
818
- crawlTime: z6.string().nullable().optional(),
819
- lastCrawlResult: z6.string().nullable().optional(),
820
- isMobileFriendly: z6.boolean().nullable().optional(),
821
- richResults: z6.array(z6.string()).default([]),
822
- inspectedAt: z6.string()
823
- });
824
- var indexTransitionSchema = z6.enum(["stable", "reindexed", "deindexed", "still-missing", "new"]);
825
- var gscDeindexedRowSchema = z6.object({
826
- url: z6.string(),
827
- previousState: z6.string().nullable(),
828
- currentState: z6.string().nullable(),
829
- transitionDate: z6.string()
830
- });
831
- var gscReasonGroupSchema = z6.object({
832
- reason: z6.string(),
833
- count: z6.number(),
834
- urls: z6.array(gscUrlInspectionDtoSchema).default([])
835
- });
836
- var gscCoverageSummaryDtoSchema = z6.object({
837
- summary: z6.object({
838
- total: z6.number(),
839
- indexed: z6.number(),
840
- notIndexed: z6.number(),
841
- deindexed: z6.number(),
842
- percentage: z6.number()
843
- }),
844
- lastInspectedAt: z6.string().nullable(),
845
- indexed: z6.array(gscUrlInspectionDtoSchema).default([]),
846
- notIndexed: z6.array(gscUrlInspectionDtoSchema).default([]),
847
- deindexed: z6.array(gscDeindexedRowSchema).default([]),
848
- reasonGroups: z6.array(gscReasonGroupSchema).default([])
849
- });
850
- var indexingNotificationDtoSchema = z6.object({
851
- url: z6.string(),
852
- type: z6.enum(["URL_UPDATED", "URL_DELETED"]),
853
- notifiedAt: z6.string()
854
- });
855
- var indexingRequestResultDtoSchema = z6.object({
856
- url: z6.string(),
857
- type: z6.enum(["URL_UPDATED", "URL_DELETED"]),
858
- notifiedAt: z6.string(),
859
- status: z6.enum(["success", "error"]),
860
- error: z6.string().optional()
861
- });
862
- var gscCoverageSnapshotDtoSchema = z6.object({
863
- date: z6.string(),
864
- indexed: z6.number(),
865
- notIndexed: z6.number(),
866
- reasonBreakdown: z6.record(z6.string(), z6.number()).default({})
867
- });
868
-
869
- // ../contracts/src/bing.ts
870
- import { z as z7 } from "zod";
871
- var bingConnectionDtoSchema = z7.object({
872
- id: z7.string(),
873
- domain: z7.string(),
874
- siteUrl: z7.string().nullable().optional(),
875
- createdAt: z7.string(),
876
- updatedAt: z7.string()
877
- });
878
- var bingUrlInspectionDtoSchema = z7.object({
879
- id: z7.string(),
880
- url: z7.string(),
881
- httpCode: z7.number().nullable().optional(),
882
- inIndex: z7.boolean().nullable().optional(),
883
- lastCrawledDate: z7.string().nullable().optional(),
884
- inIndexDate: z7.string().nullable().optional(),
885
- inspectedAt: z7.string(),
886
- // Fields derived from GetUrlInfo response (more reliable than InIndex)
887
- documentSize: z7.number().nullable().optional(),
888
- anchorCount: z7.number().nullable().optional(),
889
- discoveryDate: z7.string().nullable().optional()
890
- });
891
- var bingCoverageSummaryDtoSchema = z7.object({
892
- summary: z7.object({
893
- total: z7.number(),
894
- indexed: z7.number(),
895
- notIndexed: z7.number(),
896
- unknown: z7.number().optional(),
897
- percentage: z7.number()
898
- }),
899
- lastInspectedAt: z7.string().nullable(),
900
- indexed: z7.array(bingUrlInspectionDtoSchema).default([]),
901
- notIndexed: z7.array(bingUrlInspectionDtoSchema).default([]),
902
- unknown: z7.array(bingUrlInspectionDtoSchema).default([]).optional()
903
- });
904
- var bingKeywordStatsDtoSchema = z7.object({
905
- query: z7.string(),
906
- impressions: z7.number(),
907
- clicks: z7.number(),
908
- ctr: z7.number(),
909
- averagePosition: z7.number()
910
- });
911
- var bingCoverageSnapshotDtoSchema = z7.object({
912
- date: z7.string(),
913
- indexed: z7.number(),
914
- notIndexed: z7.number(),
915
- unknown: z7.number()
916
- });
917
- var bingSubmitResultDtoSchema = z7.object({
918
- url: z7.string(),
919
- status: z7.enum(["success", "error"]),
920
- submittedAt: z7.string(),
921
- error: z7.string().optional()
922
- });
923
-
924
- // ../contracts/src/wordpress.ts
925
- import { z as z8 } from "zod";
926
- var wordpressEnvSchema = z8.enum(["live", "staging"]);
927
- var wordpressConnectionDtoSchema = z8.object({
928
- projectName: z8.string(),
929
- url: z8.string(),
930
- stagingUrl: z8.string().optional(),
931
- username: z8.string(),
932
- defaultEnv: wordpressEnvSchema,
933
- createdAt: z8.string(),
934
- updatedAt: z8.string()
935
- });
936
- var wordpressSiteStatusDtoSchema = z8.object({
937
- url: z8.string(),
938
- reachable: z8.boolean(),
939
- pageCount: z8.number().nullable().optional(),
940
- version: z8.string().nullable().optional(),
941
- error: z8.string().nullable().optional(),
942
- plugins: z8.array(z8.string()).optional(),
943
- authenticatedUser: z8.object({
944
- id: z8.number(),
945
- slug: z8.string()
946
- }).nullable().optional()
947
- });
948
- var wordpressStatusDtoSchema = z8.object({
949
- connected: z8.boolean(),
950
- projectName: z8.string(),
951
- defaultEnv: wordpressEnvSchema,
952
- live: wordpressSiteStatusDtoSchema.nullable(),
953
- staging: wordpressSiteStatusDtoSchema.nullable(),
954
- adminUrl: z8.string().nullable().optional()
955
- });
956
- var wordpressPageSummaryDtoSchema = z8.object({
957
- id: z8.number(),
958
- slug: z8.string(),
959
- title: z8.string(),
960
- status: z8.string(),
961
- modifiedAt: z8.string().nullable().optional(),
962
- link: z8.string().nullable().optional()
963
- });
964
- var wordpressSeoStateDtoSchema = z8.object({
965
- title: z8.string().nullable(),
966
- description: z8.string().nullable(),
967
- noindex: z8.boolean().nullable(),
968
- writable: z8.boolean().default(false),
969
- writeTargets: z8.array(z8.string()).default([])
970
- });
971
- var wordpressSchemaBlockDtoSchema = z8.object({
972
- type: z8.string(),
973
- json: z8.record(z8.string(), z8.unknown())
974
- });
975
- var wordpressPageDetailDtoSchema = wordpressPageSummaryDtoSchema.extend({
976
- env: wordpressEnvSchema,
977
- content: z8.string(),
978
- seo: wordpressSeoStateDtoSchema,
979
- schemaBlocks: z8.array(wordpressSchemaBlockDtoSchema).default([])
980
- });
981
- var wordpressDiffPageDtoSchema = wordpressPageDetailDtoSchema.extend({
982
- contentHash: z8.string(),
983
- contentSnippet: z8.string()
984
- });
985
- var wordpressManualAssistDtoSchema = z8.object({
986
- manualRequired: z8.literal(true),
987
- targetUrl: z8.string(),
988
- adminUrl: z8.string().nullable().optional(),
989
- content: z8.string(),
990
- nextSteps: z8.array(z8.string()).default([])
991
- });
992
- var wordpressAuditIssueDtoSchema = z8.object({
993
- slug: z8.string(),
994
- severity: z8.enum(["high", "medium", "low"]),
995
- code: z8.enum([
996
- "noindex",
997
- "missing-seo-title",
998
- "missing-meta-description",
999
- "missing-schema",
1000
- "thin-content"
1001
- ]),
1002
- message: z8.string()
1003
- });
1004
- var wordpressAuditPageDtoSchema = z8.object({
1005
- slug: z8.string(),
1006
- title: z8.string(),
1007
- status: z8.string(),
1008
- wordCount: z8.number(),
1009
- seo: wordpressSeoStateDtoSchema,
1010
- schemaPresent: z8.boolean(),
1011
- issues: z8.array(wordpressAuditIssueDtoSchema).default([])
1012
- });
1013
- var wordpressBulkMetaEntryResultDtoSchema = z8.object({
1014
- slug: z8.string(),
1015
- status: z8.enum(["applied", "skipped", "manual"]),
1016
- error: z8.string().optional(),
1017
- manualAssist: wordpressManualAssistDtoSchema.optional()
1018
- });
1019
- var wordpressBulkMetaResultDtoSchema = z8.object({
1020
- env: wordpressEnvSchema,
1021
- strategy: z8.enum(["plugin", "manual"]),
1022
- results: z8.array(wordpressBulkMetaEntryResultDtoSchema)
1023
- });
1024
- var wordpressSchemaDeployEntryResultDtoSchema = z8.object({
1025
- slug: z8.string(),
1026
- status: z8.enum(["deployed", "stripped", "skipped", "failed"]),
1027
- schemasInjected: z8.array(z8.string()).optional(),
1028
- manualAssist: wordpressManualAssistDtoSchema.optional(),
1029
- error: z8.string().optional()
1030
- });
1031
- var wordpressSchemaDeployResultDtoSchema = z8.object({
1032
- env: wordpressEnvSchema,
1033
- results: z8.array(wordpressSchemaDeployEntryResultDtoSchema)
1034
- });
1035
- var wordpressSchemaStatusPageDtoSchema = z8.object({
1036
- slug: z8.string(),
1037
- title: z8.string(),
1038
- canonrySchemas: z8.array(z8.string()),
1039
- thirdPartySchemas: z8.array(z8.string()),
1040
- hasCanonrySchema: z8.boolean()
1041
- });
1042
- var wordpressSchemaStatusResultDtoSchema = z8.object({
1043
- env: wordpressEnvSchema,
1044
- pages: z8.array(wordpressSchemaStatusPageDtoSchema)
1045
- });
1046
- var wordpressOnboardStepDtoSchema = z8.object({
1047
- name: z8.string(),
1048
- status: z8.enum(["completed", "skipped", "failed"]),
1049
- summary: z8.string().optional(),
1050
- error: z8.string().optional()
1051
- });
1052
- var wordpressOnboardResultDtoSchema = z8.object({
1053
- projectName: z8.string(),
1054
- steps: z8.array(wordpressOnboardStepDtoSchema)
1055
- });
1056
- var wordpressDiffDtoSchema = z8.object({
1057
- slug: z8.string(),
1058
- live: wordpressDiffPageDtoSchema,
1059
- staging: wordpressDiffPageDtoSchema,
1060
- hasDifferences: z8.boolean(),
1061
- differences: z8.object({
1062
- title: z8.boolean(),
1063
- slug: z8.boolean(),
1064
- content: z8.boolean(),
1065
- seoTitle: z8.boolean(),
1066
- seoDescription: z8.boolean(),
1067
- noindex: z8.boolean(),
1068
- schema: z8.boolean()
1069
- })
1070
- });
1071
-
1072
- // ../contracts/src/providers.ts
1073
- var ProviderIds = {
1074
- claude: "claude",
1075
- openai: "openai",
1076
- gemini: "gemini",
1077
- perplexity: "perplexity",
1078
- local: "local",
1079
- cdpChatgpt: "cdp:chatgpt",
1080
- zai: "zai"
1081
- };
1082
- var PROVIDER_IDS = Object.values(ProviderIds);
1083
- var SweepProviderIds = {
1084
- claude: ProviderIds.claude,
1085
- openai: ProviderIds.openai,
1086
- gemini: ProviderIds.gemini,
1087
- perplexity: ProviderIds.perplexity,
1088
- local: ProviderIds.local,
1089
- cdpChatgpt: ProviderIds.cdpChatgpt
1090
- };
1091
- var SWEEP_PROVIDER_IDS = Object.values(SweepProviderIds);
1092
- var AgentProviderIds = {
1093
- claude: ProviderIds.claude,
1094
- openai: ProviderIds.openai,
1095
- gemini: ProviderIds.gemini,
1096
- zai: ProviderIds.zai
1097
- };
1098
- var AGENT_PROVIDER_IDS = Object.values(AgentProviderIds);
1099
- function isAgentProviderId(value) {
1100
- return AGENT_PROVIDER_IDS.includes(value);
1101
- }
1102
-
1103
- // ../contracts/src/snapshot.ts
1104
- import { z as z9 } from "zod";
1105
- var snapshotAccuracySchema = z9.enum(["yes", "no", "unknown", "not-mentioned"]);
1106
- var snapshotRequestSchema = z9.object({
1107
- companyName: z9.string().min(1),
1108
- domain: z9.string().min(1),
1109
- phrases: z9.array(z9.string().min(1)).optional().default([]),
1110
- competitors: z9.array(z9.string().min(1)).optional().default([])
1111
- });
1112
- var snapshotCompetitorEntrySchema = z9.object({
1113
- name: z9.string(),
1114
- count: z9.number().int().nonnegative()
1115
- });
1116
- var snapshotAuditFactorSchema = z9.object({
1117
- id: z9.string(),
1118
- name: z9.string(),
1119
- weight: z9.number(),
1120
- score: z9.number(),
1121
- grade: z9.string(),
1122
- status: z9.enum(["pass", "partial", "fail"]),
1123
- findings: z9.array(z9.object({
1124
- type: z9.string(),
1125
- message: z9.string()
1126
- })).default([]),
1127
- recommendations: z9.array(z9.string()).default([])
1128
- });
1129
- var snapshotAuditSchema = z9.object({
1130
- url: z9.string(),
1131
- finalUrl: z9.string(),
1132
- auditedAt: z9.string(),
1133
- overallScore: z9.number(),
1134
- overallGrade: z9.string(),
1135
- summary: z9.string(),
1136
- factors: z9.array(snapshotAuditFactorSchema).default([])
1137
- });
1138
- var snapshotProfileSchema = z9.object({
1139
- industry: z9.string(),
1140
- summary: z9.string(),
1141
- services: z9.array(z9.string()).default([]),
1142
- categoryTerms: z9.array(z9.string()).default([])
1143
- });
1144
- var snapshotProviderResultSchema = z9.object({
1145
- provider: z9.string(),
1146
- displayName: z9.string(),
1147
- model: z9.string().nullable().optional(),
1148
- mentioned: z9.boolean(),
1149
- cited: z9.boolean(),
1150
- describedAccurately: snapshotAccuracySchema,
1151
- accuracyNotes: z9.string().nullable().optional(),
1152
- incorrectClaims: z9.array(z9.string()).default([]),
1153
- recommendedCompetitors: z9.array(z9.string()).default([]),
1154
- citedDomains: z9.array(z9.string()).default([]),
1155
- groundingSources: z9.array(groundingSourceSchema).default([]),
1156
- searchQueries: z9.array(z9.string()).default([]),
1157
- answerText: z9.string(),
1158
- error: z9.string().nullable().optional()
1159
- });
1160
- var snapshotQueryResultSchema = z9.object({
1161
- phrase: z9.string(),
1162
- providerResults: z9.array(snapshotProviderResultSchema).default([])
1163
- });
1164
- var snapshotSummarySchema = z9.object({
1165
- totalQueries: z9.number().int().nonnegative(),
1166
- totalProviders: z9.number().int().nonnegative(),
1167
- totalComparisons: z9.number().int().nonnegative(),
1168
- mentionCount: z9.number().int().nonnegative(),
1169
- citationCount: z9.number().int().nonnegative(),
1170
- topCompetitors: z9.array(snapshotCompetitorEntrySchema).default([]),
1171
- visibilityGap: z9.string(),
1172
- whatThisMeans: z9.array(z9.string()).default([]),
1173
- recommendedActions: z9.array(z9.string()).default([])
1174
- });
1175
- var snapshotReportSchema = z9.object({
1176
- companyName: z9.string(),
1177
- domain: z9.string(),
1178
- homepageUrl: z9.string(),
1179
- generatedAt: z9.string(),
1180
- phrases: z9.array(z9.string()).default([]),
1181
- competitors: z9.array(z9.string()).default([]),
1182
- profile: snapshotProfileSchema,
1183
- audit: snapshotAuditSchema,
1184
- queryResults: z9.array(snapshotQueryResultSchema).default([]),
1185
- summary: snapshotSummarySchema
1186
- });
1187
-
1188
- // ../contracts/src/schedule.ts
1189
- import { z as z10 } from "zod";
1190
- var scheduleDtoSchema = z10.object({
1191
- id: z10.string(),
1192
- projectId: z10.string(),
1193
- cronExpr: z10.string(),
1194
- preset: z10.string().nullable().optional(),
1195
- timezone: z10.string().default("UTC"),
1196
- enabled: z10.boolean().default(true),
1197
- providers: z10.array(providerNameSchema).default([]),
1198
- lastRunAt: z10.string().nullable().optional(),
1199
- nextRunAt: z10.string().nullable().optional(),
1200
- createdAt: z10.string(),
1201
- updatedAt: z10.string()
1202
- });
1203
- var scheduleUpsertRequestSchema = z10.object({
1204
- preset: z10.string().optional(),
1205
- cron: z10.string().optional(),
1206
- timezone: z10.string().optional().default("UTC"),
1207
- enabled: z10.boolean().optional().default(true),
1208
- providers: z10.array(providerNameSchema).optional().default([])
1209
- }).refine(
1210
- (data) => data.preset && !data.cron || !data.preset && data.cron,
1211
- { message: 'Exactly one of "preset" or "cron" must be provided' }
1212
- );
1213
-
1214
- // ../contracts/src/analytics.ts
1215
- import { z as z11 } from "zod";
1216
- var visibilityMetricModeSchema = z11.enum(["mentioned", "cited"]);
1217
- var VisibilityMetricModes = visibilityMetricModeSchema.enum;
1218
- function parseWindow(value) {
1219
- if (value === "7d" || value === "30d" || value === "90d" || value === "all") return value;
1220
- return "all";
1221
- }
1222
- function windowCutoff(window) {
1223
- if (window === "all") return null;
1224
- const days = window === "7d" ? 7 : window === "30d" ? 30 : 90;
1225
- const d = /* @__PURE__ */ new Date();
1226
- d.setDate(d.getDate() - days);
1227
- return d.toISOString();
1228
- }
1229
-
1230
- // ../contracts/src/source-categories.ts
1231
- var SOURCE_CATEGORY_RULES = [
1232
- // Forums
1233
- { pattern: "reddit.com", category: "forum", label: "Reddit" },
1234
- { pattern: "quora.com", category: "forum", label: "Quora" },
1235
- { pattern: "stackexchange.com", category: "forum", label: "Stack Exchange" },
1236
- { pattern: "stackoverflow.com", category: "forum", label: "Stack Overflow" },
1237
- { pattern: "discourse.org", category: "forum", label: "Discourse" },
1238
- // Social
1239
- { pattern: "linkedin.com", category: "social", label: "LinkedIn" },
1240
- { pattern: "twitter.com", category: "social", label: "X (Twitter)" },
1241
- { pattern: "x.com", category: "social", label: "X (Twitter)" },
1242
- { pattern: "facebook.com", category: "social", label: "Facebook" },
1243
- { pattern: "instagram.com", category: "social", label: "Instagram" },
1244
- { pattern: "threads.net", category: "social", label: "Threads" },
1245
- { pattern: "pinterest.com", category: "social", label: "Pinterest" },
1246
- { pattern: "tiktok.com", category: "social", label: "TikTok" },
1247
- // Video
1248
- { pattern: "youtube.com", category: "video", label: "YouTube" },
1249
- { pattern: "youtu.be", category: "video", label: "YouTube" },
1250
- { pattern: "vimeo.com", category: "video", label: "Vimeo" },
1251
- // News
1252
- { pattern: "nytimes.com", category: "news", label: "NY Times" },
1253
- { pattern: "bbc.com", category: "news", label: "BBC" },
1254
- { pattern: "bbc.co.uk", category: "news", label: "BBC" },
1255
- { pattern: "cnn.com", category: "news", label: "CNN" },
1256
- { pattern: "reuters.com", category: "news", label: "Reuters" },
1257
- { pattern: "apnews.com", category: "news", label: "AP News" },
1258
- { pattern: "theguardian.com", category: "news", label: "The Guardian" },
1259
- { pattern: "washingtonpost.com", category: "news", label: "Washington Post" },
1260
- { pattern: "wsj.com", category: "news", label: "WSJ" },
1261
- { pattern: "forbes.com", category: "news", label: "Forbes" },
1262
- { pattern: "techcrunch.com", category: "news", label: "TechCrunch" },
1263
- { pattern: "theverge.com", category: "news", label: "The Verge" },
1264
- { pattern: "wired.com", category: "news", label: "Wired" },
1265
- { pattern: "arstechnica.com", category: "news", label: "Ars Technica" },
1266
- // Reference
1267
- { pattern: "wikipedia.org", category: "reference", label: "Wikipedia" },
1268
- { pattern: "wikimedia.org", category: "reference", label: "Wikimedia" },
1269
- { pattern: "britannica.com", category: "reference", label: "Britannica" },
1270
- { pattern: "merriam-webster.com", category: "reference", label: "Merriam-Webster" },
1271
- // Blog / Content platforms
1272
- { pattern: "medium.com", category: "blog", label: "Medium" },
1273
- { pattern: "substack.com", category: "blog", label: "Substack" },
1274
- { pattern: "dev.to", category: "blog", label: "DEV Community" },
1275
- { pattern: "hashnode.dev", category: "blog", label: "Hashnode" },
1276
- { pattern: "wordpress.com", category: "blog", label: "WordPress" },
1277
- { pattern: "blogger.com", category: "blog", label: "Blogger" },
1278
- { pattern: "hubspot.com", category: "blog", label: "HubSpot" },
1279
- // E-commerce
1280
- { pattern: "amazon.com", category: "ecommerce", label: "Amazon" },
1281
- { pattern: "amazon.co.uk", category: "ecommerce", label: "Amazon UK" },
1282
- { pattern: "shopify.com", category: "ecommerce", label: "Shopify" },
1283
- { pattern: "ebay.com", category: "ecommerce", label: "eBay" },
1284
- // Academic
1285
- { pattern: "scholar.google.com", category: "academic", label: "Google Scholar" },
1286
- { pattern: "arxiv.org", category: "academic", label: "arXiv" },
1287
- { pattern: "pubmed.ncbi.nlm.nih.gov", category: "academic", label: "PubMed" },
1288
- { pattern: "researchgate.net", category: "academic", label: "ResearchGate" },
1289
- { pattern: ".edu", category: "academic", label: "Academic (.edu)" }
1290
- ];
1291
- var CATEGORY_LABELS = {
1292
- social: "Social Media",
1293
- forum: "Forums & Q&A",
1294
- news: "News & Media",
1295
- reference: "Reference",
1296
- blog: "Blogs & Content",
1297
- ecommerce: "E-commerce",
1298
- video: "Video",
1299
- academic: "Academic",
1300
- other: "Other"
1301
- };
1302
- function categorizeSource(uri) {
1303
- let domain;
1304
- try {
1305
- const url = new URL(uri.startsWith("http") ? uri : `https://${uri}`);
1306
- domain = url.hostname.replace(/^www\./, "");
1307
- } catch {
1308
- domain = uri.replace(/^https?:\/\//, "").replace(/^www\./, "").split("/")[0] ?? uri;
1309
- }
1310
- const domainLower = domain.toLowerCase();
1311
- for (const rule of SOURCE_CATEGORY_RULES) {
1312
- if (domainLower === rule.pattern || domainLower.endsWith(`.${rule.pattern}`) || rule.pattern.startsWith(".") && domainLower.endsWith(rule.pattern)) {
1313
- return { category: rule.category, label: rule.label, domain };
1314
- }
1315
- }
1316
- return { category: "other", label: CATEGORY_LABELS.other, domain };
1317
- }
1318
- function categoryLabel(category) {
1319
- return CATEGORY_LABELS[category];
1320
- }
1321
-
1322
- // ../contracts/src/ga.ts
1323
- import { z as z12 } from "zod";
1324
- var ga4ConnectionDtoSchema = z12.object({
1325
- id: z12.string(),
1326
- projectId: z12.string(),
1327
- propertyId: z12.string(),
1328
- clientEmail: z12.string(),
1329
- connected: z12.boolean(),
1330
- createdAt: z12.string(),
1331
- updatedAt: z12.string()
1332
- });
1333
- var ga4TrafficSnapshotDtoSchema = z12.object({
1334
- date: z12.string(),
1335
- landingPage: z12.string(),
1336
- sessions: z12.number(),
1337
- organicSessions: z12.number(),
1338
- users: z12.number()
1339
- });
1340
- var ga4SourceDimensionSchema = z12.enum(["session", "first_user", "manual_utm"]);
1341
- var ga4AiReferralDtoSchema = z12.object({
1342
- source: z12.string(),
1343
- medium: z12.string(),
1344
- sessions: z12.number(),
1345
- users: z12.number(),
1346
- sourceDimension: ga4SourceDimensionSchema
1347
- });
1348
- var ga4AiReferralLandingPageDtoSchema = z12.object({
1349
- source: z12.string(),
1350
- medium: z12.string(),
1351
- sourceDimension: ga4SourceDimensionSchema,
1352
- landingPage: z12.string(),
1353
- sessions: z12.number(),
1354
- users: z12.number()
1355
- });
1356
- var ga4SocialReferralDtoSchema = z12.object({
1357
- source: z12.string(),
1358
- medium: z12.string(),
1359
- sessions: z12.number(),
1360
- users: z12.number(),
1361
- /** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
1362
- channelGroup: z12.string()
1363
- });
1364
- var ga4TrafficSummaryDtoSchema = z12.object({
1365
- totalSessions: z12.number(),
1366
- totalOrganicSessions: z12.number(),
1367
- /** Direct-channel sessions (sessions with no source — bookmarks, typed URLs, AI-driven traffic with stripped referrer). 0 for legacy rows from before the column was added. */
1368
- totalDirectSessions: z12.number(),
1369
- totalUsers: z12.number(),
1370
- topPages: z12.array(z12.object({
1371
- landingPage: z12.string(),
1372
- sessions: z12.number(),
1373
- organicSessions: z12.number(),
1374
- /** Per-page Direct-channel sessions. 0 for legacy rows. */
1375
- directSessions: z12.number(),
1376
- users: z12.number()
1377
- })),
1378
- aiReferrals: z12.array(ga4AiReferralDtoSchema),
1379
- aiReferralLandingPages: z12.array(ga4AiReferralLandingPageDtoSchema),
1380
- /** Deduped AI session total: MAX(sessions) per date+source+medium across attribution dimensions, then summed. Cross-cutting: can overlap with Direct/Organic/Social via firstUserSource. */
1381
- aiSessionsDeduped: z12.number(),
1382
- /** Deduped AI user total: MAX(users) per date+source+medium across attribution dimensions, then summed. */
1383
- aiUsersDeduped: z12.number(),
1384
- /** AI sessions whose CURRENT sessionSource matched an AI engine. Disjoint from Direct/Organic/Social — safe for the channel breakdown. */
1385
- aiSessionsBySession: z12.number(),
1386
- /** AI users whose CURRENT sessionSource matched an AI engine. Disjoint from Direct/Organic/Social — safe for the channel breakdown. */
1387
- aiUsersBySession: z12.number(),
1388
- socialReferrals: z12.array(ga4SocialReferralDtoSchema),
1389
- /** Total social sessions (session-scoped, no cross-dimension dedup needed). */
1390
- socialSessions: z12.number(),
1391
- /** Total social users (session-scoped, no cross-dimension dedup needed). */
1392
- socialUsers: z12.number(),
1393
- /** Organic sessions as a percentage of total sessions (0–100, rounded). */
1394
- organicSharePct: z12.number(),
1395
- /** Deduped AI sessions as a percentage of total sessions (0–100, rounded). Cross-cutting: can overlap with Direct/Organic/Social. */
1396
- aiSharePct: z12.number(),
1397
- /** Session-source-only AI sessions as a percentage of total sessions (0–100, rounded). Disjoint from Direct/Organic/Social. */
1398
- aiSharePctBySession: z12.number(),
1399
- /** Direct-channel sessions as a percentage of total sessions (0–100, rounded). */
1400
- directSharePct: z12.number(),
1401
- /** Social sessions as a percentage of total sessions (0–100, rounded). */
1402
- socialSharePct: z12.number(),
1403
- /** Display string for organicSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1404
- organicSharePctDisplay: z12.string(),
1405
- /** Display string for aiSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1406
- aiSharePctDisplay: z12.string(),
1407
- /** Display string for aiSharePctBySession: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1408
- aiSharePctBySessionDisplay: z12.string(),
1409
- /** Display string for directSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1410
- directSharePctDisplay: z12.string(),
1411
- /** Display string for socialSharePct: 'X%', '<1%' for non-zero shares that round below 1, or '—' when sessions exist but total is unknown (partial sync). */
1412
- socialSharePctDisplay: z12.string(),
1413
- lastSyncedAt: z12.string().nullable()
1414
- });
1415
- var ga4AiReferralHistoryEntrySchema = z12.object({
1416
- date: z12.string(),
1417
- source: z12.string(),
1418
- medium: z12.string(),
1419
- landingPage: z12.string(),
1420
- sessions: z12.number(),
1421
- users: z12.number(),
1422
- /** Which GA4 dimension this row came from: session (sessionSource), first_user (firstUserSource), or manual_utm (utm_source parameter) */
1423
- sourceDimension: ga4SourceDimensionSchema
1424
- });
1425
- var ga4SocialReferralHistoryEntrySchema = z12.object({
1426
- date: z12.string(),
1427
- source: z12.string(),
1428
- medium: z12.string(),
1429
- sessions: z12.number(),
1430
- users: z12.number(),
1431
- /** GA4 default channel group (e.g. 'Organic Social', 'Paid Social') */
1432
- channelGroup: z12.string()
1433
- });
1434
- var ga4SessionHistoryEntrySchema = z12.object({
1435
- date: z12.string(),
1436
- sessions: z12.number(),
1437
- organicSessions: z12.number(),
1438
- users: z12.number()
1439
- });
1440
-
1441
- // ../contracts/src/answer-visibility.ts
1442
- var GENERIC_TOKENS = /* @__PURE__ */ new Set([
1443
- "agency",
1444
- "app",
1445
- "company",
1446
- "corp",
1447
- "group",
1448
- "health",
1449
- "inc",
1450
- "llc",
1451
- "online",
1452
- "platform",
1453
- "services",
1454
- "site",
1455
- "solutions",
1456
- "software",
1457
- "systems",
1458
- "tech"
1459
- ]);
1460
- var MIN_BRAND_KEY_LENGTH = 6;
1461
- var BUSINESS_SUFFIXES = [
1462
- "incorporated",
1463
- "corporation",
1464
- "limited",
1465
- "company",
1466
- "gmbh",
1467
- "pllc",
1468
- "corp",
1469
- "group",
1470
- "llp",
1471
- "plc",
1472
- "llc",
1473
- "inc",
1474
- "ltd"
1475
- ];
1476
- function extractAnswerMentions(answerText, displayName, domains) {
1477
- if (!answerText) return { mentioned: false, matchedTerms: [] };
1478
- const matchedTerms = [];
1479
- const lowerAnswer = answerText.toLowerCase();
1480
- for (const domain of domains) {
1481
- const normalizedDomain = normalizeProjectDomain(domain);
1482
- if (!normalizedDomain || !normalizedDomain.includes(".")) continue;
1483
- if (domainMentioned(lowerAnswer, normalizedDomain)) {
1484
- matchedTerms.push(normalizedDomain);
1485
- }
1486
- }
1487
- const answerNormalized = normalizeText(answerText);
1488
- const answerBrandKey = brandKeyFromText(answerText);
1489
- const normalizedCandidates = brandNormalizedCandidates(displayName);
1490
- const brandKeyCandidates = brandKeyCandidatesForMatch(displayName);
1491
- const matchesNormalized = normalizedCandidates.some(
1492
- (c) => new RegExp(`\\b${escapeRegExp(c)}\\b`).test(answerNormalized)
1493
- );
1494
- const matchesBrandKey = brandKeyCandidates.some(
1495
- (c) => c.length >= MIN_BRAND_KEY_LENGTH && answerBrandKey.includes(c)
1496
- );
1497
- if (matchesNormalized || matchesBrandKey) {
1498
- matchedTerms.push(displayName);
1499
- }
1500
- const tokens = collectDistinctiveTokens(displayName, domains);
1501
- let tokenMatches = 0;
1502
- const matchedTokens = [];
1503
- for (const token of tokens) {
1504
- if (new RegExp(`\\b${escapeRegExp(token)}\\b`).test(lowerAnswer)) {
1505
- tokenMatches++;
1506
- matchedTokens.push(token);
1507
- }
1508
- }
1509
- const tokenThresholdMet = tokens.length > 0 && (tokens.length === 1 && tokenMatches >= 1 || tokenMatches >= Math.min(2, tokens.length));
1510
- if (tokenThresholdMet) {
1511
- matchedTerms.push(...matchedTokens);
1512
- }
1513
- const unique = [...new Set(matchedTerms)];
1514
- const domainMatches = unique.filter((t) => t.includes("."));
1515
- const dedupedFinal = unique.filter((term) => {
1516
- if (term.includes(".")) return true;
1517
- return !domainMatches.some((d) => d.toLowerCase().startsWith(term.toLowerCase() + "."));
1518
- });
1519
- return { mentioned: dedupedFinal.length > 0, matchedTerms: dedupedFinal };
1520
- }
1521
- function determineAnswerMentioned(answerText, displayName, domains) {
1522
- return extractAnswerMentions(answerText, displayName, domains).mentioned;
1523
- }
1524
- function visibilityStateFromAnswerMentioned(answerMentioned) {
1525
- return answerMentioned ? "visible" : "not-visible";
1526
- }
1527
- function brandKeyFromText(value) {
1528
- return value.toLowerCase().replace(/[^a-z0-9]/g, "");
1529
- }
1530
- function domainMentioned(lowerAnswer, normalizedDomain) {
1531
- const escapedDomain = escapeRegExp(normalizedDomain.toLowerCase());
1532
- const patterns = [
1533
- new RegExp(`(^|[^a-z0-9-])${escapedDomain}($|[^a-z0-9-])`),
1534
- new RegExp(`https?://(?:www\\.)?${escapedDomain}(?:[/:?#]|$)`),
1535
- new RegExp(`www\\.${escapedDomain}(?:[/:?#]|$)`)
1536
- ];
1537
- return patterns.some((pattern) => pattern.test(lowerAnswer));
1538
- }
1539
- function collectDistinctiveTokens(displayName, domains) {
1540
- const tokens = /* @__PURE__ */ new Set();
1541
- for (const token of extractDistinctiveTokens(displayName)) {
1542
- tokens.add(token);
1543
- }
1544
- for (const domain of domains) {
1545
- const reg = registrableDomain(domain);
1546
- const brand = reg ? brandLabelFromDomain(reg) : normalizeProjectDomain(domain).split("/")[0]?.split(".")[0] ?? "";
1547
- const token = brand.replace(/[^a-z0-9]/gi, "").toLowerCase();
1548
- if (isDistinctiveToken(token)) tokens.add(token);
1549
- }
1550
- return [...tokens];
1551
- }
1552
- function extractDistinctiveTokens(value) {
1553
- return normalizeText(value).split(" ").filter(isDistinctiveToken);
1554
- }
1555
- function isDistinctiveToken(token) {
1556
- if (token.length < 4) return false;
1557
- return !GENERIC_TOKENS.has(token);
1558
- }
1559
- function normalizeText(value) {
1560
- return value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
1561
- }
1562
- function brandNormalizedCandidates(displayName) {
1563
- const original = normalizeText(displayName);
1564
- if (!original) return [];
1565
- const stripped = stripBusinessSuffix(original, " ");
1566
- if (!stripped || stripped === original) return [original];
1567
- return [original, stripped];
1568
- }
1569
- function brandKeyCandidatesForMatch(displayName) {
1570
- const original = brandKeyFromText(displayName);
1571
- if (!original) return [];
1572
- const stripped = stripBusinessSuffix(original, "");
1573
- return stripped && stripped !== original ? [original, stripped] : [original];
1574
- }
1575
- function stripBusinessSuffix(value, separator) {
1576
- for (const suffix of BUSINESS_SUFFIXES) {
1577
- const trailing = `${separator}${suffix}`;
1578
- if (value.endsWith(trailing) && value.length - trailing.length >= 3) {
1579
- return value.slice(0, -trailing.length);
1580
- }
1581
- }
1582
- return value;
1583
- }
1584
- function escapeRegExp(value) {
1585
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1586
- }
1587
-
1588
- // ../contracts/src/agent.ts
1589
- import { z as z13 } from "zod";
1590
- var memorySourceSchema = z13.enum(["aero", "user", "compaction"]);
1591
- var MemorySources = memorySourceSchema.enum;
1592
- var AGENT_MEMORY_VALUE_MAX_BYTES = 2 * 1024;
1593
- var AGENT_MEMORY_KEY_MAX_LENGTH = 128;
1594
- var agentMemoryUpsertRequestSchema = z13.object({
1595
- key: z13.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH),
1596
- value: z13.string().min(1)
1597
- });
1598
- var agentMemoryDeleteRequestSchema = z13.object({
1599
- key: z13.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH)
1600
- });
1601
-
1602
- // ../contracts/src/backlinks.ts
1603
- import { z as z14 } from "zod";
1604
- var ccReleaseSyncStatusSchema = z14.enum(["queued", "downloading", "querying", "ready", "failed"]);
1605
- var CcReleaseSyncStatuses = ccReleaseSyncStatusSchema.enum;
1606
- var ccReleaseSyncDtoSchema = z14.object({
1607
- id: z14.string(),
1608
- release: z14.string(),
1609
- status: ccReleaseSyncStatusSchema,
1610
- phaseDetail: z14.string().nullable().optional(),
1611
- vertexPath: z14.string().nullable().optional(),
1612
- edgesPath: z14.string().nullable().optional(),
1613
- vertexSha256: z14.string().nullable().optional(),
1614
- edgesSha256: z14.string().nullable().optional(),
1615
- vertexBytes: z14.number().int().nullable().optional(),
1616
- edgesBytes: z14.number().int().nullable().optional(),
1617
- projectsProcessed: z14.number().int().nullable().optional(),
1618
- domainsDiscovered: z14.number().int().nullable().optional(),
1619
- downloadStartedAt: z14.string().nullable().optional(),
1620
- downloadFinishedAt: z14.string().nullable().optional(),
1621
- queryStartedAt: z14.string().nullable().optional(),
1622
- queryFinishedAt: z14.string().nullable().optional(),
1623
- error: z14.string().nullable().optional(),
1624
- createdAt: z14.string(),
1625
- updatedAt: z14.string()
1626
- });
1627
- var backlinkDomainDtoSchema = z14.object({
1628
- linkingDomain: z14.string(),
1629
- numHosts: z14.number().int()
1630
- });
1631
- var backlinkSummaryDtoSchema = z14.object({
1632
- projectId: z14.string(),
1633
- release: z14.string(),
1634
- targetDomain: z14.string(),
1635
- totalLinkingDomains: z14.number().int(),
1636
- totalHosts: z14.number().int(),
1637
- top10HostsShare: z14.string(),
1638
- queriedAt: z14.string(),
1639
- // Populated when the response is filtered (e.g. ?excludeCrawlers=1).
1640
- // Counts the rows omitted from totalLinkingDomains/totalHosts so callers
1641
- // can show "N hidden" hints without re-deriving them.
1642
- excludedLinkingDomains: z14.number().int().optional(),
1643
- excludedHosts: z14.number().int().optional()
1644
- });
1645
- var backlinkListResponseSchema = z14.object({
1646
- summary: backlinkSummaryDtoSchema.nullable(),
1647
- total: z14.number().int(),
1648
- rows: z14.array(backlinkDomainDtoSchema)
1649
- });
1650
- var backlinkHistoryEntrySchema = z14.object({
1651
- release: z14.string(),
1652
- totalLinkingDomains: z14.number().int(),
1653
- totalHosts: z14.number().int(),
1654
- top10HostsShare: z14.string(),
1655
- queriedAt: z14.string()
1656
- });
1657
- var backlinksInstallStatusDtoSchema = z14.object({
1658
- duckdbInstalled: z14.boolean(),
1659
- duckdbVersion: z14.string().nullable().optional(),
1660
- duckdbSpec: z14.string(),
1661
- pluginDir: z14.string()
1662
- });
1663
- var backlinksInstallResultDtoSchema = z14.object({
1664
- installed: z14.boolean(),
1665
- version: z14.string(),
1666
- path: z14.string(),
1667
- alreadyPresent: z14.boolean()
1668
- });
1669
- var ccAvailableReleaseSchema = z14.object({
1670
- release: z14.string(),
1671
- vertexUrl: z14.string(),
1672
- edgesUrl: z14.string(),
1673
- vertexBytes: z14.number().int().nullable(),
1674
- edgesBytes: z14.number().int().nullable(),
1675
- lastModified: z14.string().nullable()
1676
- });
1677
- var ccCachedReleaseSchema = z14.object({
1678
- release: z14.string(),
1679
- syncStatus: ccReleaseSyncStatusSchema.nullable(),
1680
- bytes: z14.number().int(),
1681
- lastUsedAt: z14.string().nullable()
1682
- });
1683
-
1684
- // ../contracts/src/composites.ts
1685
- import { z as z15 } from "zod";
1686
- var searchHitKindSchema = z15.enum(["snapshot", "insight"]);
1687
- var projectSearchSnapshotHitSchema = z15.object({
1688
- kind: z15.literal("snapshot"),
1689
- id: z15.string(),
1690
- runId: z15.string(),
1691
- keyword: z15.string(),
1692
- provider: z15.string(),
1693
- model: z15.string().nullable(),
1694
- citationState: citationStateSchema,
1695
- matchedField: z15.enum(["answerText", "citedDomains", "searchQueries", "keyword"]),
1696
- snippet: z15.string(),
1697
- createdAt: z15.string()
1698
- });
1699
- var projectSearchInsightHitSchema = z15.object({
1700
- kind: z15.literal("insight"),
1701
- id: z15.string(),
1702
- runId: z15.string().nullable(),
1703
- type: z15.enum(["regression", "gain", "opportunity"]),
1704
- severity: z15.enum(["critical", "high", "medium", "low"]),
1705
- title: z15.string(),
1706
- keyword: z15.string(),
1707
- provider: z15.string(),
1708
- matchedField: z15.enum(["title", "keyword", "recommendation", "cause"]),
1709
- snippet: z15.string(),
1710
- dismissed: z15.boolean(),
1711
- createdAt: z15.string()
1712
- });
1713
- var projectSearchHitSchema = z15.discriminatedUnion("kind", [
1714
- projectSearchSnapshotHitSchema,
1715
- projectSearchInsightHitSchema
1716
- ]);
1717
- var projectSearchResponseSchema = z15.object({
1718
- query: z15.string(),
1719
- totalHits: z15.number().int().nonnegative(),
1720
- truncated: z15.boolean(),
1721
- hits: z15.array(projectSearchHitSchema)
1722
- });
1723
-
1724
- // ../contracts/src/content.ts
1725
- import { z as z16 } from "zod";
1726
- var contentActionSchema = z16.enum(["create", "expand", "refresh", "add-schema"]);
1727
- var ContentActions = contentActionSchema.enum;
1728
- var demandSourceSchema = z16.enum(["gsc", "competitor-evidence", "both"]);
1729
- var DemandSources = demandSourceSchema.enum;
1730
- var actionConfidenceSchema = z16.enum(["high", "medium", "low"]);
1731
- var ActionConfidences = actionConfidenceSchema.enum;
1732
- var pageTypeSchema = z16.enum([
1733
- "blog-post",
1734
- "comparison",
1735
- "listicle",
1736
- "how-to",
1737
- "guide",
1738
- "glossary"
1739
- ]);
1740
- var PageTypes = pageTypeSchema.enum;
1741
- var contentActionStateSchema = z16.enum([
1742
- "proposed",
1743
- "briefed",
1744
- "payload-generated",
1745
- "draft-created",
1746
- "published",
1747
- "validated",
1748
- "dismissed"
1749
- ]);
1750
- var ContentActionStates = contentActionStateSchema.enum;
1751
- var ourBestPageSchema = z16.object({
1752
- url: z16.string(),
1753
- gscImpressions: z16.number().nonnegative(),
1754
- gscClicks: z16.number().nonnegative(),
1755
- // Null when the page came from the inventory fallback (no GSC ranking data).
1756
- gscAvgPosition: z16.number().nonnegative().nullable(),
1757
- organicSessions: z16.number().nonnegative()
1758
- });
1759
- var winningCompetitorSchema = z16.object({
1760
- domain: z16.string(),
1761
- url: z16.string(),
1762
- title: z16.string(),
1763
- citationCount: z16.number().int().nonnegative()
1764
- });
1765
- var scoreBreakdownSchema = z16.object({
1766
- demand: z16.number(),
1767
- competitor: z16.number(),
1768
- absence: z16.number(),
1769
- gapSeverity: z16.number()
1770
- });
1771
- var existingActionRefSchema = z16.object({
1772
- actionId: z16.string(),
1773
- state: contentActionStateSchema,
1774
- lastUpdated: z16.string()
1775
- });
1776
- var contentTargetRowDtoSchema = z16.object({
1777
- targetRef: z16.string(),
1778
- query: z16.string(),
1779
- action: contentActionSchema,
1780
- ourBestPage: ourBestPageSchema.nullable(),
1781
- winningCompetitor: winningCompetitorSchema.nullable(),
1782
- score: z16.number(),
1783
- scoreBreakdown: scoreBreakdownSchema,
1784
- drivers: z16.array(z16.string()),
1785
- demandSource: demandSourceSchema,
1786
- actionConfidence: actionConfidenceSchema,
1787
- existingAction: existingActionRefSchema.nullable()
1788
- });
1789
- var contentTargetsResponseDtoSchema = z16.object({
1790
- targets: z16.array(contentTargetRowDtoSchema),
1791
- contextMetrics: z16.object({
1792
- totalAiReferralSessions: z16.number().int().nonnegative(),
1793
- latestRunId: z16.string(),
1794
- runTimestamp: z16.string()
1795
- })
1796
- });
1797
- var contentGroundingSourceSchema = z16.object({
1798
- uri: z16.string(),
1799
- title: z16.string(),
1800
- domain: z16.string(),
1801
- isOurDomain: z16.boolean(),
1802
- isCompetitor: z16.boolean(),
1803
- citationCount: z16.number().int().nonnegative(),
1804
- providers: z16.array(providerNameSchema)
1805
- });
1806
- var contentSourceRowDtoSchema = z16.object({
1807
- query: z16.string(),
1808
- groundingSources: z16.array(contentGroundingSourceSchema)
1809
- });
1810
- var contentSourcesResponseDtoSchema = z16.object({
1811
- sources: z16.array(contentSourceRowDtoSchema),
1812
- latestRunId: z16.string()
1813
- });
1814
- var contentGapRowDtoSchema = z16.object({
1815
- query: z16.string(),
1816
- competitorDomains: z16.array(z16.string()),
1817
- competitorCount: z16.number().int().nonnegative(),
1818
- missRate: z16.number().min(0).max(1),
1819
- lastSeenInRunId: z16.string()
1820
- });
1821
- var contentGapsResponseDtoSchema = z16.object({
1822
- gaps: z16.array(contentGapRowDtoSchema),
1823
- latestRunId: z16.string()
1824
- });
1825
-
1826
- // ../contracts/src/doctor.ts
1827
- import { z as z17 } from "zod";
1828
- var checkStatusSchema = z17.enum(["ok", "warn", "fail", "skipped"]);
1829
- var CheckStatuses = checkStatusSchema.enum;
1830
- var checkScopeSchema = z17.enum(["global", "project"]);
1831
- var CheckScopes = checkScopeSchema.enum;
1832
- var checkCategorySchema = z17.enum([
1833
- "auth",
1834
- "config",
1835
- "providers",
1836
- "integrations",
1837
- "database",
1838
- "schedules"
1839
- ]);
1840
- var CheckCategories = checkCategorySchema.enum;
1841
- var checkResultSchema = z17.object({
1842
- id: z17.string(),
1843
- category: checkCategorySchema,
1844
- scope: checkScopeSchema,
1845
- title: z17.string(),
1846
- status: checkStatusSchema,
1847
- code: z17.string().describe('Stable machine-readable code (e.g. "google.token.refresh-failed"). Use this for filtering and remediation logic.'),
1848
- summary: z17.string(),
1849
- remediation: z17.string().nullable().optional().describe('Operator-facing next step. Null when status is "ok" or no specific remediation applies.'),
1850
- details: z17.record(z17.string(), z17.unknown()).optional().describe("Structured context \u2014 principal email, redirect URI, missing scopes, etc. Stable per check id."),
1851
- durationMs: z17.number().int().nonnegative().describe("How long the check took to execute.")
1852
- });
1853
- var doctorReportSchema = z17.object({
1854
- scope: checkScopeSchema,
1855
- project: z17.string().nullable().describe('Project name when scope is "project", null otherwise.'),
1856
- generatedAt: z17.string().describe("ISO-8601 timestamp when this doctor run started."),
1857
- durationMs: z17.number().int().nonnegative(),
1858
- summary: z17.object({
1859
- total: z17.number().int().nonnegative(),
1860
- ok: z17.number().int().nonnegative(),
1861
- warn: z17.number().int().nonnegative(),
1862
- fail: z17.number().int().nonnegative(),
1863
- skipped: z17.number().int().nonnegative()
1864
- }),
1865
- checks: z17.array(checkResultSchema)
1866
- });
1867
- function summarizeCheckResults(results) {
1868
- const summary = { total: results.length, ok: 0, warn: 0, fail: 0, skipped: 0 };
1869
- for (const result of results) {
1870
- switch (result.status) {
1871
- case CheckStatuses.ok:
1872
- summary.ok += 1;
1873
- break;
1874
- case CheckStatuses.warn:
1875
- summary.warn += 1;
1876
- break;
1877
- case CheckStatuses.fail:
1878
- summary.fail += 1;
1879
- break;
1880
- case CheckStatuses.skipped:
1881
- summary.skipped += 1;
1882
- break;
1883
- }
1884
- }
1885
- return summary;
1886
- }
1887
-
1888
- // ../contracts/src/url-normalize.ts
1889
- var STRIP_KEYS = /* @__PURE__ */ new Set([
1890
- // Click identifiers
1891
- "fbclid",
1892
- "gclid",
1893
- "msclkid",
1894
- "ttclid",
1895
- "li_fat_id",
1896
- "igshid",
1897
- "yclid",
1898
- "dclid",
1899
- "gbraid",
1900
- "wbraid",
1901
- "bingid",
1902
- // Mailchimp
1903
- "mc_cid",
1904
- "mc_eid",
1905
- // Google Analytics linkers
1906
- "_ga",
1907
- "_gl",
1908
- // Google Tag Manager debug
1909
- "gtm_latency",
1910
- "gtm_debug",
1911
- // WordPress internal noise
1912
- "preview",
1913
- "preview_id",
1914
- "preview_nonce",
1915
- "_thumbnail_id",
1916
- // Common cache-busters/versioning
1917
- "v",
1918
- "ver",
1919
- "version"
1920
- ]);
1921
- function shouldStrip(key) {
1922
- if (STRIP_KEYS.has(key)) return true;
1923
- if (key.startsWith("utm_")) return true;
1924
- return false;
1925
- }
1926
- function parseQuery(query) {
1927
- if (query === "") return [];
1928
- return query.split("&").map((pair) => {
1929
- const eq = pair.indexOf("=");
1930
- if (eq === -1) return { key: pair, value: null };
1931
- return { key: pair.slice(0, eq), value: pair.slice(eq + 1) };
1932
- });
1933
- }
1934
- function encodeQuery(pairs) {
1935
- return pairs.map((p) => p.value === null ? p.key : `${p.key}=${p.value}`).join("&");
1936
- }
1937
- function collapseRootIndex(path2) {
1938
- if (path2 === "/index.html" || path2 === "/index.php") return "/";
1939
- return path2;
1940
- }
1941
- function dropTrailingSlash(path2) {
1942
- if (path2.length > 1 && path2.endsWith("/")) {
1943
- return path2.replace(/\/+$/, "");
1944
- }
1945
- return path2;
1946
- }
1947
- function normalizeUrlPath(input) {
1948
- if (input == null) return null;
1949
- let trimmed = input.trim();
1950
- if (trimmed === "") return null;
1951
- trimmed = trimmed.replace(/&nbsp;/g, " ").replace(/\s+/g, " ").trim();
1952
- if (trimmed === "" || trimmed === "/") return "/";
1953
- if (trimmed === "(not set)") return null;
1954
- trimmed = trimmed.replace(/([a-zA-Z0-9])([).]+)$/, "$1");
1955
- if (trimmed.startsWith("/)") || trimmed.startsWith("/ ")) {
1956
- trimmed = "/";
1957
- }
1958
- if (trimmed.includes(" ")) {
1959
- trimmed = trimmed.split(" ")[0];
1960
- }
1961
- if (trimmed === "" || trimmed === "/") return "/";
1962
- let pathPart;
1963
- let queryPart;
1964
- if (/^https?:\/\//i.test(trimmed)) {
1965
- let url;
1966
- try {
1967
- url = new URL(trimmed);
1968
- } catch {
1969
- return null;
1970
- }
1971
- pathPart = url.pathname || "/";
1972
- queryPart = url.search.startsWith("?") ? url.search.slice(1) : url.search;
1973
- } else {
1974
- let raw = trimmed;
1975
- const hashIdx = raw.indexOf("#");
1976
- if (hashIdx !== -1) raw = raw.slice(0, hashIdx);
1977
- const qIdx = raw.indexOf("?");
1978
- if (qIdx === -1) {
1979
- pathPart = raw;
1980
- queryPart = "";
1981
- } else {
1982
- pathPart = raw.slice(0, qIdx);
1983
- queryPart = raw.slice(qIdx + 1);
1984
- }
1985
- }
1986
- if (pathPart === "") pathPart = "/";
1987
- pathPart = collapseRootIndex(pathPart);
1988
- pathPart = dropTrailingSlash(pathPart);
1989
- const pairs = parseQuery(queryPart).filter((p) => !shouldStrip(p.key));
1990
- pairs.sort((a, b) => {
1991
- if (a.key < b.key) return -1;
1992
- if (a.key > b.key) return 1;
1993
- return 0;
1994
- });
1995
- if (pairs.length === 0) return pathPart;
1996
- return `${pathPart}?${encodeQuery(pairs)}`;
1997
- }
1998
-
1999
- // ../contracts/src/citations.ts
2000
- import { z as z18 } from "zod";
2001
- var citationCoverageProviderSchema = z18.object({
2002
- provider: z18.string(),
2003
- citationState: citationStateSchema,
2004
- cited: z18.boolean(),
2005
- mentioned: z18.boolean(),
2006
- runId: z18.string(),
2007
- runCreatedAt: z18.string()
2008
- });
2009
- var citationCoverageRowSchema = z18.object({
2010
- keywordId: z18.string(),
2011
- keyword: z18.string(),
2012
- providers: z18.array(citationCoverageProviderSchema),
2013
- citedCount: z18.number().int().nonnegative(),
2014
- mentionedCount: z18.number().int().nonnegative(),
2015
- totalProviders: z18.number().int().nonnegative()
2016
- });
2017
- var competitorGapRowSchema = z18.object({
2018
- keywordId: z18.string(),
2019
- keyword: z18.string(),
2020
- provider: z18.string(),
2021
- citingCompetitors: z18.array(z18.string()),
2022
- runId: z18.string(),
2023
- runCreatedAt: z18.string()
2024
- });
2025
- var citationVisibilitySummarySchema = z18.object({
2026
- providersConfigured: z18.number().int().nonnegative(),
2027
- providersCiting: z18.number().int().nonnegative(),
2028
- providersMentioning: z18.number().int().nonnegative(),
2029
- totalKeywords: z18.number().int().nonnegative(),
2030
- // Cross-tab buckets — each tracked keyword with at least one snapshot lands
2031
- // in exactly one of these. Keywords with zero snapshots are not counted in
2032
- // any bucket; (sum of buckets) ≤ totalKeywords.
2033
- keywordsCitedAndMentioned: z18.number().int().nonnegative(),
2034
- keywordsCitedOnly: z18.number().int().nonnegative(),
2035
- keywordsMentionedOnly: z18.number().int().nonnegative(),
2036
- keywordsInvisible: z18.number().int().nonnegative(),
2037
- latestRunId: z18.string().nullable(),
2038
- latestRunAt: z18.string().nullable()
2039
- });
2040
- var citationVisibilityResponseSchema = z18.object({
2041
- summary: citationVisibilitySummarySchema,
2042
- byKeyword: z18.array(citationCoverageRowSchema),
2043
- competitorGaps: z18.array(competitorGapRowSchema),
2044
- status: z18.enum(["ready", "no-data"]),
2045
- reason: z18.enum(["no-runs-yet", "no-keywords"]).optional()
2046
- });
2047
- function emptyCitationVisibility(reason) {
2048
- return {
2049
- summary: {
2050
- providersConfigured: 0,
2051
- providersCiting: 0,
2052
- providersMentioning: 0,
2053
- totalKeywords: 0,
2054
- keywordsCitedAndMentioned: 0,
2055
- keywordsCitedOnly: 0,
2056
- keywordsMentionedOnly: 0,
2057
- keywordsInvisible: 0,
2058
- latestRunId: null,
2059
- latestRunAt: null
2060
- },
2061
- byKeyword: [],
2062
- competitorGaps: [],
2063
- status: "no-data",
2064
- reason
2065
- };
2066
- }
2067
- function citationStateToCited(state) {
2068
- return state === "cited";
2069
- }
2070
-
2071
- // ../contracts/src/skills.ts
2072
- import { z as z19 } from "zod";
2073
- var codingAgentSchema = z19.enum(["claude", "codex"]);
2074
- var CodingAgents = codingAgentSchema.enum;
2075
- var skillsClientSchema = z19.enum(["claude", "codex", "all"]);
2076
- var SkillsClients = skillsClientSchema.enum;
2077
-
2078
255
  // src/client.ts
2079
256
  function createApiClient() {
2080
257
  const config = loadConfig();
@@ -2745,21 +922,21 @@ var ApiClient = class {
2745
922
  };
2746
923
 
2747
924
  // src/mcp/tool-registry.ts
2748
- import { z as z21 } from "zod";
925
+ import { z as z2 } from "zod";
2749
926
 
2750
927
  // src/mcp/schema.ts
2751
- import { z as z20 } from "zod";
2752
- var projectNameSchema = z20.string().min(1).describe("Canonry project name.");
2753
- var runIdSchema = z20.string().min(1).describe("Canonry run ID.");
2754
- var insightIdSchema = z20.string().min(1).describe("Canonry insight ID.");
2755
- var analyticsWindowSchema = z20.enum(["7d", "30d", "90d", "all"]).describe("Analytics time window.");
2756
- var emptyInputSchema = z20.object({});
2757
- var projectInputSchema = z20.object({
928
+ import { z } from "zod";
929
+ var projectNameSchema = z.string().min(1).describe("Canonry project name.");
930
+ var runIdSchema = z.string().min(1).describe("Canonry run ID.");
931
+ var insightIdSchema = z.string().min(1).describe("Canonry insight ID.");
932
+ var analyticsWindowSchema = z.enum(["7d", "30d", "90d", "all"]).describe("Analytics time window.");
933
+ var emptyInputSchema = z.object({});
934
+ var projectInputSchema = z.object({
2758
935
  project: projectNameSchema
2759
936
  });
2760
937
  function toJsonSchema(schema, name) {
2761
938
  return {
2762
- ...z20.toJSONSchema(schema, { target: "draft-7" }),
939
+ ...z.toJSONSchema(schema, { target: "draft-7" }),
2763
940
  title: name
2764
941
  };
2765
942
  }
@@ -2801,119 +978,119 @@ function defineTool(tool) {
2801
978
  inputJsonSchema: toJsonSchema(tool.inputSchema, tool.name)
2802
979
  };
2803
980
  }
2804
- var runTriggerInputSchema = z21.object({
981
+ var runTriggerInputSchema = z2.object({
2805
982
  project: projectNameSchema,
2806
983
  request: runTriggerRequestSchema.optional()
2807
984
  });
2808
- var runsListInputSchema = z21.object({
985
+ var runsListInputSchema = z2.object({
2809
986
  project: projectNameSchema,
2810
- limit: z21.number().int().positive().max(500).optional()
987
+ limit: z2.number().int().positive().max(500).optional()
2811
988
  });
2812
- var runGetInputSchema = z21.object({
989
+ var runGetInputSchema = z2.object({
2813
990
  runId: runIdSchema
2814
991
  });
2815
- var timelineInputSchema = z21.object({
992
+ var timelineInputSchema = z2.object({
2816
993
  project: projectNameSchema,
2817
- location: z21.string().optional().describe("Location label. Use an empty string for locationless results.")
994
+ location: z2.string().optional().describe("Location label. Use an empty string for locationless results.")
2818
995
  });
2819
- var snapshotsListInputSchema = z21.object({
996
+ var snapshotsListInputSchema = z2.object({
2820
997
  project: projectNameSchema,
2821
- limit: z21.number().int().positive().max(500).optional(),
2822
- offset: z21.number().int().nonnegative().optional(),
2823
- location: z21.string().optional().describe("Location label. Use an empty string for locationless results.")
998
+ limit: z2.number().int().positive().max(500).optional(),
999
+ offset: z2.number().int().nonnegative().optional(),
1000
+ location: z2.string().optional().describe("Location label. Use an empty string for locationless results.")
2824
1001
  });
2825
- var snapshotsDiffInputSchema = z21.object({
1002
+ var snapshotsDiffInputSchema = z2.object({
2826
1003
  project: projectNameSchema,
2827
1004
  run1: runIdSchema,
2828
1005
  run2: runIdSchema
2829
1006
  });
2830
- var insightsListInputSchema = z21.object({
1007
+ var insightsListInputSchema = z2.object({
2831
1008
  project: projectNameSchema,
2832
- dismissed: z21.boolean().optional(),
1009
+ dismissed: z2.boolean().optional(),
2833
1010
  runId: runIdSchema.optional()
2834
1011
  });
2835
- var insightInputSchema = z21.object({
1012
+ var insightInputSchema = z2.object({
2836
1013
  project: projectNameSchema,
2837
1014
  insightId: insightIdSchema
2838
1015
  });
2839
- var healthHistoryInputSchema = z21.object({
1016
+ var healthHistoryInputSchema = z2.object({
2840
1017
  project: projectNameSchema,
2841
- limit: z21.number().int().positive().max(100).optional()
1018
+ limit: z2.number().int().positive().max(100).optional()
2842
1019
  });
2843
- var gscPerformanceInputSchema = z21.object({
1020
+ var gscPerformanceInputSchema = z2.object({
2844
1021
  project: projectNameSchema,
2845
- startDate: z21.string().optional(),
2846
- endDate: z21.string().optional(),
2847
- query: z21.string().optional(),
2848
- page: z21.string().optional(),
2849
- limit: z21.number().int().positive().max(500).optional(),
1022
+ startDate: z2.string().optional(),
1023
+ endDate: z2.string().optional(),
1024
+ query: z2.string().optional(),
1025
+ page: z2.string().optional(),
1026
+ limit: z2.number().int().positive().max(500).optional(),
2850
1027
  window: analyticsWindowSchema.optional()
2851
1028
  });
2852
- var gscInspectionsInputSchema = z21.object({
1029
+ var gscInspectionsInputSchema = z2.object({
2853
1030
  project: projectNameSchema,
2854
- url: z21.string().optional(),
2855
- limit: z21.number().int().positive().max(500).optional()
1031
+ url: z2.string().optional(),
1032
+ limit: z2.number().int().positive().max(500).optional()
2856
1033
  });
2857
- var gscCoverageHistoryInputSchema = z21.object({
1034
+ var gscCoverageHistoryInputSchema = z2.object({
2858
1035
  project: projectNameSchema,
2859
- limit: z21.number().int().positive().max(500).optional()
1036
+ limit: z2.number().int().positive().max(500).optional()
2860
1037
  });
2861
- var gaWindowInputSchema = z21.object({
1038
+ var gaWindowInputSchema = z2.object({
2862
1039
  project: projectNameSchema,
2863
1040
  window: analyticsWindowSchema.optional()
2864
1041
  });
2865
1042
  var gaTrafficInputSchema = gaWindowInputSchema.extend({
2866
- limit: z21.number().int().positive().max(500).optional()
1043
+ limit: z2.number().int().positive().max(500).optional()
2867
1044
  });
2868
- var keywordsInputSchema = z21.object({
1045
+ var keywordsInputSchema = z2.object({
2869
1046
  project: projectNameSchema,
2870
1047
  request: keywordBatchRequestSchema
2871
1048
  });
2872
- var keywordGenerateInputSchema = z21.object({
1049
+ var keywordGenerateInputSchema = z2.object({
2873
1050
  project: projectNameSchema,
2874
1051
  request: keywordGenerateRequestSchema
2875
1052
  });
2876
- var competitorsInputSchema = z21.object({
1053
+ var competitorsInputSchema = z2.object({
2877
1054
  project: projectNameSchema,
2878
1055
  request: competitorBatchRequestSchema
2879
1056
  });
2880
- var projectUpsertInputSchema = z21.object({
1057
+ var projectUpsertInputSchema = z2.object({
2881
1058
  project: projectNameSchema,
2882
1059
  request: projectUpsertRequestSchema
2883
1060
  });
2884
- var applyConfigInputSchema = z21.object({
1061
+ var applyConfigInputSchema = z2.object({
2885
1062
  config: projectConfigSchema
2886
1063
  });
2887
- var scheduleSetInputSchema = z21.object({
1064
+ var scheduleSetInputSchema = z2.object({
2888
1065
  project: projectNameSchema,
2889
1066
  schedule: scheduleUpsertRequestSchema
2890
1067
  });
2891
- var agentWebhookAttachInputSchema = z21.object({
1068
+ var agentWebhookAttachInputSchema = z2.object({
2892
1069
  project: projectNameSchema,
2893
- url: z21.string().url()
1070
+ url: z2.string().url()
2894
1071
  });
2895
- var doctorInputSchema = z21.object({
1072
+ var doctorInputSchema = z2.object({
2896
1073
  project: projectNameSchema.optional().describe("Project name to scope project-level checks. Omit to run global checks (provider keys, config, etc.)."),
2897
- checks: z21.array(z21.string().min(1)).optional().describe('Optional check IDs or wildcard prefixes (e.g. "google.auth.*", "config.providers"). Empty/omitted runs all matching checks for the chosen scope.')
1074
+ checks: z2.array(z2.string().min(1)).optional().describe('Optional check IDs or wildcard prefixes (e.g. "google.auth.*", "config.providers"). Empty/omitted runs all matching checks for the chosen scope.')
2898
1075
  });
2899
- var contentTargetsInputSchema = z21.object({
1076
+ var contentTargetsInputSchema = z2.object({
2900
1077
  project: projectNameSchema,
2901
- limit: z21.number().int().positive().max(500).optional().describe("Max rows. Defaults to all. Use a small number (3-10) when summarizing for the user."),
2902
- includeInProgress: z21.boolean().optional().describe("Include rows that already have an in-flight tracked action. Default false.")
1078
+ limit: z2.number().int().positive().max(500).optional().describe("Max rows. Defaults to all. Use a small number (3-10) when summarizing for the user."),
1079
+ includeInProgress: z2.boolean().optional().describe("Include rows that already have an in-flight tracked action. Default false.")
2903
1080
  });
2904
- var backlinksDomainsInputSchema = z21.object({
1081
+ var backlinksDomainsInputSchema = z2.object({
2905
1082
  project: projectNameSchema,
2906
- limit: z21.number().int().positive().max(200).optional().describe("Max linking-domain rows. Default 50, max 200."),
2907
- release: z21.string().optional().describe("Common Crawl release id (e.g., cc-main-2026-jan-feb-mar). Omit for the most recent release with data.")
1083
+ limit: z2.number().int().positive().max(200).optional().describe("Max linking-domain rows. Default 50, max 200."),
1084
+ release: z2.string().optional().describe("Common Crawl release id (e.g., cc-main-2026-jan-feb-mar). Omit for the most recent release with data.")
2908
1085
  });
2909
- var memoryUpsertInputSchema = z21.object({
1086
+ var memoryUpsertInputSchema = z2.object({
2910
1087
  project: projectNameSchema,
2911
- key: z21.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH).describe(`Stable identifier for the note (max ${AGENT_MEMORY_KEY_MAX_LENGTH} chars). Writing the same key overwrites the prior value.`),
2912
- value: z21.string().min(1).describe(`Plain-text note body (max ${AGENT_MEMORY_VALUE_MAX_BYTES} bytes). Use for durable operator preferences, migration context, or non-obvious reasoning that should survive future sessions.`)
1088
+ key: z2.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH).describe(`Stable identifier for the note (max ${AGENT_MEMORY_KEY_MAX_LENGTH} chars). Writing the same key overwrites the prior value.`),
1089
+ value: z2.string().min(1).describe(`Plain-text note body (max ${AGENT_MEMORY_VALUE_MAX_BYTES} bytes). Use for durable operator preferences, migration context, or non-obvious reasoning that should survive future sessions.`)
2913
1090
  });
2914
- var memoryForgetInputSchema = z21.object({
1091
+ var memoryForgetInputSchema = z2.object({
2915
1092
  project: projectNameSchema,
2916
- key: z21.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH).describe("Exact key of the note to remove. No-op (status=missing) when no note exists for that key.")
1093
+ key: z2.string().min(1).max(AGENT_MEMORY_KEY_MAX_LENGTH).describe("Exact key of the note to remove. No-op (status=missing) when no note exists for that key.")
2917
1094
  });
2918
1095
  var AGENT_WEBHOOK_EVENTS = [
2919
1096
  notificationEventSchema.enum["run.completed"],
@@ -2972,10 +1149,10 @@ var canonryMcpTools = [
2972
1149
  description: "Search query snapshots and intelligence insights for the given text. Looks at snapshot answer text, cited domains, raw provider responses, and insight title/keyword/recommendation/cause. Returns ranked hits with snippets \u2014 use it instead of paginating snapshots when you need to find a competitor mention or term.",
2973
1150
  access: "read",
2974
1151
  tier: "core",
2975
- inputSchema: z21.object({
1152
+ inputSchema: z2.object({
2976
1153
  project: projectNameSchema,
2977
- q: z21.string().min(2).describe("Search term, at least 2 characters."),
2978
- limit: z21.number().int().positive().max(50).optional().describe("Max combined hits (1-50, default 25).")
1154
+ q: z2.string().min(2).describe("Search term, at least 2 characters."),
1155
+ limit: z2.number().int().positive().max(50).optional().describe("Max combined hits (1-50, default 25).")
2979
1156
  }),
2980
1157
  annotations: readAnnotations(),
2981
1158
  openApiOperations: ["GET /api/v1/projects/{name}/search"],
@@ -3674,74 +1851,6 @@ export {
3674
1851
  usageError,
3675
1852
  isEndpointMissing,
3676
1853
  printCliError,
3677
- providerQuotaPolicySchema,
3678
- ProviderNames,
3679
- isBrowserProvider,
3680
- resolveProviderInput,
3681
- locationContextSchema,
3682
- notificationEventSchema,
3683
- findDuplicateLocationLabels,
3684
- hasLocationLabel,
3685
- projectUpsertRequestSchema,
3686
- keywordGenerateRequestSchema,
3687
- competitorBatchRequestSchema,
3688
- normalizeProjectDomain,
3689
- registrableDomain,
3690
- brandLabelFromDomain,
3691
- effectiveDomains,
3692
- projectConfigSchema,
3693
- AppError,
3694
- notFound,
3695
- validationError,
3696
- authRequired,
3697
- authInvalid,
3698
- providerError,
3699
- runInProgress,
3700
- runNotCancellable,
3701
- unsupportedKind,
3702
- notImplemented,
3703
- deliveryFailed,
3704
- agentBusy,
3705
- missingDependency,
3706
- internalError,
3707
- wordpressEnvSchema,
3708
- AgentProviderIds,
3709
- AGENT_PROVIDER_IDS,
3710
- isAgentProviderId,
3711
- RunStatuses,
3712
- RunKinds,
3713
- RunTriggers,
3714
- CitationStates,
3715
- runTriggerRequestSchema,
3716
- parseRunError,
3717
- buildRunErrorFromMessages,
3718
- serializeRunError,
3719
- formatRunErrorOneLine,
3720
- snapshotRequestSchema,
3721
- scheduleUpsertRequestSchema,
3722
- parseWindow,
3723
- windowCutoff,
3724
- categorizeSource,
3725
- categoryLabel,
3726
- extractAnswerMentions,
3727
- determineAnswerMentioned,
3728
- visibilityStateFromAnswerMentioned,
3729
- brandKeyFromText,
3730
- MemorySources,
3731
- AGENT_MEMORY_VALUE_MAX_BYTES,
3732
- agentMemoryUpsertRequestSchema,
3733
- agentMemoryDeleteRequestSchema,
3734
- CcReleaseSyncStatuses,
3735
- CheckStatuses,
3736
- CheckScopes,
3737
- CheckCategories,
3738
- summarizeCheckResults,
3739
- normalizeUrlPath,
3740
- emptyCitationVisibility,
3741
- citationStateToCited,
3742
- CodingAgents,
3743
- skillsClientSchema,
3744
- SkillsClients,
3745
1854
  createApiClient,
3746
1855
  ApiClient,
3747
1856
  canonryMcpTools