@ainyc/canonry 4.60.2 → 4.61.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/assets/agent-workspace/skills/aero/references/regression-playbook.md +4 -1
  2. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +4 -0
  3. package/assets/agent-workspace/skills/canonry/references/google-business-profile.md +24 -2
  4. package/assets/assets/{BacklinksPage-Dj4AVTma.js → BacklinksPage-CsGOAPNN.js} +1 -1
  5. package/assets/assets/{ChartPrimitives-7SFwUlCh.js → ChartPrimitives-Bjow7aaC.js} +1 -1
  6. package/assets/assets/{ProjectPage-4tWuU1ZR.js → ProjectPage-BZoMD93_.js} +1 -1
  7. package/assets/assets/{RunRow-CgPJfmWX.js → RunRow-ve7H_XIu.js} +1 -1
  8. package/assets/assets/{RunsPage-Cdo4jBn4.js → RunsPage-mYmYevh0.js} +1 -1
  9. package/assets/assets/{SettingsPage-N5iccPoU.js → SettingsPage-DoRiIJK5.js} +1 -1
  10. package/assets/assets/{TrafficPage-pSlQPdDg.js → TrafficPage-1LFyX4OT.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-BQx3Evf6.js → TrafficSourceDetailPage-BYDJtQdO.js} +1 -1
  12. package/assets/assets/{extract-error-message-BOembgFV.js → extract-error-message-Bt6jcL_M.js} +1 -1
  13. package/assets/assets/{index-DjKFsFsl.js → index-BQxaYi-t.js} +70 -70
  14. package/assets/assets/{server-traffic-DNgNJ4Ht.js → server-traffic-C5f87b84.js} +1 -1
  15. package/assets/assets/{trash-2-DOznxxMW.js → trash-2-BFSmyr_7.js} +1 -1
  16. package/assets/index.html +1 -1
  17. package/dist/{chunk-AUR7VMQF.js → chunk-4FLI5VSQ.js} +59 -4
  18. package/dist/{chunk-CKWHFAVB.js → chunk-PITZUUFV.js} +33 -1
  19. package/dist/{chunk-3G3GAT3E.js → chunk-QU62IX7K.js} +531 -172
  20. package/dist/{chunk-DXWUBWBD.js → chunk-URPUUKLC.js} +22 -0
  21. package/dist/cli.js +32 -4
  22. package/dist/index.d.ts +16 -0
  23. package/dist/index.js +4 -4
  24. package/dist/{intelligence-service-UYVVKQ2K.js → intelligence-service-AZDX2EBS.js} +2 -2
  25. package/dist/mcp.js +2 -2
  26. package/package.json +7 -6
