@ainyc/canonry 4.189.1 → 4.190.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/README.md +1 -1
  2. package/assets/assets/{AuditHistoryPanel-jkTli_49.js → AuditHistoryPanel-wWLs088f.js} +1 -1
  3. package/assets/assets/{BacklinksPage-UvZsCycW.js → BacklinksPage-DJEO5o9c.js} +1 -1
  4. package/assets/assets/{HistoryPage-BNhAdEgU.js → HistoryPage-CV5bTBU6.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-BlAQhKbf.js → MeasurementPropertyPage-C7KLIAad.js} +1 -1
  6. package/assets/assets/ProjectPage-DIW1h05b.js +8 -0
  7. package/assets/assets/{RunRow-DT_T7pqA.js → RunRow-C3Ryj_9u.js} +1 -1
  8. package/assets/assets/{RunsPage-Bl0L0rlS.js → RunsPage-BxoEkZu3.js} +1 -1
  9. package/assets/assets/{SettingsPage-Bqn1dpbS.js → SettingsPage-D_mB1JUZ.js} +1 -1
  10. package/assets/assets/{SiteHealthSection-z2DhR3t6.js → SiteHealthSection-Dgqtz9J2.js} +3 -3
  11. package/assets/assets/{TrafficPage-C_5kd1cm.js → TrafficPage-DgsWuDtv.js} +1 -1
  12. package/assets/assets/{TrafficSourceDetailPage-Rrwaz-mV.js → TrafficSourceDetailPage-BLWlQ8aT.js} +1 -1
  13. package/assets/assets/{extract-error-message-CBGBgQDU.js → extract-error-message-DHIHApUf.js} +1 -1
  14. package/assets/assets/{index-KTeRanN1.css → index-BjjM151x.css} +1 -1
  15. package/assets/assets/{index-vRk2f6HY.js → index-nb8QHq99.js} +23 -23
  16. package/assets/assets/{react-sigma_core.esm.min-5Q-_e_E0.js → react-sigma_core.esm.min-DzTADS1A.js} +1 -1
  17. package/assets/index.html +2 -2
  18. package/dist/{chunk-J533DKYE.js → chunk-2II4ZMMH.js} +2 -2
  19. package/dist/{chunk-YDYB3H4O.js → chunk-32QBVRMN.js} +34 -3
  20. package/dist/{chunk-HG6NLN7H.js → chunk-4NIQ3GMO.js} +4 -4
  21. package/dist/{chunk-QQLMRABM.js → chunk-6POEZ7GT.js} +110 -16
  22. package/dist/{chunk-CDI3YR57.js → chunk-ROPJUNQN.js} +55 -1
  23. package/dist/cli.js +47 -19
  24. package/dist/index.js +4 -4
  25. package/dist/{intelligence-service-M5TYY4TH.js → intelligence-service-WNASQFN4.js} +2 -2
  26. package/dist/mcp.js +3 -3
  27. package/package.json +12 -12
  28. package/assets/assets/ProjectPage-C2oKQpyS.js +0 -9
@@ -1,4 +1,4 @@
1
- import{g as Bt,t as S,r as C}from"./vendor-tanstack-CYBjbqVr.js";import{e as Ht,G as Wt}from"./SiteHealthSection-z2DhR3t6.js";import"./index-vRk2f6HY.js";import"./vendor-radix-BpmvLvpp.js";import"./vendor-recharts-FA0uySU7.js";import"./vendor-lucide-dNHw1I5G.js";import"./vendor-markdown-9tTeP8v7.js";import"./vendor-yaml-GWJz5H2G.js";import"./ChartPrimitives-DLEICrrL.js";function Vt(r,n){if(typeof r!="object"||!r)return r;var i=r[Symbol.toPrimitive];if(i!==void 0){var e=i.call(r,n);if(typeof e!="object")return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}function ae(r){var n=Vt(r,"string");return typeof n=="symbol"?n:n+""}function A(r,n){if(!(r instanceof n))throw new TypeError("Cannot call a class as a function")}function He(r,n){for(var i=0;i<n.length;i++){var e=n[i];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(r,ae(e.key),e)}}function L(r,n,i){return n&&He(r.prototype,n),i&&He(r,i),Object.defineProperty(r,"prototype",{writable:!1}),r}function Q(r){return Q=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},Q(r)}function yt(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(yt=function(){return!!r})()}function jt(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function Zt(r,n){if(n&&(typeof n=="object"||typeof n=="function"))return n;if(n!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return jt(r)}function I(r,n,i){return n=Q(n),Zt(r,yt()?Reflect.construct(n,i||[],Q(r).constructor):n.apply(r,i))}function xe(r,n){return xe=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(i,e){return i.__proto__=e,i},xe(r,n)}function G(r,n){if(typeof n!="function"&&n!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(n&&n.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),n&&xe(r,n)}function qt(r){if(Array.isArray(r))return r}function Yt(r,n){var i=r==null?null:typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(i!=null){var e,t,a,o,s=[],l=!0,h=!1;try{if(a=(i=i.call(r)).next,n===0){if(Object(i)!==i)return;l=!1}else for(;!(l=(e=a.call(i)).done)&&(s.push(e.value),s.length!==n);l=!0);}catch(u){h=!0,t=u}finally{try{if(!l&&i.return!=null&&(o=i.return(),Object(o)!==o))return}finally{if(h)throw t}}return s}}function Se(r,n){(n==null||n>r.length)&&(n=r.length);for(var i=0,e=Array(n);i<n;i++)e[i]=r[i];return e}function Tt(r,n){if(r){if(typeof r=="string")return Se(r,n);var i={}.toString.call(r).slice(8,-1);return i==="Object"&&r.constructor&&(i=r.constructor.name),i==="Map"||i==="Set"?Array.from(r):i==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?Se(r,n):void 0}}function Xt(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
1
+ import{g as Bt,t as S,r as C}from"./vendor-tanstack-CYBjbqVr.js";import{e as Ht,G as Wt}from"./SiteHealthSection-Dgqtz9J2.js";import"./index-nb8QHq99.js";import"./vendor-radix-BpmvLvpp.js";import"./vendor-recharts-FA0uySU7.js";import"./vendor-lucide-dNHw1I5G.js";import"./vendor-markdown-9tTeP8v7.js";import"./vendor-yaml-GWJz5H2G.js";import"./ChartPrimitives-DLEICrrL.js";function Vt(r,n){if(typeof r!="object"||!r)return r;var i=r[Symbol.toPrimitive];if(i!==void 0){var e=i.call(r,n);if(typeof e!="object")return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}function ae(r){var n=Vt(r,"string");return typeof n=="symbol"?n:n+""}function A(r,n){if(!(r instanceof n))throw new TypeError("Cannot call a class as a function")}function He(r,n){for(var i=0;i<n.length;i++){var e=n[i];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(r,ae(e.key),e)}}function L(r,n,i){return n&&He(r.prototype,n),i&&He(r,i),Object.defineProperty(r,"prototype",{writable:!1}),r}function Q(r){return Q=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(n){return n.__proto__||Object.getPrototypeOf(n)},Q(r)}function yt(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(yt=function(){return!!r})()}function jt(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function Zt(r,n){if(n&&(typeof n=="object"||typeof n=="function"))return n;if(n!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return jt(r)}function I(r,n,i){return n=Q(n),Zt(r,yt()?Reflect.construct(n,i||[],Q(r).constructor):n.apply(r,i))}function xe(r,n){return xe=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(i,e){return i.__proto__=e,i},xe(r,n)}function G(r,n){if(typeof n!="function"&&n!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(n&&n.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),n&&xe(r,n)}function qt(r){if(Array.isArray(r))return r}function Yt(r,n){var i=r==null?null:typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(i!=null){var e,t,a,o,s=[],l=!0,h=!1;try{if(a=(i=i.call(r)).next,n===0){if(Object(i)!==i)return;l=!1}else for(;!(l=(e=a.call(i)).done)&&(s.push(e.value),s.length!==n);l=!0);}catch(u){h=!0,t=u}finally{try{if(!l&&i.return!=null&&(o=i.return(),Object(o)!==o))return}finally{if(h)throw t}}return s}}function Se(r,n){(n==null||n>r.length)&&(n=r.length);for(var i=0,e=Array(n);i<n;i++)e[i]=r[i];return e}function Tt(r,n){if(r){if(typeof r=="string")return Se(r,n);var i={}.toString.call(r).slice(8,-1);return i==="Object"&&r.constructor&&(i=r.constructor.name),i==="Map"||i==="Set"?Array.from(r):i==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?Se(r,n):void 0}}function Xt(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
2
2
  In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function ee(r,n){return qt(r)||Yt(r,n)||Tt(r,n)||Xt()}var pe={black:"#000000",silver:"#C0C0C0",gray:"#808080",grey:"#808080",white:"#FFFFFF",maroon:"#800000",red:"#FF0000",purple:"#800080",fuchsia:"#FF00FF",green:"#008000",lime:"#00FF00",olive:"#808000",yellow:"#FFFF00",navy:"#000080",blue:"#0000FF",teal:"#008080",aqua:"#00FFFF",darkblue:"#00008B",mediumblue:"#0000CD",darkgreen:"#006400",darkcyan:"#008B8B",deepskyblue:"#00BFFF",darkturquoise:"#00CED1",mediumspringgreen:"#00FA9A",springgreen:"#00FF7F",cyan:"#00FFFF",midnightblue:"#191970",dodgerblue:"#1E90FF",lightseagreen:"#20B2AA",forestgreen:"#228B22",seagreen:"#2E8B57",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",limegreen:"#32CD32",mediumseagreen:"#3CB371",turquoise:"#40E0D0",royalblue:"#4169E1",steelblue:"#4682B4",darkslateblue:"#483D8B",mediumturquoise:"#48D1CC",indigo:"#4B0082",darkolivegreen:"#556B2F",cadetblue:"#5F9EA0",cornflowerblue:"#6495ED",rebeccapurple:"#663399",mediumaquamarine:"#66CDAA",dimgray:"#696969",dimgrey:"#696969",slateblue:"#6A5ACD",olivedrab:"#6B8E23",slategray:"#708090",slategrey:"#708090",lightslategray:"#778899",lightslategrey:"#778899",mediumslateblue:"#7B68EE",lawngreen:"#7CFC00",chartreuse:"#7FFF00",aquamarine:"#7FFFD4",skyblue:"#87CEEB",lightskyblue:"#87CEFA",blueviolet:"#8A2BE2",darkred:"#8B0000",darkmagenta:"#8B008B",saddlebrown:"#8B4513",darkseagreen:"#8FBC8F",lightgreen:"#90EE90",mediumpurple:"#9370DB",darkviolet:"#9400D3",palegreen:"#98FB98",darkorchid:"#9932CC",yellowgreen:"#9ACD32",sienna:"#A0522D",brown:"#A52A2A",darkgray:"#A9A9A9",darkgrey:"#A9A9A9",lightblue:"#ADD8E6",greenyellow:"#ADFF2F",paleturquoise:"#AFEEEE",lightsteelblue:"#B0C4DE",powderblue:"#B0E0E6",firebrick:"#B22222",darkgoldenrod:"#B8860B",mediumorchid:"#BA55D3",rosybrown:"#BC8F8F",darkkhaki:"#BDB76B",mediumvioletred:"#C71585",indianred:"#CD5C5C",peru:"#CD853F",chocolate:"#D2691E",tan:"#D2B48C",lightgray:"#D3D3D3",lightgrey:"#D3D3D3",thistle:"#D8BFD8",orchid:"#DA70D6",goldenrod:"#DAA520",palevioletred:"#DB7093",crimson:"#DC143C",gainsboro:"#DCDCDC",plum:"#DDA0DD",burlywood:"#DEB887",lightcyan:"#E0FFFF",lavender:"#E6E6FA",darksalmon:"#E9967A",violet:"#EE82EE",palegoldenrod:"#EEE8AA",lightcoral:"#F08080",khaki:"#F0E68C",aliceblue:"#F0F8FF",honeydew:"#F0FFF0",azure:"#F0FFFF",sandybrown:"#F4A460",wheat:"#F5DEB3",beige:"#F5F5DC",whitesmoke:"#F5F5F5",mintcream:"#F5FFFA",ghostwhite:"#F8F8FF",salmon:"#FA8072",antiquewhite:"#FAEBD7",linen:"#FAF0E6",lightgoldenrodyellow:"#FAFAD2",oldlace:"#FDF5E6",magenta:"#FF00FF",deeppink:"#FF1493",orangered:"#FF4500",tomato:"#FF6347",hotpink:"#FF69B4",coral:"#FF7F50",darkorange:"#FF8C00",lightsalmon:"#FFA07A",orange:"#FFA500",lightpink:"#FFB6C1",pink:"#FFC0CB",gold:"#FFD700",peachpuff:"#FFDAB9",navajowhite:"#FFDEAD",moccasin:"#FFE4B5",bisque:"#FFE4C4",mistyrose:"#FFE4E1",blanchedalmond:"#FFEBCD",papayawhip:"#FFEFD5",lavenderblush:"#FFF0F5",seashell:"#FFF5EE",cornsilk:"#FFF8DC",lemonchiffon:"#FFFACD",floralwhite:"#FFFAF0",snow:"#FFFAFA",lightyellow:"#FFFFE0",ivory:"#FFFFF0"},Ct=new Int8Array(4),be=new Int32Array(Ct.buffer,0,1),$t=new Float32Array(Ct.buffer,0,1),Kt=/^\s*rgba?\s*\(/,Jt=/^\s*rgba?\s*\(\s*([0-9]*)\s*,\s*([0-9]*)\s*,\s*([0-9]*)(?:\s*,\s*(.*)?)?\)\s*$/;function Qt(r){var n=0,i=0,e=0,t=1;if(r[0]==="#")r.length===4?(n=parseInt(r.charAt(1)+r.charAt(1),16),i=parseInt(r.charAt(2)+r.charAt(2),16),e=parseInt(r.charAt(3)+r.charAt(3),16)):(n=parseInt(r.charAt(1)+r.charAt(2),16),i=parseInt(r.charAt(3)+r.charAt(4),16),e=parseInt(r.charAt(5)+r.charAt(6),16)),r.length===9&&(t=parseInt(r.charAt(7)+r.charAt(8),16)/255);else if(Kt.test(r)){var a=r.match(Jt);a&&(n=+a[1],i=+a[2],e=+a[3],a[4]&&(t=+a[4]))}return{r:n,g:i,b:e,a:t}}var J={};for(var le in pe)J[le]=oe(pe[le]),J[pe[le]]=J[le];function Rt(r,n,i,e,t){return be[0]=e<<24|i<<16|n<<8|r,be[0]=be[0]&4278190079,$t[0]}function oe(r){if(r=r.toLowerCase(),typeof J[r]<"u")return J[r];var n=Qt(r),i=n.r,e=n.g,t=n.b,a=n.a;a=a*255|0;var o=Rt(i,e,t,a);return J[r]=o,o}var Ee={};function _t(r){if(typeof Ee[r]<"u")return Ee[r];var n=(r&16711680)>>>16,i=(r&65280)>>>8,e=r&255,t=255,a=Rt(n,i,e,t);return Ee[r]=a,a}function We(r,n,i,e){return i+(n<<8)+(r<<16)}function Ve(r,n,i,e,t,a){var o=Math.floor(i/a*t),s=Math.floor(r.drawingBufferHeight/a-e/a*t),l=new Uint8Array(4);r.bindFramebuffer(r.FRAMEBUFFER,n),r.readPixels(o,s,1,1,r.RGBA,r.UNSIGNED_BYTE,l);var h=ee(l,4),u=h[0],d=h[1],f=h[2],g=h[3];return[u,d,f,g]}function c(r,n,i){return(n=ae(n))in r?Object.defineProperty(r,n,{value:i,enumerable:!0,configurable:!0,writable:!0}):r[n]=i,r}function je(r,n){var i=Object.keys(r);if(Object.getOwnPropertySymbols){var e=Object.getOwnPropertySymbols(r);n&&(e=e.filter(function(t){return Object.getOwnPropertyDescriptor(r,t).enumerable})),i.push.apply(i,e)}return i}function b(r){for(var n=1;n<arguments.length;n++){var i=arguments[n]!=null?arguments[n]:{};n%2?je(Object(i),!0).forEach(function(e){c(r,e,i[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(i)):je(Object(i)).forEach(function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(i,e))})}return r}function ei(r,n){for(;!{}.hasOwnProperty.call(r,n)&&(r=Q(r))!==null;);return r}function Ae(){return Ae=typeof Reflect<"u"&&Reflect.get?Reflect.get.bind():function(r,n,i){var e=ei(r,n);if(e){var t=Object.getOwnPropertyDescriptor(e,n);return t.get?t.get.call(arguments.length<3?r:i):t.value}},Ae.apply(null,arguments)}function wt(r,n,i,e){var t=Ae(Q(r.prototype),n,i);return typeof t=="function"?function(a){return t.apply(i,a)}:t}function ti(r){return r.normalized?1:r.size}function ye(r){var n=0;return r.forEach(function(i){return n+=ti(i)}),n}function xt(r,n,i){var e=r==="VERTEX"?n.VERTEX_SHADER:n.FRAGMENT_SHADER,t=n.createShader(e);if(t===null)throw new Error("loadShader: error while creating the shader");n.shaderSource(t,i),n.compileShader(t);var a=n.getShaderParameter(t,n.COMPILE_STATUS);if(!a){var o=n.getShaderInfoLog(t);throw n.deleteShader(t),new Error(`loadShader: error while compiling the shader:
3
3
  `.concat(o,`
4
4
  `).concat(i))}return t}function ii(r,n){return xt("VERTEX",r,n)}function ri(r,n){return xt("FRAGMENT",r,n)}function ni(r,n){var i=r.createProgram();if(i===null)throw new Error("loadProgram: error while creating the program.");var e,t;for(e=0,t=n.length;e<t;e++)r.attachShader(i,n[e]);r.linkProgram(i);var a=r.getProgramParameter(i,r.LINK_STATUS);if(!a){var o=r.getProgramInfoLog(i);throw r.deleteProgram(i),new Error("loadProgram: error while linking the program: ".concat(o))}return i}function Ze(r){var n=r.gl,i=r.buffer,e=r.program,t=r.vertexShader,a=r.fragmentShader;n.deleteShader(t),n.deleteShader(a),n.deleteProgram(e),n.deleteBuffer(i)}var qe=`#define PICKING_MODE
package/assets/index.html CHANGED
@@ -12,14 +12,14 @@
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-vRk2f6HY.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-nb8QHq99.js"></script>
16
16
  <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-CYBjbqVr.js">
17
17
  <link rel="modulepreload" crossorigin href="./assets/vendor-radix-BpmvLvpp.js">
18
18
  <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-FA0uySU7.js">
19
19
  <link rel="modulepreload" crossorigin href="./assets/vendor-lucide-dNHw1I5G.js">
20
20
  <link rel="modulepreload" crossorigin href="./assets/vendor-markdown-9tTeP8v7.js">
21
21
  <link rel="modulepreload" crossorigin href="./assets/vendor-yaml-GWJz5H2G.js">
22
- <link rel="stylesheet" crossorigin href="./assets/index-KTeRanN1.css">
22
+ <link rel="stylesheet" crossorigin href="./assets/index-BjjM151x.css">
23
23
  </head>
24
24
  <body>
25
25
  <div id="root"></div>
@@ -5,11 +5,11 @@ import {
5
5
  installSkills,
6
6
  loadConfigRaw,
7
7
  saveConfigPatch
8
- } from "./chunk-YDYB3H4O.js";
8
+ } from "./chunk-32QBVRMN.js";
9
9
  import {
10
10
  SKILL_MANIFEST_FILENAME,
11
11
  SkillsClients
12
- } from "./chunk-CDI3YR57.js";
12
+ } from "./chunk-ROPJUNQN.js";
13
13
 
14
14
  // src/skills-autosync.ts
15
15
  import fs from "fs";
@@ -63,6 +63,7 @@ import {
63
63
  measurementDraftReplaceAssignmentsRequestSchema,
64
64
  measurementDraftUpsertCompetitorRequestSchema,
65
65
  measurementDraftUpsertGroupRequestSchema,
66
+ measurementDraftUpsertMarketRequestSchema,
66
67
  measurementDraftUpsertTargetRequestSchema,
67
68
  measurementOverviewQuerySchema,
68
69
  measurementPlanAuthoringSchema,
@@ -99,7 +100,7 @@ import {
99
100
  trafficEventKindSchema,
100
101
  trafficSeriesGranularitySchema,
101
102
  visibilityReportRequestSchema
102
- } from "./chunk-CDI3YR57.js";
103
+ } from "./chunk-ROPJUNQN.js";
103
104
 
104
105
  // src/cli-error.ts
105
106
  function isMachineFormat(format) {
@@ -1895,6 +1896,22 @@ var postApiV1ProjectsByNameMeasurementPlanDraftActionsUpsertGroup = (options) =>
1895
1896
  }
1896
1897
  });
1897
1898
  };
1899
+ var postApiV1ProjectsByNameMeasurementPlanDraftActionsUpsertMarket = (options) => {
1900
+ return (options.client ?? client).post({
1901
+ security: [
1902
+ {
1903
+ scheme: "bearer",
1904
+ type: "http"
1905
+ }
1906
+ ],
1907
+ url: "/api/v1/projects/{name}/measurement-plan/draft/actions/upsert-market",
1908
+ ...options,
1909
+ headers: {
1910
+ "Content-Type": "application/json",
1911
+ ...options.headers
1912
+ }
1913
+ });
1914
+ };
1898
1915
  var postApiV1ProjectsByNameMeasurementPlanDraftActionsRemoveGroup = (options) => {
1899
1916
  return (options.client ?? client).post({
1900
1917
  security: [
@@ -6628,6 +6645,16 @@ var ApiClient = class {
6628
6645
  })
6629
6646
  );
6630
6647
  }
6648
+ async upsertMeasurementDraftMarket(project, request, idempotencyKey, etag) {
6649
+ return this.invoke(
6650
+ () => postApiV1ProjectsByNameMeasurementPlanDraftActionsUpsertMarket({
6651
+ client: this.heyClient,
6652
+ path: { name: project },
6653
+ body: request,
6654
+ headers: this.measurementDraftMutationHeaders(idempotencyKey, etag)
6655
+ })
6656
+ );
6657
+ }
6631
6658
  async removeMeasurementDraftGroup(project, request, idempotencyKey, etag) {
6632
6659
  return this.invoke(
6633
6660
  () => postApiV1ProjectsByNameMeasurementPlanDraftActionsRemoveGroup({
@@ -8782,6 +8809,7 @@ var measurementDraftOperationSchema = z2.discriminatedUnion("action", [
8782
8809
  mutationOperationSchema("clear-assignments", measurementDraftClearAssignmentsRequestSchema),
8783
8810
  mutationOperationSchema("classify-assignments", measurementDraftClassifyAssignmentsRequestSchema),
8784
8811
  mutationOperationSchema("upsert-group", measurementDraftUpsertGroupRequestSchema),
8812
+ mutationOperationSchema("upsert-market", measurementDraftUpsertMarketRequestSchema),
8785
8813
  mutationOperationSchema("remove-group", measurementDraftRemoveGroupRequestSchema),
8786
8814
  z2.object({
8787
8815
  action: z2.literal("preview-group-membership"),
@@ -8833,6 +8861,8 @@ function runMeasurementDraftAction(client2, project, actionInput) {
8833
8861
  return client2.classifyMeasurementDraftAssignments(project, actionInput.request, actionInput.idempotencyKey, actionInput.etag);
8834
8862
  case "upsert-group":
8835
8863
  return client2.upsertMeasurementDraftGroup(project, actionInput.request, actionInput.idempotencyKey, actionInput.etag);
8864
+ case "upsert-market":
8865
+ return client2.upsertMeasurementDraftMarket(project, actionInput.request, actionInput.idempotencyKey, actionInput.etag);
8836
8866
  case "remove-group":
8837
8867
  return client2.removeMeasurementDraftGroup(project, actionInput.request, actionInput.idempotencyKey, actionInput.etag);
8838
8868
  case "preview-group-membership":
@@ -9023,6 +9053,7 @@ var measurementDraftActionOpenApiOperations = [
9023
9053
  "POST /api/v1/projects/{name}/measurement-plan/draft/actions/clear-assignments",
9024
9054
  "POST /api/v1/projects/{name}/measurement-plan/draft/actions/classify-assignments",
9025
9055
  "POST /api/v1/projects/{name}/measurement-plan/draft/actions/upsert-group",
9056
+ "POST /api/v1/projects/{name}/measurement-plan/draft/actions/upsert-market",
9026
9057
  "POST /api/v1/projects/{name}/measurement-plan/draft/actions/remove-group",
9027
9058
  "POST /api/v1/projects/{name}/measurement-plan/draft/actions/preview-group-membership",
9028
9059
  "POST /api/v1/projects/{name}/measurement-plan/draft/actions/apply-group-membership",
@@ -9522,7 +9553,7 @@ var discoverySessionIdInputSchema = z4.object({
9522
9553
  });
9523
9554
  var researchRunStartInputSchema = z4.object({
9524
9555
  project: projectNameSchema,
9525
- request: researchRunCreateSchema.describe("One shared provider/model/location context for every free-form query in this saved research batch.")
9556
+ request: researchRunCreateSchema.describe("One shared provider/model/location context for every final free-form query in this saved research batch. An optional market or Property destination is saved with the batch. Template provenance records a template ID and version only; it never expands or alters queries.")
9526
9557
  });
9527
9558
  var researchRunsListInputSchema = z4.object({
9528
9559
  project: projectNameSchema,
@@ -11471,7 +11502,7 @@ var canonryMcpTools = [
11471
11502
  defineTool({
11472
11503
  name: "canonry_research_run_start",
11473
11504
  title: "Start research query run",
11474
- description: "Run a batch of free-form queries once each against one API provider, with an optional exact model and location. Results are saved as a research run for later inspection. This does not add any query to the tracked basket or affect overview tracking.",
11505
+ description: "Run final free-form queries once each against one API provider, with an optional exact model, location, or one configured market or Property destination. Scope never changes query text or fans out a group. Optional template provenance records the source template ID and version; callers must submit the fully expanded, editable final query text. Results retain that destination and provenance for later inspection. This does not add any query to the tracked basket or affect overview tracking.",
11475
11506
  access: "write",
11476
11507
  tier: "discovery",
11477
11508
  inputSchema: researchRunStartInputSchema,
@@ -14,7 +14,7 @@ import {
14
14
  loadConfig,
15
15
  loadConfigRaw,
16
16
  saveConfigPatch
17
- } from "./chunk-YDYB3H4O.js";
17
+ } from "./chunk-32QBVRMN.js";
18
18
  import {
19
19
  CC_CACHE_DIR,
20
20
  DUCKDB_SPEC,
@@ -162,7 +162,7 @@ import {
162
162
  siteCrawlSnapshots,
163
163
  toAlertView,
164
164
  usageCounters
165
- } from "./chunk-QQLMRABM.js";
165
+ } from "./chunk-6POEZ7GT.js";
166
166
  import {
167
167
  AGENT_MEMORY_VALUE_MAX_BYTES,
168
168
  AGENT_PROVIDER_IDS,
@@ -305,7 +305,7 @@ import {
305
305
  validationError,
306
306
  winnabilityClassLabel,
307
307
  withRetry
308
- } from "./chunk-CDI3YR57.js";
308
+ } from "./chunk-ROPJUNQN.js";
309
309
 
310
310
  // src/telemetry.ts
311
311
  import crypto from "crypto";
@@ -12041,7 +12041,7 @@ function readStoredGroundingSources(rawResponse) {
12041
12041
  return result;
12042
12042
  }
12043
12043
  async function backfillInsightsCommand(project, opts) {
12044
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-M5TYY4TH.js");
12044
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-WNASQFN4.js");
12045
12045
  const config = loadConfig();
12046
12046
  const db = createClient(config.database);
12047
12047
  migrate(db);
@@ -267,6 +267,7 @@ import {
267
267
  createdApiKeyDtoSchema,
268
268
  dedupeReportActions,
269
269
  dedupeReportOpportunities,
270
+ deduplicateResearchQueries,
270
271
  deliveryFailed,
271
272
  deltaPercent,
272
273
  deltaTone,
@@ -293,6 +294,8 @@ import {
293
294
  emptyCitationVisibility,
294
295
  escapeLikePattern,
295
296
  evaluateModelPointerExposure,
297
+ expandQueryTemplate,
298
+ expandResearchTemplate,
296
299
  extractAnswerMentions,
297
300
  extractDomainsFromText,
298
301
  factorStatusFromScore,
@@ -441,6 +444,7 @@ import {
441
444
  measurementDraftTargetPageSchema,
442
445
  measurementDraftUpsertCompetitorRequestSchema,
443
446
  measurementDraftUpsertGroupRequestSchema,
447
+ measurementDraftUpsertMarketRequestSchema,
444
448
  measurementDraftUpsertTargetRequestSchema,
445
449
  measurementIdempotencyKeyConflict,
446
450
  measurementIdempotencyKeyRequired,
@@ -672,7 +676,7 @@ import {
672
676
  wordpressSchemaDeployResultDtoSchema,
673
677
  wordpressSchemaStatusResultDtoSchema,
674
678
  wordpressStatusDtoSchema
675
- } from "./chunk-CDI3YR57.js";
679
+ } from "./chunk-ROPJUNQN.js";
676
680
 
677
681
  // src/intelligence-service.ts
678
682
  import { eq as eq67, desc as desc29, asc as asc12, and as and57, ne as ne10, or as or14, inArray as inArray25, gte as gte18, lte as lte15, isNull as isNull12, sql as sql26, exists } from "drizzle-orm";
@@ -2723,6 +2727,8 @@ var researchRuns = sqliteTable("research_runs", {
2723
2727
  requestedModel: text("requested_model"),
2724
2728
  resolvedModel: text("resolved_model").notNull(),
2725
2729
  location: text("location", { mode: "json" }).$type(),
2730
+ scope: text("scope", { mode: "json" }).$type(),
2731
+ template: text("template", { mode: "json" }).$type(),
2726
2732
  totalQueries: integer("total_queries").notNull(),
2727
2733
  completedQueries: integer("completed_queries").notNull().default(0),
2728
2734
  failedQueries: integer("failed_queries").notNull().default(0),
@@ -2739,6 +2745,7 @@ var researchRunQueries = sqliteTable("research_run_queries", {
2739
2745
  researchRunId: text("research_run_id").notNull().references(() => researchRuns.id, { onDelete: "cascade" }),
2740
2746
  position: integer("position").notNull(),
2741
2747
  queryText: text("query_text").notNull(),
2748
+ queryClass: text("query_class").$type(),
2742
2749
  status: text("status").notNull().default("queued"),
2743
2750
  requestedModel: text("requested_model"),
2744
2751
  resolvedModel: text("resolved_model").notNull(),
@@ -7161,6 +7168,15 @@ var MIGRATION_VERSIONS = [
7161
7168
  statements: [
7162
7169
  `ALTER TABLE schedules ADD COLUMN recurrence TEXT`
7163
7170
  ]
7171
+ },
7172
+ {
7173
+ version: 153,
7174
+ name: "research-run-scope",
7175
+ statements: [
7176
+ `ALTER TABLE research_runs ADD COLUMN scope TEXT`,
7177
+ `ALTER TABLE research_runs ADD COLUMN template TEXT`,
7178
+ `ALTER TABLE research_run_queries ADD COLUMN query_class TEXT`
7179
+ ]
7164
7180
  }
7165
7181
  ];
7166
7182
  function addRunsMeasurementPlanVersionForeignKey(tx) {
@@ -17891,6 +17907,7 @@ var MEASUREMENT_DRAFT_ACTIONS = [
17891
17907
  "clear-assignments",
17892
17908
  "classify-assignments",
17893
17909
  "upsert-group",
17910
+ "upsert-market",
17894
17911
  "remove-group",
17895
17912
  "upsert-competitor",
17896
17913
  "remove-competitor"
@@ -18288,6 +18305,23 @@ function upsertGroup(authoring, body) {
18288
18305
  warnings: unknown.length ? [warn("group-unknown-target", `Group "${group.stableKey}" names ${unknown.length} Target(s) the draft does not hold yet.`, ["groups", groupIndex, "targetKeys"])] : []
18289
18306
  };
18290
18307
  }
18308
+ function upsertMarket(authoring, body) {
18309
+ const { market } = parseBody(measurementDraftUpsertMarketRequestSchema, body, "upsert-market");
18310
+ const included = new Set(authoring.targets.filter((target) => target.status === "included").map((target) => target.stableKey));
18311
+ const frozen = new Set(authoring.assignments.flatMap((assignment) => (assignment.executionContexts ?? []).filter((context) => context.executionNodeKey !== void 0).map((context) => measurementV2UsageEdgeKey({ targetKey: assignment.targetKey, queryId: assignment.queryId, executionNodeKey: context.executionNodeKey }))));
18312
+ const seen2 = /* @__PURE__ */ new Set();
18313
+ for (const edge of market.usageEdges) {
18314
+ const key = measurementV2UsageEdgeKey(edge);
18315
+ if (!included.has(edge.targetKey) || !frozen.has(key)) throw validationError("Market members must be existing frozen assignments on included Properties.");
18316
+ if (seen2.has(key)) throw validationError("Market membership contains a duplicate assignment.");
18317
+ seen2.add(key);
18318
+ }
18319
+ const reportingScopes = [...authoring.reportingScopes ?? []];
18320
+ const index2 = reportingScopes.findIndex((scope) => scope.stableKey === market.stableKey);
18321
+ if (index2 === -1) reportingScopes.push(market);
18322
+ else reportingScopes[index2] = market;
18323
+ return { authoring: { ...authoring, reportingScopes }, warnings: [] };
18324
+ }
18291
18325
  function removeGroup(authoring, body) {
18292
18326
  const { groupKey } = parseBody(measurementDraftRemoveGroupRequestSchema, body, "remove-group");
18293
18327
  const children = authoring.groups.filter((group) => group.parentGroupKey === groupKey);
@@ -18352,6 +18386,8 @@ function applyDraftAction(action, authoring, body, context) {
18352
18386
  return classifyAssignments(authoring, body);
18353
18387
  case "upsert-group":
18354
18388
  return upsertGroup(authoring, body);
18389
+ case "upsert-market":
18390
+ return upsertMarket(authoring, body);
18355
18391
  case "remove-group":
18356
18392
  return removeGroup(authoring, body);
18357
18393
  case "upsert-competitor":
@@ -20220,9 +20256,9 @@ async function measurementDraftRoutes(app, opts = {}) {
20220
20256
  if (missing.length) {
20221
20257
  throw validationError(`Binding ${index2} does not supply ${missing.map((name) => `"${name}"`).join(", ")}.`);
20222
20258
  }
20223
- let text2 = template.pattern;
20224
- for (const variable of template.variables) text2 = text2.split(`{${variable}}`).join(binding[variable]);
20225
- const trimmed = text2.trim();
20259
+ const trimmed = expandQueryTemplate(template.pattern, Object.fromEntries(
20260
+ template.variables.map((variable) => [variable, binding[variable]])
20261
+ ));
20226
20262
  if (!trimmed) throw validationError(`Binding ${index2} expands to an empty question.`);
20227
20263
  if (!expansions.includes(trimmed)) expansions.push(trimmed);
20228
20264
  });
@@ -23842,9 +23878,9 @@ function templateRecords(db, state, addition, audience) {
23842
23878
  const needsMarket = template.variables.includes("market");
23843
23879
  const needsProperty = template.variables.includes("property");
23844
23880
  const expand = (bindings, scopedAudience) => {
23845
- let queryText = template.pattern;
23846
- for (const variable of template.variables) queryText = queryText.split(`{${variable}}`).join(bindings[variable] ?? "");
23847
- queryText = queryText.trim();
23881
+ const queryText = expandQueryTemplate(template.pattern, Object.fromEntries(
23882
+ template.variables.map((variable) => [variable, bindings[variable] ?? ""])
23883
+ ));
23848
23884
  if (!queryText) throw validationError("Template expansion produced an empty query.");
23849
23885
  return {
23850
23886
  queryText,
@@ -34582,6 +34618,7 @@ var SCHEMA_TABLE = {
34582
34618
  MeasurementDraftTargetPage: measurementDraftTargetPageSchema,
34583
34619
  MeasurementDraftUpsertCompetitorRequest: measurementDraftUpsertCompetitorRequestSchema,
34584
34620
  MeasurementDraftUpsertGroupRequest: measurementDraftUpsertGroupRequestSchema,
34621
+ MeasurementDraftUpsertMarketRequest: measurementDraftUpsertMarketRequestSchema,
34585
34622
  MeasurementDraftUpsertTargetRequest: measurementDraftUpsertTargetRequestSchema,
34586
34623
  MeasurementOverviewResponse: measurementOverviewResponseSchema,
34587
34624
  MeasurementPortfolioSummaryResponse: measurementPortfolioSummaryResponseSchema,
@@ -35707,6 +35744,12 @@ var routeCatalog = [
35707
35744
  description: "Reporting membership only. When `competitors` is present it replaces the complete competitor list atomically; omission preserves the existing list for backward compatibility. A payload carrying queries, providers, locations or models is rejected.",
35708
35745
  request: "MeasurementDraftUpsertGroupRequest"
35709
35746
  }),
35747
+ measurementDraftAction({
35748
+ action: "upsert-market",
35749
+ summary: "Configure an explicit market name and frozen membership",
35750
+ description: "Adds or updates a reporting market using existing frozen assignment edges. It never infers geography from groups or creates query executions. Requires draft review and publication before Research can select it.",
35751
+ request: "MeasurementDraftUpsertMarketRequest"
35752
+ }),
35710
35753
  measurementDraftAction({
35711
35754
  action: "remove-group",
35712
35755
  summary: "Remove a draft group",
@@ -36173,7 +36216,7 @@ var routeCatalog = [
36173
36216
  method: "post",
36174
36217
  path: "/api/v1/projects/{name}/research/runs",
36175
36218
  summary: "Start an isolated research query batch",
36176
- description: "Runs one to fifty ad-hoc queries through one API provider and saves the answer evidence. Research never creates tracked queries, shared runs, snapshots, insights, or notifications. Administrators are always allowed; signed-in viewers require the deployment opt-in and a per-project daily allowance. Read-only and narrowly scoped API keys are refused.",
36219
+ description: "Runs one to fifty ad-hoc queries through one API provider and saves the answer evidence. An optional published Advanced Measurement market or property scope and optional template provenance are frozen with the batch. The provider receives the exact submitted editor question; scope never infers geographic provider location. Research never creates tracked queries, shared runs, snapshots, insights, or notifications. Administrators are always allowed; signed-in viewers require the deployment opt-in and a per-project daily allowance. Read-only and narrowly scoped API keys are refused.",
36177
36220
  tags: ["research"],
36178
36221
  parameters: [nameParameter],
36179
36222
  requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ResearchRunCreate" } } } },
@@ -83142,14 +83185,19 @@ async function researchRoutes(app, opts) {
83142
83185
  adapter.modelValidationPattern.lastIndex = 0;
83143
83186
  if (!adapter.modelConfigurable || !adapter.modelValidationPattern.test(input.model)) throw validationError(`Invalid model "${input.model}" for provider "${providerName}".`, { provider: providerName, model: input.model, hint: adapter.modelValidationHint });
83144
83187
  }
83145
- const location = input.location === void 0 ? project.defaultLocation ? project.locations.find((item2) => item2.label === project.defaultLocation) ?? null : null : input.location;
83188
+ const existingReceipt = input.idempotencyKey ? app.db.select().from(researchRuns).where(and55(eq65(researchRuns.projectId, project.id), eq65(researchRuns.idempotencyKey, input.idempotencyKey))).get() : void 0;
83189
+ const active = activeMeasurementPlan(app.db, project.id);
83190
+ const scope = input.scope ? existingReceipt ? resolveStoredResearchScope(existingReceipt.scope, input.scope, input.idempotencyKey) : resolveResearchScope(active, input.scope) : null;
83191
+ const template = input.template ? existingReceipt ? resolveStoredResearchTemplate(existingReceipt.template, input.template, input.idempotencyKey) : resolveResearchTemplate(app, project.id, input.template, scope) : null;
83192
+ const location = input.location === void 0 ? scope ? null : project.defaultLocation ? project.locations.find((item2) => item2.label === project.defaultLocation) ?? null : null : input.location;
83146
83193
  if (location && !project.locations.some((item2) => sameLocation(item2, location))) throw validationError("Research location must exactly match a configured project location.", { location });
83147
83194
  const requestedModel2 = input.model ?? null;
83148
83195
  const resolvedModel = requestedModel2 ?? (project.providerModels[providerName] || opts.getEffectiveProviderModels?.()[providerName] || adapter.defaultModel);
83149
83196
  adapter.modelValidationPattern.lastIndex = 0;
83150
- if (!adapter.modelValidationPattern.test(resolvedModel)) throw validationError(`Invalid resolved model "${resolvedModel}" for provider "${providerName}".`, { provider: providerName, model: resolvedModel, hint: adapter.modelValidationHint });
83151
- if (new Set(input.queries.map((query) => query.toLocaleLowerCase())).size !== input.queries.length) throw validationError("Research queries must be unique within a batch.");
83152
- const normalized = { queries: input.queries, provider: providerName, model: requestedModel2, location: location ?? null };
83197
+ if (!adapter.modelValidationPattern.test(resolvedModel)) throw validationError('Invalid resolved model "' + resolvedModel + '" for provider "' + providerName + '".', { provider: providerName, model: resolvedModel, hint: adapter.modelValidationHint });
83198
+ if (deduplicateResearchQueries(input.queries).length !== input.queries.length) throw validationError("Research queries must be unique within a batch.");
83199
+ const queryClasses = classifyResearchQueries(project, active?.plan ?? null, input.queries);
83200
+ const normalized = { queries: input.queries, provider: providerName, model: requestedModel2, location: location ?? null, ...scope ? { scope } : {}, ...template ? { template } : {} };
83153
83201
  const requestHash2 = crypto49.createHash("sha256").update(JSON.stringify(normalized)).digest("hex");
83154
83202
  const now = (/* @__PURE__ */ new Date()).toISOString();
83155
83203
  const initiatedBy = researchPrincipal(request);
@@ -83174,8 +83222,8 @@ async function researchRoutes(app, opts) {
83174
83222
  }
83175
83223
  }
83176
83224
  const id = crypto49.randomUUID();
83177
- tx.insert(researchRuns).values({ id, projectId: project.id, status: ResearchRunStatuses.queued, provider: providerName, requestedModel: requestedModel2, resolvedModel, location: location ?? null, totalQueries: input.queries.length, idempotencyKey: input.idempotencyKey ?? null, requestHash: input.idempotencyKey ? requestHash2 : null, initiatedBy, createdAt: now }).run();
83178
- for (const [position, query] of input.queries.entries()) tx.insert(researchRunQueries).values({ id: crypto49.randomUUID(), researchRunId: id, position, queryText: query, status: ResearchQueryStatuses.queued, requestedModel: requestedModel2, resolvedModel, groundingSources: [], citedDomains: [], searchQueries: [], createdAt: now }).run();
83225
+ tx.insert(researchRuns).values({ id, projectId: project.id, status: ResearchRunStatuses.queued, provider: providerName, requestedModel: requestedModel2, resolvedModel, location: location ?? null, totalQueries: input.queries.length, scope, template, idempotencyKey: input.idempotencyKey ?? null, requestHash: input.idempotencyKey ? requestHash2 : null, initiatedBy, createdAt: now }).run();
83226
+ for (const [position, query] of input.queries.entries()) tx.insert(researchRunQueries).values({ id: crypto49.randomUUID(), researchRunId: id, position, queryText: query, queryClass: queryClasses[position] ?? null, status: ResearchQueryStatuses.queued, requestedModel: requestedModel2, resolvedModel, groundingSources: [], citedDomains: [], searchQueries: [], createdAt: now }).run();
83179
83227
  writeAuditLog(tx, { projectId: project.id, actor: initiatedBy ? `${initiatedBy.kind}:${initiatedBy.id}` : "api", action: "research.created", entityType: "research_run", entityId: id });
83180
83228
  return { reused: false, id, shouldDispatch: true };
83181
83229
  });
@@ -83210,6 +83258,52 @@ async function researchRoutes(app, opts) {
83210
83258
  return getDetail(app, project.id, request.params.runId);
83211
83259
  });
83212
83260
  }
83261
+ function resolveStoredResearchScope(stored, selection, idempotencyKey) {
83262
+ if (!stored || stored.kind !== selection.kind || stored.key !== selection.key || selection.expectedPlanRevision !== void 0 && selection.expectedPlanRevision !== stored.planRevision) {
83263
+ throw alreadyExists("Research idempotency key", idempotencyKey);
83264
+ }
83265
+ return stored;
83266
+ }
83267
+ function resolveResearchScope(active, selection) {
83268
+ if (!active || active.plan.schemaVersion !== 2) {
83269
+ throw validationError("Research scope requires an active Advanced Measurement plan.");
83270
+ }
83271
+ if (selection.expectedPlanRevision !== void 0 && selection.expectedPlanRevision !== active.version.revision) {
83272
+ throw validationError("The selected research scope is stale. Reload the published measurement plan and try again.", {
83273
+ expectedPlanRevision: selection.expectedPlanRevision,
83274
+ activePlanRevision: active.version.revision
83275
+ });
83276
+ }
83277
+ const label = selection.kind === "market" ? active.plan.reportingScopes?.find((scope) => scope.stableKey === selection.key)?.label : active.plan.targets.find((target) => target.stableKey === selection.key)?.label;
83278
+ if (!label) throw validationError("Unknown published research " + selection.kind + ' scope "' + selection.key + '".');
83279
+ return { kind: selection.kind, key: selection.key, label, planRevision: active.version.revision };
83280
+ }
83281
+ function resolveStoredResearchTemplate(stored, selection, idempotencyKey) {
83282
+ if (!stored || stored.templateId !== selection.templateId || stored.templateVersion !== selection.templateVersion) {
83283
+ throw alreadyExists("Research idempotency key", idempotencyKey);
83284
+ }
83285
+ return stored;
83286
+ }
83287
+ function resolveResearchTemplate(app, projectId, selection, scope) {
83288
+ if (!scope) throw validationError("Research templates require a selected market or property scope.");
83289
+ const savedTemplate = app.db.select().from(measurementQueryTemplates).where(and55(
83290
+ eq65(measurementQueryTemplates.projectId, projectId),
83291
+ eq65(measurementQueryTemplates.id, selection.templateId)
83292
+ )).get();
83293
+ if (!savedTemplate) throw validationError("Unknown or stale research template. Reload the selected template and try again.");
83294
+ const templateVersion = savedTemplate.updatedAt;
83295
+ if (templateVersion !== selection.templateVersion) {
83296
+ throw validationError("The selected research template is stale. Reload it and try again.");
83297
+ }
83298
+ const { bindings, output } = expandResearchTemplate(savedTemplate, scope);
83299
+ if (!output || output.length > 4e3) throw validationError("Research template output must be between 1 and 4000 characters.");
83300
+ return { templateId: selection.templateId, templateVersion, template: savedTemplate.pattern, bindings, output };
83301
+ }
83302
+ function classifyResearchQueries(project, plan, queries2) {
83303
+ const propertyNames = plan ? plan.targets.flatMap((target) => [target.label, ...target.aliases]) : [];
83304
+ const classifier = compileQueryClassifier([...effectiveBrandNames(project), ...propertyNames]);
83305
+ return queries2.map((query) => classifier?.classify(query) ?? null);
83306
+ }
83213
83307
  function getDetail(app, projectId, id) {
83214
83308
  const row = app.db.select().from(researchRuns).where(and55(eq65(researchRuns.id, id), eq65(researchRuns.projectId, projectId))).get();
83215
83309
  if (!row) throw notFound("Research run", id);
@@ -83217,10 +83311,10 @@ function getDetail(app, projectId, id) {
83217
83311
  return { ...serializeRun(row), queries: queries2 };
83218
83312
  }
83219
83313
  function serializeRun(row) {
83220
- return { id: row.id, projectId: row.projectId, status: row.status, provider: row.provider, requestedModel: row.requestedModel, resolvedModel: row.resolvedModel, location: row.location ?? null, totalQueries: row.totalQueries, completedQueries: row.completedQueries, failedQueries: row.failedQueries, error: row.error, initiatedBy: row.initiatedBy ?? null, startedAt: row.startedAt, finishedAt: row.finishedAt, createdAt: row.createdAt };
83314
+ return { id: row.id, projectId: row.projectId, status: row.status, provider: row.provider, requestedModel: row.requestedModel, resolvedModel: row.resolvedModel, location: row.location ?? null, scope: row.scope ?? null, template: row.template ?? null, totalQueries: row.totalQueries, completedQueries: row.completedQueries, failedQueries: row.failedQueries, error: row.error, initiatedBy: row.initiatedBy ?? null, startedAt: row.startedAt, finishedAt: row.finishedAt, createdAt: row.createdAt };
83221
83315
  }
83222
83316
  function serializeQuery(row) {
83223
- return { id: row.id, position: row.position, query: row.queryText, status: row.status, requestedModel: row.requestedModel, resolvedModel: row.resolvedModel, servedModel: row.servedModel, answerText: row.answerText, groundingSources: row.groundingSources, citedDomains: row.citedDomains, searchQueries: row.searchQueries, namedCompetitors: row.namedCompetitors, citedCompetitorDomains: row.citedCompetitorDomains, answerMentioned: row.answerMentioned, citationState: row.citationState, error: row.error, startedAt: row.startedAt, finishedAt: row.finishedAt, createdAt: row.createdAt };
83317
+ return { id: row.id, position: row.position, query: row.queryText, queryClass: row.queryClass ?? null, status: row.status, requestedModel: row.requestedModel, resolvedModel: row.resolvedModel, servedModel: row.servedModel, answerText: row.answerText, groundingSources: row.groundingSources, citedDomains: row.citedDomains, searchQueries: row.searchQueries, namedCompetitors: row.namedCompetitors, citedCompetitorDomains: row.citedCompetitorDomains, answerMentioned: row.answerMentioned, citationState: row.citationState, error: row.error, startedAt: row.startedAt, finishedAt: row.finishedAt, createdAt: row.createdAt };
83224
83318
  }
83225
83319
  function researchPrincipal(request) {
83226
83320
  const principal = request.principal;
@@ -6379,6 +6379,11 @@ var visibilityReportResponseSchema = z15.object({
6379
6379
 
6380
6380
  // ../contracts/src/query-tracking.ts
6381
6381
  import { z as z16 } from "zod";
6382
+ function expandQueryTemplate(pattern, bindings) {
6383
+ let output = pattern;
6384
+ for (const [variable, value] of Object.entries(bindings)) output = output.split(`{${variable}}`).join(value);
6385
+ return output.trim();
6386
+ }
6382
6387
  var sha256HexSchema2 = z16.string().regex(/^[a-f0-9]{64}$/);
6383
6388
  var queryTrackingIdSchema = z16.string().trim().min(1).max(256);
6384
6389
  var queryTrackingTextSchema = z16.string().trim().min(1).max(4e3);
@@ -7611,6 +7616,9 @@ var measurementDraftUpsertGroupRequestSchema = z19.object({
7611
7616
  competitors: z19.array(measurementDraftCompetitorSchema).optional()
7612
7617
  }).strict()
7613
7618
  }).strict();
7619
+ var measurementDraftUpsertMarketRequestSchema = z19.object({
7620
+ market: measurementDraftReportingScopeSchema
7621
+ }).strict();
7614
7622
  var measurementDraftRemoveGroupRequestSchema = z19.object({
7615
7623
  groupKey: measurementV2StableKeySchema
7616
7624
  }).strict();
@@ -16217,11 +16225,50 @@ var ResearchRunStatuses = researchRunStatusSchema.enum;
16217
16225
  var researchQueryStatusSchema = z56.enum(["queued", "running", "completed", "failed"]);
16218
16226
  var ResearchQueryStatuses = researchQueryStatusSchema.enum;
16219
16227
  var DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT = 20;
16228
+ var researchScopeSelectionSchema = z56.object({
16229
+ kind: z56.enum(["market", "property"]),
16230
+ key: measurementV2StableKeySchema,
16231
+ /** Guards a reviewed scope preview from silently using a newer plan revision. */
16232
+ expectedPlanRevision: z56.number().int().positive().optional()
16233
+ }).strict();
16234
+ var researchRunScopeSchema = z56.object({
16235
+ kind: z56.enum(["market", "property"]),
16236
+ key: measurementV2StableKeySchema,
16237
+ label: z56.string().trim().min(1),
16238
+ planRevision: z56.number().int().positive()
16239
+ }).strict();
16240
+ var researchQueryTextSchema = z56.string().min(1).max(4e3).refine((value) => value.trim().length > 0, "Research queries cannot be blank.");
16241
+ function deduplicateResearchQueries(queries) {
16242
+ const seen = /* @__PURE__ */ new Set();
16243
+ return queries.filter((query) => {
16244
+ const key = normalizeQueryText(query);
16245
+ if (!key || seen.has(key)) return false;
16246
+ seen.add(key);
16247
+ return true;
16248
+ });
16249
+ }
16250
+ function researchTemplateBindings(scope) {
16251
+ if (!scope) return {};
16252
+ return scope.kind === "market" ? { market: scope.label, submarket: scope.label } : { property: scope.label, propertyBrand: scope.label };
16253
+ }
16254
+ function expandResearchTemplate(template, scope) {
16255
+ const available = researchTemplateBindings(scope);
16256
+ const unavailable = template.variables.filter((variable) => available[variable] === void 0);
16257
+ if (unavailable.length) throw validationError("The selected research template requires unavailable bindings: " + unavailable.join(", "));
16258
+ const bindings = Object.fromEntries(template.variables.map((variable) => [variable, available[variable]]));
16259
+ return { bindings, output: expandQueryTemplate(template.pattern, bindings) };
16260
+ }
16261
+ var researchTemplateSelectionSchema = z56.object({
16262
+ templateId: z56.string().trim().min(1).max(256),
16263
+ templateVersion: z56.string().trim().min(1).max(256)
16264
+ }).strict();
16220
16265
  var researchRunCreateSchema = z56.object({
16221
- queries: z56.array(z56.string().trim().min(1).max(4e3)).min(1).max(50),
16266
+ queries: z56.array(researchQueryTextSchema).min(1).max(50),
16222
16267
  provider: z56.string().trim().min(1).optional(),
16223
16268
  model: z56.string().trim().min(1).max(200).optional(),
16224
16269
  location: locationContextSchema.nullable().optional(),
16270
+ scope: researchScopeSelectionSchema.optional(),
16271
+ template: researchTemplateSelectionSchema.optional(),
16225
16272
  idempotencyKey: z56.string().trim().min(1).max(128).optional()
16226
16273
  }).superRefine((value, ctx) => {
16227
16274
  if (value.model && !value.provider) ctx.addIssue({ code: z56.ZodIssueCode.custom, path: ["provider"], message: "provider is required when model is supplied" });
@@ -16240,6 +16287,8 @@ var researchRunSummarySchema = z56.object({
16240
16287
  requestedModel: z56.string().nullable(),
16241
16288
  resolvedModel: z56.string(),
16242
16289
  location: locationContextSchema.nullable(),
16290
+ scope: researchRunScopeSchema.nullable().optional(),
16291
+ template: queryTrackingTemplateProvenanceSchema.nullable().optional(),
16243
16292
  totalQueries: z56.number().int(),
16244
16293
  completedQueries: z56.number().int(),
16245
16294
  failedQueries: z56.number().int(),
@@ -16253,6 +16302,7 @@ var researchRunQuerySchema = z56.object({
16253
16302
  id: z56.string(),
16254
16303
  position: z56.number().int(),
16255
16304
  query: z56.string(),
16305
+ queryClass: queryClassSchema.nullable().optional(),
16256
16306
  status: researchQueryStatusSchema,
16257
16307
  requestedModel: z56.string().nullable(),
16258
16308
  resolvedModel: z56.string(),
@@ -17667,6 +17717,7 @@ export {
17667
17717
  visibilityReportRequestSchema,
17668
17718
  visibilityReportQuerySchema,
17669
17719
  visibilityReportResponseSchema,
17720
+ expandQueryTemplate,
17670
17721
  queryTrackingProvenanceSchema,
17671
17722
  queryTrackingPreviewRequestSchema,
17672
17723
  queryTrackingCommitRequestSchema,
@@ -17732,6 +17783,7 @@ export {
17732
17783
  measurementDraftClearAssignmentsRequestSchema,
17733
17784
  measurementDraftClassifyAssignmentsRequestSchema,
17734
17785
  measurementDraftUpsertGroupRequestSchema,
17786
+ measurementDraftUpsertMarketRequestSchema,
17735
17787
  measurementDraftRemoveGroupRequestSchema,
17736
17788
  measurementDraftUpsertCompetitorRequestSchema,
17737
17789
  measurementDraftPinCompetitorRequestSchema,
@@ -18169,6 +18221,8 @@ export {
18169
18221
  ResearchRunStatuses,
18170
18222
  ResearchQueryStatuses,
18171
18223
  DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT,
18224
+ deduplicateResearchQueries,
18225
+ expandResearchTemplate,
18172
18226
  researchRunCreateSchema,
18173
18227
  researchRunDetailSchema,
18174
18228
  researchRunListSchema,