@@ -1 +1 @@
1
- import{c as d,j as a,bN as S,bH as l,bO as v,ao as m,l as t,bP as y,bI as i,bQ as T,bR as h,bS as p,bT as b}from"./index-DjKFsFsl.js";import{u as s,r as C,n as c,o}from"./vendor-tanstack-Dq7p98wZ.js";const g=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],B=d("refresh-cw",g);function M(e){switch(e){case i.connected:return"positive";case i.paused:return"caution";case i.error:return"negative";case i.archived:return"neutral"}}function w(e){const r={};return e.kind&&e.kind!=="all"&&(r.kind=e.kind),e.sourceId&&(r.sourceId=e.sourceId),e.sinceMinutes!==void 0&&(r.since=new Date(Date.now()-e.sinceMinutes*6e4).toISOString()),e.limit!==void 0&&(r.limit=String(e.limit)),r}function u(e){e.invalidateQueries({predicate:r=>{const n=r.queryKey[0];return typeof n?._id=="string"&&n._id.startsWith("getApiV1ProjectsByNameTraffic")}})}function k(e){return s({...S({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function F(e){return s({...b({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function V(e,r){return s({...l({client:t,path:{name:e??"",id:r??""}}),enabled:!!(e&&r),staleTime:a})}function A(e,r){const n=C.useMemo(()=>w(r),[r.kind,r.sourceId,r.sinceMinutes,r.limit]);return s({...v({client:t,path:{name:e??""},query:n}),enabled:!!e,staleTime:a})}function E(e){const r=c();return o({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Cloud Run source");return p(e,n)},onSuccess:()=>{e&&u(r)}})}function I(e){const r=c();return o({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a WordPress source");return T(e,n)},onSuccess:()=>{e&&u(r)}})}function Q(e){const r=c();return o({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Vercel source");return h(e,n)},onSuccess:()=>{e&&u(r)}})}function R(e,r){const n=c();return o({mutationFn:f=>{if(!e||!r)throw new Error("Project and sourceId are required to sync");return y(e,r,f??void 0)},onSuccess:()=>{e&&(u(n),n.invalidateQueries({queryKey:m({client:t})}))}})}export{B as R,I as a,Q as b,E as c,k as d,V as e,A as f,R as g,M as t,F as u};
1
+ import{c as d,j as a,bN as S,bH as l,bO as v,ao as m,l as t,bP as y,bI as i,bQ as T,bR as h,bS as p,bT as b}from"./index-BQxaYi-t.js";import{u as s,r as C,n as c,o}from"./vendor-tanstack-Dq7p98wZ.js";const g=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],B=d("refresh-cw",g);function M(e){switch(e){case i.connected:return"positive";case i.paused:return"caution";case i.error:return"negative";case i.archived:return"neutral"}}function w(e){const r={};return e.kind&&e.kind!=="all"&&(r.kind=e.kind),e.sourceId&&(r.sourceId=e.sourceId),e.sinceMinutes!==void 0&&(r.since=new Date(Date.now()-e.sinceMinutes*6e4).toISOString()),e.limit!==void 0&&(r.limit=String(e.limit)),r}function u(e){e.invalidateQueries({predicate:r=>{const n=r.queryKey[0];return typeof n?._id=="string"&&n._id.startsWith("getApiV1ProjectsByNameTraffic")}})}function k(e){return s({...S({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function F(e){return s({...b({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function V(e,r){return s({...l({client:t,path:{name:e??"",id:r??""}}),enabled:!!(e&&r),staleTime:a})}function A(e,r){const n=C.useMemo(()=>w(r),[r.kind,r.sourceId,r.sinceMinutes,r.limit]);return s({...v({client:t,path:{name:e??""},query:n}),enabled:!!e,staleTime:a})}function E(e){const r=c();return o({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Cloud Run source");return p(e,n)},onSuccess:()=>{e&&u(r)}})}function I(e){const r=c();return o({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a WordPress source");return T(e,n)},onSuccess:()=>{e&&u(r)}})}function Q(e){const r=c();return o({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Vercel source");return h(e,n)},onSuccess:()=>{e&&u(r)}})}function R(e,r){const n=c();return o({mutationFn:f=>{if(!e||!r)throw new Error("Project and sourceId are required to sync");return y(e,r,f??void 0)},onSuccess:()=>{e&&(u(n),n.invalidateQueries({queryKey:m({client:t})}))}})}export{B as R,I as a,Q as b,E as c,k as d,V as e,A as f,R as g,M as t,F as u};
@@ -1 +1 @@
1
- import{c}from"./index-DjKFsFsl.js";const a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],h=c("circle-check",a);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],n=c("circle-question-mark",e);const o=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=c("download",o);const t=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],r=c("trash-2",t);export{h as C,s as D,r as T,n as a};
1
+ import{c}from"./index-BQxaYi-t.js";const a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],h=c("circle-check",a);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],n=c("circle-question-mark",e);const o=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=c("download",o);const t=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],r=c("trash-2",t);export{h as C,s as D,r as T,n as a};
package/assets/index.html CHANGED
@@ -12,7 +12,7 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index-DjKFsFsl.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-BQxaYi-t.js"></script>
16
16
  <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Dq7p98wZ.js">
17
17
  <link rel="modulepreload" crossorigin href="./assets/vendor-radix-B57xfQbP.js">
18
18
  <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-DWvKDyBF.js">
@@ -8,7 +8,7 @@ import {
8
8
  loadConfig,
9
9
  loadConfigRaw,
10
10
  saveConfigPatch
11
- } from "./chunk-CKWHFAVB.js";
11
+ } from "./chunk-PITZUUFV.js";
12
12
  import {
13
13
  CC_CACHE_DIR,
14
14
  DUCKDB_SPEC,
@@ -54,14 +54,17 @@ import {
54
54
  gbpLocations,
55
55
  gbpLodgingSnapshots,
56
56
  gbpPlaceActions,
57
+ gbpPlaceDetails,
57
58
  getCrawlIssues,
58
59
  getLodging,
60
+ getPlaceDetails,
59
61
  getUrlInfo,
60
62
  groupRunsByCreatedAt,
61
63
  gscCoverageSnapshots,
62
64
  gscSearchData,
63
65
  gscUrlInspections,
64
66
  hashLodging,
67
+ hashPlaceDetails,
65
68
  insights,
66
69
  inspectUrl,
67
70
  installDuckdb,
@@ -90,7 +93,7 @@ import {
90
93
  runs,
91
94
  schedules,
92
95
  usageCounters
93
- } from "./chunk-3G3GAT3E.js";
96
+ } from "./chunk-QU62IX7K.js";
94
97
  import {
95
98
  AGENT_MEMORY_VALUE_MAX_BYTES,
96
99
  AGENT_PROVIDER_IDS,
@@ -138,7 +141,7 @@ import {
138
141
  skillsClientSchema,
139
142
  validationError,
140
143
  withRetry
141
- } from "./chunk-DXWUBWBD.js";
144
+ } from "./chunk-URPUUKLC.js";
142
145
 
143
146
  // src/telemetry.ts
144
147
  import crypto from "crypto";
@@ -2692,6 +2695,21 @@ var perplexityAdapter = {
2692
2695
  }
2693
2696
  };
2694
2697
 
2698
+ // src/places-config.ts
2699
+ var DEFAULT_TIER = "atmosphere";
2700
+ var DEFAULT_REFRESH_INTERVAL_DAYS = 7;
2701
+ function parseTier(raw) {
2702
+ return raw === "atmosphere" || raw === "pro" || raw === "off" ? raw : void 0;
2703
+ }
2704
+ function getPlacesConfig(config) {
2705
+ const envKey = process.env.GOOGLE_PLACES_API_KEY?.trim();
2706
+ const apiKey = envKey || config.places?.apiKey || void 0;
2707
+ const tier = parseTier(process.env.GOOGLE_PLACES_TIER?.trim()) ?? config.places?.tier ?? DEFAULT_TIER;
2708
+ const envInterval = Number(process.env.GOOGLE_PLACES_REFRESH_INTERVAL_DAYS);
2709
+ const refreshIntervalDays = Number.isFinite(envInterval) && envInterval > 0 ? envInterval : config.places?.refreshIntervalDays ?? DEFAULT_REFRESH_INTERVAL_DAYS;
2710
+ return { apiKey, tier, refreshIntervalDays };
2711
+ }
2712
+
2695
2713
  // src/google-config.ts
2696
2714
  function ensureConnections(config) {
2697
2715
  if (!config.google) config.google = {};
@@ -3790,6 +3808,7 @@ async function executeGscSync(db, runId, projectId, opts) {
3790
3808
  // src/gbp-sync.ts
3791
3809
  import crypto5 from "crypto";
3792
3810
  import { eq as eq3, and as and3, desc, inArray as inArray2, lt } from "drizzle-orm";
3811
+ var MS_PER_DAY = 864e5;
3793
3812
  var log3 = createLogger("GbpSync");
3794
3813
  var LOCATION_CONCURRENCY = 4;
3795
3814
  var DEFAULT_DAYS_OF_METRICS = 30;
@@ -3849,6 +3868,7 @@ async function executeGbpSync(db, runId, projectId, opts) {
3849
3868
  const keywordsEnd = monthMinus(0);
3850
3869
  const trendMonths = Array.from({ length: KEYWORD_TREND_MONTHS }, (_, i) => monthMinus(i + 1));
3851
3870
  const keywordRetentionCutoff = monthKey(monthMinus(KEYWORD_HISTORY_RETENTION_MONTHS));
3871
+ const { apiKey: placesApiKey, tier: placesTier, refreshIntervalDays: placesRefreshDays } = getPlacesConfig(opts.config);
3852
3872
  log3.info("sync.start", { runId, projectId, locations: locationRows.length, daysOfMetrics, monthsOfKeywords });
3853
3873
  const errors = /* @__PURE__ */ new Map();
3854
3874
  let okCount = 0;
@@ -3880,6 +3900,25 @@ async function executeGbpSync(db, runId, projectId, opts) {
3880
3900
  const lodgingHash = lodging ? hashLodging(lodging) : null;
3881
3901
  const latestLodging = lodging ? db.select().from(gbpLodgingSnapshots).where(and3(eq3(gbpLodgingSnapshots.projectId, projectId), eq3(gbpLodgingSnapshots.locationName, loc.locationName))).orderBy(desc(gbpLodgingSnapshots.syncedAt)).limit(1).get() : void 0;
3882
3902
  const lodgingChanged = lodging !== null && latestLodging?.contentHash !== lodgingHash;
3903
+ let placeToWrite = null;
3904
+ let placeToTouch = null;
3905
+ if (placesTier !== "off" && placesApiKey && lodging !== null && loc.placeId) {
3906
+ const latestPlace = db.select().from(gbpPlaceDetails).where(and3(eq3(gbpPlaceDetails.projectId, projectId), eq3(gbpPlaceDetails.locationName, loc.locationName))).orderBy(desc(gbpPlaceDetails.syncedAt)).limit(1).get();
3907
+ const ageDays = latestPlace ? (Date.now() - new Date(latestPlace.syncedAt).getTime()) / MS_PER_DAY : Infinity;
3908
+ if (ageDays >= placesRefreshDays) {
3909
+ try {
3910
+ const place = await getPlaceDetails(loc.placeId, placesApiKey, { tier: placesTier });
3911
+ const hash = hashPlaceDetails(place);
3912
+ if (!latestPlace || latestPlace.contentHash !== hash) {
3913
+ placeToWrite = { contentHash: hash, attributes: place, tier: placesTier, placeId: loc.placeId };
3914
+ } else {
3915
+ placeToTouch = latestPlace.id;
3916
+ }
3917
+ } catch (placesErr) {
3918
+ log3.warn("places.failed", { runId, location: loc.locationName, error: placesErr instanceof Error ? placesErr.message : String(placesErr) });
3919
+ }
3920
+ }
3921
+ }
3883
3922
  const insertNow = (/* @__PURE__ */ new Date()).toISOString();
3884
3923
  db.transaction((tx) => {
3885
3924
  tx.delete(gbpDailyMetrics).where(and3(eq3(gbpDailyMetrics.projectId, projectId), eq3(gbpDailyMetrics.locationName, loc.locationName))).run();
@@ -3962,6 +4001,21 @@ async function executeGbpSync(db, runId, projectId, opts) {
3962
4001
  syncRunId: runId
3963
4002
  }).run();
3964
4003
  }
4004
+ if (placeToWrite) {
4005
+ tx.insert(gbpPlaceDetails).values({
4006
+ id: crypto5.randomUUID(),
4007
+ projectId,
4008
+ locationName: loc.locationName,
4009
+ placeId: placeToWrite.placeId,
4010
+ contentHash: placeToWrite.contentHash,
4011
+ tier: placeToWrite.tier,
4012
+ attributes: placeToWrite.attributes,
4013
+ syncedAt: insertNow,
4014
+ syncRunId: runId
4015
+ }).run();
4016
+ } else if (placeToTouch) {
4017
+ tx.update(gbpPlaceDetails).set({ syncedAt: insertNow, syncRunId: runId }).where(eq3(gbpPlaceDetails.id, placeToTouch)).run();
4018
+ }
3965
4019
  tx.update(gbpLocations).set({ syncedAt: insertNow, updatedAt: insertNow }).where(eq3(gbpLocations.id, loc.id)).run();
3966
4020
  });
3967
4021
  okCount++;
@@ -5562,7 +5616,7 @@ function readStoredGroundingSources(rawResponse) {
5562
5616
  return result;
5563
5617
  }
5564
5618
  async function backfillInsightsCommand(project, opts) {
5565
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-UYVVKQ2K.js");
5619
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-AZDX2EBS.js");
5566
5620
  const config = loadConfig();
5567
5621
  const db = createClient(config.database);
5568
5622
  migrate(db);
@@ -9776,6 +9830,7 @@ async function createServer(opts) {
9776
9830
  registerAgentRoutes(scope, { db: opts.db, sessionRegistry });
9777
9831
  },
9778
9832
  getGoogleAuthConfig: () => getGoogleAuthConfig(opts.config),
9833
+ getPlacesConfig: () => getPlacesConfig(opts.config),
9779
9834
  googleConnectionStore,
9780
9835
  googleStateSecret,
9781
9836
  publicUrl: opts.config.publicUrl,
@@ -22,7 +22,7 @@ import {
22
22
  trafficConnectVercelRequestSchema,
23
23
  trafficConnectWordpressRequestSchema,
24
24
  trafficEventKindSchema
25
- } from "./chunk-DXWUBWBD.js";
25
+ } from "./chunk-URPUUKLC.js";
26
26
 
27
27
  // src/config.ts
28
28
  import fs from "fs";
@@ -2153,6 +2153,18 @@ var getApiV1ProjectsByNameGbpLodging = (options) => {
2153
2153
  ...options
2154
2154
  });
2155
2155
  };
2156
+ var getApiV1ProjectsByNameGbpPlaces = (options) => {
2157
+ return (options.client ?? client).get({
2158
+ security: [
2159
+ {
2160
+ scheme: "bearer",
2161
+ type: "http"
2162
+ }
2163
+ ],
2164
+ url: "/api/v1/projects/{name}/gbp/places",
2165
+ ...options
2166
+ });
2167
+ };
2156
2168
  var getApiV1ProjectsByNameGbpSummary = (options) => {
2157
2169
  return (options.client ?? client).get({
2158
2170
  security: [
@@ -4033,6 +4045,15 @@ var ApiClient = class {
4033
4045
  })
4034
4046
  );
4035
4047
  }
4048
+ async listGbpPlaces(project, opts) {
4049
+ return this.invoke(
4050
+ () => getApiV1ProjectsByNameGbpPlaces({
4051
+ client: this.heyClient,
4052
+ path: { name: project },
4053
+ query: opts?.locationName ? { locationName: opts.locationName } : void 0
4054
+ })
4055
+ );
4056
+ }
4036
4057
  async getGbpSummary(project, opts) {
4037
4058
  return this.invoke(
4038
4059
  () => getApiV1ProjectsByNameGbpSummary({
@@ -5719,6 +5740,17 @@ var canonryMcpTools = [
5719
5740
  openApiOperations: ["GET /api/v1/projects/{name}/gbp/lodging"],
5720
5741
  handler: (client2, input) => client2.listGbpLodging(input.project, compactStringParams(input, ["locationName"]))
5721
5742
  }),
5743
+ defineTool({
5744
+ name: "canonry_gbp_places",
5745
+ title: "Get GBP Places rendered-listing data",
5746
+ description: "List the latest Google Places (New) snapshot per location \u2014 the amenities Google's public listing advertises (server-derived `amenities`), cross-referenced against the GBP profile to surface listing discrepancies. Empty until a Places API key is configured and a gbp sync runs.",
5747
+ access: "read",
5748
+ tier: "gbp",
5749
+ inputSchema: gbpLocationScopedInputSchema,
5750
+ annotations: readAnnotations(),
5751
+ openApiOperations: ["GET /api/v1/projects/{name}/gbp/places"],
5752
+ handler: (client2, input) => client2.listGbpPlaces(input.project, compactStringParams(input, ["locationName"]))
5753
+ }),
5722
5754
  defineTool({
5723
5755
  name: "canonry_gbp_summary",
5724
5756
  title: "Get GBP local-AEO summary",